Compare commits

...

65 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
95 changed files with 44257 additions and 42925 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

@ -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个字符
## 编译 ## 编译

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

@ -1166,5 +1166,12 @@
"云存会员": "عضوية التخزين السحابي", "云存会员": "عضوية التخزين السحابي",
"服务,图像视频信息随心存!": "معلومات الخدمة والصور والفيديو في قلبك!", "服务,图像视频信息随心存!": "معلومات الخدمة والصور والفيديو في قلبك!",
"图像": "صورة", "图像": "صورة",
"视频": "فيديو" "视频": "فيديو",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "حاليا ، لا تدعم الدولة تسجيل رمز التحقق من الهاتف المحمول ، يرجى استخدام عنوان بريدك الإلكتروني للتسجيل",
"注:": "ملاحظة:",
"必需在开始时间24小时内使用一次否则将失效": "يجب استخدامه مرة واحدة خلال 24 ساعة من وقت البدء، وإلا سيصبح غير صالح",
"这是单次密码,只能使用一次": "هذا رمز مرور لمرة واحدة فقط، ولا يمكن استخدامه سوى مرة واحدة",
"您好": "مرحبًا",
"您的开门密码是": "رمز فتح الباب الخاص بك هو",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "عند الفتح، قم أولاً بتنشيط لوحة مفاتيح القفل، ثم أدخل الرمز وكلّمه بـ #، ويقع مفتاح # في الزاوية السفلى اليمنى من لوحة المفاتيح وقد يكون مُميّزًا برمز آخر"
} }

View File

@ -1167,5 +1167,12 @@
"云存会员": "Членство в Cloud Storage", "云存会员": "Членство в Cloud Storage",
"服务,图像视频信息随心存!": "Информацията за обслужване, изображения и видео са във вашето сърце!", "服务,图像视频信息随心存!": "Информацията за обслужване, изображения и видео са във вашето сърце!",
"图像": "изображение", "图像": "изображение",
"视频": "Видео" "视频": "Видео",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "В момента страната не поддържа регистрация на код за потвърждение на мобилен телефон, моля, използвайте имейл адреса си, за да се регистрирате",
"注:": "примечание:",
"必需在开始时间24小时内使用一次否则将失效": "Его необходимо использовать один раз в течение 24 часов с момента начала, иначе он будет недействительным.",
"这是单次密码,只能使用一次": "Это однократный пароль, который можно использовать только один раз.",
"您好": "Здравствуйте",
"您的开门密码是": "Ваш пароль",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "При открытии замка сначала активируйте клавиатуру замка, затем введите пароль, чтобы закончить #, # клавиша в правом нижнем углу клавиатуры, возможно, другие значки"
} }

View File

@ -1167,5 +1167,12 @@
"云存会员": "ক্লাউড স্টোরেজ সদস্যতা", "云存会员": "ক্লাউড স্টোরেজ সদস্যতা",
"服务,图像视频信息随心存!": "পরিষেবা, চিত্র এবং ভিডিও তথ্য আপনার হৃদয়ে!", "服务,图像视频信息随心存!": "পরিষেবা, চিত্র এবং ভিডিও তথ্য আপনার হৃদয়ে!",
"图像": "প্রতিচ্ছবি", "图像": "প্রতিচ্ছবি",
"视频": "ভিডিও" "视频": "ভিডিও",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "বর্তমানে, দেশটি মোবাইল ফোন যাচাইকরণ কোড নিবন্ধন সমর্থন করে না, নিবন্ধন করতে দয়া করে আপনার ইমেল ঠিকানা ব্যবহার করুন",
"注:": "নোট:",
"必需在开始时间24小时内使用一次否则将失效": "শুরু করার সময় 24 ঘন্টার মধ্যে একবার ব্যবহার করা প্রয়োজন, অন্যথায় এটি শেষ হবে",
"这是单次密码,只能使用一次": "এটি একক পাসওয়ার্ড, শুধুমাত্র একবার ব্যবহার করা যায়।",
"您好": "হ্যালো!",
"您的开门密码是": "আপনার দরজা খোলার পাসওয়ার্ড",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "লক খোলার সময়, প্রথমে লক কীবোর্ড সক্রিয় করুন, তারপর পাসওয়ার্ড টাইপ করুন, যা # সংখ্যা দিয়ে শেষ হয়, # সংখ্যা কী কীবোর্ডের নিচের"
} }

View File

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

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

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

@ -1167,5 +1167,12 @@
"云存会员": "Συνδρομή Cloud Storage", "云存会员": "Συνδρομή Cloud Storage",
"服务,图像视频信息随心存!": "Οι πληροφορίες εξυπηρέτησης, εικόνας και βίντεο είναι στην καρδιά σας!", "服务,图像视频信息随心存!": "Οι πληροφορίες εξυπηρέτησης, εικόνας και βίντεο είναι στην καρδιά σας!",
"图像": "εικόνα", "图像": "εικόνα",
"视频": "Βίντεο" "视频": "Βίντεο",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Προς το παρόν, η χώρα δεν υποστηρίζει την εγγραφή κωδικού επαλήθευσης κινητού τηλεφώνου, χρησιμοποιήστε τη διεύθυνση email σας για να εγγραφείτε",
"注:": "Σημείωση:",
"必需在开始时间24小时内使用一次否则将失效": "Πρέπει να χρησιμοποιηθεί μία φορά εντός 24 ωρών από την ώρα έναρξης, διαφορετικά θα λήξει",
"这是单次密码,只能使用一次": "Είναι ένας μοναδικός κωδικός πρόσβασης. Μπορεί να χρησιμοποιηθεί μόνο μία φορά.",
"您好": "Γεια σας.",
"您的开门密码是": "Ο κωδικός σας είναι",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Όταν ξεκλειδώσετε, ενεργοποιήστε το πληκτρολόγιο κλειδαριού και πληκτρολογήστε τον κωδικό πρόσβασης, ο οποίος τελειώνει με το νούμερο # και το νούμερο # είναι στην κάτω δεξιά γωνία του πληκτρολόγιου, μπορεί να είναι ένα άλλο εικονίδιο"
} }

View File

@ -1173,5 +1173,12 @@
"云存会员": "Cloud Storage Membership", "云存会员": "Cloud Storage Membership",
"服务,图像视频信息随心存!": "Service, image and video information are at your heart!", "服务,图像视频信息随心存!": "Service, image and video information are at your heart!",
"图像": "image", "图像": "image",
"视频": "Video" "视频": "Video",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Currently, the country does not support mobile phone verification code registration, please use your email address to register",
"注:": "Note:",
"必需在开始时间24小时内使用一次否则将失效": "Must be used once within 24 hours of the start time, otherwise it will expire",
"这是单次密码,只能使用一次": "This is a one-time password and can only be used once",
"您好": "Hello",
"您的开门密码是": "Your door access code is",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "To unlock, first activate the lock keypad, then enter the password and end with #. The # key is located at the bottom right corner of the keypad and may have a different icon"
} }

View File

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

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

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

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

@ -1167,5 +1167,12 @@
"云存会员": "חברות באחסון בענן", "云存会员": "חברות באחסון בענן",
"服务,图像视频信息随心存!": "מידע על שירות, תמונה ווידאו נמצאים בלב שלך!", "服务,图像视频信息随心存!": "מידע על שירות, תמונה ווידאו נמצאים בלב שלך!",
"图像": "תמונה", "图像": "תמונה",
"视频": "וידאו" "视频": "וידאו",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "נכון לעכשיו, המדינה אינה תומכת ברישום קוד אימות טלפון נייד, אנא השתמש בכתובת הדוא\"ל שלך כדי להירשם",
"注:": "הערה:",
"必需在开始时间24小时内使用一次否则将失效": "יש להשתמש בו פעם אחת בתוך 24 שעות מזמן ההתחלה, אחרת הוא יפוג",
"这是单次密码,只能使用一次": "זו סיסמה חד-פעמית שניתן להשתמש בה רק פעם אחת",
"您好": "שלום",
"您的开门密码是": "קוד הפתיחה שלך הוא",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "כדי לבטל את הנעילה, הפעל תחילה את מקלדת המנעול, לאחר מכן הזן את הסיסמה וסיים ב-#. המקש # נמצא בפינה הימנית התחתונה של המקלדת ועשוי להיות סמל אחר"
} }

View File

@ -1167,5 +1167,12 @@
"云存会员": "क्लाउड स्टोरेज सदस्यता", "云存会员": "क्लाउड स्टोरेज सदस्यता",
"服务,图像视频信息随心存!": "सेवा, छवि और वीडियो जानकारी आपके दिल में हैं!", "服务,图像视频信息随心存!": "सेवा, छवि और वीडियो जानकारी आपके दिल में हैं!",
"图像": "प्रतिबिंब", "图像": "प्रतिबिंब",
"视频": "वीडियो" "视频": "वीडियो",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "वर्तमान में, देश मोबाइल फोन सत्यापन कोड पंजीकरण का समर्थन नहीं करता है, कृपया पंजीकरण करने के लिए अपने ईमेल पते का उपयोग करें",
"注:": "नोट:",
"必需在开始时间24小时内使用一次否则将失效": "आरंभ समय के 24 घंटे के भीतर एक बार उपयोग करना आवश्यक है, अन्यथा इसकी समय सीमा समाप्त हो जाएगी",
"这是单次密码,只能使用一次": "यह एकल उपयोग का पासवर्ड है और केवल एक बार उपयोग किया जा सकता है",
"您好": "नमस्ते",
"您的开门密码是": "आपका दरवाज़ा खोलने का कोड है",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "अनलॉक करने के लिए, पहले लॉक कीबोर्ड को सक्रिय करें, फिर पासवर्ड दर्ज करें और # के साथ समाप्त करें। # कुंजी कीबोर्ड के निचले दाएं कोने में है और इसमें कोई अन्य चिह्न हो सकता है"
} }

View File

@ -1043,7 +1043,6 @@
"一键开锁": "一鍵解鎖", "一键开锁": "一鍵解鎖",
"已开通": "打開", "已开通": "打開",
"英文": "English", "英文": "English",
"英文": "English",
"简体中文": "简体中文", "简体中文": "简体中文",
"繁体中文": "繁體中文", "繁体中文": "繁體中文",
"法语": "Français", "法语": "Français",
@ -1168,5 +1167,12 @@
"云存会员": "雲存會員", "云存会员": "雲存會員",
"服务,图像视频信息随心存!": "服務,圖像視頻資訊隨心存!", "服务,图像视频信息随心存!": "服務,圖像視頻資訊隨心存!",
"图像": "圖像", "图像": "圖像",
"视频": "視頻" "视频": "視頻",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "當前國家不支援手機驗證碼註冊,請使用郵箱進行註冊",
"注:": "註:",
"必需在开始时间24小时内使用一次否则将失效": "必須在開始時間24小時內使用一次否則將失效",
"这是单次密码,只能使用一次": "這是單次密碼,只能使用一次",
"您好": "您好",
"您的开门密码是": "您的開門密碼是",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "開鎖時,先啟動鎖鍵盤,再輸入密碼,以#號結束,#號鍵在鍵盤右下角,有可能是其他圖標"
} }

View File

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

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

@ -1173,5 +1173,12 @@
"云存会员": "Cloud Storage Membership", "云存会员": "Cloud Storage Membership",
"服务,图像视频信息随心存!": "Ծառայությունը, պատկերը եւ վիդեո տեղեկատվությունը ձեր սրտում են:", "服务,图像视频信息随心存!": "Ծառայությունը, պատկերը եւ վիդեո տեղեկատվությունը ձեր սրտում են:",
"图像": "Պատկերասրահ", "图像": "Պատկերասրահ",
"视频": "Տեսանյութ" "视频": "Տեսանյութ",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Ներկայումս երկիրը չի աջակցում բջջային հեռախոսի ստուգման կոդի գրանցմանը, խնդրում ենք գրանցվելու համար օգտագործել ձեր էլ. փոստի հասցեն",
"注:": "Նշում՝",
"必需在开始时间24小时内使用一次否则将失效": "Անհրաժեշտ է օգտագործել մեկ անգամ սկսելու ժամանակից 24 ժամվա ընթացքում, հակառակ դեպքում այն կվազվի",
"这是单次密码,只能使用一次": "Սա մեկ անգամյա գաղտնաբառ է եւ կարող է օգտագործվել միայն մեկ անգամ",
"您好": "Ողջույն",
"您的开门密码是": "Ձեր դռան բանալին հետեւյալն է",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Ապակողպելու համար նախ ակտիվացրեք կողպեքի ստեղնաշարը, ապա մուտքագրեք գաղտնաբառը եւ ավարտեք #-ով: #-ի ստեղնը գտնվում է ստեղնաշարի ներքեւի աջ անկյունում եւ կարող է ունենալ այլ պատկերակ"
} }

View File

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

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

@ -1167,5 +1167,12 @@
"云存会员": "クラウドストレージメンバーシップ", "云存会员": "クラウドストレージメンバーシップ",
"服务,图像视频信息随心存!": "サービス、画像、ビデオ情報があなたの中心にあります!", "服务,图像视频信息随心存!": "サービス、画像、ビデオ情報があなたの中心にあります!",
"图像": "画像", "图像": "画像",
"视频": "ビデオ" "视频": "ビデオ",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "現在、この国は携帯電話の認証コード登録をサポートしていませんので、メールアドレスを使用して登録してください",
"注:": "注:",
"必需在开始时间24小时内使用一次否则将失效": "開始時刻から24時間以内に1回使用する必要があり、そうでなければ無効になります",
"这是单次密码,只能使用一次": "これはワンタイムパスワードで、一度だけ使用できます",
"您好": "こんにちは",
"您的开门密码是": "あなたのドアアクセスコードは",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "ロックを解除するには、まずロックキーボードをアクティブにし、次にパスワードを入力し、#で終了します。#キーはキーボードの右下隅にあり、別のアイコンの場合があります"
} }

View File

@ -1173,5 +1173,12 @@
"云存会员": "Cloud Storage წევრობა", "云存会员": "Cloud Storage წევრობა",
"服务,图像视频信息随心存!": "მომსახურება, სურათი და ვიდეო ინფორმაცია თქვენს გულშია!", "服务,图像视频信息随心存!": "მომსახურება, სურათი და ვიდეო ინფორმაცია თქვენს გულშია!",
"图像": "სურათი", "图像": "სურათი",
"视频": "ვიდეო" "视频": "ვიდეო",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "ამჟამად, ქვეყანა არ უჭერს მხარს მობილური ტელეფონის დამადასტურებელი კოდის რეგისტრაციას, გთხოვთ გამოიყენოთ თქვენი ელექტრონული ფოსტის მისამართი რეგისტრაციისთვის",
"注:": "შენიშვნა:",
"必需在开始时间24小时内使用一次否则将失效": "უნდა გამოიყენოთ ერთხელ დაწყების დროიდან 24 საათის განმავლობაში, წინააღმდეგ შემთხვევაში ვადა გაუვა",
"这是单次密码,只能使用一次": "ეს არის ერთჯერადი პაროლი და შეიძლება გამოყენებულ იქნას მხოლოდ ერთხელ",
"您好": "გამარჯობა",
"您的开门密码是": "თქვენი კარის გახსნის კოდი არის",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "განბლოკვისთვის პირველ რიგში გაააქტიურეთ დამკეტის კლავიატურა, შემდეგ შეიყვანეთ პაროლი და დაასრულეთ #. # ღილაკი მდებარეობს კლავიატურის ქვედა მარჯვენა კუთხეში და შეიძლება ჰქონდეს სხვა ხატულა"
} }

View File

@ -1178,5 +1178,12 @@
"云存会员": "云存会员", "云存会员": "云存会员",
"服务,图像视频信息随心存!": "服务,图像视频信息随心存!", "服务,图像视频信息随心存!": "服务,图像视频信息随心存!",
"图像": "图像", "图像": "图像",
"视频": "视频" "视频": "视频",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "当前国家不支持手机验证码注册,请使用邮箱进行注册",
"注:":"注:",
"必需在开始时间24小时内使用一次否则将失效": "必需在开始时间24小时内使用一次否则将失效",
"这是单次密码,只能使用一次": "这是单次密码,只能使用一次",
"您好": "您好",
"您的开门密码是": "您的开门密码是",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标"
} }

View File

@ -1167,5 +1167,12 @@
"云存会员": "Бұлтты сақтауға мүшелік", "云存会员": "Бұлтты сақтауға мүшелік",
"服务,图像视频信息随心存!": "Қызмет, бейне және бейне ақпарат сіздің жүрегіңізде жатыр!", "服务,图像视频信息随心存!": "Қызмет, бейне және бейне ақпарат сіздің жүрегіңізде жатыр!",
"图像": "кескіні", "图像": "кескіні",
"视频": "Бейне" "视频": "Бейне",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Қазіргі уақытта елде ұялы телефонды растау кодын тіркеуді қолдамайды, тіркелу үшін электрондық пошта мекенжайыңызды пайдаланыңыз",
"注:": "Ескерту:",
"必需在开始时间24小时内使用一次否则将失效": "Бастау уақытынан бастап 24 сағат ішінде бір рет қолдану керек, әйтпесе мерзімі аяқталады",
"这是单次密码,只能使用一次": "Бұл бір реттік құпиясөз, оны тек бір рет қолдануға болады",
"您好": "Сәлеметсіз бе",
"您的开门密码是": "Есікті ашу кодыңыз",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Құлыпты ашу үшін алдымен құлып пернетақтасын іске қосыңыз, содан кейін құпиясөзді енгізіп, # арқылы аяқтаңыз. # пернесі пернетақтаның төменгі оң жақ бұрышында орналасқан және басқа белгі болуы мүмкін"
} }

View File

@ -1167,5 +1167,12 @@
"云存会员": "클라우드 스토리지 멤버십", "云存会员": "클라우드 스토리지 멤버십",
"服务,图像视频信息随心存!": "서비스, 이미지 및 비디오 정보가 당신의 중심에 있습니다!", "服务,图像视频信息随心存!": "서비스, 이미지 및 비디오 정보가 당신의 중심에 있습니다!",
"图像": "이미지", "图像": "이미지",
"视频": "비디오" "视频": "비디오",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "현재 해당 국가는 휴대폰 인증코드 등록을 지원하지 않으니 이메일 주소를 사용하여 등록하세요.",
"注:": "참고:",
"必需在开始时间24小时内使用一次否则将失效": "시작 시간으로부터 24시간 이내에 한 번 사용해야 하며, 그렇지 않으면 만료됩니다.",
"这是单次密码,只能使用一次": "이것은 일회용 비밀번호로 한 번만 사용할 수 있습니다.",
"您好": "안녕하세요",
"您的开门密码是": "귀하의 문 열기 코드는",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "잠금을 해제하려면 먼저 잠금 키보드를 활성화한 다음 비밀번호를 입력하고 #로 끝냅니다. # 키는 키보드의 오른쪽 하단 모서리에 있으며 다른 아이콘일 수 있습니다."
} }

View File

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

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

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

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

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

View File

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

View File

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

@ -1171,5 +1171,12 @@
"云存会员": "Членство в облачном хранилище", "云存会员": "Членство в облачном хранилище",
"服务,图像视频信息随心存!": "Сервисная, имиджевая и видеоинформация в Вашем сердце!", "服务,图像视频信息随心存!": "Сервисная, имиджевая и видеоинформация в Вашем сердце!",
"图像": "образ", "图像": "образ",
"视频": "Видео" "视频": "Видео",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "В настоящее время страна не поддерживает регистрацию кода верификации мобильного телефона, пожалуйста, используйте свой адрес электронной почты для регистрации",
"注:": "Примечание:",
"必需在开始时间24小时内使用一次否则将失效": "Должен быть использован один раз в течение 24 часов с момента начала, иначе он истечет",
"这是单次密码,只能使用一次": "Это одноразовый пароль, который можно использовать только один раз",
"您好": "Привет!",
"您的开门密码是": "Ваш код доступа к двери",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Чтобы разблокировать, сначала активируйте клавиатуру замка, затем введите пароль и закончите #. Клавиша # находится в правом нижнем углу клавиатуры и может иметь другой значок"
} }

View File

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

@ -1167,5 +1167,12 @@
"云存会员": "Чланство у облаку за складиштење", "云存会员": "Чланство у облаку за складиштење",
"服务,图像视频信息随心存!": "Сервис , слике и видео информације су у вашем срцу!", "服务,图像视频信息随心存!": "Сервис , слике и видео информације су у вашем срцу!",
"图像": "Слика", "图像": "Слика",
"视频": "Пријава" "视频": "Пријава",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Тренутно , земља не подржава регистрацију кода за верификацију мобилног телефона, молимо вас да користите своју адресу е-поште за регистрацију",
"注:": "Напомена:",
"必需在开始时间24小时内使用一次否则将失效": "Мора се користити једном у року од 24 сата од времена почетка, иначе истиче",
"这是单次密码,只能使用一次": "Ово је једнократна лозинка која се може користити само једном",
"您好": "Здраво",
"您的开门密码是": "Ваш код за отварање врата је",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Да бисте откључали, прво активирајте тастатуру браве, затим унесите лозинку и завршите са #. Тастер # се налази у доњем десном углу тастатуре и може имати другу икону"
} }

View File

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

@ -1167,5 +1167,12 @@
"云存会员": "สมาชิกที่เก็บข้อมูลบนคลาวด์", "云存会员": "สมาชิกที่เก็บข้อมูลบนคลาวด์",
"服务,图像视频信息随心存!": "ข้อมูลบริการ รูปภาพ และวิดีโออยู่ที่หัวใจของคุณ!", "服务,图像视频信息随心存!": "ข้อมูลบริการ รูปภาพ และวิดีโออยู่ที่หัวใจของคุณ!",
"图像": "ภาพ", "图像": "ภาพ",
"视频": "วีดิทัศน์" "视频": "วีดิทัศน์",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "ปัจจุบันประเทศไม่รองรับการลงทะเบียนรหัสยืนยันโทรศัพท์มือถือ โปรดใช้ที่อยู่อีเมลของคุณในการลงทะเบียน",
"注:": "หมายเหตุ:",
"必需在开始时间24小时内使用一次否则将失效": "ต้องใช้ภายใน 24 ชั่วโมงหลังจากเวลาเริ่มต้น มิฉะนั้นจะหมดอายุ",
"这是单次密码,只能使用一次": "นี่คือรหัสผ่านแบบใช้ครั้งเดียวและสามารถใช้ได้เพียงครั้งเดียวเท่านั้น",
"您好": "สวัสดี",
"您的开门密码是": "รหัสการเข้าถึงประตูของคุณคือ",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "ในการปลดล็อค ให้เปิดใช้งานแป้นพิมพ์ล็อคก่อน จากนั้นป้อนรหัสผ่านและจบด้วย # ปุ่ม # อยู่ที่มุมล่างขวาของแป้นพิมพ์และอาจมีไอคอนอื่น"
} }

View File

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

@ -1167,5 +1167,12 @@
"云存会员": "雲存會員", "云存会员": "雲存會員",
"服务,图像视频信息随心存!": "服務,圖像視頻資訊隨心存!", "服务,图像视频信息随心存!": "服務,圖像視頻資訊隨心存!",
"图像": "圖像", "图像": "圖像",
"视频": "視頻" "视频": "視頻",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "當前國家不支援手機驗證碼註冊,請使用郵箱進行註冊",
"注:": "註:",
"必需在开始时间24小时内使用一次否则将失效": "必須在開始時間24小時內使用一次否則將失效",
"这是单次密码,只能使用一次": "這是單次密碼,只能使用一次",
"您好": "您好",
"您的开门密码是": "您的開門密碼是",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "開鎖時,先啟動鎖鍵盤,再輸入密碼,以#號結束,#號鍵在鍵盤右下角,有可能是其他圖標"
} }

View File

@ -1167,5 +1167,12 @@
"云存会员": "Членство в хмарних сховищах", "云存会员": "Членство в хмарних сховищах",
"服务,图像视频信息随心存!": "Сервіс, зображення та відео інформація у вашому серці!", "服务,图像视频信息随心存!": "Сервіс, зображення та відео інформація у вашому серці!",
"图像": "образ", "图像": "образ",
"视频": "Відео" "视频": "Відео",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Наразі країна не підтримує реєстрацію коду підтвердження на мобільному телефоні, будь ласка, використовуйте свою адресу електронної пошти для реєстрації",
"注:": "Примітка:",
"必需在开始时间24小时内使用一次否则将失效": "Потрібно використати один раз протягом 24 годин після початкового часу, інакше термін дії спливе",
"这是单次密码,只能使用一次": "Це одноразовий пароль, який можна використовувати лише один раз",
"您好": "Привіт",
"您的开门密码是": "Ваш код доступу до дверей",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Щоб розблокувати, спочатку активуйте клавіатуру замка, потім введіть пароль і закінчіть #. Клавіша # знаходиться в правому нижньому куті клавіатури та може мати інший значок"
} }

View File

@ -1167,5 +1167,12 @@
"云存会员": "Cloud Storage Membership", "云存会员": "Cloud Storage Membership",
"服务,图像视频信息随心存!": "خدمت، تصویر اور ویڈیو کی معلومات آپ کے دل میں ہیں!", "服务,图像视频信息随心存!": "خدمت، تصویر اور ویڈیو کی معلومات آپ کے دل میں ہیں!",
"图像": "روپ", "图像": "روپ",
"视频": "ویڈیو" "视频": "ویڈیو",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "فی الحال، ملک موبائل فون کی توثیقی کوڈ رجسٹریشن کی حمایت نہیں کرتا ہے، براہ کرم رجسٹر کرنے کے لئے اپنا ای میل ایڈریس استعمال کریں",
"注:": "نوٹ:",
"必需在开始时间24小时内使用一次否则将失效": "وقت آغاز سے 24 گھنٹوں کے اندر ایک بار استعمال کرنا ضروری ہے، ورنہ اس کی میعاد ختم ہو جائے گی",
"这是单次密码,只能使用一次": "یہ ایک بار کا پاس ورڈ ہے اور صرف ایک بار استعمال کیا جا سکتا ہے",
"您好": "ہیلو",
"您的开门密码是": "آپ کا دروازہ کھولنے کا کوڈ ہے",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "غیر مقفل کرنے کے لئے، پہلے لاک کی بورڈ کو چالو کریں، پھر پاس ورڈ درج کریں اور # کے ساتھ ختم کریں۔ # کلید کی بورڈ کے دائیں نچلے کونے میں ہے اور اس میں کوئی اور آئیکن ہو سکتی ہے"
} }

View File

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

@ -1179,5 +1179,12 @@
"云存会员": "云存会员", "云存会员": "云存会员",
"服务,图像视频信息随心存!": "服务,图像视频信息随心存!", "服务,图像视频信息随心存!": "服务,图像视频信息随心存!",
"图像": "图像", "图像": "图像",
"视频": "视频" "视频": "视频",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "当前国家不支持手机验证码注册,请使用邮箱进行注册",
"注:":"注:",
"必需在开始时间24小时内使用一次否则将失效": "必需在开始时间24小时内使用一次否则将失效",
"这是单次密码,只能使用一次": "这是单次密码,只能使用一次",
"您好": "您好",
"您的开门密码是": "您的开门密码是",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标"
} }

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

@ -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;
@ -111,8 +109,7 @@ class BlueManage {
} }
void _initAdapterStateStateSubscription() { void _initAdapterStateStateSubscription() {
_adapterStateStateSubscription ??= _adapterStateStateSubscription ??= FlutterBluePlus.adapterState.listen((BluetoothAdapterState state) {
FlutterBluePlus.adapterState.listen((BluetoothAdapterState state) {
AppLog.log('蓝牙状态:$state'); AppLog.log('蓝牙状态:$state');
_adapterState = state; _adapterState = state;
}); });
@ -122,18 +119,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 {
@ -158,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) {
@ -202,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;
@ -224,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);
} }
} }
@ -233,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);
@ -244,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 {
@ -264,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) {
@ -285,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;
@ -333,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) {
@ -367,8 +326,7 @@ class BlueManage {
} else { } else {
// UUID的第31321 // UUID的第31321
if (cleanUuid.length >= 32) { if (cleanUuid.length >= 32) {
String pairStatus = String pairStatus = cleanUuid.substring(30, 32); // 31321
cleanUuid.substring(30, 32); // 31321
// 00=01= // 00=01=
if (pairStatus == '00') { if (pairStatus == '00') {
return true; // true return true; // true
@ -386,12 +344,11 @@ class BlueManage {
// //
bool hasNewEvent = (byte1 == 1); bool hasNewEvent = (byte1 == 1);
// //
if (isPaired) { if (!isPaired) {
return true; // false return true; // true
} else { } else {
return false; // true return false; // false
} }
} }
// 01trueuuid // 01trueuuid
@ -408,8 +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
@ -428,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');
@ -438,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) { //
_connect(
deviceName,
(BluetoothConnectionState state) {
stateCallBack(bluetoothConnectionState!); stateCallBack(bluetoothConnectionState!);
}, isAddEquipment: isAddEquipment); },
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();
@ -465,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('开始扫描 蓝牙不可用,不能进行蓝牙操作');
} }
@ -482,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',
@ -512,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) {
@ -536,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);
}); });
} }
// //
@ -554,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(
@ -572,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;
} }
@ -592,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: true);
});
} 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');
@ -754,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);
@ -764,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(
@ -801,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;
@ -864,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;
@ -876,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++) {
@ -900,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 {
// //
@ -931,8 +775,7 @@ class BlueManage {
} }
if (!packetSent) { if (!packetSent) {
throw Exception( throw Exception('蓝牙写入失败,数据包 ${i + 1}/${subData.length} 已达到最大重试次数');
'蓝牙写入失败,数据包 ${i + 1}/${subData.length} 已达到最大重试次数');
} }
} }
@ -971,14 +814,12 @@ class BlueManage {
_mtuSize = 20; // MTU为默认值 _mtuSize = 20; // MTU为默认值
if (bluetoothConnectionState == BluetoothConnectionState.connected) { if (bluetoothConnectionState == BluetoothConnectionState.connected) {
AppLog.log('请求断开蓝牙连接');
// //
await bluetoothConnectDevice!.disconnect(timeout: 3); await bluetoothConnectDevice!.disconnect(timeout: 1);
AppLog.log('断开连接成功');
} }
} on Exception catch (e, _) { } on Exception catch (e, _) {
AppLog.log('断开连接失败: $e'); AppLog.log('断开连接失败: $e');
} finally {
bluetoothConnectionState = BluetoothConnectionState.disconnected;
} }
} }

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,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

@ -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;
@ -53,6 +53,8 @@ enum CommandType {
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
@ -245,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;
@ -353,6 +365,12 @@ extension ExtensionCommandType on CommandType {
case CommandType.setLockCurrentVoicePacket: case CommandType.setLockCurrentVoicePacket:
type = 0x30A5; type = 0x30A5;
break; break;
case CommandType.sendAuthorizationCode:
type = 0x30A6;
break;
case CommandType.readRegisterKey:
type = 0x30A7;
break;
default: default:
type = 0x300A; type = 0x300A;
break; break;
@ -492,6 +510,12 @@ extension ExtensionCommandType on CommandType {
case 0x30A5: case 0x30A5:
t = '设置锁当前语音包'; t = '设置锁当前语音包';
break; break;
case 0x30A6:
t = '发送授权码';
break;
case 0x30A7:
t = '读取注册密钥';
break;
default: default:
t = '读星锁状态信息'; t = '读星锁状态信息';
break; break;

View File

@ -16,10 +16,12 @@ 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_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_setVoicePackageFinalResult.dart';
@ -331,6 +333,18 @@ class CommandReciverManager {
SetVoicePackageFinalResultReply.parseData(commandType, data); SetVoicePackageFinalResultReply.parseData(commandType, data);
} }
break; 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;
@ -146,10 +146,8 @@ class SenderBeforeDataManage {
// //
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,19 +195,20 @@ 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;
} }
@ -217,7 +216,7 @@ class SenderBeforeDataManage {
// 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);
}
//
static void readRegisterKey({
required String? lockID,
CommandSendCallBack? callBack,
}) {
CommandSenderManager().managerSendData(
command: SenderReadRegisterKeyCommand(lockID: lockID),
isBeforeAddUser: true, isBeforeAddUser: true,
callBack: callBack); 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

@ -55,8 +55,7 @@ class _StarLockLoginPageState extends State<StarLockLoginPage> {
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,
@ -81,7 +80,7 @@ class _StarLockLoginPageState extends State<StarLockLoginPage> {
], ],
), ),
body: GestureDetector( body: GestureDetector(
onTap: (){ onTap: () {
FocusScope.of(context).unfocus(); FocusScope.of(context).unfocus();
}, },
child: ListView( child: ListView(
@ -89,9 +88,7 @@ class _StarLockLoginPageState extends State<StarLockLoginPage> {
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,
@ -103,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'];
@ -124,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,
@ -149,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,
@ -172,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,
), ),
@ -189,19 +179,15 @@ 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
}); });
@ -210,13 +196,10 @@ class _StarLockLoginPageState extends State<StarLockLoginPage> {
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
}); });
@ -272,45 +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(
@ -351,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,8 +84,7 @@ 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,
@ -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},' +
'请确认后再继续'.tr,
tipTitle: '确认国家或地区'.tr, tipTitle: '确认国家或地区'.tr,
sureStr: '我知道了'.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';
@ -65,7 +68,8 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
_buildBottomAgreement() _buildBottomAgreement()
], ],
), ),
)); ),
);
} }
Widget topSelectCountryAndRegionWidget() { Widget topSelectCountryAndRegionWidget() {
@ -79,7 +83,8 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
width: 340.w, width: 340.w,
height: 60.h, height: 60.h,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(30.h)), border: Border.all(width: 1.0, color: AppColors.greyLineColor)), borderRadius: BorderRadius.all(Radius.circular(30.h)),
border: Border.all(width: 1.0, color: AppColors.greyLineColor)),
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
GestureDetector( GestureDetector(
@ -153,13 +158,16 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
SizedBox(width: 5.w), SizedBox(width: 5.w),
Expanded(child: Text('你所在的国家/地区'.tr, style: TextStyle(fontSize: 26.sp, color: AppColors.blackColor))), Expanded(
child: Text('你所在的国家/地区'.tr, style: TextStyle(fontSize: 26.sp, color: AppColors.blackColor))),
SizedBox(width: 20.w), SizedBox(width: 20.w),
Row( Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[ children: <Widget>[
Text( Text(
state.isIphoneType.value ? '${state.countryName.value} +${state.countryCode.value}' : state.countryName.value, state.isIphoneType.value
? '${state.countryName.value} +${state.countryCode.value}'
: state.countryName.value,
textAlign: TextAlign.end, textAlign: TextAlign.end,
style: TextStyle(fontSize: 26.sp, color: AppColors.blackColor), style: TextStyle(fontSize: 26.sp, color: AppColors.blackColor),
) )
@ -279,9 +287,19 @@ 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(context, Routers.safetyVerificationPage, final Object? result = await Navigator.pushNamed(context, Routers.safetyVerificationPage,
arguments: <String, Object>{'countryCode': state.countryCode, 'account': state.phoneOrEmailStr.value}); arguments: <String, Object>{
'countryCode': state.countryCode,
'account': state.phoneOrEmailStr.value
});
state.xWidth.value = (result! as Map<String, dynamic>)['xWidth']; state.xWidth.value = (result! as Map<String, dynamic>)['xWidth'];
logic.sendValidationCode(); logic.sendValidationCode();
} }
@ -338,7 +356,8 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
child: GestureDetector( child: GestureDetector(
child: Text('${'用户协议'.tr}', style: TextStyle(color: AppColors.mainColor, fontSize: 20.sp)), child: Text('${'用户协议'.tr}', style: TextStyle(color: AppColors.mainColor, fontSize: 20.sp)),
onTap: () { onTap: () {
Get.toNamed(Routers.webviewShowPage, arguments: <String, String>{'url': XSConstantMacro.userAgreementURL, 'title': '用户协议'.tr}); Get.toNamed(Routers.webviewShowPage,
arguments: <String, String>{'url': XSConstantMacro.userAgreementURL, 'title': '用户协议'.tr});
}, },
)), )),
WidgetSpan( WidgetSpan(
@ -346,7 +365,8 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
child: GestureDetector( child: GestureDetector(
child: Text('${'隐私政策'.tr}', style: TextStyle(color: AppColors.mainColor, fontSize: 20.sp)), child: Text('${'隐私政策'.tr}', style: TextStyle(color: AppColors.mainColor, fontSize: 20.sp)),
onTap: () { onTap: () {
Get.toNamed(Routers.webviewShowPage, arguments: <String, String>{'url': XSConstantMacro.privacyPolicyURL, 'title': '隐私政策'.tr}); Get.toNamed(Routers.webviewShowPage,
arguments: <String, String>{'url': XSConstantMacro.privacyPolicyURL, 'title': '隐私政策'.tr});
}, },
)), )),
], ],

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

@ -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 = final FingerprintListDataEntity entity = await ApiRepository.to.getFingerprintsListData(
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

@ -1,3 +1,5 @@
import 'dart:convert';
class ActivateInfoResponse { class ActivateInfoResponse {
ActivateInfoResponse({ ActivateInfoResponse({
this.description, this.description,
@ -9,16 +11,99 @@ class ActivateInfoResponse {
ActivateInfoResponse.fromJson(dynamic json) { ActivateInfoResponse.fromJson(dynamic json) {
description = json['description']; description = json['description'];
errorCode = json['errorCode']; errorCode = json['errorCode'];
// json['data'] List<ActivateInfo> // ActivateInfo
data = json['data'] != null data = json['data'] != null ? ActivateInfo.fromJson(json['data']) : null;
? (json['data'] as List).map((item) => ActivateInfo.fromJson(item)).toList()
: [];
errorMsg = json['errorMsg']; errorMsg = json['errorMsg'];
} }
String? description; String? description;
int? errorCode; int? errorCode;
List<ActivateInfo>? data; // List<ActivateInfo> 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; String? errorMsg;
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
@ -35,33 +120,28 @@ class ActivateInfoResponse {
@override @override
String toString() { String toString() {
return 'ActivateInfoResponse{description: $description, errorCode: $errorCode, data: $data, errorMsg: $errorMsg}'; return 'TppSupportResponse{description: $description, errorCode: $errorCode, data: $data, errorMsg: $errorMsg}';
} }
} }
class ActivateInfo { class TppSupportInfo {
String? platformName;
int? platform; int? platform;
String? platformName;
ActivateInfo({ TppSupportInfo({
this.platformName,
this.platform, this.platform,
this.platformName,
}); });
ActivateInfo.fromJson(dynamic json) { TppSupportInfo.fromJson(dynamic json) {
platformName = json['platformName'] ?? ''; platform = json['platform'] as int? ?? -1;
platform = json['platform'] ?? ''; platformName = json['platform_name'] as String? ?? '';
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final map = <String, dynamic>{}; final map = <String, dynamic>{};
map['platformName'] = platformName;
map['platform'] = platform; map['platform'] = platform;
map['platform_name'] = platformName;
return map; return map;
} }
@override
String toString() {
return 'ActivateInfo{platformName: $platformName, platform: $platform}';
}
} }

View File

@ -54,12 +54,26 @@ class LockDetailLogic extends BaseGetXController {
// //
FunctionBlocker functionBlocker = FunctionBlocker(duration: const Duration(seconds: 2)); FunctionBlocker functionBlocker = FunctionBlocker(duration: const Duration(seconds: 2));
// Timer
Timer? _openDoorReplyDebounceTimer;
//
void _handleOpenDoorReplyWithDebounce(Reply reply) {
// Timer
_openDoorReplyDebounceTimer?.cancel();
// Timer200ms后执行
_openDoorReplyDebounceTimer = Timer(const Duration(milliseconds: 1500), () {
_replyOpenLock(reply);
});
}
// //
void initReplySubscription() { void initReplySubscription() {
state.replySubscription = EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async { state.replySubscription = EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
// //
if (reply is OpenDoorReply) { if (reply is OpenDoorReply) {
_replyOpenLock(reply); _handleOpenDoorReplyWithDebounce(reply);
} }
// //
@ -143,7 +157,7 @@ class LockDetailLogic extends BaseGetXController {
await uploadElectricQuantityRequest(); await uploadElectricQuantityRequest();
resetOpenDoorState(); resetOpenDoorState();
state.animationController!.stop(); state.animationController?.stop();
// //
AppLog.log('开锁成功,开始同步所记录:getLockRecordLastUploadDataTime'); AppLog.log('开锁成功,开始同步所记录:getLockRecordLastUploadDataTime');
@ -165,6 +179,7 @@ class LockDetailLogic extends BaseGetXController {
} }
_handleSynchronizeUploadLockData(); _handleSynchronizeUploadLockData();
break; break;
case 0x06: case 0x06:
// //
@ -339,7 +354,7 @@ class LockDetailLogic extends BaseGetXController {
// //
void openDoorError() { void openDoorError() {
resetOpenDoorState(); resetOpenDoorState();
state.animationController!.stop(); state.animationController?.stop();
blueManageDisconnect(); blueManageDisconnect();
} }
@ -348,7 +363,7 @@ class LockDetailLogic extends BaseGetXController {
state.openLockBtnState.value = 0; state.openLockBtnState.value = 0;
// state.openDoorBtnisUneable.value = true; // state.openDoorBtnisUneable.value = true;
if (state.animationController != null) { if (state.animationController != null) {
state.animationController!.stop(canceled: true); state.animationController?.stop(canceled: true);
} }
cancelBlueConnetctToastTimer(); cancelBlueConnetctToastTimer();
} }
@ -643,6 +658,7 @@ class LockDetailLogic extends BaseGetXController {
if (list.isEmpty) { if (list.isEmpty) {
return; return;
} }
AppLog.log('list:${list}');
final KeyOperationRecordEntity entity = final KeyOperationRecordEntity entity =
await ApiRepository.to.lockRecordUploadData(lockId: state.keyInfos.value.lockId.toString(), records: list); await ApiRepository.to.lockRecordUploadData(lockId: state.keyInfos.value.lockId.toString(), records: list);
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
@ -928,7 +944,9 @@ class LockDetailLogic extends BaseGetXController {
} }
void _handleGetLockPasswordData() { void _handleGetLockPasswordData() {
BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async { BlueManage().blueSendData(
BlueManage().connectDeviceName,
(BluetoothConnectionState connectionState) async {
if (connectionState == BluetoothConnectionState.connected) { if (connectionState == BluetoothConnectionState.connected) {
final List<String>? 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!);
@ -949,7 +967,8 @@ class LockDetailLogic extends BaseGetXController {
signKey: signKeyDataList, signKey: signKeyDataList,
privateKey: getPrivateKeyList); privateKey: getPrivateKeyList);
} }
}); },
);
} }
// //
@ -963,7 +982,7 @@ class LockDetailLogic extends BaseGetXController {
// 10 // 10
state.uploadPasswordPage = state.uploadPasswordPage + 1; state.uploadPasswordPage = state.uploadPasswordPage + 1;
final List<int> token = reply.data.sublist(3, 7); final List<int> token = reply.data.sublist(3, 7);
showEasyLoading();
BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async { BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async {
if (connectionState == BluetoothConnectionState.connected) { if (connectionState == BluetoothConnectionState.connected) {
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey); final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
@ -1067,7 +1086,6 @@ class LockDetailLogic extends BaseGetXController {
final List<int> token = reply.data.sublist(3, 7); final List<int> token = reply.data.sublist(3, 7);
showEasyLoading();
BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async { BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async {
if (connectionState == BluetoothConnectionState.connected) { if (connectionState == BluetoothConnectionState.connected) {
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey); final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
@ -1171,7 +1189,6 @@ class LockDetailLogic extends BaseGetXController {
final List<int> token = reply.data.sublist(3, 7); final List<int> token = reply.data.sublist(3, 7);
showEasyLoading();
BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async { BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async {
if (connectionState == BluetoothConnectionState.connected) { if (connectionState == BluetoothConnectionState.connected) {
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey); final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
@ -1325,7 +1342,6 @@ class LockDetailLogic extends BaseGetXController {
final List<int> token = reply.data.sublist(3, 7); final List<int> token = reply.data.sublist(3, 7);
showEasyLoading();
BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async { BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async {
if (connectionState == BluetoothConnectionState.connected) { if (connectionState == BluetoothConnectionState.connected) {
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey); final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
@ -1402,7 +1418,6 @@ class LockDetailLogic extends BaseGetXController {
final List<int> token = reply.data.sublist(3, 7); final List<int> token = reply.data.sublist(3, 7);
showEasyLoading();
BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async { BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async {
if (connectionState == BluetoothConnectionState.connected) { if (connectionState == BluetoothConnectionState.connected) {
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey); final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
@ -1479,7 +1494,6 @@ class LockDetailLogic extends BaseGetXController {
final List<int> token = reply.data.sublist(3, 7); final List<int> token = reply.data.sublist(3, 7);
showEasyLoading();
BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async { BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async {
if (connectionState == BluetoothConnectionState.connected) { if (connectionState == BluetoothConnectionState.connected) {
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey); final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
@ -1503,6 +1517,8 @@ class LockDetailLogic extends BaseGetXController {
} else { } else {
state.indexCount.value = state.indexCount.value + 1; state.indexCount.value = state.indexCount.value + 1;
_lockDataUpload(uploadType: 2, recordType: 7, records: state.uploadRemoteControlDataList); _lockDataUpload(uploadType: 2, recordType: 7, records: state.uploadRemoteControlDataList);
AppLog.log('需要执行断开操作');
BlueManage().disconnect();
} }
break; break;
case 0x06: case 0x06:

View File

@ -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,17 +178,14 @@ 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( BoxShadow(
color: Colors.black.withOpacity(0.15), color: Colors.black.withOpacity(0.15),
offset: const Offset(0, 0), offset: const Offset(0, 0),
@ -247,15 +221,11 @@ 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,
borderRadius: BorderRadius.circular(16.r),
boxShadow: <BoxShadow>[
BoxShadow( BoxShadow(
color: Colors.black.withOpacity(0.15), color: Colors.black.withOpacity(0.15),
offset: const Offset(0, 0), offset: const Offset(0, 0),
@ -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({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,
), ),
), ),
); );
} }
//
Widget buildRotationTransition(
{required double width, required double 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

@ -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, allHeight: 70.h,
isHaveLine: true), 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

@ -553,6 +553,19 @@ class _LockSetPageState extends State<LockSetPage>
}); });
}, },
), ),
//
CommonItem(
leftTitel: 'AI助理'.tr,
rightTitle: '',
isHaveLine: true,
isHaveDirection: true,
action: () {
Get.toNamed(Routers.aiAssistant,
arguments: <String, LockSetInfoData>{
'lockSetInfoData': state.lockSetInfoData.value
});
},
),
// 广使 // 广使
/* 2024-01-12 广 by DaisyWu /* 2024-01-12 广 by DaisyWu
Obx(() => Visibility( Obx(() => Visibility(

View File

@ -26,8 +26,7 @@ class LockTimeLogic 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 TimingReply) { if (reply is TimingReply) {
_replyTiming(reply); _replyTiming(reply);
} }
@ -50,10 +49,8 @@ class LockTimeLogic extends BaseGetXController {
// //
final List<int> indate = reply.data.sublist(150, 154); final List<int> indate = reply.data.sublist(150, 154);
int indateValue = (0xff & indate[0]) << 24 | int indateValue =
(0xff & indate[1]) << 16 | (0xff & indate[0]) << 24 | (0xff & indate[1]) << 16 | (0xff & indate[2]) << 8 | (0xFF & indate[3]);
(0xff & indate[2]) << 8 |
(0xFF & indate[3]);
// //
if (indateValue == 0xffffffff || indateValue <= 0) { if (indateValue == 0xffffffff || indateValue <= 0) {
// 使 // 使
@ -62,23 +59,19 @@ class LockTimeLogic extends BaseGetXController {
} }
// 20002100 // 20002100
final DateTime dateTime = final DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(indateValue * 1000);
DateTime.fromMillisecondsSinceEpoch(indateValue * 1000);
if (dateTime.year < 2000 || dateTime.year > 2100) { if (dateTime.year < 2000 || dateTime.year > 2100) {
AppLog.log('时间戳超出合理范围: $indateValue'); AppLog.log('时间戳超出合理范围: $indateValue');
indateValue = DateTime.now().millisecondsSinceEpoch ~/ 1000; indateValue = DateTime.now().millisecondsSinceEpoch ~/ 1000;
} }
AppLog.log( AppLog.log('====================indate:$indate indateValue:$indateValue');
'====================indate:$indate indateValue:$indateValue');
state.dateTime.value = DateTool().dateToYMDHNString('$indateValue'); state.dateTime.value = DateTool().dateToYMDHNString('$indateValue');
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!);
IoSenderManage.senderGetStarLockStatuInfo( IoSenderManage.senderGetStarLockStatuInfo(
lockID: BlueManage().connectDeviceName, lockID: BlueManage().connectDeviceName,
@ -101,8 +94,7 @@ class LockTimeLogic extends BaseGetXController {
switch (status) { switch (status) {
case 0x00: case 0x00:
// //
final String dataEime = final String dataEime = DateTool().dateToYMDHNString('${state.serverTime}');
DateTool().dateToYMDHNString('${state.serverTime}');
state.dateTime.value = dataEime; state.dateTime.value = dataEime;
@ -149,19 +141,15 @@ class LockTimeLogic extends BaseGetXController {
dismissEasyLoading(); dismissEasyLoading();
state.sureBtnState.value = 0; state.sureBtnState.value = 0;
}); });
BlueManage().blueSendData(BlueManage().connectDeviceName, BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async {
(BluetoothConnectionState connectionState) async {
if (connectionState == BluetoothConnectionState.connected) { if (connectionState == BluetoothConnectionState.connected) {
final List<String>? privateKey = final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
await Storage.getStringList(saveBluePrivateKey); final List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
final List<int> getPrivateKeyList =
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!);
final List<String>? signKey = final List<String>? signKey = await Storage.getStringList(saveBlueSignKey);
await Storage.getStringList(saveBlueSignKey);
final List<int> getSignKeyList = changeStringListToIntList(signKey!); final List<int> getSignKeyList = changeStringListToIntList(signKey!);
IoSenderManage.senderTimingCommand( IoSenderManage.senderTimingCommand(
@ -190,13 +178,10 @@ class LockTimeLogic extends BaseGetXController {
showBlueConnetctToastTimer(action: () { showBlueConnetctToastTimer(action: () {
dismissEasyLoading(); dismissEasyLoading();
}); });
BlueManage().blueSendData(BlueManage().connectDeviceName, BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState deviceConnectionState) async {
(BluetoothConnectionState deviceConnectionState) async {
if (deviceConnectionState == BluetoothConnectionState.connected) { if (deviceConnectionState == BluetoothConnectionState.connected) {
final List<String>? privateKey = final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
await Storage.getStringList(saveBluePrivateKey); final List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
final List<int> getPrivateKeyList =
changeStringListToIntList(privateKey!);
IoSenderManage.senderGetStarLockStatuInfo( IoSenderManage.senderGetStarLockStatuInfo(
lockID: BlueManage().connectDeviceName, lockID: BlueManage().connectDeviceName,
@ -206,8 +191,7 @@ class LockTimeLogic extends BaseGetXController {
isBeforeAddUser: false, isBeforeAddUser: false,
privateKey: getPrivateKeyList, privateKey: getPrivateKeyList,
); );
} else if (deviceConnectionState == } else if (deviceConnectionState == BluetoothConnectionState.disconnected) {
BluetoothConnectionState.disconnected) {
dismissEasyLoading(); dismissEasyLoading();
cancelBlueConnetctToastTimer(); cancelBlueConnetctToastTimer();
// if (state.ifCurrentScreen.value == true) { // if (state.ifCurrentScreen.value == true) {
@ -219,8 +203,7 @@ class LockTimeLogic extends BaseGetXController {
// //
Future<void> getLockTimeFromGateway() async { Future<void> getLockTimeFromGateway() async {
final GetServerDatetimeEntity entity = final GetServerDatetimeEntity entity = await ApiRepository.to.getLockTimeFromGateway(
await ApiRepository.to.getLockTimeFromGateway(
lockId: state.lockSetInfoData.value.lockId.toString(), lockId: state.lockSetInfoData.value.lockId.toString(),
); );
if (entity.errorCode!.codeIsSuccessful) {} if (entity.errorCode!.codeIsSuccessful) {}
@ -228,10 +211,10 @@ class LockTimeLogic extends BaseGetXController {
// //
Future<void> getServerDatetime(bool isSendTime) async { Future<void> getServerDatetime(bool isSendTime) async {
final GetServerDatetimeEntity entity = final GetServerDatetimeEntity entity = await ApiRepository.to.getServerDatetimeData(isUnShowLoading: false);
await ApiRepository.to.getServerDatetimeData(isUnShowLoading: false);
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
state.serverTime = entity.data!.date! ~/ 1000; state.serverTime = entity.data!.date! ~/ 1000;
AppLog.log('msg:${state.serverTime}');
// AppLog.log("entity.data!.date! ~/ 1000:${entity.data!.date! ~/ 1000} DateTime.now().millisecondsSinceEpoch ~/ 1000:${DateTime.now().millisecondsSinceEpoch ~/ 1000} 服务器时间差:${state.differentialTime}"); // AppLog.log("entity.data!.date! ~/ 1000:${entity.data!.date! ~/ 1000} DateTime.now().millisecondsSinceEpoch ~/ 1000:${DateTime.now().millisecondsSinceEpoch ~/ 1000} 服务器时间差:${state.differentialTime}");
if (isSendTime == false) { if (isSendTime == false) {
getStarLockStatus(); getStarLockStatus();

View File

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

View File

@ -1,40 +1,317 @@
import 'dart:async';
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/app_settings/app_settings.dart';
import 'package:star_lock/blue/blue_manage.dart';
import 'package:star_lock/blue/io_protocol/io_getStarLockStatusInfo.dart';
import 'package:star_lock/blue/io_protocol/io_readRegisterKey.dart';
import 'package:star_lock/blue/io_protocol/io_sendAuthorizationCode.dart';
import 'package:star_lock/blue/io_reply.dart';
import 'package:star_lock/blue/io_tool/io_tool.dart';
import 'package:star_lock/blue/io_tool/manager_event_bus.dart';
import 'package:star_lock/blue/sender_manage.dart';
import 'package:star_lock/main/lockDetail/lockSet/lockTime/getServerDatetime_entity.dart';
import 'package:star_lock/main/lockDetail/lockSet/thirdPartyPlatform/third_party_platform_state.dart'; import 'package:star_lock/main/lockDetail/lockSet/thirdPartyPlatform/third_party_platform_state.dart';
import 'package:star_lock/network/api_repository.dart'; import 'package:star_lock/network/api_repository.dart';
import 'package:star_lock/network/start_company_api.dart'; import 'package:star_lock/network/start_company_api.dart';
import 'package:star_lock/tools/baseGetXController.dart'; import 'package:star_lock/tools/baseGetXController.dart';
import 'package:star_lock/tools/storage.dart';
class ThirdPartyPlatformLogic extends BaseGetXController { class ThirdPartyPlatformLogic extends BaseGetXController {
ThirdPartyPlatformState state = ThirdPartyPlatformState(); ThirdPartyPlatformState state = ThirdPartyPlatformState();
void savePlatFormSetting() { //
// showEasyLoading(); StreamSubscription<Reply>? _replySubscription;
showToast('功能待开放'.tr);
// dismissEasyLoading();
}
/// TPP支持
void getActivateInfo() async {
final model = state.lockSetInfoData.value.lockBasicInfo?.model;
if (model != null && model != '') {
final response = await StartCompanyApi.to.getActivateInfo(model: model);
if (response.errorCode!.codeIsSuccessful) {
AppLog.log('${response.data}');
}
}
}
@override @override
void onReady() async { void onReady() async {
// TODO: implement onReady
super.onReady(); super.onReady();
getActivateInfo(); await getActivateInfo();
_initReplySubscription();
await getServerDatetime();
showEasyLoading();
showBlueConnetctToastTimer(action: () {
dismissEasyLoading();
});
BlueManage().blueSendData(
BlueManage().connectDeviceName,
(BluetoothConnectionState connectionState) async {
if (connectionState == BluetoothConnectionState.connected) {
IoSenderManage.readRegisterKey(
lockID: BlueManage().connectDeviceName,
);
} else if (connectionState == BluetoothConnectionState.disconnected) {
dismissEasyLoading();
cancelBlueConnetctToastTimer();
}
},
);
} }
@override @override
void dispose() { void dispose() {
dismissEasyLoading(); dismissEasyLoading();
//
_replySubscription?.cancel();
_replySubscription = null;
//
AppLog.log('ThirdPartyPlatformLogic disposed, subscription cancelled');
super.dispose(); super.dispose();
} }
@override
void onClose() {
super.onClose();
//
_replySubscription?.cancel();
_replySubscription = null;
}
//
Future<void> getServerDatetime() async {
final GetServerDatetimeEntity entity = await ApiRepository.to.getServerDatetimeData(isUnShowLoading: true);
if (entity.errorCode!.codeIsSuccessful) {
state.serverTime = entity.data!.date! ~/ 1000;
state.differentialTime = entity.data!.date! ~/ 1000 - DateTime.now().millisecondsSinceEpoch ~/ 1000;
}
}
int getUTCNetTime() {
return DateTime.now().millisecondsSinceEpoch ~/ 1000 + state.differentialTime;
}
void _initReplySubscription() {
//
if (_replySubscription != null) {
AppLog.log('订阅已存在,避免重复初始化');
return;
}
_replySubscription = EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
if (reply is SenderReadRegisterKeyCommandReply) {
_handleReadRegisterKeyReply(reply);
}
if (reply is GetStarLockStatuInfoReply) {
_replyGetStarLockStatusInfo(reply);
}
if (reply is SenderAuthorizationCodeCommandReply) {
_handleAuthorizationCodeReply(reply);
}
});
AppLog.log('创建新订阅:${_replySubscription.hashCode}');
}
//
Future<void> _replyGetStarLockStatusInfo(Reply reply) async {
final int status = reply.data[2];
switch (status) {
case 0x00:
//
dismissEasyLoading();
cancelBlueConnetctToastTimer();
//
// AppLog.log('获取锁状态成功');
//
int index = 3;
final List<int> vendor = reply.data.sublist(index, index + 20);
final String vendorStr = utf8String(vendor);
state.lockInfo['vendor'] = vendorStr;
// state.lockInfo["vendor"] = "XL";
index = index + 20;
// AppLog.log('厂商名称 vendorStr:$vendorStr');
//
final int product = reply.data[index];
state.lockInfo['product'] = product;
index = index + 1;
// AppLog.log('锁设备类型 product:$product');
//
final List<int> model = reply.data.sublist(index, index + 20);
final String modelStr = utf8String(model);
state.lockInfo['model'] = modelStr;
// state.lockInfo["model"] = "JL-BLE-01";
index = index + 20;
// AppLog.log('产品名称 mmodelStr:$modelStr');
//
final List<int> fwVersion = reply.data.sublist(index, index + 20);
final String fwVersionStr = utf8String(fwVersion);
state.lockInfo['fwVersion'] = fwVersionStr;
index = index + 20;
// AppLog.log('软件版本 fwVersionStr:$fwVersionStr');
//
final List<int> hwVersion = reply.data.sublist(index, index + 20);
final String hwVersionStr = utf8String(hwVersion);
state.lockInfo['hwVersion'] = hwVersionStr;
index = index + 20;
// AppLog.log('硬件版本 hwVersionStr:$hwVersionStr');
//
final List<int> serialNum0 = reply.data.sublist(index, index + 16);
final String serialNum0Str = utf8String(serialNum0);
state.lockInfo['serialNum0'] = serialNum0Str;
// state.lockInfo["serialNum0"] = "${DateTime.now().millisecondsSinceEpoch ~/ 10}";
index = index + 16;
// AppLog.log('厂商序列号 serialNum0Str:$serialNum0Str');
final response = await StartCompanyApi.to.getAuthorizationCode(
registerKey: state.registerKey.value,
model: modelStr,
serialNum0: serialNum0Str,
platform: 1,
);
if (response.errorCode!.codeIsSuccessful) {
BlueManage().blueSendData(
BlueManage().connectDeviceName,
(BluetoothConnectionState connectionState) async {
if (connectionState == BluetoothConnectionState.connected) {
IoSenderManage.sendAuthorizationCode(
lockID: BlueManage().connectDeviceName,
uuid: response.data?.extraParams?['uuid'],
key: response.data?.authCode,
mac: response.data?.extraParams?['mac'],
platform: state.selectPlatFormIndex.value,
utcTimeStamp: getUTCNetTime(),
);
} else if (connectionState == BluetoothConnectionState.disconnected) {
dismissEasyLoading();
cancelBlueConnetctToastTimer();
}
},
isAddEquipment: true,
);
}
break;
case 0x06:
//
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
final List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
IoSenderManage.senderGetStarLockStatuInfo(
lockID: BlueManage().connectDeviceName,
userID: await Storage.getUid(),
utcTimeStamp: 0,
unixTimeStamp: 0,
isBeforeAddUser: false,
privateKey: getPrivateKeyList,
);
break;
default:
//
break;
}
}
void savePlatFormSetting() {
if (state.selectPlatFormIndex.value == 1 || state.selectPlatFormIndex.value == 0) {
if (state.registerKey.isNotEmpty) {
_requestAuthorizationCode();
}
} else {
showToast('目前只支持切换至涂鸦智能、锁通通协议'.tr);
}
}
/// TPP支持
Future<void> getActivateInfo() async {
final model = state.lockSetInfoData.value.lockBasicInfo?.model;
if (model != null && model != '') {
final response = await StartCompanyApi.to.getTppSupport(model: model);
if (response.errorCode!.codeIsSuccessful) {
response.data?.forEach((element) {
state.tppSupportList.add(element);
});
state.tppSupportList.refresh();
}
}
}
void _handleReadRegisterKeyReply(SenderReadRegisterKeyCommandReply reply) {
final int status = reply.data[6];
switch (status) {
case 0x00:
final platform = reply.data[7];
// RegisterKey (740)
final List<int> registerKeyBytes = reply.data.sublist(8, 48);
final String registerKey = String.fromCharCodes(registerKeyBytes);
state.selectPlatFormIndex.value = platform;
print('platform: $platform');
print('Register Key: $registerKey');
state.registerKey.value = registerKey;
//
cancelBlueConnetctToastTimer();
dismissEasyLoading();
break;
default:
//
dismissEasyLoading();
cancelBlueConnetctToastTimer();
break;
}
}
void _requestAuthorizationCode() async {
showEasyLoading();
showBlueConnetctToastTimer(action: () {
dismissEasyLoading();
});
BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState deviceConnectionState) async {
if (deviceConnectionState == BluetoothConnectionState.connected) {
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
final List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
IoSenderManage.senderGetStarLockStatuInfo(
lockID: BlueManage().connectDeviceName,
userID: await Storage.getUid(),
utcTimeStamp: state.serverTime,
unixTimeStamp: getLocalTime2(),
isBeforeAddUser: false,
privateKey: getPrivateKeyList,
);
} else if (deviceConnectionState == BluetoothConnectionState.disconnected) {
//
dismissEasyLoading();
cancelBlueConnetctToastTimer();
}
});
}
int getLocalTime() {
final DateTime now = DateTime.now();
final Duration timeZoneOffset = now.timeZoneOffset;
return state.differentialTime + timeZoneOffset.inSeconds;
}
int getLocalTime2() {
final DateTime now = DateTime.now();
final Duration timeZoneOffset = now.timeZoneOffset;
return state.serverTime + timeZoneOffset.inSeconds;
}
void _handleAuthorizationCodeReply(SenderAuthorizationCodeCommandReply reply) {
final int status = reply.data[6];
switch (status) {
case 0x00:
//
cancelBlueConnetctToastTimer();
dismissEasyLoading();
if (state.selectPlatFormIndex.value == 1) {
showSuccess('操作成功,请尽快用"涂鸦”APP配置如不使用请关闭该设置支持'.tr);
} else if (state.selectPlatFormIndex.value == 0) {
showSuccess('操作成功'.tr);
}
break;
default:
//
dismissEasyLoading();
cancelBlueConnetctToastTimer();
break;
}
}
} }

View File

@ -17,8 +17,7 @@ class ThirdPartyPlatformPage extends StatefulWidget {
class _ThirdPartyPlatformPageState extends State<ThirdPartyPlatformPage> { class _ThirdPartyPlatformPageState extends State<ThirdPartyPlatformPage> {
final ThirdPartyPlatformLogic logic = Get.put(ThirdPartyPlatformLogic()); final ThirdPartyPlatformLogic logic = Get.put(ThirdPartyPlatformLogic());
final ThirdPartyPlatformState state = final ThirdPartyPlatformState state = Get.find<ThirdPartyPlatformLogic>().state;
Get.find<ThirdPartyPlatformLogic>().state;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -46,7 +45,75 @@ class _ThirdPartyPlatformPageState extends State<ThirdPartyPlatformPage> {
} }
Widget _buildBody() { Widget _buildBody() {
return ListView.builder( return SingleChildScrollView(
child: Container(
decoration: BoxDecoration(
color: Colors.white,
),
constraints: BoxConstraints(
minHeight: MediaQuery.of(context).size.height - 100.h,
),
child: Stack(
children: [
// 1.
Container(
color: Colors.white,
padding: EdgeInsets.all(16.w),
),
Positioned(
top: 30.h,
left: 50.w,
child: Image.asset(
'images/other/tuya.png',
height: 80.h,
fit: BoxFit.cover,
),
),
Positioned(
top: 130.h,
left: 150.w,
right: 150.w,
child: Image.asset(
'images/other/2.png',
height: 220.h,
fit: BoxFit.contain,
),
),
// 2. 使 Row
Positioned(
top: 400.h,
right: 50.w,
child: Column(
children: [
Image.asset(
'images/other/matter.png',
width: 280.w,
fit: BoxFit.contain,
),
],
),
),
Positioned(
top: 530.h,
left: 20.w,
right: 20.w,
child: Text(
'第三方协议的支持依赖网络授权下载,打开功能开关时请保证手机数据网络的正常连接'.tr,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20.sp,
color: Colors.grey,
fontWeight: FontWeight.w500,
),
),
),
Positioned(
left: 0,
right: 0,
top: 620.h,
bottom: 0,
child: ListView.builder(
itemCount: state.platFormSet.length, itemCount: state.platFormSet.length,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
// itemCount - 1 // itemCount - 1
@ -61,12 +128,12 @@ class _ThirdPartyPlatformPageState extends State<ThirdPartyPlatformPage> {
// 线 // 线
isHaveDirection: false, isHaveDirection: false,
isHaveRightWidget: true, isHaveRightWidget: true,
rightWidget: Radio<String>( rightWidget: Obx(
() => Radio<String>(
// Radio 使 id // Radio 使 id
value: platform, value: platform,
// selectPlatFormIndex id // selectPlatFormIndex id
groupValue: groupValue: state.platFormSet.value[state.selectPlatFormIndex.value],
state.platFormSet.value[state.selectPlatFormIndex.value],
// //
activeColor: AppColors.mainColor, activeColor: AppColors.mainColor,
// Radio // Radio
@ -74,8 +141,7 @@ class _ThirdPartyPlatformPageState extends State<ThirdPartyPlatformPage> {
if (value != null) { if (value != null) {
setState(() { setState(() {
// id // id
final newIndex = final newIndex = state.platFormSet.value.indexWhere((p) => p == value);
state.platFormSet.value.indexWhere((p) => p == value);
if (newIndex != -1) { if (newIndex != -1) {
state.selectPlatFormIndex.value = newIndex; state.selectPlatFormIndex.value = newIndex;
} }
@ -83,6 +149,7 @@ class _ThirdPartyPlatformPageState extends State<ThirdPartyPlatformPage> {
} }
}, },
), ),
),
action: () { action: () {
setState(() { setState(() {
state.selectPlatFormIndex.value = index; state.selectPlatFormIndex.value = index;
@ -92,6 +159,11 @@ class _ThirdPartyPlatformPageState extends State<ThirdPartyPlatformPage> {
}, },
shrinkWrap: true, shrinkWrap: true,
physics: const AlwaysScrollableScrollPhysics(), physics: const AlwaysScrollableScrollPhysics(),
),
),
],
),
),
); );
} }
} }

View File

@ -1,6 +1,8 @@
import 'dart:ui'; import 'dart:ui';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:get/get_rx/get_rx.dart';
import 'package:star_lock/main/lockDetail/lockDetail/ActivateInfoResponse.dart';
import 'package:star_lock/main/lockDetail/lockSet/lockSet/lockSetInfo_entity.dart'; import 'package:star_lock/main/lockDetail/lockSet/lockSet/lockSetInfo_entity.dart';
import 'package:star_lock/translations/app_dept.dart'; import 'package:star_lock/translations/app_dept.dart';
@ -11,15 +13,23 @@ class ThirdPartyPlatformState {
} }
Rx<LockSetInfoData> lockSetInfoData = LockSetInfoData().obs; Rx<LockSetInfoData> lockSetInfoData = LockSetInfoData().obs;
int differentialTime = 0; // UTC+0
// UI // UI
final RxList<String> platFormSet = List.of({ final RxList<String> platFormSet = List.of({
'锁通通'.tr, '锁通通'.tr,
'涂鸦智能'.tr, '涂鸦智能'.tr,
'Matter'.tr , 'Matter'.tr,
}).obs; }).obs;
// UI
final RxList<TppSupportInfo> tppSupportList = RxList<TppSupportInfo>([]);
RxInt selectPlatFormIndex = 0.obs; RxInt selectPlatFormIndex = 0.obs;
RxBool openNumber = false.obs;
RxString registerKey = ''.obs;
Map lockInfo = {};
int serverTime = 0; // UTC+0
} }

View File

@ -79,7 +79,7 @@ class UploadDataLogic extends BaseGetXController {
final int dataLength = reply.data[8]; final int dataLength = reply.data[8];
state.uploadPasswordDataList.addAll(reply.data.sublist(9, reply.data.length)); state.uploadPasswordDataList.addAll(reply.data.sublist(9, reply.data.length));
if (dataLength == 10) { if (dataLength == 10 || dataLength == 9) {
// 10 // 10
state.uploadPasswordPage = state.uploadPasswordPage + 1; state.uploadPasswordPage = state.uploadPasswordPage + 1;
@ -128,7 +128,7 @@ class UploadDataLogic extends BaseGetXController {
final int dataLength = reply.data[8]; final int dataLength = reply.data[8];
state.uploadCardDataList.addAll(reply.data.sublist(9, reply.data.length)); state.uploadCardDataList.addAll(reply.data.sublist(9, reply.data.length));
if (dataLength == 10) { if (dataLength == 10 || dataLength == 9) {
// 10 // 10
state.uploadCardPage = state.uploadCardPage + 1; state.uploadCardPage = state.uploadCardPage + 1;
@ -175,7 +175,7 @@ class UploadDataLogic extends BaseGetXController {
final int dataLength = reply.data[8]; final int dataLength = reply.data[8];
state.uploadFingerprintDataList.addAll(reply.data.sublist(9, reply.data.length)); state.uploadFingerprintDataList.addAll(reply.data.sublist(9, reply.data.length));
if (dataLength == 10) { if (dataLength == 10 || dataLength == 9) {
// 10 // 10
state.uploadFingerprintPage = state.uploadFingerprintPage + 1; state.uploadFingerprintPage = state.uploadFingerprintPage + 1;
@ -222,7 +222,7 @@ class UploadDataLogic extends BaseGetXController {
final int dataLength = reply.data[8]; final int dataLength = reply.data[8];
state.uploadFaceDataList.addAll(reply.data.sublist(9, reply.data.length)); state.uploadFaceDataList.addAll(reply.data.sublist(9, reply.data.length));
if (dataLength == 10) { if (dataLength == 10 || dataLength == 9) {
// 10 // 10
state.uploadFacePage = state.uploadFacePage + 1; state.uploadFacePage = state.uploadFacePage + 1;
@ -269,7 +269,7 @@ class UploadDataLogic extends BaseGetXController {
final int dataLength = reply.data[8]; final int dataLength = reply.data[8];
state.uploadPalmVeinDataList.addAll(reply.data.sublist(9, reply.data.length)); state.uploadPalmVeinDataList.addAll(reply.data.sublist(9, reply.data.length));
if (dataLength == 10) { if (dataLength == 10 || dataLength == 9) {
// 10 // 10
state.uploadPalmVeinPage = state.uploadPalmVeinPage + 1; state.uploadPalmVeinPage = state.uploadPalmVeinPage + 1;
@ -316,7 +316,7 @@ class UploadDataLogic extends BaseGetXController {
final int dataLength = reply.data[8]; final int dataLength = reply.data[8];
state.uploadRemoteControlDataList.addAll(reply.data.sublist(9, reply.data.length)); state.uploadRemoteControlDataList.addAll(reply.data.sublist(9, reply.data.length));
if (dataLength == 10) { if (dataLength == 10 || dataLength == 9) {
// 10 // 10
state.uploadRemoteControlPage = state.uploadRemoteControlPage + 1; state.uploadRemoteControlPage = state.uploadRemoteControlPage + 1;

View File

@ -32,12 +32,10 @@ class LockListLogic extends BaseGetXController {
final ShowTipView showTipView = ShowTipView(); final ShowTipView showTipView = ShowTipView();
List<GroupList> get groupDataListFiltered { List<GroupList> get groupDataListFiltered {
final List<GroupList> list = final List<GroupList> list = groupDataList.map((GroupList e) => e.copy()).toList();
groupDataList.map((GroupList e) => e.copy()).toList();
if (state.searchStr.value != '' && state.showSearch.value) { if (state.searchStr.value != '' && state.showSearch.value) {
list.forEach((GroupList element) { list.forEach((GroupList element) {
element.lockList?.removeWhere((LockListInfoItemEntity element) => element.lockList?.removeWhere((LockListInfoItemEntity element) => !(element.lockAlias?.contains(state.searchStr.value) ?? true));
!(element.lockAlias?.contains(state.searchStr.value) ?? true));
}); });
} }
if (list.length > 0) { if (list.length > 0) {
@ -46,8 +44,7 @@ class LockListLogic extends BaseGetXController {
final lockList = element.lockList; final lockList = element.lockList;
if (lockList != null && lockList.length > 0) { if (lockList != null && lockList.length > 0) {
lockList.forEach((element) { lockList.forEach((element) {
if (element.network?.peerId != null && if (element.network?.peerId != null && element.network?.peerId != '') {
element.network?.peerId != '') {
StartChartManage().lockListPeerId.add(element); StartChartManage().lockListPeerId.add(element);
} }
}); });
@ -68,11 +65,9 @@ class LockListLogic extends BaseGetXController {
late StreamSubscription _setLockListInfoGroupEntity; late StreamSubscription _setLockListInfoGroupEntity;
void _initReplySubscription() { void _initReplySubscription() {
_replySubscription = _replySubscription = EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
// //
if ((reply is FactoryDataResetReply) && if ((reply is FactoryDataResetReply)) {
(state.ifCurrentScreen.value == true)) {
_replyFactoryDataResetKey(reply); _replyFactoryDataResetKey(reply);
} }
}); });
@ -93,19 +88,18 @@ class LockListLogic extends BaseGetXController {
break; break;
case 0x06: case 0x06:
// //
final List<String>? token = await Storage.getStringList(saveBlueToken); final List<int> tokenData = reply.data.sublist(2, 6);
final List<int> getTokenList = changeStringListToIntList(token!); final List<String> saveStrList = changeIntListToStringList(tokenData);
Storage.setStringList(saveBlueToken, saveStrList);
IoSenderManage.senderFactoryDataReset( IoSenderManage.senderFactoryDataReset(
lockID: BlueManage().connectDeviceName, lockID: BlueManage().connectDeviceName,
userID: await Storage.getUid(), userID: await Storage.getUid(),
keyID: '1', keyID: '1',
needAuthor: 1, needAuthor: 1,
publicKey: publicKey: state.publicKey,
state.lockListInfoItemEntity.bluetooth!.publicKey!.cast<int>(), privateKey: state.privateKey,
privateKey: token: tokenData,
state.lockListInfoItemEntity.bluetooth!.privateKey!.cast<int>(), );
token: getTokenList);
break; break;
case 0x07: case 0x07:
// //
@ -146,8 +140,7 @@ class LockListLogic extends BaseGetXController {
keyInfo.keyType == XSConstantMacro.keyTypeLong || keyInfo.keyType == XSConstantMacro.keyTypeLong ||
keyInfo.keyType == XSConstantMacro.keyTypeLoop) { keyInfo.keyType == XSConstantMacro.keyTypeLoop) {
// 使 // 使
if (keyInfo.keyStatus == XSConstantMacro.keyStatusNormalUse || if (keyInfo.keyStatus == XSConstantMacro.keyStatusNormalUse || keyInfo.keyStatus == XSConstantMacro.keyStatusWaitReceive) {
keyInfo.keyStatus == XSConstantMacro.keyStatusWaitReceive) {
return "${"".tr}${DateTool().compareTimeGetDaysFromNow(keyInfo.endDate!)}${"".tr}"; return "${"".tr}${DateTool().compareTimeGetDaysFromNow(keyInfo.endDate!)}${"".tr}";
} else { } else {
return XSConstantMacro.getKeyStatusStr(keyInfo.keyStatus!); return XSConstantMacro.getKeyStatusStr(keyInfo.keyStatus!);
@ -160,11 +153,7 @@ class LockListLogic extends BaseGetXController {
// //
bool getShowType(LockListInfoItemEntity keyInfo) { bool getShowType(LockListInfoItemEntity keyInfo) {
final List<int> keyTypes = <int>[ final List<int> keyTypes = <int>[XSConstantMacro.keyTypeTime, XSConstantMacro.keyTypeOnce, XSConstantMacro.keyTypeLoop];
XSConstantMacro.keyTypeTime,
XSConstantMacro.keyTypeOnce,
XSConstantMacro.keyTypeLoop
];
final List<int> keyStatus = <int>[ final List<int> keyStatus = <int>[
XSConstantMacro.keyStatusWaitIneffective, XSConstantMacro.keyStatusWaitIneffective,
XSConstantMacro.keyStatusFrozen, XSConstantMacro.keyStatusFrozen,
@ -172,36 +161,30 @@ class LockListLogic extends BaseGetXController {
]; ];
//--&& //--&&
final bool isLongFrozenStatus = final bool isLongFrozenStatus = keyInfo.keyType == XSConstantMacro.keyTypeLong && keyInfo.keyStatus == XSConstantMacro.keyStatusFrozen;
keyInfo.keyType == XSConstantMacro.keyTypeLong && final DateTime endDate = DateTime.fromMillisecondsSinceEpoch(keyInfo.endDate ?? 0);
keyInfo.keyStatus == XSConstantMacro.keyStatusFrozen;
final DateTime endDate =
DateTime.fromMillisecondsSinceEpoch(keyInfo.endDate ?? 0);
final DateTime now = DateTime.now(); final DateTime now = DateTime.now();
final bool isKeyType = keyTypes.contains(keyInfo.keyType); final bool isKeyType = keyTypes.contains(keyInfo.keyType);
final bool isKeyStatus = keyStatus.contains(keyInfo.keyStatus); final bool isKeyStatus = keyStatus.contains(keyInfo.keyStatus);
final Duration difference = endDate.difference(now); final Duration difference = endDate.difference(now);
final bool isExpirationSoon = isKeyType && difference.inDays <= 15; final bool isExpirationSoon = isKeyType && difference.inDays <= 15;
final bool isShow = final bool isShow = isKeyType && isKeyStatus || isExpirationSoon || isLongFrozenStatus;
isKeyType && isKeyStatus || isExpirationSoon || isLongFrozenStatus;
return isShow; return isShow;
} }
/// ///
void deleyLockLogicOfRoles() { void deleyLockLogicOfRoles(LockListInfoItemEntity keyInfo) {
if (state.lockListInfoItemEntity.isLockOwner == 1) { if (state.lockListInfoItemEntity.value.isLockOwner == 1) {
// //
showTipView.showIosTipWithContentDialog('删除锁后,所有信息都会一起删除,确定删除锁吗?'.tr, () { showTipView.showIosTipWithContentDialog('删除锁后,所有信息都会一起删除,确定删除锁吗?'.tr, () {
// //
AppLog.log('调用了删除锁'); AppLog.log('调用了删除锁');
showTipView.resetGetController(); showTipView.resetGetController();
showTipView.showTFViewAlertDialog( showTipView.showTFViewAlertDialog(state.passwordTF, '请输入登录密码'.tr, '请输入登录密码'.tr, () => checkLoginPassword(keyInfo));
state.passwordTF, '请输入登录密码'.tr, '请输入登录密码'.tr, checkLoginPassword);
}); });
} else if (state.lockListInfoItemEntity.keyRight == 1) { } else if (state.lockListInfoItemEntity.value.keyRight == 1) {
// //
showTipView.showDeleteAdministratorIsHaveAllDataDialog( showTipView.showDeleteAdministratorIsHaveAllDataDialog('同时删除其发送的所有钥匙,钥匙删除后不能恢复'.tr, (bool a) {
'同时删除其发送的所有钥匙,钥匙删除后不能恢复'.tr, (bool a) {
// //
state.deleteAdministratorIsHaveAllData.value = a; state.deleteAdministratorIsHaveAllData.value = a;
deletKeyData(); deletKeyData();
@ -213,20 +196,20 @@ class LockListLogic extends BaseGetXController {
} }
// //
Future<void> checkLoginPassword() async { Future<void> checkLoginPassword(LockListInfoItemEntity keyInfo) async {
final LockListInfoEntity entity = await ApiRepository.to.checkLoginPassword( final LockListInfoEntity entity = await ApiRepository.to.checkLoginPassword(
password: state.passwordTF.text, password: state.passwordTF.text,
); );
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
Get.back(); Get.back();
factoryDataResetAction(); factoryDataResetAction(keyInfo);
} }
} }
// //
Future<void> deletLockInfoData() async { Future<void> deletLockInfoData() async {
final LockListInfoEntity entity = await ApiRepository.to.deletOwnerLockData( final LockListInfoEntity entity = await ApiRepository.to.deletOwnerLockData(
lockId: state.lockListInfoItemEntity.lockId!, lockId: state.lockListInfoItemEntity.value.lockId!,
); );
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
BlueManage().connectDeviceMacAddress = ''; BlueManage().connectDeviceMacAddress = '';
@ -239,10 +222,9 @@ class LockListLogic extends BaseGetXController {
// //
Future<void> deletKeyData() async { Future<void> deletKeyData() async {
final LockListInfoEntity entity = await ApiRepository.to.deletOwnerKeyData( final LockListInfoEntity entity = await ApiRepository.to.deletOwnerKeyData(
lockId: state.lockListInfoItemEntity.lockId.toString(), lockId: state.lockListInfoItemEntity.value.lockId.toString(),
keyId: state.lockListInfoItemEntity.keyId.toString(), keyId: state.lockListInfoItemEntity.value.keyId.toString(),
includeUnderlings: includeUnderlings: state.deleteAdministratorIsHaveAllData.value == true ? 1 : 0);
state.deleteAdministratorIsHaveAllData.value == true ? 1 : 0);
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
BlueManage().connectDeviceMacAddress = ''; BlueManage().connectDeviceMacAddress = '';
SchedulerBinding.instance.addPostFrameCallback((_) { SchedulerBinding.instance.addPostFrameCallback((_) {
@ -252,7 +234,7 @@ class LockListLogic extends BaseGetXController {
} }
// //
Future<void> factoryDataResetAction() async { Future<void> factoryDataResetAction(LockListInfoItemEntity keyInfo) async {
showEasyLoading(); showEasyLoading();
showBlueConnetctToastTimer( showBlueConnetctToastTimer(
isShowBlueConnetctToast: false, isShowBlueConnetctToast: false,
@ -260,31 +242,23 @@ class LockListLogic extends BaseGetXController {
dismissEasyLoading(); dismissEasyLoading();
showDeletAlertTipDialog(); showDeletAlertTipDialog();
}); });
BlueManage().blueSendData(state.lockListInfoItemEntity.lockName!, BlueManage().blueSendData(state.lockListInfoItemEntity.value.lockName!, (BluetoothConnectionState connectionState) async {
(BluetoothConnectionState connectionState) async {
if (connectionState == BluetoothConnectionState.connected) { if (connectionState == BluetoothConnectionState.connected) {
final List<int> publicKeyData = final List<int> publicKeyData = state.lockListInfoItemEntity.value.bluetooth!.publicKey!.cast<int>();
state.lockListInfoItemEntity.bluetooth!.publicKey!.cast<int>(); final List<String> saveStrList = changeIntListToStringList(publicKeyData);
final List<String> saveStrList =
changeIntListToStringList(publicKeyData);
await Storage.setStringList(saveBluePublicKey, saveStrList); await Storage.setStringList(saveBluePublicKey, saveStrList);
// //
final List<int> privateKeyData = final List<int> privateKeyData = state.lockListInfoItemEntity.value.bluetooth!.privateKey!.cast<int>();
state.lockListInfoItemEntity.bluetooth!.privateKey!.cast<int>(); final List<String> savePrivateKeyList = changeIntListToStringList(privateKeyData);
final List<String> savePrivateKeyList =
changeIntListToStringList(privateKeyData);
await Storage.setStringList(saveBluePrivateKey, savePrivateKeyList); await Storage.setStringList(saveBluePrivateKey, savePrivateKeyList);
// signKey // signKey
final List<int> signKeyData = final List<int> signKeyData = state.lockListInfoItemEntity.value.bluetooth!.signKey!.cast<int>();
state.lockListInfoItemEntity.bluetooth!.signKey!.cast<int>(); final List<String> saveSignKeyList = changeIntListToStringList(signKeyData);
final List<String> saveSignKeyList =
changeIntListToStringList(signKeyData);
await Storage.setStringList(saveBlueSignKey, saveSignKeyList); await Storage.setStringList(saveBlueSignKey, saveSignKeyList);
final List<String> saveTokenList = final List<String> saveTokenList = changeIntListToStringList(<int>[0, 0, 0, 0]);
changeIntListToStringList(<int>[0, 0, 0, 0]);
await Storage.setStringList(saveBlueToken, saveTokenList); await Storage.setStringList(saveBlueToken, saveTokenList);
IoSenderManage.senderFactoryDataReset( IoSenderManage.senderFactoryDataReset(
@ -292,11 +266,13 @@ class LockListLogic extends BaseGetXController {
userID: await Storage.getUid(), userID: await Storage.getUid(),
keyID: '1', keyID: '1',
needAuthor: 1, needAuthor: 1,
publicKey: publicKey: keyInfo.bluetooth?.publicKey ?? [],
state.lockListInfoItemEntity.bluetooth!.publicKey!.cast<int>(), privateKey: keyInfo.bluetooth?.privateKey ?? [],
privateKey:
state.lockListInfoItemEntity.bluetooth!.privateKey!.cast<int>(),
token: <int>[0, 0, 0, 0]); token: <int>[0, 0, 0, 0]);
state.publicKey.value = keyInfo.bluetooth?.publicKey ?? [];
state.privateKey.value = keyInfo.bluetooth?.privateKey ?? [];
state.publicKey.refresh();
state.privateKey.refresh();
} else if (connectionState == BluetoothConnectionState.disconnected) { } else if (connectionState == BluetoothConnectionState.disconnected) {
dismissEasyLoading(); dismissEasyLoading();
cancelBlueConnetctToastTimer(); cancelBlueConnetctToastTimer();
@ -353,9 +329,7 @@ class LockListLogic extends BaseGetXController {
} }
void _initEventHandler() { void _initEventHandler() {
_setLockListInfoGroupEntity = eventBus _setLockListInfoGroupEntity = eventBus.on<SetLockListInfoGroupEntity>().listen((SetLockListInfoGroupEntity event) async {
.on<SetLockListInfoGroupEntity>()
.listen((SetLockListInfoGroupEntity event) async {
setLockListInfoGroupEntity(event.lockListInfoGroupEntity); setLockListInfoGroupEntity(event.lockListInfoGroupEntity);
}); });
} }

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:star_lock/app_settings/app_settings.dart';
import 'package:star_lock/main/lockMian/lockList/lockList_state.dart'; import 'package:star_lock/main/lockMian/lockList/lockList_state.dart';
import '../../../appRouters.dart'; import '../../../appRouters.dart';
@ -14,8 +15,7 @@ import 'lockListGroup_view.dart';
import 'lockList_logic.dart'; import 'lockList_logic.dart';
class LockListPage extends StatefulWidget { class LockListPage extends StatefulWidget {
const LockListPage({required this.lockListInfoGroupEntity, Key? key}) const LockListPage({required this.lockListInfoGroupEntity, Key? key}) : super(key: key);
: super(key: key);
final LockListInfoGroupEntity lockListInfoGroupEntity; final LockListInfoGroupEntity lockListInfoGroupEntity;
@override @override
@ -30,16 +30,15 @@ class _LockListPageState extends State<LockListPage> with RouteAware {
void initState() { void initState() {
super.initState(); super.initState();
logic = Get.put(LockListLogic(widget.lockListInfoGroupEntity)); logic = Get.put(LockListLogic(widget.lockListInfoGroupEntity));
state = Get state = Get.find<LockListLogic>().state;
.find<LockListLogic>()
.state;
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Obx(() => Scaffold( return Obx(
() => Scaffold(
body: ListView.separated( body: ListView.separated(
itemCount: logic.groupDataListFiltered.length, itemCount: logic.groupDataList.length,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
final GroupList itemData = logic.groupDataListFiltered[index]; final GroupList itemData = logic.groupDataListFiltered[index];
return _buildLockExpandedList(context, index, itemData, key: ValueKey(itemData.groupId)); return _buildLockExpandedList(context, index, itemData, key: ValueKey(itemData.groupId));
@ -51,20 +50,21 @@ class _LockListPageState extends State<LockListPage> with RouteAware {
height: 1, height: 1,
color: AppColors.greyLineColor, color: AppColors.greyLineColor,
); );
}), },
)); ),
),
);
} }
// //
Widget _buildLockExpandedList(BuildContext context, int index, Widget _buildLockExpandedList(BuildContext context, int index, GroupList itemData, {Key? key}) {
GroupList itemData, {Key? key}) { final List<LockListInfoItemEntity> lockItemList = itemData.lockList ?? <LockListInfoItemEntity>[];
final List<LockListInfoItemEntity> lockItemList =
itemData.lockList ?? <LockListInfoItemEntity>[];
return LockListGroupView( return LockListGroupView(
key: key, key: key,
onTap: () { onTap: () {
// //
if (itemData.isChecked) {} else {} if (itemData.isChecked) {
} else {}
setState(() {}); setState(() {});
}, },
typeImgList: const <dynamic>[], typeImgList: const <dynamic>[],
@ -91,8 +91,12 @@ class _LockListPageState extends State<LockListPage> with RouteAware {
children: <Widget>[ children: <Widget>[
SlidableAction( SlidableAction(
onPressed: (BuildContext context) { onPressed: (BuildContext context) {
state.lockListInfoItemEntity = keyInfo; state.publicKey.value = keyInfo.bluetooth?.publicKey ?? [];
logic.deleyLockLogicOfRoles(); state.privateKey.value = keyInfo.bluetooth?.privateKey ?? [];
state.lockListInfoItemEntity.value = keyInfo;
state.lockListInfoItemEntity.refresh();
AppLog.log('msg=================:${state.lockListInfoItemEntity.value}');
logic.deleyLockLogicOfRoles(keyInfo);
}, },
backgroundColor: Colors.red, backgroundColor: Colors.red,
foregroundColor: Colors.white, foregroundColor: Colors.white,
@ -102,10 +106,8 @@ class _LockListPageState extends State<LockListPage> with RouteAware {
], ],
), ),
child: lockInfoListItem(keyInfo, isLast, () { child: lockInfoListItem(keyInfo, isLast, () {
if ((keyInfo.keyType == XSConstantMacro.keyTypeTime || if ((keyInfo.keyType == XSConstantMacro.keyTypeTime || keyInfo.keyType == XSConstantMacro.keyTypeLoop) &&
keyInfo.keyType == XSConstantMacro.keyTypeLoop) && (keyInfo.keyStatus == XSConstantMacro.keyStatusWaitIneffective)) {
(keyInfo.keyStatus ==
XSConstantMacro.keyStatusWaitIneffective)) {
logic.showToast('您的钥匙未生效'.tr); logic.showToast('您的钥匙未生效'.tr);
return; return;
} }
@ -116,14 +118,12 @@ class _LockListPageState extends State<LockListPage> with RouteAware {
logic.showToast('您的钥匙已冻结'.tr); logic.showToast('您的钥匙已冻结'.tr);
return; return;
} }
if ((keyInfo.keyType == XSConstantMacro.keyTypeTime || if ((keyInfo.keyType == XSConstantMacro.keyTypeTime || keyInfo.keyType == XSConstantMacro.keyTypeLoop) &&
keyInfo.keyType == XSConstantMacro.keyTypeLoop) &&
(keyInfo.keyStatus == XSConstantMacro.keyStatusExpired)) { (keyInfo.keyStatus == XSConstantMacro.keyStatusExpired)) {
logic.showToast('您的钥匙已过期'.tr); logic.showToast('您的钥匙已过期'.tr);
return; return;
} }
Get.toNamed(Routers.lockDetailMainPage, Get.toNamed(Routers.lockDetailMainPage, arguments: <String, Object>{
arguments: <String, Object>{
// "lockMainEntity": widget.lockMainEntity, // "lockMainEntity": widget.lockMainEntity,
'keyInfo': keyInfo, 'keyInfo': keyInfo,
'isOnlyOneData': false, 'isOnlyOneData': false,
@ -134,26 +134,18 @@ class _LockListPageState extends State<LockListPage> with RouteAware {
); );
} }
Widget lockInfoListItem(LockListInfoItemEntity keyInfo, bool isLast, Widget lockInfoListItem(LockListInfoItemEntity keyInfo, bool isLast, Function() action) {
Function() action) {
return GestureDetector( return GestureDetector(
onTap: action, onTap: action,
child: Container( child: Container(
// height: 122.h, // height: 122.h,
margin: isLast margin: isLast ? EdgeInsets.only(left: 20.w, right: 20.w, top: 20.w, bottom: 20.w) : EdgeInsets.only(left: 20.w, right: 20.w, top: 20.w),
? EdgeInsets.only(left: 20.w, right: 20.w, top: 20.w, bottom: 20.w)
: EdgeInsets.only(left: 20.w, right: 20.w, top: 20.w),
decoration: BoxDecoration( decoration: BoxDecoration(
color: (((keyInfo.keyType == XSConstantMacro.keyTypeTime || color: (((keyInfo.keyType == XSConstantMacro.keyTypeTime || keyInfo.keyType == XSConstantMacro.keyTypeLoop) &&
keyInfo.keyType == XSConstantMacro.keyTypeLoop) && (keyInfo.keyStatus == XSConstantMacro.keyStatusWaitIneffective ||
(keyInfo.keyStatus == keyInfo.keyStatus == XSConstantMacro.keyStatusFrozen ||
XSConstantMacro.keyStatusWaitIneffective || keyInfo.keyStatus == XSConstantMacro.keyStatusExpired)) ||
keyInfo.keyStatus == (keyInfo.keyType == XSConstantMacro.keyTypeLong && keyInfo.keyStatus == XSConstantMacro.keyStatusFrozen))
XSConstantMacro.keyStatusFrozen ||
keyInfo.keyStatus ==
XSConstantMacro.keyStatusExpired)) ||
(keyInfo.keyType == XSConstantMacro.keyTypeLong &&
keyInfo.keyStatus == XSConstantMacro.keyStatusFrozen))
? AppColors.greyBackgroundColor ? AppColors.greyBackgroundColor
: Colors.white, : Colors.white,
borderRadius: BorderRadius.circular(20.w), borderRadius: BorderRadius.circular(20.w),
@ -177,9 +169,7 @@ class _LockListPageState extends State<LockListPage> with RouteAware {
style: TextStyle( style: TextStyle(
fontSize: 24.sp, fontSize: 24.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: keyInfo.passageMode == 1 color: keyInfo.passageMode == 1 ? AppColors.openPassageModeColor : AppColors.darkGrayTextColor),
? AppColors.openPassageModeColor
: AppColors.darkGrayTextColor),
), ),
], ],
), ),
@ -193,8 +183,7 @@ class _LockListPageState extends State<LockListPage> with RouteAware {
SizedBox(width: 2.w), SizedBox(width: 2.w),
Text( Text(
'${keyInfo.electricQuantity!}%', '${keyInfo.electricQuantity!}%',
style: TextStyle( style: TextStyle(fontSize: 18.sp, color: AppColors.darkGrayTextColor),
fontSize: 18.sp, color: AppColors.darkGrayTextColor),
), ),
SizedBox(width: 30.w), SizedBox(width: 30.w),
], ],
@ -211,10 +200,7 @@ class _LockListPageState extends State<LockListPage> with RouteAware {
borderRadius: BorderRadius.circular(5.w), borderRadius: BorderRadius.circular(5.w),
color: AppColors.openPassageModeColor, color: AppColors.openPassageModeColor,
), ),
child: Text('常开模式开启'.tr, child: Text('常开模式开启'.tr, style: TextStyle(fontSize: 18.sp, color: AppColors.appBarIconColor)),
style: TextStyle(
fontSize: 18.sp,
color: AppColors.appBarIconColor)),
), ),
], ],
)), )),
@ -226,8 +212,7 @@ class _LockListPageState extends State<LockListPage> with RouteAware {
SizedBox(width: 30.w), SizedBox(width: 30.w),
Text( Text(
'远程开锁'.tr, '远程开锁'.tr,
style: TextStyle( style: TextStyle(fontSize: 18.sp, color: AppColors.darkGrayTextColor),
fontSize: 18.sp, color: AppColors.darkGrayTextColor),
), ),
], ],
)), )),
@ -241,13 +226,9 @@ class _LockListPageState extends State<LockListPage> with RouteAware {
padding: EdgeInsets.only(right: 5.w, left: 5.w), padding: EdgeInsets.only(right: 5.w, left: 5.w),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.w), borderRadius: BorderRadius.circular(5.w),
color: color: DateTool().compareTimeIsOvertime(keyInfo.endDate!) ? AppColors.listTimeYellowColor : AppColors.mainColor,
DateTool().compareTimeIsOvertime(keyInfo.endDate!)
? AppColors.listTimeYellowColor
: AppColors.mainColor,
), ),
child: Text(logic.getKeyEffective(keyInfo), child: Text(logic.getKeyEffective(keyInfo), style: TextStyle(fontSize: 18.sp, color: Colors.white)
style: TextStyle(fontSize: 18.sp, color: Colors.white)
// child: Text(logic.compareTimeIsOvertime(keyInfo.endDate!) ? "已过期" : "${logic.compareTimeGetDaysFromNow(keyInfo.endDate!)}", style: TextStyle(fontSize: 18.sp, color: Colors.white) // child: Text(logic.compareTimeIsOvertime(keyInfo.endDate!) ? "已过期" : "${logic.compareTimeGetDaysFromNow(keyInfo.endDate!)}", style: TextStyle(fontSize: 18.sp, color: Colors.white)
), ),
), ),
@ -258,13 +239,8 @@ class _LockListPageState extends State<LockListPage> with RouteAware {
children: <Widget>[ children: <Widget>[
SizedBox(width: 30.w), SizedBox(width: 30.w),
Text( Text(
"${logic.getUseKeyTypeStr(keyInfo.startDate, keyInfo.endDate, "${logic.getUseKeyTypeStr(keyInfo.startDate, keyInfo.endDate, keyInfo.keyType)}/${keyInfo.isLockOwner == 1 ? '超级管理员'.tr : (keyInfo.keyRight == 1 ? "授权管理员".tr : "普通用户".tr)}",
keyInfo.keyType)}/${keyInfo.isLockOwner == 1 style: TextStyle(fontSize: 18.sp, color: AppColors.darkGrayTextColor),
? '超级管理员'.tr
: (keyInfo.keyRight == 1 ? "授权管理员".tr : "普通用户"
.tr)}",
style: TextStyle(
fontSize: 18.sp, color: AppColors.darkGrayTextColor),
), ),
], ],
), ),
@ -286,13 +262,10 @@ class _LockListPageState extends State<LockListPage> with RouteAware {
@override @override
void dispose() { void dispose() {
Get.delete<LockListLogic>(); Get.delete<LockListLogic>();
/// ///
AppRouteObserver().routeObserver.unsubscribe(this); AppRouteObserver().routeObserver.unsubscribe(this);
super super.dispose();
.
dispose
(
);
} }
/// ///

View File

@ -7,11 +7,14 @@ import '../entity/lockListInfo_entity.dart';
class LockListState{ class LockListState{
RxBool itemStatusIsEable = false.obs; // item是否能点击 RxBool itemStatusIsEable = false.obs; // item是否能点击
LockListInfoItemEntity lockListInfoItemEntity = LockListInfoItemEntity(); // item //
Rx<LockListInfoItemEntity> lockListInfoItemEntity = LockListInfoItemEntity().obs; // item
TextEditingController passwordTF = TextEditingController(); TextEditingController passwordTF = TextEditingController();
RxBool deleteAdministratorIsHaveAllData = false.obs; // RxBool deleteAdministratorIsHaveAllData = false.obs; //
RxBool ifCurrentScreen = true.obs; // , RxBool ifCurrentScreen = true.obs; // ,
RxBool showSearch = false.obs; // , RxBool showSearch = false.obs; // ,
RxString searchStr = ''.obs; // , RxString searchStr = ''.obs; // ,
RxList<int> publicKey=<int>[].obs;
RxList<int> privateKey=<int>[].obs;
} }

View File

@ -192,8 +192,9 @@ class _LockListXHJPageState extends State<LockListXHJPage> with RouteAware {
children: <Widget>[ children: <Widget>[
SlidableAction( SlidableAction(
onPressed: (BuildContext context) { onPressed: (BuildContext context) {
state.lockListInfoItemEntity = keyInfo; state.lockListInfoItemEntity.value = keyInfo;
logic.deleyLockLogicOfRoles(); state.lockListInfoItemEntity.refresh();
logic.deleyLockLogicOfRoles(keyInfo);
}, },
backgroundColor: Colors.red, backgroundColor: Colors.red,
foregroundColor: Colors.white, foregroundColor: Colors.white,

View File

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

View File

@ -31,8 +31,7 @@ class SaveLockLogic 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 AddUserReply && state.ifCurrentScreen.value == true) { if (reply is AddUserReply && state.ifCurrentScreen.value == true) {
_replyAddUserKey(reply); _replyAddUserKey(reply);
} }
@ -66,15 +65,11 @@ class SaveLockLogic 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>? publicKey = final List<String>? publicKey = await Storage.getStringList(saveBluePublicKey);
await Storage.getStringList(saveBluePublicKey); final List<int> publicKeyDataList = changeStringListToIntList(publicKey!);
final List<int> publicKeyDataList =
changeStringListToIntList(publicKey!);
IoSenderManage.senderAddUser( IoSenderManage.senderAddUser(
lockID: BlueManage().connectDeviceName, lockID: BlueManage().connectDeviceName,
@ -215,19 +210,14 @@ class SaveLockLogic extends BaseGetXController {
showBlueConnetctToast(); showBlueConnetctToast();
} }
}); });
BlueManage().blueSendData(BlueManage().connectDeviceName, BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState deviceConnectionState) async {
(BluetoothConnectionState deviceConnectionState) async {
if (deviceConnectionState == BluetoothConnectionState.connected) { if (deviceConnectionState == BluetoothConnectionState.connected) {
// //
final List<String>? privateKey = final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
await Storage.getStringList(saveBluePrivateKey); final List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
final List<int> getPrivateKeyList =
changeStringListToIntList(privateKey!);
final List<String>? publicKey = final List<String>? publicKey = await Storage.getStringList(saveBluePublicKey);
await Storage.getStringList(saveBluePublicKey); final List<int> publicKeyDataList = changeStringListToIntList(publicKey!);
final List<int> publicKeyDataList =
changeStringListToIntList(publicKey!);
final List<String>? token = await Storage.getStringList(saveBlueToken); final List<String>? token = await Storage.getStringList(saveBlueToken);
List<int> getTokenList = <int>[0, 0, 0, 0]; List<int> getTokenList = <int>[0, 0, 0, 0];
@ -257,8 +247,7 @@ class SaveLockLogic extends BaseGetXController {
privateKey: getPrivateKeyList, privateKey: getPrivateKeyList,
token: getTokenList, token: getTokenList,
isBeforeAddUser: true); isBeforeAddUser: true);
} else if (deviceConnectionState == } else if (deviceConnectionState == BluetoothConnectionState.disconnected) {
BluetoothConnectionState.disconnected) {
dismissEasyLoading(); dismissEasyLoading();
cancelBlueConnetctToastTimer(); cancelBlueConnetctToastTimer();
state.sureBtnState.value = 0; state.sureBtnState.value = 0;
@ -376,16 +365,14 @@ class SaveLockLogic extends BaseGetXController {
// positionMap['address'] = state.addressInfo['address']; // positionMap['address'] = state.addressInfo['address'];
final Map<String, dynamic> bluetooth = <String, dynamic>{}; final Map<String, dynamic> bluetooth = <String, dynamic>{};
bluetooth['bluetoothDeviceId'] = BlueManage().connectDeviceMacAddress; bluetooth['bluetoothDeviceId'] = state.lockInfo['mac'];
bluetooth['bluetoothDeviceName'] = BlueManage().connectDeviceName; bluetooth['bluetoothDeviceName'] = BlueManage().connectDeviceName;
final List<String>? publicKey = final List<String>? publicKey = await Storage.getStringList(saveBluePublicKey);
await Storage.getStringList(saveBluePublicKey);
final List<int> publicKeyDataList = changeStringListToIntList(publicKey!); final List<int> publicKeyDataList = changeStringListToIntList(publicKey!);
bluetooth['publicKey'] = publicKeyDataList; bluetooth['publicKey'] = publicKeyDataList;
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!);
bluetooth['privateKey'] = getPrivateKeyList; bluetooth['privateKey'] = getPrivateKeyList;
@ -410,8 +397,7 @@ class SaveLockLogic extends BaseGetXController {
final String getMobile = (await Storage.getMobile())!; final String getMobile = (await Storage.getMobile())!;
ApmHelper.instance.trackEvent('save_lock_result', { ApmHelper.instance.trackEvent('save_lock_result', {
'lock_name': BlueManage().connectDeviceName, 'lock_name': BlueManage().connectDeviceName,
'account': 'account': getMobile.isNotEmpty ? getMobile : (await Storage.getEmail())!,
getMobile.isNotEmpty ? getMobile : (await Storage.getEmail())!,
'date': DateTool().getNowDateWithType(1), 'date': DateTool().getNowDateWithType(1),
'save_lock_result': '成功', 'save_lock_result': '成功',
}); });
@ -427,8 +413,7 @@ class SaveLockLogic extends BaseGetXController {
final String getMobile = (await Storage.getMobile())!; final String getMobile = (await Storage.getMobile())!;
ApmHelper.instance.trackEvent('save_lock_result', { ApmHelper.instance.trackEvent('save_lock_result', {
'lock_name': BlueManage().connectDeviceName, 'lock_name': BlueManage().connectDeviceName,
'account': 'account': getMobile.isNotEmpty ? getMobile : (await Storage.getEmail())!,
getMobile.isNotEmpty ? getMobile : (await Storage.getEmail())!,
'date': DateTool().getNowDateWithType(1), 'date': DateTool().getNowDateWithType(1),
'save_lock_result': '${entity.errorCode}--${entity.errorMsg}', 'save_lock_result': '${entity.errorCode}--${entity.errorMsg}',
}); });
@ -489,26 +474,18 @@ class SaveLockLogic extends BaseGetXController {
// BlueManage().disconnect(); // BlueManage().disconnect();
// //
final LockSetInfoEntity entity = final LockSetInfoEntity entity = await ApiRepository.to.getLockSettingInfoData(
await ApiRepository.to.getLockSettingInfoData(
lockId: state.lockId.toString(), lockId: state.lockId.toString(),
); );
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
state.lockSetInfoData.value = entity.data!; state.lockSetInfoData.value = entity.data!;
if (state.lockSetInfoData.value.lockFeature?.wifi == 1) { if (state.lockSetInfoData.value.lockFeature?.wifi == 1) {
// wifi锁WIFI // wifi锁WIFI
Get.toNamed(Routers.wifiListPage, arguments: { Get.toNamed(Routers.wifiListPage, arguments: {'lockSetInfoData': state.lockSetInfoData.value, 'pageName': 'saveLock'});
'lockSetInfoData': state.lockSetInfoData.value,
'pageName': 'saveLock'
});
} else if (state.lockSetInfoData.value.lockFeature?.languageSpeech == 1) { } else if (state.lockSetInfoData.value.lockFeature?.languageSpeech == 1) {
Get.toNamed(Routers.lockVoiceSettingPage, arguments: { Get.toNamed(Routers.lockVoiceSettingPage, arguments: {'lockSetInfoData': state.lockSetInfoData.value, 'pageName': 'saveLock'});
'lockSetInfoData': state.lockSetInfoData.value,
'pageName': 'saveLock'
});
} else { } else {
eventBus.fire(RefreshLockListInfoDataEvent( eventBus.fire(RefreshLockListInfoDataEvent(clearScanDevices: true, isUnShowLoading: true));
clearScanDevices: true, isUnShowLoading: true));
Future<void>.delayed(const Duration(seconds: 1), () { Future<void>.delayed(const Duration(seconds: 1), () {
// Get.close(state.isFromMap == 1 // Get.close(state.isFromMap == 1
// ? (CommonDataManage().seletLockType == 0 ? 4 : 5) // ? (CommonDataManage().seletLockType == 0 ? 4 : 5)
@ -518,15 +495,12 @@ class SaveLockLogic extends BaseGetXController {
// 2 // 2
Future<void>.delayed(const Duration(milliseconds: 200), () { Future<void>.delayed(const Duration(milliseconds: 200), () {
if (Get.isRegistered<LockDetailLogic>()) { if (Get.isRegistered<LockDetailLogic>()) {
Get.find<LockDetailLogic>() Get.find<LockDetailLogic>().functionBlocker.countdownProhibited(duration: const Duration(seconds: 2));
.functionBlocker
.countdownProhibited(duration: const Duration(seconds: 2));
} }
}); });
} }
} else { } else {
eventBus.fire(RefreshLockListInfoDataEvent( eventBus.fire(RefreshLockListInfoDataEvent(clearScanDevices: true, isUnShowLoading: true));
clearScanDevices: true, isUnShowLoading: true));
Future<void>.delayed(const Duration(seconds: 1), () { Future<void>.delayed(const Duration(seconds: 1), () {
// Get.close(state.isFromMap == 1 // Get.close(state.isFromMap == 1
// ? (CommonDataManage().seletLockType == 0 ? 4 : 5) // ? (CommonDataManage().seletLockType == 0 ? 4 : 5)
@ -536,9 +510,7 @@ class SaveLockLogic extends BaseGetXController {
// 2 // 2
Future<void>.delayed(const Duration(milliseconds: 200), () { Future<void>.delayed(const Duration(milliseconds: 200), () {
if (Get.isRegistered<LockDetailLogic>()) { if (Get.isRegistered<LockDetailLogic>()) {
Get.find<LockDetailLogic>() Get.find<LockDetailLogic>().functionBlocker.countdownProhibited(duration: const Duration(seconds: 2));
.functionBlocker
.countdownProhibited(duration: const Duration(seconds: 2));
} }
}); });
} }

View File

@ -22,8 +22,7 @@ class GatewayConfigurationWifiLogic extends BaseGetXController {
final GatewayConfigurationWifiState state = GatewayConfigurationWifiState(); final GatewayConfigurationWifiState state = GatewayConfigurationWifiState();
Future<void> gatewayDistributionNetwork() async { Future<void> gatewayDistributionNetwork() async {
final LoginEntity entity = await ApiRepository.to final LoginEntity entity = await ApiRepository.to.gatewayDistributionNetwork(
.gatewayDistributionNetwork(
gatewayName: state.gatewayNameTF.text, gatewayName: state.gatewayNameTF.text,
gatewayMac: state.gatewayModel.mac, gatewayMac: state.gatewayModel.mac,
serialNumber: state.gatewayModel.serialNum, serialNumber: state.gatewayModel.serialNum,
@ -42,19 +41,35 @@ class GatewayConfigurationWifiLogic extends BaseGetXController {
} }
Future<void> getGatewayConfiguration() async { Future<void> getGatewayConfiguration() async {
final GetGatewayConfigurationEntity entity = final GetGatewayConfigurationEntity entity = await ApiRepository.to.getGatewayConfiguration(timeout: 60);
await ApiRepository.to.getGatewayConfiguration(timeout: 60);
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
state.getGatewayConfigurationStr = entity.data ?? ''; String configStr = entity.data ?? '';
// AppLog.log('state.getGatewayConfigurationStr:${state.getGatewayConfigurationStr}');
//
if (configStr.isNotEmpty) {
try {
Map<String, dynamic> config = jsonDecode(configStr);
config['timeZoneOffset'] = DateTime.now().timeZoneOffset.inSeconds;
AppLog.log('state.config:$config');
state.getGatewayConfigurationStr = jsonEncode(config);
} catch (e) {
AppLog.log('处理网关配置时区信息失败: $e');
// 使
state.getGatewayConfigurationStr = configStr;
}
} else {
state.getGatewayConfigurationStr = configStr;
}
AppLog.log('state.getGatewayConfigurationStr:${state.getGatewayConfigurationStr}');
} }
} }
// //
late StreamSubscription<Reply> _replySubscription; late StreamSubscription<Reply> _replySubscription;
void _initReplySubscription() { void _initReplySubscription() {
_replySubscription = _replySubscription = EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
// WIFI配网 // WIFI配网
// if(reply is GatewayConfiguringWifiReply) { // if(reply is GatewayConfiguringWifiReply) {
// _replySenderConfiguringWifi(reply); // _replySenderConfiguringWifi(reply);
@ -96,8 +111,7 @@ class GatewayConfigurationWifiLogic extends BaseGetXController {
cancelBlueConnetctToastTimer(); cancelBlueConnetctToastTimer();
dismissEasyLoading(); dismissEasyLoading();
final int secretKeyJsonLength = (reply.data[3] << 8) + reply.data[4]; final int secretKeyJsonLength = (reply.data[3] << 8) + reply.data[4];
final List<int> secretKeyList = final List<int> secretKeyList = reply.data.sublist(5, 5 + secretKeyJsonLength);
reply.data.sublist(5, 5 + secretKeyJsonLength);
state.gatewayJson = utf8String(secretKeyList); state.gatewayJson = utf8String(secretKeyList);
gatewayDistributionNetwork(); gatewayDistributionNetwork();
@ -113,8 +127,7 @@ class GatewayConfigurationWifiLogic extends BaseGetXController {
// wifi // wifi
Future<void> senderConfiguringWifiAction() async { Future<void> senderConfiguringWifiAction() async {
AppLog.log( AppLog.log('state.getGatewayConfigurationStr:${state.getGatewayConfigurationStr}');
'state.getGatewayConfigurationStr:${state.getGatewayConfigurationStr}');
if (state.wifiNameTF.text.isEmpty) { if (state.wifiNameTF.text.isEmpty) {
showToast('请输入wifi名称'.tr); showToast('请输入wifi名称'.tr);
return; return;
@ -142,8 +155,7 @@ class GatewayConfigurationWifiLogic extends BaseGetXController {
dismissEasyLoading(); dismissEasyLoading();
state.sureBtnState.value = 0; state.sureBtnState.value = 0;
}); });
BlueManage().blueSendData(BlueManage().connectDeviceName, BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async {
(BluetoothConnectionState connectionState) async {
if (connectionState == BluetoothConnectionState.connected) { if (connectionState == BluetoothConnectionState.connected) {
IoSenderManage.gatewayConfiguringWifiCommand( IoSenderManage.gatewayConfiguringWifiCommand(
ssid: state.wifiNameTF.text, ssid: state.wifiNameTF.text,
@ -162,6 +174,7 @@ class GatewayConfigurationWifiLogic extends BaseGetXController {
} }
final NetworkInfo _networkInfo = NetworkInfo(); final NetworkInfo _networkInfo = NetworkInfo();
Future<String> getWifiName() async { Future<String> getWifiName() async {
String ssid = ''; String ssid = '';
ssid = (await _networkInfo.getWifiName())!; ssid = (await _networkInfo.getWifiName())!;

View File

@ -305,6 +305,8 @@ abstract class Api {
'/lockSetting/updateLockSetting'; // '/lockSetting/updateLockSetting'; //
final String reportBuyRequestURL = final String reportBuyRequestURL =
'/service/reportBuyRequest'; // '/service/reportBuyRequest'; //
final String getActivateInfoURL = final String getTppSupportURL =
'/api/authCode/getTppSupport'; // ttp '/api/authCode/getTppSupport'; // ttp
final String getActivateInfoURL =
'/api/authCode/getActivateInfo'; // ttp
} }

View File

@ -10,28 +10,48 @@ import 'package:star_lock/talk/starChart/entity/star_chart_register_node_entity.
import 'package:star_lock/tools/storage.dart'; import 'package:star_lock/tools/storage.dart';
class StartCompanyApi extends BaseProvider { class StartCompanyApi extends BaseProvider {
// url // url
String _startChartHost = 'https://company.skychip.top'; String _startChartHost = 'https://company.skychip.top';
static StartCompanyApi get to => Get.put(StartCompanyApi()); static StartCompanyApi get to => Get.put(StartCompanyApi());
// host // host
set startChartHost(String value) { set startChartHost(String value) {
_startChartHost = value; _startChartHost = value;
} }
// host // host
String get startChartHost => _startChartHost; String get startChartHost => _startChartHost;
// ttp查询 // ttp查询
Future<ActivateInfoResponse> getActivateInfo({ Future<TppSupportResponse> getTppSupport({
required String model, required String model,
}) async {
final response = await post(
_startChartHost + getTppSupportURL.toUrl,
jsonEncode(<String, dynamic>{
'model': model,
}),
isUnShowLoading: true,
isUserBaseUrl: false,
);
return TppSupportResponse.fromJson(response.body);
}
//
Future<ActivateInfoResponse> getAuthorizationCode({
required String registerKey,
required String model,
required String serialNum0,
required int platform,
}) async { }) async {
final response = await post( final response = await post(
_startChartHost + getActivateInfoURL.toUrl, _startChartHost + getActivateInfoURL.toUrl,
jsonEncode(<String, dynamic>{ jsonEncode(<String, dynamic>{
'register_key': registerKey,
'platform': platform,
'model': model, 'model': model,
'serial_num0': serialNum0,
}), }),
isUnShowLoading: true, isUnShowLoading: true,
isUserBaseUrl: false, isUserBaseUrl: false,

View File

@ -14,8 +14,7 @@ import 'package:star_lock/talk/starChart/proto/talk_data_h264_frame.pb.dart';
// class UdpTalkDataHandler extends ScpMessageBaseHandle // class UdpTalkDataHandler extends ScpMessageBaseHandle
// implements ScpMessageHandler { // implements ScpMessageHandler {
class UdpTalkDataHandler extends ScpMessageBaseHandle class UdpTalkDataHandler extends ScpMessageBaseHandle implements ScpMessageHandler {
implements ScpMessageHandler {
// //
static final UdpTalkDataHandler instance = UdpTalkDataHandler(); static final UdpTalkDataHandler instance = UdpTalkDataHandler();
@ -73,10 +72,7 @@ class UdpTalkDataHandler extends ScpMessageBaseHandle
// _asyncLog( // _asyncLog(
// '分包数据:messageId:$messageId [$spIndex/$spTotal] PayloadLength:$PayloadLength'); // '分包数据:messageId:$messageId [$spIndex/$spTotal] PayloadLength:$PayloadLength');
if (messageType == MessageTypeConstant.RealTimeData) { if (messageType == MessageTypeConstant.RealTimeData) {
if (spTotal != null && if (spTotal != null && spTotal > 1 && messageId != null && spIndex != null) {
spTotal > 1 &&
messageId != null &&
spIndex != null) {
// //
return handleFragmentedPayload( return handleFragmentedPayload(
messageId: messageId, messageId: messageId,
@ -129,13 +125,11 @@ class UdpTalkDataHandler extends ScpMessageBaseHandle
talkDataH264Frame.mergeFromBuffer(talkData.content); talkDataH264Frame.mergeFromBuffer(talkData.content);
// AppLog.log('处理H264帧: frameType=${talkDataH264Frame.frameType}, frameSeq=${talkDataH264Frame.frameSeq},MessageId:${scpMessage.MessageId}'); // AppLog.log('处理H264帧: frameType=${talkDataH264Frame.frameType}, frameSeq=${talkDataH264Frame.frameSeq},MessageId:${scpMessage.MessageId}');
frameHandler.handleFrame(talkDataH264Frame, talkData, scpMessage); frameHandler.handleFrame(talkDataH264Frame, talkData, scpMessage);
} }
/// ///
void _handleVideoImage(TalkData talkData) async { void _handleVideoImage(TalkData talkData) async {
final List<Uint8List> processCompletePayload = final List<Uint8List> processCompletePayload = await _processCompletePayload(Uint8List.fromList(talkData.content));
await _processCompletePayload(Uint8List.fromList(talkData.content));
processCompletePayload.forEach((element) { processCompletePayload.forEach((element) {
talkData.content = element; talkData.content = element;
talkDataRepository.addTalkData( talkDataRepository.addTalkData(
@ -177,8 +171,7 @@ class UdpTalkDataHandler extends ScpMessageBaseHandle
startIdx = i; startIdx = i;
i++; // Skip the next byte i++; // Skip the next byte
} else if (nextByte == 0xD9 && startIdx != -1) { } else if (nextByte == 0xD9 && startIdx != -1) {
frames frames.add(Uint8List.view(payload.buffer, startIdx, i + 2 - startIdx));
.add(Uint8List.view(payload.buffer, startIdx, i + 2 - startIdx));
startIdx = -1; startIdx = -1;
i++; // Skip the next byte i++; // Skip the next byte
} }

View File

@ -18,20 +18,18 @@ import 'package:star_lock/tools/push/xs_jPhush.dart';
import 'package:star_lock/tools/storage.dart'; import 'package:star_lock/tools/storage.dart';
import 'package:star_lock/translations/current_locale_tool.dart'; import 'package:star_lock/translations/current_locale_tool.dart';
class UdpTalkRequestHandler extends ScpMessageBaseHandle class UdpTalkRequestHandler extends ScpMessageBaseHandle implements ScpMessageHandler {
implements ScpMessageHandler { RxString currentLanguage = CurrentLocaleTool.getCurrentLocaleString().obs; //
RxString currentLanguage =
CurrentLocaleTool.getCurrentLocaleString().obs; //
@override @override
void handleReq(ScpMessage scpMessage) async { void handleReq(ScpMessage scpMessage) async {
// //
final loginData = await Storage.getLoginData(); final loginData = await Storage.getLoginData();
// //
if (loginData != null && if (loginData != null && (talkStatus.status != TalkStatus.passiveCallWaitingAnswer || talkStatus.status != TalkStatus.answeredSuccessfully)) {
(talkStatus.status != TalkStatus.passiveCallWaitingAnswer ||
talkStatus.status != TalkStatus.answeredSuccessfully)) {
// //
AppLog.log('收到对讲请求ToPeerId${scpMessage.ToPeerId}');
AppLog.log('收到对讲请求FromPeerId${scpMessage.FromPeerId}');
final TalkReq talkReq = scpMessage.Payload; final TalkReq talkReq = scpMessage.Payload;
startChartManage.FromPeerId = scpMessage.ToPeerId!; startChartManage.FromPeerId = scpMessage.ToPeerId!;
startChartManage.ToPeerId = scpMessage.FromPeerId!; startChartManage.ToPeerId = scpMessage.FromPeerId!;
@ -64,8 +62,6 @@ class UdpTalkRequestHandler extends ScpMessageBaseHandle
_handleResponseSendExpect( _handleResponseSendExpect(
lockPeerID: scpMessage.FromPeerId!, lockPeerID: scpMessage.FromPeerId!,
); );
//
startChartManage.startTalkExpectTimer();
// //
startChartManage.stopCallRequestMessageTimer(); startChartManage.stopCallRequestMessageTimer();
// //
@ -97,8 +93,7 @@ class UdpTalkRequestHandler extends ScpMessageBaseHandle
} }
// //
Future<void> _showTalkRequestNotification( Future<void> _showTalkRequestNotification({required String talkObjectName}) async {
{required String talkObjectName}) async {
if (Platform.isAndroid) { if (Platform.isAndroid) {
final Map<String, dynamic> message = { final Map<String, dynamic> message = {
'platform': 'all', 'platform': 'all',
@ -167,14 +162,12 @@ class UdpTalkRequestHandler extends ScpMessageBaseHandle
void _handleRequestSendExpect({ void _handleRequestSendExpect({
required String lockPeerID, required String lockPeerID,
}) async { }) async {
final LockListInfoItemEntity currentKeyInfo = final LockListInfoItemEntity currentKeyInfo = CommonDataManage().currentKeyInfo;
CommonDataManage().currentKeyInfo;
var isH264 = currentKeyInfo.lockFeature?.isH264 == 1; var isH264 = currentKeyInfo.lockFeature?.isH264 == 1;
var isMJpeg = currentKeyInfo.lockFeature?.isMJpeg == 1; var isMJpeg = currentKeyInfo.lockFeature?.isMJpeg == 1;
final LockListInfoGroupEntity? lockListInfoGroupEntity = final LockListInfoGroupEntity? lockListInfoGroupEntity = await Storage.getLockMainListData();
await Storage.getLockMainListData();
if (lockListInfoGroupEntity != null) { if (lockListInfoGroupEntity != null) {
lockListInfoGroupEntity!.groupList?.forEach((element) { lockListInfoGroupEntity!.groupList?.forEach((element) {
final lockList = element.lockList; final lockList = element.lockList;
@ -195,18 +188,15 @@ class UdpTalkRequestHandler extends ScpMessageBaseHandle
if (isH264) { if (isH264) {
// H264H264视频和G711音频期望 // H264H264视频和G711音频期望
startChartManage.sendOnlyH264VideoTalkExpectData(); startChartManage.sendOnlyH264VideoTalkExpectData();
print( print('app收到的对讲请求后发送的预期数据=========锁支持H264发送H264视频格式期望数据,peerID=${lockPeerID}');
'app收到的对讲请求后发送的预期数据=========锁支持H264发送H264视频格式期望数据,peerID=${lockPeerID}');
} else if (isMJpeg) { } else if (isMJpeg) {
// MJPEGG711音频期望 // MJPEGG711音频期望
startChartManage.sendOnlyImageVideoTalkExpectData(); startChartManage.sendOnlyImageVideoTalkExpectData();
print( print('app收到的对讲请求后发送的预期数据=========锁不支持H264支持MJPEG发送MJPEG视频格式期望数据,peerID=${lockPeerID}');
'app收到的对讲请求后发送的预期数据=========锁不支持H264支持MJPEG发送MJPEG视频格式期望数据,peerID=${lockPeerID}');
} else { } else {
// 使 // 使
startChartManage.sendOnlyImageVideoTalkExpectData(); startChartManage.sendOnlyImageVideoTalkExpectData();
print( print('app收到的对讲请求后发送的预期数据=========锁不支持H264和MJPEG默认发送MJPEG视频格式期望数据,peerID=${lockPeerID}');
'app收到的对讲请求后发送的预期数据=========锁不支持H264和MJPEG默认发送MJPEG视频格式期望数据,peerID=${lockPeerID}');
} }
} }
@ -214,14 +204,12 @@ class UdpTalkRequestHandler extends ScpMessageBaseHandle
void _handleResponseSendExpect({ void _handleResponseSendExpect({
required String lockPeerID, required String lockPeerID,
}) async { }) async {
final LockListInfoItemEntity currentKeyInfo = final LockListInfoItemEntity currentKeyInfo = CommonDataManage().currentKeyInfo;
CommonDataManage().currentKeyInfo;
var isH264 = currentKeyInfo.lockFeature?.isH264 == 1; var isH264 = currentKeyInfo.lockFeature?.isH264 == 1;
var isMJpeg = currentKeyInfo.lockFeature?.isMJpeg == 1; var isMJpeg = currentKeyInfo.lockFeature?.isMJpeg == 1;
final LockListInfoGroupEntity? lockListInfoGroupEntity = final LockListInfoGroupEntity? lockListInfoGroupEntity = await Storage.getLockMainListData();
await Storage.getLockMainListData();
if (lockListInfoGroupEntity != null) { if (lockListInfoGroupEntity != null) {
lockListInfoGroupEntity!.groupList?.forEach((element) { lockListInfoGroupEntity!.groupList?.forEach((element) {
final lockList = element.lockList; final lockList = element.lockList;
@ -242,18 +230,15 @@ class UdpTalkRequestHandler extends ScpMessageBaseHandle
if (isH264) { if (isH264) {
// H264H264视频和G711音频期望 // H264H264视频和G711音频期望
startChartManage.sendH264VideoAndG711AudioTalkExpectData(); startChartManage.sendH264VideoAndG711AudioTalkExpectData();
AppLog.log( AppLog.log('app主动发对讲请求收到回复后发送的预期数据=======锁支持H264发送H264视频格式期望数据,peerID=${lockPeerID}');
'app主动发对讲请求收到回复后发送的预期数据=======锁支持H264发送H264视频格式期望数据,peerID=${lockPeerID}');
} else if (isMJpeg) { } else if (isMJpeg) {
// MJPEGG711音频期望 // MJPEGG711音频期望
startChartManage.sendImageVideoAndG711AudioTalkExpectData(); startChartManage.sendImageVideoAndG711AudioTalkExpectData();
AppLog.log( AppLog.log('app主动发对讲请求收到回复后发送的预期数据=======锁不支持H264支持MJPEG发送MJPEG视频格式期望数据,peerID=${lockPeerID}');
'app主动发对讲请求收到回复后发送的预期数据=======锁不支持H264支持MJPEG发送MJPEG视频格式期望数据,peerID=${lockPeerID}');
} else { } else {
// 使 // 使
startChartManage.sendImageVideoAndG711AudioTalkExpectData(); startChartManage.sendImageVideoAndG711AudioTalkExpectData();
AppLog.log( AppLog.log('app主动发对讲请求收到回复后发送的预期数据=======锁不支持H264和MJPEG默认发送MJPEG视频格式期望数据,peerID=${lockPeerID}');
'app主动发对讲请求收到回复后发送的预期数据=======锁不支持H264和MJPEG默认发送MJPEG视频格式期望数据,peerID=${lockPeerID}');
} }
} }
} }

View File

@ -61,12 +61,9 @@ class StartChartManage {
// //
static final StartChartManage _instance = StartChartManage._internal(); static final StartChartManage _instance = StartChartManage._internal();
final TalkeRequestOverTimeTimerManager talkeRequestOverTimeTimerManager = final TalkeRequestOverTimeTimerManager talkeRequestOverTimeTimerManager = TalkeRequestOverTimeTimerManager();
TalkeRequestOverTimeTimerManager(); final TalkePingOverTimeTimerManager talkePingOverTimeTimerManager = TalkePingOverTimeTimerManager();
final TalkePingOverTimeTimerManager talkePingOverTimeTimerManager = final TalkDataOverTimeTimerManager talkDataOverTimeTimerManager = TalkDataOverTimeTimerManager();
TalkePingOverTimeTimerManager();
final TalkDataOverTimeTimerManager talkDataOverTimeTimerManager =
TalkDataOverTimeTimerManager();
// //
factory StartChartManage() { factory StartChartManage() {
@ -171,8 +168,7 @@ class StartChartManage {
FromPeerId = loginData?.starchart?.starchartId ?? ''; FromPeerId = loginData?.starchart?.starchartId ?? '';
} else { } else {
_log(text: '开始注册客户端'); _log(text: '开始注册客户端');
final StarChartRegisterNodeEntity requestStarChartRegisterNode = final StarChartRegisterNodeEntity requestStarChartRegisterNode = await _requestStarChartRegisterNode();
await _requestStarChartRegisterNode();
await _saveStarChartRegisterNodeToStorage(requestStarChartRegisterNode); await _saveStarChartRegisterNodeToStorage(requestStarChartRegisterNode);
FromPeerId = requestStarChartRegisterNode.peer!.id ?? ''; FromPeerId = requestStarChartRegisterNode.peer!.id ?? '';
bindUserStarchart(requestStarChartRegisterNode); bindUserStarchart(requestStarChartRegisterNode);
@ -180,18 +176,14 @@ class StartChartManage {
} }
// //
Future<void> bindUserStarchart( Future<void> bindUserStarchart(StarChartRegisterNodeEntity requestStarChartRegisterNode) async {
StarChartRegisterNodeEntity requestStarChartRegisterNode) async {
try { try {
final LoginEntity entity = await ApiRepository.to.bindUserStarchart( final LoginEntity entity = await ApiRepository.to.bindUserStarchart(
starchartId: requestStarChartRegisterNode.peer?.id ?? '', starchartId: requestStarChartRegisterNode.peer?.id ?? '',
starchartPeerPublicKey: starchartPeerPublicKey: requestStarChartRegisterNode.peer?.publicKey ?? '',
requestStarChartRegisterNode.peer?.publicKey ?? '', starchartPeerPrivateKey: requestStarChartRegisterNode.peer?.privateKey ?? '',
starchartPeerPrivateKey:
requestStarChartRegisterNode.peer?.privateKey ?? '',
); );
requestStarChartRegisterNode.peer?.id = requestStarChartRegisterNode.peer?.id = entity.data?.starchart?.starchartId;
entity.data?.starchart?.starchartId;
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
AppLog.log('绑定成功'); AppLog.log('绑定成功');
} else { } else {
@ -204,14 +196,12 @@ class StartChartManage {
// //
Future<void> _relayQuery() async { Future<void> _relayQuery() async {
final RelayInfoEntity relayInfoEntity = final RelayInfoEntity relayInfoEntity = await StartChartApi.to.relayQueryInfo();
await StartChartApi.to.relayQueryInfo();
_saveRelayInfoEntityToStorage(relayInfoEntity); _saveRelayInfoEntityToStorage(relayInfoEntity);
if (relayInfoEntity.client_addr != null) { if (relayInfoEntity.client_addr != null) {
localPublicHost = relayInfoEntity.client_addr!; localPublicHost = relayInfoEntity.client_addr!;
} }
if (relayInfoEntity.relay_list != null && if (relayInfoEntity.relay_list != null && relayInfoEntity.relay_list!.length > 0) {
relayInfoEntity.relay_list!.length > 0) {
for (int i = 0; i <= relayInfoEntity.relay_list!.length; i++) { for (int i = 0; i <= relayInfoEntity.relay_list!.length; i++) {
final data = relayInfoEntity.relay_list?[i]; final data = relayInfoEntity.relay_list?[i];
if (data?.peerID != FromPeerId) { if (data?.peerID != FromPeerId) {
@ -239,8 +229,7 @@ class StartChartManage {
// udp // udp
Future<void> _onlineRelayService() async { Future<void> _onlineRelayService() async {
var addressIListenFrom = InternetAddress.anyIPv4; var addressIListenFrom = InternetAddress.anyIPv4;
await RawDatagramSocket.bind(addressIListenFrom, localPort) await RawDatagramSocket.bind(addressIListenFrom, localPort).then((RawDatagramSocket socket) {
.then((RawDatagramSocket socket) {
// (SO_RCVBUF = 8) // (SO_RCVBUF = 8)
if (AppPlatform.isAndroid) { if (AppPlatform.isAndroid) {
socket.setRawOption( socket.setRawOption(
@ -291,15 +280,15 @@ class StartChartManage {
} }
// RbcuInfo // RbcuInfo
void _sendRbcuInfoMessage( void _sendRbcuInfoMessage({required String ToPeerId, bool isResp = false}) async {
{required String ToPeerId, bool isResp = false}) async {
final uuid = _uuid.v1(); final uuid = _uuid.v1();
final int timestamp = DateTime.now().millisecondsSinceEpoch; final int timestamp = DateTime
.now()
.millisecondsSinceEpoch;
final Int64 int64Timestamp = Int64(timestamp); // 使 final Int64 int64Timestamp = Int64(timestamp); // 使
// ip地址和中继返回的外网地址 // ip地址和中继返回的外网地址
final List<ListenAddrData> listenAddrDataList = final List<ListenAddrData> listenAddrDataList = await _makeListenAddrDataList();
await _makeListenAddrDataList();
listenAddrDataList.insert( listenAddrDataList.insert(
0, // 0, //
ListenAddrData( ListenAddrData(
@ -309,15 +298,13 @@ class StartChartManage {
); );
final address = listenAddrDataList final address = listenAddrDataList
.where((element) => .where((element) => element.type == ListenAddrTypeConstant.local) //
element.type == ListenAddrTypeConstant.local) //
.map((e) => e.address) // List<String?> .map((e) => e.address) // List<String?>
.where((addr) => addr != null) // null .where((addr) => addr != null) // null
.map( .map(
(addr) => addr!.replaceAll(IpConstant.udpUrl, ''), (addr) => addr!.replaceAll(IpConstant.udpUrl, ''),
) // "udp://" ) // "udp://"
.cast< .cast<String>(); // Iterable<String>// Iterable<String?> Iterable<String>
String>(); // Iterable<String>// Iterable<String?> Iterable<String>
_rbcuSessionId = uuid; _rbcuSessionId = uuid;
final RbcuInfo rbcuInfo = RbcuInfo( final RbcuInfo rbcuInfo = RbcuInfo(
sessionId: uuid, sessionId: uuid,
@ -340,28 +327,21 @@ class StartChartManage {
void _sendRbcuProbeMessage() async { void _sendRbcuProbeMessage() async {
// //
String generateRandomString(int length) { String generateRandomString(int length) {
const chars = const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
final random = Random(); final random = Random();
return String.fromCharCodes( return String.fromCharCodes(
List.generate( List.generate(length, (index) => chars.codeUnitAt(random.nextInt(chars.length))),
length, (index) => chars.codeUnitAt(random.nextInt(chars.length))),
); );
} }
if (rbcuInfo != null && if (rbcuInfo != null && rbcuInfo!.address != null && rbcuInfo!.address.length > 0) {
rbcuInfo!.address != null &&
rbcuInfo!.address.length > 0) {
rbcuInfo!.address.forEach((element) { rbcuInfo!.address.forEach((element) {
// element // element
final parts = element.split(':'); final parts = element.split(':');
final host = parts[0]; // IP final host = parts[0]; // IP
final port = int.tryParse(parts[1]) ?? 0; // 0 final port = int.tryParse(parts[1]) ?? 0; // 0
final RbcuProbe rbcuProbe = RbcuProbe( final RbcuProbe rbcuProbe = RbcuProbe(sessionId: _rbcuSessionId, data: generateRandomString(100), targetAddress: element);
sessionId: _rbcuSessionId,
data: generateRandomString(100),
targetAddress: element);
final rbcuProBeBuffer = rbcuProbe.writeToBuffer(); final rbcuProBeBuffer = rbcuProbe.writeToBuffer();
_sendNatMessage(message: rbcuProBeBuffer, host: host, port: port); _sendNatMessage(message: rbcuProBeBuffer, host: host, port: port);
}); });
@ -378,8 +358,7 @@ class StartChartManage {
// //
void startSendingRbcuInfoMessages({required String ToPeerId}) { void startSendingRbcuInfoMessages({required String ToPeerId}) {
// 1 _sendRbcuInfoMessage // 1 _sendRbcuInfoMessage
rbcuInfoTimer ??= rbcuInfoTimer ??= Timer.periodic(Duration(seconds: _defaultIntervalTime), (timer) {
Timer.periodic(Duration(seconds: _defaultIntervalTime), (timer) {
// RbcuInfo // RbcuInfo
_log(text: '发送RbcuInfo 地址交换消息'); _log(text: '发送RbcuInfo 地址交换消息');
_sendRbcuInfoMessage(ToPeerId: ToPeerId); _sendRbcuInfoMessage(ToPeerId: ToPeerId);
@ -389,8 +368,7 @@ class StartChartManage {
// //
void startSendingRbcuProbeTMessages() { void startSendingRbcuProbeTMessages() {
// 1 _sendRbcuInfoMessage // 1 _sendRbcuInfoMessage
rbcuProbeTimer ??= rbcuProbeTimer ??= Timer.periodic(Duration(seconds: _defaultIntervalTime), (timer) {
Timer.periodic(Duration(seconds: _defaultIntervalTime), (timer) {
// RbcuProbe // RbcuProbe
_sendRbcuProbeMessage(); _sendRbcuProbeMessage();
}); });
@ -398,8 +376,7 @@ class StartChartManage {
// //
void startSendingRbcuConfirmTMessages() { void startSendingRbcuConfirmTMessages() {
rbcuConfirmTimer ??= rbcuConfirmTimer ??= Timer.periodic(Duration(seconds: _defaultIntervalTime), (timer) {
Timer.periodic(Duration(seconds: _defaultIntervalTime), (timer) {
// RbcuProbe // RbcuProbe
_sendRbcuConfirmMessage(); _sendRbcuConfirmMessage();
}); });
@ -458,11 +435,11 @@ class StartChartManage {
// ); // );
// } // }
// } // }
final LockListInfoItemEntity currentKeyInfo = final LockListInfoItemEntity currentKeyInfo = CommonDataManage().currentKeyInfo;
CommonDataManage().currentKeyInfo;
final isH264 = currentKeyInfo.lockFeature?.isH264 == 1; final isH264 = currentKeyInfo.lockFeature?.isH264 == 1;
final isMJpeg = currentKeyInfo.lockFeature?.isMJpeg == 1; final isMJpeg = currentKeyInfo.lockFeature?.isMJpeg == 1;
AppLog.log('isH264:${isH264}');
AppLog.log('isMJpeg:${isMJpeg}');
// 使H264MJPEG // 使H264MJPEG
if (isH264) { if (isH264) {
Get.toNamed( Get.toNamed(
@ -483,6 +460,7 @@ class StartChartManage {
seconds: _defaultIntervalTime, seconds: _defaultIntervalTime,
), ),
(Timer timer) async { (Timer timer) async {
AppLog.log('发送对讲请求:${ToPeerId}');
await sendCallRequestMessage(ToPeerId: ToPeerId); await sendCallRequestMessage(ToPeerId: ToPeerId);
}, },
); );
@ -526,8 +504,7 @@ class StartChartManage {
List<int> packetTalkData = payload.sublist(start, end); List<int> packetTalkData = payload.sublist(start, end);
// messageID // messageID
final messageId = final messageId = MessageCommand.getNextMessageId(toPeerId, increment: false);
MessageCommand.getNextMessageId(toPeerId, increment: false);
// //
final message = MessageCommand.talkDataMessage( final message = MessageCommand.talkDataMessage(
ToPeerId: toPeerId, ToPeerId: toPeerId,
@ -562,8 +539,7 @@ class StartChartManage {
final List<int> message = MessageCommand.heartbeatMessage( final List<int> message = MessageCommand.heartbeatMessage(
FromPeerId: FromPeerId, FromPeerId: FromPeerId,
ToPeerId: relayPeerId, ToPeerId: relayPeerId,
MessageId: MessageId: MessageCommand.getNextMessageId(relayPeerId, increment: true),
MessageCommand.getNextMessageId(relayPeerId, increment: true),
); );
await _sendMessage(message: message); await _sendMessage(message: message);
}, },
@ -572,8 +548,7 @@ class StartChartManage {
} }
// //
void sendEchoMessage( void sendEchoMessage({required List<int> payload, required String toPeerId}) async {
{required List<int> payload, required String toPeerId}) async {
// //
final int totalPackets = (payload.length / _maxPayloadSize).ceil(); final int totalPackets = (payload.length / _maxPayloadSize).ceil();
// //
@ -587,8 +562,7 @@ class StartChartManage {
List<int> packet = payload.sublist(start, end); List<int> packet = payload.sublist(start, end);
// messageID // messageID
final messageId = final messageId = MessageCommand.getNextMessageId(toPeerId, increment: false);
MessageCommand.getNextMessageId(toPeerId, increment: false);
// //
final message = MessageCommand.echoMessage( final message = MessageCommand.echoMessage(
ToPeerId: toPeerId, ToPeerId: toPeerId,
@ -606,13 +580,14 @@ class StartChartManage {
} }
// //
void sendGatewayResetMessage( void sendGatewayResetMessage({required String ToPeerId, required int gatewayId}) async {
{required String ToPeerId, required int gatewayId}) async {
final message = MessageCommand.gatewayResetMessage( final message = MessageCommand.gatewayResetMessage(
ToPeerId: ToPeerId, ToPeerId: ToPeerId,
FromPeerId: FromPeerId, FromPeerId: FromPeerId,
gatewayId: gatewayId, gatewayId: gatewayId,
time: DateTime.now().millisecondsSinceEpoch ~/ 1000, time: DateTime
.now()
.millisecondsSinceEpoch ~/ 1000,
MessageId: MessageCommand.getNextMessageId(ToPeerId, increment: true), MessageId: MessageCommand.getNextMessageId(ToPeerId, increment: true),
); );
await _sendMessage(message: message); await _sendMessage(message: message);
@ -728,8 +703,7 @@ class StartChartManage {
} }
// //
Future<void> sendTalkPingMessage( Future<void> sendTalkPingMessage({required String ToPeerId, required String FromPeerId}) async {
{required String ToPeerId, required String FromPeerId}) async {
final message = MessageCommand.talkPingMessage( final message = MessageCommand.talkPingMessage(
ToPeerId: ToPeerId, ToPeerId: ToPeerId,
FromPeerId: FromPeerId, FromPeerId: FromPeerId,
@ -825,11 +799,9 @@ class StartChartManage {
// //
Future<void> _sendMessage({required List<int> message}) async { Future<void> _sendMessage({required List<int> message}) async {
var result = await _udpSocket?.send( var result = await _udpSocket?.send(message, InternetAddress(remoteHost), remotePort);
message, InternetAddress(remoteHost), remotePort);
if (result != message.length) { if (result != message.length) {
throw StartChartMessageException( throw StartChartMessageException('❌Udp send data error----> $result ${message.length}');
'❌Udp send data error----> $result ${message.length}');
// _udpSocket = null; // _udpSocket = null;
} }
@ -846,15 +818,11 @@ class StartChartManage {
} }
// //
Future<void> _sendNatMessage( Future<void> _sendNatMessage({required List<int> message, required String host, required int port}) async {
{required List<int> message,
required String host,
required int port}) async {
_log(text: '发送nat消息'); _log(text: '发送nat消息');
var result = await _udpSocket?.send(message, InternetAddress(host), port); var result = await _udpSocket?.send(message, InternetAddress(host), port);
if (result != message.length) { if (result != message.length) {
throw StartChartMessageException( throw StartChartMessageException('❌Udp send data error----> $result ${message.length}');
'❌Udp send data error----> $result ${message.length}');
// _udpSocket = null; // _udpSocket = null;
} }
} }
@ -864,8 +832,7 @@ class StartChartManage {
// //
final Map<String, String> deviceInfo = await _getDeviceInfo(); final Map<String, String> deviceInfo = await _getDeviceInfo();
// //
final StarChartRegisterNodeEntity response = final StarChartRegisterNodeEntity response = await StartChartApi.to.starChartRegisterNode(
await StartChartApi.to.starChartRegisterNode(
product: _productName, product: _productName,
model: '${deviceInfo['brand']}_${deviceInfo['model']}', model: '${deviceInfo['brand']}_${deviceInfo['model']}',
name: '${deviceInfo['id']}', name: '${deviceInfo['id']}',
@ -875,8 +842,7 @@ class StartChartManage {
} }
// //
Future<void> _saveStarChartRegisterNodeToStorage( Future<void> _saveStarChartRegisterNodeToStorage(StarChartRegisterNodeEntity starChartRegisterNodeEntity) async {
StarChartRegisterNodeEntity starChartRegisterNodeEntity) async {
if (starChartRegisterNodeEntity != null) { if (starChartRegisterNodeEntity != null) {
await Storage.saveStarChartRegisterNodeInfo(starChartRegisterNodeEntity); await Storage.saveStarChartRegisterNodeInfo(starChartRegisterNodeEntity);
final LoginData? loginData = await Storage.getLoginData(); final LoginData? loginData = await Storage.getLoginData();
@ -886,8 +852,7 @@ class StartChartManage {
} }
// //
Future<void> _saveRelayInfoEntityToStorage( Future<void> _saveRelayInfoEntityToStorage(RelayInfoEntity relayInfoEntity) async {
RelayInfoEntity relayInfoEntity) async {
if (relayInfoEntity != null) { if (relayInfoEntity != null) {
await Storage.saveRelayInfo(relayInfoEntity); await Storage.saveRelayInfo(relayInfoEntity);
} }
@ -909,8 +874,7 @@ class StartChartManage {
); );
// ip地址和中继返回的外网地址 // ip地址和中继返回的外网地址
final List<ListenAddrData> listenAddrDataList = final List<ListenAddrData> listenAddrDataList = await _makeListenAddrDataList();
await _makeListenAddrDataList();
// //
final RelayServiceData relayServiceData = RelayServiceData( final RelayServiceData relayServiceData = RelayServiceData(
@ -977,11 +941,12 @@ class StartChartManage {
String ipAddress = address.address; String ipAddress = address.address;
// IPv6 // IPv6
if (ipAddress.contains('%')) { if (ipAddress.contains('%')) {
ipAddress = ipAddress.split('%').first; ipAddress = ipAddress
.split('%')
.first;
} }
// IP // IP
if (ipAddress.isNotEmpty && if (ipAddress.isNotEmpty && !IpConstant.reportExcludeIp.contains(ipAddress)) {
!IpConstant.reportExcludeIp.contains(ipAddress)) {
ipAddresses.add(ipAddress); ipAddresses.add(ipAddress);
} }
} }
@ -998,8 +963,7 @@ class StartChartManage {
/// ///
Future<Map<String, String>> _getDeviceInfo() async { Future<Map<String, String>> _getDeviceInfo() async {
final Map<String, String> deviceInfo = final Map<String, String> deviceInfo = await DeviceInfoUtils.getDeviceInfo();
await DeviceInfoUtils.getDeviceInfo();
return deviceInfo; return deviceInfo;
} }
@ -1016,8 +980,7 @@ class StartChartManage {
if (host != null && port != null) { if (host != null && port != null) {
try { try {
// DNS // DNS
final List<InternetAddress> addresses = final List<InternetAddress> addresses = await InternetAddress.lookup(host);
await InternetAddress.lookup(host);
if (addresses.isEmpty) { if (addresses.isEmpty) {
throw FormatException('DNS resolution failed for $host'); throw FormatException('DNS resolution failed for $host');
} }
@ -1082,8 +1045,7 @@ class StartChartManage {
final int payloadType = scpMessage.PayloadType ?? 0; final int payloadType = scpMessage.PayloadType ?? 0;
final int messageType = scpMessage.MessageType ?? 0; final int messageType = scpMessage.MessageType ?? 0;
try { try {
final ScpMessageHandler handler = final ScpMessageHandler handler = ScpMessageHandlerFactory.createHandler(payloadType);
ScpMessageHandlerFactory.createHandler(payloadType);
if (messageType == MessageTypeConstant.Req) { if (messageType == MessageTypeConstant.Req) {
handler.handleReq(scpMessage); handler.handleReq(scpMessage);
} else if (messageType == MessageTypeConstant.Resp) { } else if (messageType == MessageTypeConstant.Resp) {
@ -1170,10 +1132,18 @@ class StartChartManage {
} }
/// ///
void changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer( void changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer({required TalkExpectReq talkExpect}) {
{required TalkExpectReq talkExpect}) {
_defaultTalkExpect = talkExpect; _defaultTalkExpect = talkExpect;
reStartTalkExpectMessageTimer(); sendTalkExpectMessage(
talkExpect: _defaultTalkExpect,
);
sendTalkExpectMessage(
talkExpect: _defaultTalkExpect,
);
sendTalkExpectMessage(
talkExpect: _defaultTalkExpect,
);
// reStartTalkExpectMessageTimer();
} }
void reSetDefaultTalkExpect() { void reSetDefaultTalkExpect() {
@ -1190,8 +1160,7 @@ class StartChartManage {
videoType: [VideoTypeE.IMAGE], videoType: [VideoTypeE.IMAGE],
audioType: [], audioType: [],
); );
changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer( changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer(talkExpect: talkExpectReq);
talkExpect: talkExpectReq);
} }
/// ///
@ -1200,20 +1169,17 @@ class StartChartManage {
videoType: [VideoTypeE.H264], videoType: [VideoTypeE.H264],
audioType: [], audioType: [],
); );
changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer( changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer(talkExpect: talkExpectReq);
talkExpect: talkExpectReq);
} }
/// ///
void sendImageVideoAndG711AudioTalkExpectData() { void sendImageVideoAndG711AudioTalkExpectData() {
changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer( changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer(talkExpect: TalkConstant.ImageExpect);
talkExpect: TalkConstant.ImageExpect);
} }
/// ///
void sendH264VideoAndG711AudioTalkExpectData() { void sendH264VideoAndG711AudioTalkExpectData() {
changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer( changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer(talkExpect: TalkConstant.H264Expect);
talkExpect: TalkConstant.H264Expect);
} }
/// ///

View File

@ -104,10 +104,6 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
codecType: 'h264', codecType: 'h264',
); );
// textureId // textureId
AppLog.log(
'StartChartManage().videoWidth:${StartChartManage().videoWidth}');
AppLog.log(
'StartChartManage().videoHeight:${StartChartManage().videoHeight}');
final textureId = await VideoDecodePlugin.initDecoder(config); final textureId = await VideoDecodePlugin.initDecoder(config);
if (textureId != null) { if (textureId != null) {
Future.microtask(() => state.textureId.value = textureId); Future.microtask(() => state.textureId.value = textureId);
@ -172,15 +168,11 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
ScpMessage scpMessage, ScpMessage scpMessage,
) { ) {
// frameSeq较小时阈值也小 // frameSeq较小时阈值也小
if (!_pendingStreamReset && if (!_pendingStreamReset && _lastFrameSeq != null && frameType == TalkDataH264Frame_FrameTypeE.I && frameSeq < _lastFrameSeq!) {
_lastFrameSeq != null &&
frameType == TalkDataH264Frame_FrameTypeE.I &&
frameSeq < _lastFrameSeq!) {
int dynamicThreshold = _getFrameSeqRolloverThreshold(_lastFrameSeq!); int dynamicThreshold = _getFrameSeqRolloverThreshold(_lastFrameSeq!);
if ((_lastFrameSeq! - frameSeq) > dynamicThreshold) { if ((_lastFrameSeq! - frameSeq) > dynamicThreshold) {
// I帧frameSeq大幅回绕loading并重置所有本地状态 // I帧frameSeq大幅回绕loading并重置所有本地状态
AppLog.log( AppLog.log('检测到新流I帧frameSeq大幅回绕进入loading并重置: frameSeq=$frameSeq, lastFrameSeq=$_lastFrameSeq, 阈值=$dynamicThreshold');
'检测到新流I帧frameSeq大幅回绕进入loading并重置: frameSeq=$frameSeq, lastFrameSeq=$_lastFrameSeq, 阈值=$dynamicThreshold');
Future.microtask(() => state.isLoading.value = true); Future.microtask(() => state.isLoading.value = true);
_pendingStreamReset = true; _pendingStreamReset = true;
// //
@ -197,8 +189,7 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
// //
} else { } else {
// //
AppLog.log( AppLog.log('检测到I帧乱序未超过回绕阈值$dynamicThreshold),丢弃: frameSeq=$frameSeq, lastFrameSeq=$_lastFrameSeq');
'检测到I帧乱序未超过回绕阈值$dynamicThreshold),丢弃: frameSeq=$frameSeq, lastFrameSeq=$_lastFrameSeq');
return; return;
} }
} }
@ -238,8 +229,7 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
// P/B帧 // P/B帧
while (state.h264FrameBuffer.length >= state.maxFrameBufferSize) { while (state.h264FrameBuffer.length >= state.maxFrameBufferSize) {
int pbIndex = state.h264FrameBuffer int pbIndex = state.h264FrameBuffer.indexWhere((f) => f['frameType'] == TalkDataH264Frame_FrameTypeE.P);
.indexWhere((f) => f['frameType'] == TalkDataH264Frame_FrameTypeE.P);
if (pbIndex != -1) { if (pbIndex != -1) {
state.h264FrameBuffer.removeAt(pbIndex); state.h264FrameBuffer.removeAt(pbIndex);
} else { } else {
@ -260,15 +250,17 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
final int intervalMs = (1000 / state.targetFps).round(); final int intervalMs = (1000 / state.targetFps).round();
// //
state.frameProcessTimer = state.frameProcessTimer = Timer.periodic(Duration(milliseconds: intervalMs), (timer) {
Timer.periodic(Duration(milliseconds: intervalMs), (timer) {
_processNextFrameFromBuffer(); _processNextFrameFromBuffer();
}); });
AppLog.log('启动帧处理定时器,目标帧率: ${state.targetFps}fps间隔: ${intervalMs}ms'); AppLog.log('启动帧处理定时器,目标帧率: ${state.targetFps}fps间隔: ${intervalMs}ms');
} }
///
/// ///
void _processNextFrameFromBuffer() async { void _processNextFrameFromBuffer() async {
final startTime = DateTime.now().microsecondsSinceEpoch;
// //
if (state.isProcessingFrame) { if (state.isProcessingFrame) {
return; return;
@ -279,25 +271,19 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
return; return;
} }
try {
// I帧frameSeq最小的I帧消费 // I帧frameSeq最小的I帧消费
final iFrames = state.h264FrameBuffer final iFrames = state.h264FrameBuffer.where((f) => f['frameType'] == TalkDataH264Frame_FrameTypeE.I).toList();
.where((f) => f['frameType'] == TalkDataH264Frame_FrameTypeE.I) iFrames.sort((a, b) => (a['frameSeq'] as int).compareTo(b['frameSeq'] as int));
.toList();
iFrames
.sort((a, b) => (a['frameSeq'] as int).compareTo(b['frameSeq'] as int));
if (iFrames.isNotEmpty) { if (iFrames.isNotEmpty) {
// I帧I帧frameSeq
final minIFrame = iFrames.first; final minIFrame = iFrames.first;
final minIFrameSeq = minIFrame['frameSeq']; final minIFrameSeq = minIFrame['frameSeq'];
final targetIndex = state.h264FrameBuffer.indexWhere( final targetIndex = state.h264FrameBuffer.indexWhere(
(f) => (f) => f['frameType'] == TalkDataH264Frame_FrameTypeE.I && f['frameSeq'] == minIFrameSeq,
f['frameType'] == TalkDataH264Frame_FrameTypeE.I &&
f['frameSeq'] == minIFrameSeq,
); );
state.isProcessingFrame = true; state.isProcessingFrame = true;
final Map<String, dynamic>? frameMap = final Map<String, dynamic>? frameMap = state.h264FrameBuffer.removeAt(targetIndex);
state.h264FrameBuffer.removeAt(targetIndex);
if (frameMap == null) { if (frameMap == null) {
state.isProcessingFrame = false; state.isProcessingFrame = false;
return; return;
@ -307,12 +293,7 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
final int? frameSeq = frameMap['frameSeq']; final int? frameSeq = frameMap['frameSeq'];
final int? frameSeqI = frameMap['frameSeqI']; final int? frameSeqI = frameMap['frameSeqI'];
final int? pts = frameMap['pts']; final int? pts = frameMap['pts'];
final ScpMessage? scpMessage = frameMap['scpMessage']; if (frameData == null || frameType == null || frameSeq == null || frameSeqI == null || pts == null) {
if (frameData == null ||
frameType == null ||
frameSeq == null ||
frameSeqI == null ||
pts == null) {
state.isProcessingFrame = false; state.isProcessingFrame = false;
return; return;
} }
@ -321,11 +302,7 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
return; return;
} }
lastDecodedIFrameSeq = minIFrameSeq; lastDecodedIFrameSeq = minIFrameSeq;
// AppLog.log('送入解码器的P帧数据frameSeq:${frameSeq},frameSeqI:${frameSeqI},'
// 'frameType:${frameType},messageId:${scpMessage!.MessageId}');
// final spsData = NaluUtils.filterNalusByType(frameData, 7);
// final ppsData = NaluUtils.filterNalusByType(frameData, 8);
// AppLog.log('SPSDATA:${spsData}ppsData:${ppsData}');
await VideoDecodePlugin.sendFrame( await VideoDecodePlugin.sendFrame(
frameData: frameData, frameData: frameData,
frameType: 0, frameType: 0,
@ -340,24 +317,17 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
// I帧时refIFrameSeq等于lastDecodedIFrameSeq的P帧 // I帧时refIFrameSeq等于lastDecodedIFrameSeq的P帧
if (lastDecodedIFrameSeq != null) { if (lastDecodedIFrameSeq != null) {
final validPFrames = state.h264FrameBuffer final validPFrames =
.where((f) => state.h264FrameBuffer.where((f) => f['frameType'] == TalkDataH264Frame_FrameTypeE.P && f['frameSeqI'] == lastDecodedIFrameSeq).toList();
f['frameType'] == TalkDataH264Frame_FrameTypeE.P &&
f['frameSeqI'] == lastDecodedIFrameSeq)
.toList();
if (validPFrames.isNotEmpty) { if (validPFrames.isNotEmpty) {
validPFrames.sort( validPFrames.sort((a, b) => (a['frameSeq'] as int).compareTo(b['frameSeq'] as int));
(a, b) => (a['frameSeq'] as int).compareTo(b['frameSeq'] as int));
final minPFrame = validPFrames.first; final minPFrame = validPFrames.first;
final targetIndex = state.h264FrameBuffer.indexWhere( final targetIndex = state.h264FrameBuffer.indexWhere(
(f) => (f) =>
f['frameType'] == TalkDataH264Frame_FrameTypeE.P && f['frameType'] == TalkDataH264Frame_FrameTypeE.P && f['frameSeq'] == minPFrame['frameSeq'] && f['frameSeqI'] == lastDecodedIFrameSeq,
f['frameSeq'] == minPFrame['frameSeq'] &&
f['frameSeqI'] == lastDecodedIFrameSeq,
); );
state.isProcessingFrame = true; state.isProcessingFrame = true;
final Map<String, dynamic>? frameMap = final Map<String, dynamic>? frameMap = state.h264FrameBuffer.removeAt(targetIndex);
state.h264FrameBuffer.removeAt(targetIndex);
if (frameMap == null) { if (frameMap == null) {
state.isProcessingFrame = false; state.isProcessingFrame = false;
return; return;
@ -367,12 +337,7 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
final int? frameSeq = frameMap['frameSeq']; final int? frameSeq = frameMap['frameSeq'];
final int? frameSeqI = frameMap['frameSeqI']; final int? frameSeqI = frameMap['frameSeqI'];
final int? pts = frameMap['pts']; final int? pts = frameMap['pts'];
final ScpMessage? scpMessage = frameMap['scpMessage']; if (frameData == null || frameType == null || frameSeq == null || frameSeqI == null || pts == null) {
if (frameData == null ||
frameType == null ||
frameSeq == null ||
frameSeqI == null ||
pts == null) {
state.isProcessingFrame = false; state.isProcessingFrame = false;
return; return;
} }
@ -380,8 +345,6 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
state.isProcessingFrame = false; state.isProcessingFrame = false;
return; return;
} }
// AppLog.log('送入解码器的I帧数据frameSeq:${frameSeq},frameSeqI:${frameSeqI},'
// 'frameType:${frameType},messageId:${scpMessage!.MessageId}');
await VideoDecodePlugin.sendFrame( await VideoDecodePlugin.sendFrame(
frameData: frameData, frameData: frameData,
@ -396,6 +359,16 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
} }
} }
// I帧到来 // I帧到来
} finally {
final endTime = DateTime.now().microsecondsSinceEpoch;
final durationMs = (endTime - startTime) / 1000.0;
// > 5ms
if (durationMs > 5) {
debugPrint('[_processNextFrameFromBuffer] 耗时: ${durationMs.toStringAsFixed(2)} ms');
// 使
// AppLog.log('Frame processing took ${durationMs.toStringAsFixed(2)} ms');
}
}
} }
/// ///
@ -427,8 +400,7 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
AppLog.log("==== 启动新的数据流监听 ===="); AppLog.log("==== 启动新的数据流监听 ====");
_isListening = true; _isListening = true;
_streamSubscription = state.talkDataRepository.talkDataStream _streamSubscription = state.talkDataRepository.talkDataStream.listen((TalkDataModel talkDataModel) async {
.listen((TalkDataModel talkDataModel) async {
_processFrame(talkDataModel); _processFrame(talkDataModel);
}); });
} }
@ -437,8 +409,7 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
void _playAudioFrames() { void _playAudioFrames() {
// //
// //
if (state.audioBuffer.isEmpty || if (state.audioBuffer.isEmpty || state.audioBuffer.length < audioBufferSize) {
state.audioBuffer.length < audioBufferSize) {
return; return;
} }
@ -446,8 +417,7 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
TalkData? oldestFrame; TalkData? oldestFrame;
int oldestIndex = -1; int oldestIndex = -1;
for (int i = 0; i < state.audioBuffer.length; i++) { for (int i = 0; i < state.audioBuffer.length; i++) {
if (oldestFrame == null || if (oldestFrame == null || state.audioBuffer[i].durationMs < oldestFrame.durationMs) {
state.audioBuffer[i].durationMs < oldestFrame.durationMs) {
oldestFrame = state.audioBuffer[i]; oldestFrame = state.audioBuffer[i];
oldestIndex = i; oldestIndex = i;
} }
@ -477,8 +447,7 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
break; break;
case TalkStatus.answeredSuccessfully: case TalkStatus.answeredSuccessfully:
state.oneMinuteTimeTimer?.cancel(); // state.oneMinuteTimeTimer?.cancel(); //
state.oneMinuteTimeTimer ??= state.oneMinuteTimeTimer ??= Timer.periodic(const Duration(seconds: 1), (Timer t) {
Timer.periodic(const Duration(seconds: 1), (Timer t) {
if (state.isLoading.isFalse) { if (state.isLoading.isFalse) {
state.oneMinuteTime.value++; state.oneMinuteTime.value++;
} }
@ -493,9 +462,7 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
/// ///
void _playAudioData(TalkData talkData) async { void _playAudioData(TalkData talkData) async {
if (state.isOpenVoice.value && if (state.isOpenVoice.value && state.isLoading.isFalse && state.isRecordingAudio.value == false) {
state.isLoading.isFalse &&
state.isRecordingAudio.value == false) {
List<int> encodedData = G711Tool.decode(talkData.content, 0); // 0A-law List<int> encodedData = G711Tool.decode(talkData.content, 0); // 0A-law
// PCM PcmArrayInt16 // PCM PcmArrayInt16
final PcmArrayInt16 fromList = PcmArrayInt16.fromList(encodedData); final PcmArrayInt16 fromList = PcmArrayInt16.fromList(encodedData);
@ -670,11 +637,9 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
AppLog.log('截图失败: 未找到当前上下文'); AppLog.log('截图失败: 未找到当前上下文');
return; return;
} }
final RenderRepaintBoundary boundary = state.globalKey.currentContext! final RenderRepaintBoundary boundary = state.globalKey.currentContext!.findRenderObject()! as RenderRepaintBoundary;
.findRenderObject()! as RenderRepaintBoundary;
final ui.Image image = await boundary.toImage(); final ui.Image image = await boundary.toImage();
final ByteData? byteData = final ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png);
await image.toByteData(format: ui.ImageByteFormat.png);
if (byteData == null) { if (byteData == null) {
AppLog.log('截图失败: 图像数据为空'); AppLog.log('截图失败: 图像数据为空');
@ -702,15 +667,13 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
// //
Future<void> remoteOpenLock() async { Future<void> remoteOpenLock() async {
final LockListInfoItemEntity currentKeyInfo = final LockListInfoItemEntity currentKeyInfo = CommonDataManage().currentKeyInfo;
CommonDataManage().currentKeyInfo;
var lockId = currentKeyInfo.lockId ?? 0; var lockId = currentKeyInfo.lockId ?? 0;
var remoteUnlock = currentKeyInfo.lockSetting?.remoteUnlock ?? 0; var remoteUnlock = currentKeyInfo.lockSetting?.remoteUnlock ?? 0;
final lockPeerId = StartChartManage().lockPeerId; final lockPeerId = StartChartManage().lockPeerId;
final LockListInfoGroupEntity? lockListInfoGroupEntity = final LockListInfoGroupEntity? lockListInfoGroupEntity = await Storage.getLockMainListData();
await Storage.getLockMainListData();
if (lockListInfoGroupEntity != null) { if (lockListInfoGroupEntity != null) {
lockListInfoGroupEntity!.groupList?.forEach((element) { lockListInfoGroupEntity!.groupList?.forEach((element) {
final lockList = element.lockList; final lockList = element.lockList;
@ -728,8 +691,7 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
}); });
} }
if (remoteUnlock == 1) { if (remoteUnlock == 1) {
final LoginEntity entity = await ApiRepository.to final LoginEntity entity = await ApiRepository.to.remoteOpenLock(lockId: lockId.toString(), timeOut: 60);
.remoteOpenLock(lockId: lockId.toString(), timeOut: 60);
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
showToast('已开锁'.tr); showToast('已开锁'.tr);
StartChartManage().lockListPeerId = []; StartChartManage().lockListPeerId = [];
@ -756,8 +718,7 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
state.startRecordingAudioTime.value = DateTime.now(); state.startRecordingAudioTime.value = DateTime.now();
// //
state.voiceProcessor state.voiceProcessor?.addFrameListeners(<VoiceProcessorFrameListener>[_onFrame]);
?.addFrameListeners(<VoiceProcessorFrameListener>[_onFrame]);
state.voiceProcessor?.addErrorListener(_onError); state.voiceProcessor?.addErrorListener(_onError);
} else { } else {
// state.errorMessage.value = 'Recording permission not granted'; // state.errorMessage.value = 'Recording permission not granted';
@ -777,8 +738,7 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
state.endRecordingAudioTime.value = DateTime.now(); state.endRecordingAudioTime.value = DateTime.now();
// //
final Duration duration = state.endRecordingAudioTime.value final Duration duration = state.endRecordingAudioTime.value.difference(state.startRecordingAudioTime.value);
.difference(state.startRecordingAudioTime.value);
state.recordingAudioTime.value = duration.inSeconds; state.recordingAudioTime.value = duration.inSeconds;
} on PlatformException catch (ex) { } on PlatformException catch (ex) {
@ -848,10 +808,8 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
_bufferedAudioFrames.addAll(encodedData); _bufferedAudioFrames.addAll(encodedData);
// //
if (_startProcessingAudioTimer == null && if (_startProcessingAudioTimer == null && _bufferedAudioFrames.length > chunkSize) {
_bufferedAudioFrames.length > chunkSize) { _startProcessingAudioTimer = Timer.periodic(Duration(milliseconds: intervalMs), _sendAudioChunk);
_startProcessingAudioTimer =
Timer.periodic(Duration(milliseconds: intervalMs), _sendAudioChunk);
} }
} }
@ -887,8 +845,7 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
} }
/// ///
StartChartManage().changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer( StartChartManage().changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer(talkExpect: talkExpectReq);
talkExpect: talkExpectReq);
// loadingframeSeq回绕检测 // loadingframeSeq回绕检测
// frameSeq回绕检测标志 // frameSeq回绕检测标志

View File

@ -29,15 +29,12 @@ class TalkViewNativeDecodePage extends StatefulWidget {
const TalkViewNativeDecodePage({Key? key}) : super(key: key); const TalkViewNativeDecodePage({Key? key}) : super(key: key);
@override @override
State<TalkViewNativeDecodePage> createState() => State<TalkViewNativeDecodePage> createState() => _TalkViewNativeDecodePageState();
_TalkViewNativeDecodePageState();
} }
class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> with TickerProviderStateMixin {
with TickerProviderStateMixin {
final TalkViewNativeDecodeLogic logic = Get.put(TalkViewNativeDecodeLogic()); final TalkViewNativeDecodeLogic logic = Get.put(TalkViewNativeDecodeLogic());
final TalkViewNativeDecodeState state = final TalkViewNativeDecodeState state = Get.find<TalkViewNativeDecodeLogic>().state;
Get.find<TalkViewNativeDecodeLogic>().state;
final startChartManage = StartChartManage(); final startChartManage = StartChartManage();
@override @override
@ -69,56 +66,39 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage>
// false 退 // false 退
return false; return false;
}, },
child: SizedBox( child: Container(
width: 1.sw, width: 1.sw,
height: 1.sh, height: 1.sh,
color: Colors.black.withOpacity(0.7),
child: Stack( child: Stack(
alignment: Alignment.center, alignment: Alignment.center,
children: <Widget>[ children: <Widget>[
// //
Obx( Obx(
() { () {
final double screenWidth = MediaQuery.of(context).size.width;
final double screenHeight = MediaQuery.of(context).size.height;
final double logicalWidth = MediaQuery.of(context).size.width;
final double logicalHeight = MediaQuery.of(context).size.height;
final double devicePixelRatio =
MediaQuery.of(context).devicePixelRatio;
//
final double physicalWidth = logicalWidth * devicePixelRatio;
final double physicalHeight = logicalHeight * devicePixelRatio;
//
const int rotatedImageWidth = 480; //
const int rotatedImageHeight = 864; //
//
final double scaleWidth = physicalWidth / rotatedImageWidth;
final double scaleHeight = physicalHeight / rotatedImageHeight;
max(scaleWidth, scaleHeight); //
// loading中或textureId为nullloading/ // loading中或textureId为nullloading/
if (state.isLoading.isTrue || state.textureId.value == null) { if (state.isLoading.isTrue || state.textureId.value == null) {
return Image.asset( return Image.asset(
'images/main/monitorBg.png', 'images/main/monitorBg.png',
width: screenWidth, width: 1.sw,
height: screenHeight, height: 1.sh,
fit: BoxFit.cover, fit: BoxFit.cover,
); );
} else { } else {
return Positioned.fill( return Positioned(
top: 0,
left: 0,
right: 0,
child: PopScope( child: PopScope(
canPop: false, canPop: false,
child: RepaintBoundary( child: RepaintBoundary(
key: state.globalKey, key: state.globalKey,
child: SizedBox.expand(
child: RotatedBox( child: RotatedBox(
// 使RotatedBox // 使RotatedBox
quarterTurns: startChartManage.rotateAngle ~/ 90, quarterTurns: startChartManage.rotateAngle ~/ 90,
child: Platform.isIOS child: state.isFullScreen.isFalse
? Transform.scale( ? AspectRatio(
scale: 1.008, // iOS白边 aspectRatio: StartChartManage().videoWidth / StartChartManage().videoHeight,
child: Texture( child: Texture(
textureId: state.textureId.value!, textureId: state.textureId.value!,
filterQuality: FilterQuality.medium, filterQuality: FilterQuality.medium,
@ -131,7 +111,6 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage>
), ),
), ),
), ),
),
); );
} }
}, },
@ -151,19 +130,14 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage>
width: 1.sw, width: 1.sw,
child: Obx( child: Obx(
() { () {
final String sec = (state.oneMinuteTime.value % 60) final String sec = (state.oneMinuteTime.value % 60).toString().padLeft(2, '0');
.toString() final String min = (state.oneMinuteTime.value ~/ 60).toString().padLeft(2, '0');
.padLeft(2, '0');
final String min = (state.oneMinuteTime.value ~/ 60)
.toString()
.padLeft(2, '0');
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
Text( Text(
'$min:$sec', '$min:$sec',
style: TextStyle( style: TextStyle(fontSize: 26.sp, color: Colors.white),
fontSize: 26.sp, color: Colors.white),
), ),
], ],
); );
@ -177,9 +151,7 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage>
width: 1.sw - 30.w * 2, width: 1.sw - 30.w * 2,
// height: 300.h, // height: 300.h,
margin: EdgeInsets.all(30.w), margin: EdgeInsets.all(30.w),
decoration: BoxDecoration( decoration: BoxDecoration(color: Colors.black.withOpacity(0.2), borderRadius: BorderRadius.circular(20.h)),
color: Colors.black.withOpacity(0.2),
borderRadius: BorderRadius.circular(20.h)),
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
SizedBox(height: 20.h), SizedBox(height: 20.h),
@ -191,9 +163,7 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage>
), ),
), ),
), ),
Obx(() => state.isLoading.isTrue Obx(() => state.isLoading.isTrue ? buildRotationTransition() : Container()),
? buildRotationTransition()
: Container()),
Obx(() => state.isLongPressing.value Obx(() => state.isLongPressing.value
? Positioned( ? Positioned(
top: 80.h, top: 80.h,
@ -213,8 +183,7 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage>
SizedBox(width: 10.w), SizedBox(width: 10.w),
Text( Text(
'正在说话...'.tr, '正在说话...'.tr,
style: TextStyle( style: TextStyle(fontSize: 20.sp, color: Colors.white),
fontSize: 20.sp, color: Colors.white),
), ),
], ],
), ),
@ -246,10 +215,8 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage>
width: 40.w, width: 40.w,
height: 40.w, height: 40.w,
image: state.isOpenVoice.value image: state.isOpenVoice.value
? const AssetImage( ? const AssetImage('images/main/icon_lockDetail_monitoringOpenVoice.png')
'images/main/icon_lockDetail_monitoringOpenVoice.png') : const AssetImage('images/main/icon_lockDetail_monitoringCloseVoice.png'))),
: const AssetImage(
'images/main/icon_lockDetail_monitoringCloseVoice.png'))),
), ),
), ),
SizedBox(width: 50.w), SizedBox(width: 50.w),
@ -264,11 +231,7 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage>
width: 50.w, width: 50.w,
height: 50.w, height: 50.w,
padding: EdgeInsets.all(5.w), padding: EdgeInsets.all(5.w),
child: Image( child: Image(width: 40.w, height: 40.w, image: const AssetImage('images/main/icon_lockDetail_monitoringScreenshot.png')),
width: 40.w,
height: 40.w,
image: const AssetImage(
'images/main/icon_lockDetail_monitoringScreenshot.png')),
), ),
), ),
SizedBox(width: 50.w), SizedBox(width: 50.w),
@ -293,8 +256,7 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage>
width: 40.w, width: 40.w,
height: 40.w, height: 40.w,
fit: BoxFit.fill, fit: BoxFit.fill,
image: const AssetImage( image: const AssetImage('images/main/icon_lockDetail_monitoringScreenRecording.png'),
'images/main/icon_lockDetail_monitoringScreenRecording.png'),
), ),
), ),
), ),
@ -330,13 +292,8 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage>
Text( Text(
q, q,
style: TextStyle( style: TextStyle(
color: state.currentQuality.value == q color: state.currentQuality.value == q ? AppColors.mainColor : Colors.black,
? AppColors.mainColor fontWeight: state.currentQuality.value == q ? FontWeight.bold : FontWeight.normal,
: Colors.black,
fontWeight:
state.currentQuality.value == q
? FontWeight.bold
: FontWeight.normal,
fontSize: 28.sp, fontSize: 28.sp,
), ),
), ),
@ -352,8 +309,7 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage>
); );
}, },
child: Container( child: Container(
child: Icon(Icons.high_quality_outlined, child: Icon(Icons.high_quality_outlined, color: Colors.white, size: 38.w),
color: Colors.white, size: 38.w),
), ),
), ),
Visibility( Visibility(
@ -377,9 +333,7 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage>
} }
Widget bottomBottomBtnWidget() { Widget bottomBottomBtnWidget() {
return Row( return Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
// //
Obx( Obx(
() => bottomBtnItemWidget( () => bottomBtnItemWidget(
@ -399,17 +353,14 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage>
state.isLongPressing.value = false; state.isLongPressing.value = false;
}, },
onClick: () async { onClick: () async {
if (state.talkStatus.value == if (state.talkStatus.value == TalkStatus.passiveCallWaitingAnswer) {
TalkStatus.passiveCallWaitingAnswer) {
// //
logic.initiateAnswerCommand(); logic.initiateAnswerCommand();
} }
}, },
), ),
), ),
bottomBtnItemWidget( bottomBtnItemWidget('images/main/icon_lockDetail_hangUp.png', '挂断'.tr, Colors.red, onClick: () {
'images/main/icon_lockDetail_hangUp.png', '挂断'.tr, Colors.red,
onClick: () {
// //
logic.udpHangUpAction(); logic.udpHangUpAction();
}), }),

View File

@ -0,0 +1,518 @@
import 'dart:async';
import 'dart:math';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:http/http.dart' as http;
import 'package:provider/provider.dart';
import 'package:star_lock/appRouters.dart';
import 'package:star_lock/flavors.dart';
import 'package:star_lock/talk/call/callTalk.dart';
import 'package:star_lock/talk/starChart/constant/talk_status.dart';
import 'package:star_lock/talk/starChart/handle/impl/debug_Info_model.dart';
import 'package:star_lock/talk/starChart/handle/impl/udp_talk_data_handler.dart';
import 'package:star_lock/talk/starChart/star_chart_manage.dart';
import 'package:star_lock/talk/starChart/views/native/talk_view_native_decode_logic.dart';
import 'package:star_lock/talk/starChart/views/native/talk_view_native_decode_state.dart';
import 'package:star_lock/talk/starChart/views/talkView/talk_view_logic.dart';
import 'package:star_lock/talk/starChart/views/talkView/talk_view_state.dart';
import 'package:video_decode_plugin/video_decode_plugin.dart';
import '../../../../app_settings/app_colors.dart';
import '../../../../tools/showTFView.dart';
class TalkViewNativeDecodePageDebug extends StatefulWidget {
const TalkViewNativeDecodePageDebug({Key? key}) : super(key: key);
@override
State<TalkViewNativeDecodePageDebug> createState() => _TalkViewNativeDecodePageDebugState();
}
class _TalkViewNativeDecodePageDebugState extends State<TalkViewNativeDecodePageDebug> with TickerProviderStateMixin {
final TalkViewNativeDecodeLogic logic = Get.put(TalkViewNativeDecodeLogic());
final TalkViewNativeDecodeState state = Get.find<TalkViewNativeDecodeLogic>().state;
final startChartManage = StartChartManage();
@override
void initState() {
super.initState();
state.animationController = AnimationController(
vsync: this, // 使TickerProvider是当前Widget
duration: const Duration(seconds: 1),
);
state.animationController.repeat();
//StatusListener
state.animationController.addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed) {
state.animationController.reset();
state.animationController.forward();
} else if (status == AnimationStatus.dismissed) {
state.animationController.reset();
state.animationController.forward();
}
});
}
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
// false 退
return false;
},
child: Container(
width: 1.sw,
height: 1.sh,
color: Colors.black.withOpacity(0.7),
child: Stack(
alignment: Alignment.center,
children: <Widget>[
//
Obx(
() {
final double screenWidth = MediaQuery.of(context).size.width;
final double screenHeight = MediaQuery.of(context).size.height;
// loading中或textureId为nullloading/
if (state.isLoading.isTrue || state.textureId.value == null) {
return Image.asset(
'images/main/monitorBg.png',
width: screenWidth,
height: screenHeight,
fit: BoxFit.cover,
);
} else {
return PopScope(
canPop: false,
child: RepaintBoundary(
key: state.globalKey,
child: RotatedBox(
// 使RotatedBox
quarterTurns: startChartManage.rotateAngle ~/ 90,
child: Platform.isIOS
? Transform.scale(
scale: 1.008, // iOS白边
child: Texture(
textureId: state.textureId.value!,
filterQuality: FilterQuality.medium,
),
)
: state.isFullScreen.isFalse
? AspectRatio(
aspectRatio: StartChartManage().videoWidth / StartChartManage().videoHeight,
child: Texture(
textureId: state.textureId.value!,
filterQuality: FilterQuality.medium,
),
)
: Texture(
textureId: state.textureId.value!,
filterQuality: FilterQuality.medium,
),
),
),
);
}
},
),
ElevatedButton(
onPressed: () {
state.isFullScreen.value = !state.isFullScreen.value;
},
child: Obx(
() => Text(state.isFullScreen.isTrue ? '退出全屏' : '全屏'),
),
),
Obx(() => state.isLoading.isTrue
? Positioned(
bottom: 310.h,
child: Text(
'正在创建安全连接...'.tr,
style: TextStyle(color: Colors.black, fontSize: 26.sp),
))
: Container()),
Obx(() => state.isLoading.isFalse && state.oneMinuteTime.value > 0
? Positioned(
top: ScreenUtil().statusBarHeight + 75.h,
width: 1.sw,
child: Obx(
() {
final String sec = (state.oneMinuteTime.value % 60).toString().padLeft(2, '0');
final String min = (state.oneMinuteTime.value ~/ 60).toString().padLeft(2, '0');
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'$min:$sec',
style: TextStyle(fontSize: 26.sp, color: Colors.white),
),
],
);
},
),
)
: Container()),
Positioned(
bottom: 10.w,
child: Container(
width: 1.sw - 30.w * 2,
// height: 300.h,
margin: EdgeInsets.all(30.w),
decoration: BoxDecoration(color: Colors.black.withOpacity(0.2), borderRadius: BorderRadius.circular(20.h)),
child: Column(
children: <Widget>[
SizedBox(height: 20.h),
bottomTopBtnWidget(),
SizedBox(height: 20.h),
bottomBottomBtnWidget(),
SizedBox(height: 20.h),
],
),
),
),
Obx(() => state.isLoading.isTrue ? buildRotationTransition() : Container()),
Obx(() => state.isLongPressing.value
? Positioned(
top: 80.h,
left: 0,
right: 0,
child: Center(
child: Container(
padding: EdgeInsets.all(10.w),
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.7),
borderRadius: BorderRadius.circular(10.w),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Icon(Icons.mic, color: Colors.white, size: 24.w),
SizedBox(width: 10.w),
Text(
'正在说话...'.tr,
style: TextStyle(fontSize: 20.sp, color: Colors.white),
),
],
),
),
),
)
: Container()),
],
),
),
);
}
Widget bottomTopBtnWidget() {
return Row(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
//
GestureDetector(
onTap: () {
if (state.talkStatus.value == TalkStatus.answeredSuccessfully) {
//
logic.updateTalkExpect();
}
},
child: Container(
width: 50.w,
height: 50.w,
padding: EdgeInsets.all(5.w),
child: Obx(() => Image(
width: 40.w,
height: 40.w,
image: state.isOpenVoice.value
? const AssetImage('images/main/icon_lockDetail_monitoringOpenVoice.png')
: const AssetImage('images/main/icon_lockDetail_monitoringCloseVoice.png'))),
),
),
SizedBox(width: 50.w),
//
GestureDetector(
onTap: () async {
if (state.talkStatus.value == TalkStatus.answeredSuccessfully) {
await logic.captureAndSavePng();
}
},
child: Container(
width: 50.w,
height: 50.w,
padding: EdgeInsets.all(5.w),
child: Image(width: 40.w, height: 40.w, image: const AssetImage('images/main/icon_lockDetail_monitoringScreenshot.png')),
),
),
SizedBox(width: 50.w),
//
GestureDetector(
onTap: () async {
logic.showToast('功能暂未开放'.tr);
// if (
// state.talkStatus.value == TalkStatus.answeredSuccessfully) {
// if (state.isRecordingScreen.value) {
// await logic.stopRecording();
// } else {
// await logic.startRecording();
// }
// }
},
child: Container(
width: 50.w,
height: 50.w,
padding: EdgeInsets.all(5.w),
child: Image(
width: 40.w,
height: 40.w,
fit: BoxFit.fill,
image: const AssetImage('images/main/icon_lockDetail_monitoringScreenRecording.png'),
),
),
),
SizedBox(width: 50.w),
//
GestureDetector(
onTap: () async {
//
showModalBottomSheet(
context: context,
backgroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(20.w)),
),
builder: (BuildContext context) {
final List<String> qualities = ['高清', '标清'];
return SafeArea(
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: qualities.map((q) {
return Obx(() => InkWell(
onTap: () {
Navigator.of(context).pop();
logic.onQualityChanged(q);
},
child: Container(
padding: EdgeInsets.symmetric(vertical: 18.w),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Text(
q,
style: TextStyle(
color: state.currentQuality.value == q ? AppColors.mainColor : Colors.black,
fontWeight: state.currentQuality.value == q ? FontWeight.bold : FontWeight.normal,
fontSize: 28.sp,
),
),
],
),
),
));
}).toList(),
),
),
);
},
);
},
child: Container(
child: Icon(Icons.high_quality_outlined, color: Colors.white, size: 38.w),
),
),
Visibility(
visible: state.currentLanguage == 'zh_CN' && Platform.isAndroid,
child: SizedBox(width: 38.w),
),
Visibility(
visible: state.currentLanguage == 'zh_CN' && Platform.isAndroid,
child: IconButton(
icon: Icon(
Icons.notification_add_sharp,
size: 32.w,
color: Colors.white,
),
onPressed: () {
Get.toNamed(Routers.permissionGuidancePage);
},
),
)
]);
}
Widget bottomBottomBtnWidget() {
return Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[
//
Obx(
() => bottomBtnItemWidget(
getAnswerBtnImg(),
getAnswerBtnName(),
Colors.white,
longPress: () async {
if (state.talkStatus.value == TalkStatus.answeredSuccessfully) {
//
logic.startProcessingAudio();
state.isLongPressing.value = true;
}
},
longPressUp: () async {
//
logic.stopProcessingAudio();
state.isLongPressing.value = false;
},
onClick: () async {
if (state.talkStatus.value == TalkStatus.passiveCallWaitingAnswer) {
//
logic.initiateAnswerCommand();
}
},
),
),
bottomBtnItemWidget('images/main/icon_lockDetail_hangUp.png', '挂断'.tr, Colors.red, onClick: () {
//
logic.udpHangUpAction();
}),
bottomBtnItemWidget(
'images/main/icon_lockDetail_monitoringUnlock.png',
'开锁'.tr,
AppColors.mainColor,
onClick: () {
// if (state.talkStatus.value == TalkStatus.answeredSuccessfully &&
// state.listData.value.length > 0) {
// logic.udpOpenDoorAction();
// }
// if (UDPManage().remoteUnlock == 1) {
// logic.udpOpenDoorAction();
// showDeletPasswordAlertDialog(context);
// } else {
// logic.showToast('请在锁设置中开启远程开锁'.tr);
// }
logic.remoteOpenLock();
},
)
]);
}
String getAnswerBtnImg() {
switch (state.talkStatus.value) {
case TalkStatus.passiveCallWaitingAnswer:
return 'images/main/icon_lockDetail_monitoringAnswerCalls.png';
case TalkStatus.answeredSuccessfully:
case TalkStatus.proactivelyCallWaitingAnswer:
return 'images/main/icon_lockDetail_monitoringUnTalkback.png';
default:
return 'images/main/icon_lockDetail_monitoringAnswerCalls.png';
}
}
String getAnswerBtnName() {
switch (state.talkStatus.value) {
case TalkStatus.passiveCallWaitingAnswer:
return '接听'.tr;
case TalkStatus.proactivelyCallWaitingAnswer:
case TalkStatus.answeredSuccessfully:
return '长按说话'.tr;
default:
return '接听'.tr;
}
}
Widget bottomBtnItemWidget(
String iconUrl,
String name,
Color backgroundColor, {
required Function() onClick,
Function()? longPress,
Function()? longPressUp,
}) {
double wh = 80.w;
return GestureDetector(
onTap: onClick,
onLongPress: longPress,
onLongPressUp: longPressUp,
child: SizedBox(
height: 160.w,
width: 140.w,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
width: wh,
height: wh,
constraints: BoxConstraints(
minWidth: wh,
),
decoration: BoxDecoration(
color: backgroundColor,
borderRadius: BorderRadius.circular((wh + 10.w * 2) / 2),
),
padding: EdgeInsets.all(20.w),
child: Image.asset(iconUrl, fit: BoxFit.fitWidth),
),
SizedBox(height: 20.w),
Text(
name,
style: TextStyle(fontSize: 20.sp, color: Colors.white),
textAlign: TextAlign.center, // 使
maxLines: 2, // 1
)
],
),
),
);
}
//
Color _getPacketLossColor(double lossRate) {
if (lossRate < 1.0) {
return Colors.green; // 1%绿
} else if (lossRate < 5.0) {
return Colors.yellow; // 1%-5%
} else if (lossRate < 10.0) {
return Colors.orange; // 5%-10%
} else {
return Colors.red; // 10%
}
}
//
Widget buildRotationTransition() {
return Positioned(
left: ScreenUtil().screenWidth / 2 - 220.w / 2,
top: ScreenUtil().screenHeight / 2 - 220.w / 2 - 150.h,
child: GestureDetector(
child: RotationTransition(
//
alignment: Alignment.center,
//
turns: state.animationController,
//view
child: AnimatedOpacity(
opacity: 0.5,
duration: const Duration(seconds: 2),
child: Image.asset(
'images/main/realTime_connecting.png',
width: 220.w,
height: 220.w,
),
),
),
onTap: () {
state.animationController.forward();
},
),
);
}
@override
void dispose() {
state.animationController.dispose();
CallTalk().finishAVData();
super.dispose();
}
}

View File

@ -37,8 +37,7 @@ class TalkViewNativeDecodeState {
Future<String?> userMobileIP = NetworkInfo().getWifiIP(); Future<String?> userMobileIP = NetworkInfo().getWifiIP();
Future<String?> userUid = Storage.getUid(); Future<String?> userUid = Storage.getUid();
RxInt udpStatus = RxInt udpStatus = 0.obs; //0 1 2 3 4 5 6 8 9
0.obs; //0 1 2 3 4 5 6 8 9
TextEditingController passwordTF = TextEditingController(); TextEditingController passwordTF = TextEditingController();
RxList<int> listAudioData = <int>[].obs; // RxList<int> listAudioData = <int>[].obs; //
@ -63,13 +62,12 @@ class TalkViewNativeDecodeState {
RxBool isPlaying = false.obs; // RxBool isPlaying = false.obs; //
Rx<TalkStatus> talkStatus = TalkStatus.none.obs; // Rx<TalkStatus> talkStatus = TalkStatus.none.obs; //
// startChartTalkStatus // startChartTalkStatus
final StartChartTalkStatus startChartTalkStatus = final StartChartTalkStatus startChartTalkStatus = StartChartTalkStatus.instance;
StartChartTalkStatus.instance;
// //
final TalkDataRepository talkDataRepository = TalkDataRepository.instance; final TalkDataRepository talkDataRepository = TalkDataRepository.instance;
RxBool isOpenVoice = true.obs; // RxBool isOpenVoice = false.obs; //
RxBool isRecordingScreen = false.obs; // RxBool isRecordingScreen = false.obs; //
RxBool isRecordingAudio = false.obs; // RxBool isRecordingAudio = false.obs; //
Rx<DateTime> startRecordingAudioTime = DateTime.now().obs; // Rx<DateTime> startRecordingAudioTime = DateTime.now().obs; //
@ -81,6 +79,7 @@ class TalkViewNativeDecodeState {
RxBool isLongPressing = false.obs; // RxBool isLongPressing = false.obs; //
// ID // ID
Rx<int?> textureId = Rx<int?>(null); Rx<int?> textureId = Rx<int?>(null);
// FPS监测相关变量 // FPS监测相关变量
RxInt lastFpsUpdateTime = 0.obs; // FPS更新时间 RxInt lastFpsUpdateTime = 0.obs; // FPS更新时间
@ -110,8 +109,8 @@ class TalkViewNativeDecodeState {
// H264帧缓冲区相关 // H264帧缓冲区相关
final List<Map<String, dynamic>> h264FrameBuffer = <Map<String, dynamic>>[]; // H264帧缓冲区 final List<Map<String, dynamic>> h264FrameBuffer = <Map<String, dynamic>>[]; // H264帧缓冲区
final int maxFrameBufferSize = 50; // final int maxFrameBufferSize = 25; //
final int targetFps = 60; // ,native的缓冲区 final int targetFps = 25; // ,native的缓冲区
Timer? frameProcessTimer; // Timer? frameProcessTimer; //
bool isProcessingFrame = false; // bool isProcessingFrame = false; //
int lastProcessedTimestamp = 0; // int lastProcessedTimestamp = 0; //
@ -122,6 +121,8 @@ class TalkViewNativeDecodeState {
// '高清' // '高清'
RxString currentQuality = '高清'.obs; // RxString currentQuality = '高清'.obs; //
RxString currentLanguage = RxString currentLanguage = CurrentLocaleTool.getCurrentLocaleString().obs; //
CurrentLocaleTool.getCurrentLocaleString().obs; //
//
RxBool isFullScreen = false.obs;
} }

View File

@ -176,7 +176,7 @@ dependencies:
url_launcher: ^6.1.10 url_launcher: ^6.1.10
#蓝牙 #蓝牙
# flutter_reactive_ble: ^5.1.1 # flutter_reactive_ble: ^5.1.1
flutter_blue_plus: 1.32.7 flutter_blue_plus: 1.33.0
# #
event_bus: ^2.0.0 event_bus: ^2.0.0
#菊花 #菊花
@ -235,6 +235,7 @@ dependencies:
# ffmpeg_kit_flutter: 5.1.0-LTS # ffmpeg_kit_flutter: 5.1.0-LTS
fast_gbk: ^1.0.0 fast_gbk: ^1.0.0
flutter_pcm_sound: ^1.1.0 flutter_pcm_sound: ^1.1.0
intl: ^0.18.0 intl: ^0.18.0
# flutter_audio_capture: <1.1.5 # flutter_audio_capture: <1.1.5
@ -246,7 +247,7 @@ dependencies:
#侧滑删除 #侧滑删除
flutter_slidable: ^3.0.1 flutter_slidable: ^3.0.1
# audio_service: ^0.18.12 # audio_service: ^0.18.12
app_settings: ^5.1.1 app_settings: ^6.1.1
flutter_local_notifications: ^17.0.0 flutter_local_notifications: ^17.0.0
fluwx: 4.5.5 fluwx: 4.5.5
system_settings: ^2.0.0 system_settings: ^2.0.0
@ -321,6 +322,7 @@ flutter:
assets: assets:
- images/ - images/
- images/tabbar/ - images/tabbar/
- images/other/
- images/guide/ - images/guide/
- images/main/ - images/main/
- images/main/addFingerprint/ - images/main/addFingerprint/