Compare commits

..

82 Commits

Author SHA1 Message Date
217705fc8d Merge branch 'develop_sky' into 'canary_release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!282
2025-09-19 04:02:42 +00:00
8b1f3a8e65 Merge branch 'release_sky' into 'canary_release_sky'
Release sky

See merge request StarlockTeam/app-starlock!279
2025-09-15 01:52:41 +00:00
2954afefb6 Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!278
2025-09-15 01:36:55 +00:00
73618a7fb0 Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!275
2025-09-04 10:05:41 +00:00
472a6f20d3 Merge branch 'develop_sky' into 'canary_release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!274
2025-09-04 09:19:35 +00:00
c9683b4cba Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!271
2025-09-03 09:20:35 +00:00
eb3d53c0af Merge branch 'develop_sky' into 'canary_release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!269
2025-09-01 06:49:57 +00:00
b67e23ebaf Merge branch 'develop_sky' into 'canary_release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!267
2025-09-01 02:03:30 +00:00
bcf7f04a70 Merge branch 'develop_sky' into 'canary_release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!265
2025-08-29 05:52:24 +00:00
f77009d6d9 Merge branch 'develop_sky' into 'canary_release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!263
2025-08-28 06:16:47 +00:00
7704083571 Merge branch 'develop_sky' into 'canary_release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!261
2025-08-26 07:37:59 +00:00
61fa6c7e77 Merge branch 'develop_sky' into 'canary_release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!259
2025-08-26 03:55:09 +00:00
bd04e2dc88 Merge branch 'develop_sky' into 'canary_release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!257
2025-08-22 05:46:48 +00:00
cebc1c09f3 Merge branch 'release_sky' into 'canary_release_sky'
Release sky

See merge request StarlockTeam/app-starlock!255
2025-08-20 07:27:56 +00:00
272b02f2c9 Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!254
2025-08-20 06:46:37 +00:00
392cb83156 Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!251
2025-08-12 03:26:22 +00:00
a5b5d6ad0e Merge branch 'release_sky' into 'canary_release_sky'
Release sky

See merge request StarlockTeam/app-starlock!245
2025-08-08 02:27:41 +00:00
19e300b4db Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!244
2025-08-08 02:17:05 +00:00
bc8f9c364a Merge branch 'release_sky' into 'canary_release_sky'
Release sky

See merge request StarlockTeam/app-starlock!242
2025-08-05 07:43:08 +00:00
73988c9bab Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!241
2025-08-05 07:34:36 +00:00
cfa9796a2a Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!237
2025-07-30 03:26:06 +00:00
d3ced373d8 Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!234
2025-07-30 02:58:54 +00:00
572a41a23c Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!231
2025-07-30 02:50:13 +00:00
197f21e26c Merge branch 'release_sky' into 'canary_release_sky'
Release sky

See merge request StarlockTeam/app-starlock!228
2025-07-29 06:22:06 +00:00
1a9db3bc28 Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!227
2025-07-29 06:12:00 +00:00
9bb7fcf7a5 Merge branch 'release_sky' into 'canary_release_sky'
Release sky

See merge request StarlockTeam/app-starlock!224
2025-07-26 08:31:07 +00:00
16bdb49173 Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!223
2025-07-26 08:23:51 +00:00
7a71bea629 Merge branch 'release_sky' into 'canary_release_sky'
Release sky

See merge request StarlockTeam/app-starlock!221
2025-07-25 07:21:27 +00:00
0ba2364d5d Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!220
2025-07-25 07:13:46 +00:00
4f522919af Merge branch 'release_sky' into 'canary_release_sky'
Release sky

See merge request StarlockTeam/app-starlock!218
2025-07-23 06:08:05 +00:00
5e29e2c780 Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!217
2025-07-23 05:35:10 +00:00
22956365f0 Merge branch 'release_sky' into 'canary_release_sky'
Release sky

See merge request StarlockTeam/app-starlock!215
2025-07-23 02:44:25 +00:00
9cf543d638 Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!214
2025-07-23 02:20:18 +00:00
dd0e7fd1f1 Merge branch 'release_sky' into 'canary_release_sky'
Release sky

See merge request StarlockTeam/app-starlock!202
2025-07-14 01:11:54 +00:00
dc5bfdb756 Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!200
2025-07-11 01:07:24 +00:00
1bdfc43b53 Merge branch 'develop_sky' into 'canary_release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!199
2025-07-09 03:46:04 +00:00
6f1f1e44cd Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!196
2025-07-04 01:14:38 +00:00
c98772c806 Merge branch 'develop_sky' into 'canary_release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!195
2025-07-03 09:21:28 +00:00
72d451268e Merge branch 'develop_sky' into 'canary_release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!193
2025-07-03 07:32:15 +00:00
f55e69c67f Merge branch 'develop_sky' into 'canary_release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!191
2025-07-03 07:06:51 +00:00
e983540b79 Merge branch 'develop_sky' into 'canary_release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!189
2025-07-03 03:41:34 +00:00
20c7b5ba9b Merge branch 'develop_sky' into 'canary_release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!187
2025-07-02 10:05:24 +00:00
507ba73fa9 Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!184
2025-06-26 01:55:03 +00:00
b506e679da Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!180
2025-06-24 08:01:48 +00:00
e04fb1adbc Merge branch 'develop_sky' into 'canary_release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!179
2025-06-23 08:29:51 +00:00
91c597b9a5 Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!172
2025-06-14 01:43:53 +00:00
d5a608cb50 Merge branch 'develop_sky' into 'canary_release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!168
2025-06-13 06:31:39 +00:00
ed10354105 Merge branch 'develop_sky' into 'canary_release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!165
2025-06-12 10:07:53 +00:00
376a8a1bd8 Merge branch 'develop_sky' into 'canary_release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!162
2025-06-12 01:54:43 +00:00
5767351b6e Merge branch 'develop_sky' into 'canary_release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!160
2025-06-11 01:24:16 +00:00
ba2fb28018 Merge branch 'develop_sky_liyi' into 'canary_release_sky'
Develop sky liyi

See merge request StarlockTeam/app-starlock!158
2025-06-10 02:42:30 +00:00
e105a0f9cc Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!155
2025-06-06 08:20:59 +00:00
b77f29a0bf Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!147
2025-06-06 01:06:42 +00:00
bb13b9fb87 Merge branch 'release_sky' into 'canary_release_sky'
Release sky

See merge request StarlockTeam/app-starlock!145
2025-06-05 05:43:56 +00:00
700e713279 Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!144
2025-06-05 03:52:36 +00:00
5a8f4afc26 Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!139
2025-06-04 07:11:09 +00:00
2a2e6d31f5 Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!136
2025-06-04 01:19:31 +00:00
fad838a6c6 Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!133
2025-06-03 01:55:07 +00:00
b41bf00f8a Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!130
2025-06-03 01:49:59 +00:00
b8d34cda29 Merge branch 'develop_sky' into 'release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!127
2025-06-03 01:25:21 +00:00
311fddf1ed Merge branch 'develop_sky' into 'canary_release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!117
2025-05-30 07:08:57 +00:00
7105f16daa Merge branch 'develop_sky' into 'canary_release_sky'
Develop sky

See merge request StarlockTeam/app-starlock!110
2025-05-30 06:16:20 +00:00
0fffc2c4b2 Merge branch 'develop_sky' into 'canary_release'
fix:恢复原有ci

See merge request StarlockTeam/app-starlock!96
2025-05-19 02:16:11 +00:00
c6940e56cf Merge branch 'develop_sky' into 'canary_release'
fix:恢复原有ci

See merge request StarlockTeam/app-starlock!95
2025-05-19 01:25:31 +00:00
f4fd0668b0 Merge branch 'develop_sky' into 'canary_release'
fix:恢复原有ci

See merge request StarlockTeam/app-starlock!94
2025-05-17 10:13:10 +00:00
ec80c224f8 Merge branch 'develop_sky' into 'canary_release'
fix:恢复原有ci

See merge request StarlockTeam/app-starlock!93
2025-05-17 10:08:00 +00:00
1f0172f61f Merge branch 'develop_sky' into 'canary_release'
fix:恢复原有ci

See merge request StarlockTeam/app-starlock!92
2025-05-17 09:51:09 +00:00
b907028e26 Merge branch 'develop_sky' into 'canary_release'
fix:恢复原有ci

See merge request StarlockTeam/app-starlock!91
2025-05-17 09:46:35 +00:00
c26e2068b6 Merge branch 'develop_sky' into 'canary_release'
fix:恢复原有ci

See merge request StarlockTeam/app-starlock!90
2025-05-17 09:37:40 +00:00
d32529518e Merge branch 'develop_sky' into 'canary_release'
fix:恢复原有ci

See merge request StarlockTeam/app-starlock!89
2025-05-17 09:11:06 +00:00
fe955dd9bb Merge branch 'develop_sky' into 'canary_release'
Develop sky

See merge request StarlockTeam/app-starlock!88
2025-05-17 08:33:25 +00:00
f98370a6ef Merge branch 'develop_sky_liyi' into 'canary_release'
fix:调整ci

See merge request StarlockTeam/app-starlock!66
2025-05-16 08:45:57 +00:00
bd12720b33 Merge branch 'develop_sky_liyi' into 'canary_release'
fix:调整ci

See merge request StarlockTeam/app-starlock!65
2025-05-16 08:43:00 +00:00
eed55cb920 Merge branch 'develop_sky_liyi' into 'canary_release'
fix:调整ci

See merge request StarlockTeam/app-starlock!64
2025-05-16 08:26:25 +00:00
336915144a Merge branch 'develop_sky_liyi' into 'canary_release'
fix:调整ci

See merge request StarlockTeam/app-starlock!63
2025-05-16 08:22:34 +00:00
72f1bfbe61 Merge branch 'develop_sky_liyi' into 'canary_release'
fix:调整ci

See merge request StarlockTeam/app-starlock!62
2025-05-16 08:03:37 +00:00
8f75c8805d Merge branch 'develop_sky_liyi' into 'canary_release'
fix:调整ci

See merge request StarlockTeam/app-starlock!61
2025-05-16 07:44:15 +00:00
8c17f506b7 Merge branch 'develop_sky_liyi' into 'canary_release'
fix:调整ci

See merge request StarlockTeam/app-starlock!60
2025-05-16 07:25:38 +00:00
453150a570 Merge branch 'develop_sky_liyi' into 'canary_release'
fix:调整ci

See merge request StarlockTeam/app-starlock!59
2025-05-16 07:18:41 +00:00
067b5f9022 Merge branch 'develop_sky_liyi' into 'canary_release'
fix:调整ci

See merge request StarlockTeam/app-starlock!58
2025-05-16 04:05:42 +00:00
204bbc9483 Merge branch 'develop_sky_liyi' into 'canary_release'
fix:调整ci

See merge request StarlockTeam/app-starlock!57
2025-05-16 03:43:08 +00:00
8d0222240a Merge branch 'develop_sky_liyi' into 'canary_release'
fix:更新对讲插件依赖

See merge request StarlockTeam/app-starlock!56
2025-05-15 08:51:36 +00:00
94 changed files with 42653 additions and 44056 deletions

View File

@ -1,251 +0,0 @@
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可以看到
测试ci
一般需要的是:证书指纹-SHA1 看起来像 95:6B:***********共59个字符
## 编译

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1174,11 +1174,5 @@
"服务,图像视频信息随心存!": "Service, image and video information are at your heart!",
"图像": "image",
"视频": "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"
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Currently, the country does not support mobile phone verification code registration, please use your email address to register"
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1173,11 +1173,5 @@
"服务,图像视频信息随心存!": "Informações de serviço, imagem e vídeo estão no seu coração!",
"图像": "imagem",
"视频": "Vídeo",
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "Atualmente, o país não suporta o registro do código de verificação do telefone celular, use seu endereço de e-mail para se registrar",
"注:": "Nota:",
"必需在开始时间24小时内使用一次否则将失效": "Deve ser usado uma vez dentro de 24 horas após o horário de início, caso contrário expirará",
"这是单次密码,只能使用一次": "Esta é uma senha de uso único e só pode ser usada uma vez",
"您好": "Olá",
"您的开门密码是": "Seu código de acesso à porta é",
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "Para desbloquear, primeiro ative o teclado do cadeado e depois digite a senha terminando com #. A tecla # está no canto inferior direito do teclado e pode ter um ícone diferente"
"当前国家不支持手机验证码注册,请使用邮箱进行注册": "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"
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@ -18,7 +18,6 @@ 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/irisList/irisList_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/catEyeSet/catEyeSet_page.dart';
import 'package:star_lock/main/lockDetail/lockSet/catEyeSet/videoSlot/videoSlot_page.dart';
@ -533,7 +532,6 @@ abstract class Routers {
static const String permissionGuidancePage =
'/permissionGuidancePage'; //
static const String lockVoiceSettingPage = '/lockVoiceSetting'; //
static const String aiAssistant = '/aiAssistant';
}
abstract class AppRouters {
@ -1226,9 +1224,6 @@ abstract class AppRouters {
GetPage<dynamic>(
name: Routers.thirdPartyPlatformPage,
page: () => ThirdPartyPlatformPage()),
GetPage<dynamic>(
name: Routers.aiAssistant,
page: () => AiAssistantPage()),
//
// GetPage<dynamic>(name: Routers.h264View, page: () => H264WebView()), // webview播放页面
];

View File

@ -46,7 +46,7 @@ class BlueManage {
StreamSubscription<BluetoothConnectionState>? _connectionStateSubscription;
StreamSubscription<int>? _mtuSubscription;
int? _mtuSize = 30;
int? _mtuSize = 20;
//
String connectDeviceName = '';
@ -119,7 +119,8 @@ class BlueManage {
_connectionStateSubscription?.cancel();
_connectionStateSubscription = null;
_connectionStateSubscription = bluetoothConnectDevice!.connectionState.listen((BluetoothConnectionState state) async {
_connectionStateSubscription =
bluetoothConnectDevice!.connectionState.listen((BluetoothConnectionState state) async {
bluetoothConnectionState = state;
AppLog.log('蓝牙连接回调状态:$state');
});
@ -158,20 +159,26 @@ class BlueManage {
// AppLog.log('startScanSingle 蓝牙状态 系统蓝牙状态:$_adapterState 蓝牙连接状态:$bluetoothConnectionState');
if (_adapterState == BluetoothAdapterState.on) {
try {
BuglyTool.uploadException(message: '开始指定设备名称的扫描蓝牙设备', detail: '调用方法是:startScanSingle 指定设备名称是:$deviceName', upload: false);
BuglyTool.uploadException(
message: '开始指定设备名称的扫描蓝牙设备', detail: '调用方法是:startScanSingle 指定设备名称是:$deviceName', upload: false);
//android 3
final int divisor = Platform.isAndroid ? 3 : 1;
FlutterBluePlus.startScan(
continuousDivisor: divisor, continuousUpdates: true, withKeywords: <String>[deviceName], timeout: Duration(seconds: timeout));
continuousDivisor: divisor,
continuousUpdates: true,
withKeywords: <String>[deviceName],
timeout: Duration(seconds: timeout));
final Completer<dynamic> completer = Completer<dynamic>();
final StreamSubscription<List<ScanResult>> subscription = FlutterBluePlus.scanResults.listen((List<ScanResult> results) {
final bool isExit = results
.any((ScanResult element) => (element.device.platformName == deviceName) || (element.advertisementData.advName == deviceName));
final StreamSubscription<List<ScanResult>> subscription =
FlutterBluePlus.scanResults.listen((List<ScanResult> results) {
final bool isExit = results.any((ScanResult element) =>
(element.device.platformName == deviceName) || (element.advertisementData.advName == deviceName));
final int milliseconds = DateTime.now().millisecondsSinceEpoch - start.millisecondsSinceEpoch;
AppLog.log('扫描到的设备数:${results.length} 是否查找到 $isExit 以查找$milliseconds毫秒');
BuglyTool.uploadException(
message: '指定设备名称的扫描蓝牙设备 监听扫描结果',
detail: 'startScanSingle$deviceName 监听扫描结果 是否查找到 $isExit 以查找$milliseconds毫秒 扫描到的设备数:${results.length} results:$results',
detail:
'startScanSingle$deviceName 监听扫描结果 是否查找到 $isExit 以查找$milliseconds毫秒 扫描到的设备数:${results.length} results:$results',
upload: false);
if (isExit) {
for (final ScanResult scanResult in results) {
@ -208,7 +215,8 @@ class BlueManage {
completer.complete();
}
}, onError: (e) {
BuglyTool.uploadException(message: '指定设备名称的扫描蓝牙设备 监听扫描结果失败', detail: '打印失败问题 e${e.toString()}', upload: false);
BuglyTool.uploadException(
message: '指定设备名称的扫描蓝牙设备 监听扫描结果失败', detail: '打印失败问题 e${e.toString()}', upload: false);
AppLog.log('扫描失败:$e');
});
FlutterBluePlus.cancelWhenScanComplete(subscription);
@ -216,7 +224,8 @@ class BlueManage {
scanDevicesCallBack(scanDevices);
subscription.cancel();
} catch (e) {
BuglyTool.uploadException(message: '指定设备名称的扫描蓝牙设备 内部逻辑整形失败', detail: 'tartScanSingle内部逻辑整形失败 e:${e.toString()}', upload: false);
BuglyTool.uploadException(
message: '指定设备名称的扫描蓝牙设备 内部逻辑整形失败', detail: 'tartScanSingle内部逻辑整形失败 e:${e.toString()}', upload: false);
AppLog.log('扫描失败');
}
} else {
@ -233,14 +242,16 @@ class BlueManage {
}
///
Future<void> startScan(int timeout, DeviceType deviceType, ScanDevicesCallBack scanDevicesCallBack, {List<Guid>? idList}) async {
Future<void> startScan(int timeout, DeviceType deviceType, ScanDevicesCallBack scanDevicesCallBack,
{List<Guid>? idList}) async {
FlutterBluePlus.isSupported.then((bool isAvailable) async {
if (isAvailable) {
AppLog.log('startScan 蓝牙状态 系统蓝牙状态:$_adapterState 蓝牙连接状态:$bluetoothConnectionState');
// AppLog.log('startScan 蓝牙状态 系统蓝牙状态:$_adapterState 蓝牙连接状态:$bluetoothConnectionState');
if (_adapterState == BluetoothAdapterState.on) {
try {
FlutterBluePlus.startScan(timeout: Duration(seconds: timeout));
final StreamSubscription<List<ScanResult>> subscription = FlutterBluePlus.scanResults.listen((List<ScanResult> results) {
final StreamSubscription<List<ScanResult>> subscription =
FlutterBluePlus.scanResults.listen((List<ScanResult> results) {
scanDevices.clear();
for (final ScanResult scanResult in results) {
if (scanResult.advertisementData.serviceUuids.isNotEmpty) {
@ -383,11 +394,8 @@ class BlueManage {
}
/// List senderData,
Future<void> blueSendData(
String deviceName,
ConnectStateCallBack stateCallBack, {
bool isAddEquipment = false,
}) async {
Future<void> blueSendData(String deviceName, ConnectStateCallBack stateCallBack,
{bool isAddEquipment = false}) async {
FlutterBluePlus.isSupported.then((bool isAvailable) async {
if (isAvailable) {
// AppLog.log('蓝牙状态 系统蓝牙状态:$_adapterState 蓝牙连接状态:$bluetoothConnectionState');
@ -398,24 +406,22 @@ class BlueManage {
message: '点击按钮 蓝牙未连接 下一步扫描连接蓝牙',
detail: 'blueSendData 蓝牙连接状态 bluetoothConnectionState$bluetoothConnectionState deviceName:$deviceName',
upload: false);
//
_connect(
deviceName,
(BluetoothConnectionState state) {
stateCallBack(bluetoothConnectionState!);
},
isAddEquipment: isAddEquipment,
);
_connect(deviceName, (BluetoothConnectionState state) {
stateCallBack(bluetoothConnectionState!);
}, isAddEquipment: isAddEquipment);
} else {
BuglyTool.uploadException(
message: '点击按钮 蓝牙已经连接 下一步扫描连接蓝牙',
detail: 'blueSendData 直接回调状态 蓝牙连接状态bluetoothConnectionState$bluetoothConnectionState deviceName:$deviceName',
detail:
'blueSendData 直接回调状态 蓝牙连接状态bluetoothConnectionState$bluetoothConnectionState deviceName:$deviceName',
upload: false);
stateCallBack(bluetoothConnectionState!);
}
} else {
BuglyTool.uploadException(
message: '点击按钮 蓝牙未打开', detail: 'blueSendData 蓝牙未打开--_adapterState:${BluetoothAdapterState.on} deviceName:$deviceName', upload: false);
message: '点击按钮 蓝牙未打开',
detail: 'blueSendData 蓝牙未打开--_adapterState:${BluetoothAdapterState.on} deviceName:$deviceName',
upload: false);
try {
stateCallBack(BluetoothConnectionState.disconnected);
openBlue();
@ -428,7 +434,8 @@ class BlueManage {
}
}
} else {
BuglyTool.uploadException(message: '点击按钮 蓝牙状态不可用', detail: 'blueSendData 蓝牙状态不可用--isAvailable:$isAvailable', upload: false);
BuglyTool.uploadException(
message: '点击按钮 蓝牙状态不可用', detail: 'blueSendData 蓝牙状态不可用--isAvailable:$isAvailable', upload: false);
stateCallBack(BluetoothConnectionState.disconnected);
AppLog.log('开始扫描 蓝牙不可用,不能进行蓝牙操作');
}
@ -436,7 +443,8 @@ class BlueManage {
}
///
Future<void> _connect(String deviceName, ConnectStateCallBack connectStateCallBack, {bool isAddEquipment = false}) async {
Future<void> _connect(String deviceName, ConnectStateCallBack connectStateCallBack,
{bool isAddEquipment = false}) async {
connectDeviceName = deviceName;
//
final List<ScanResult> devicesList = scanDevices;
@ -517,8 +525,8 @@ class BlueManage {
//
bool isExistScanDevices(String connectDeviceName) {
final bool isExistDevice = scanDevices
.any((ScanResult element) => element.device.platformName == connectDeviceName || element.advertisementData.advName == connectDeviceName);
final bool isExistDevice = scanDevices.any((ScanResult element) =>
element.device.platformName == connectDeviceName || element.advertisementData.advName == connectDeviceName);
return isExistDevice;
}
@ -529,8 +537,11 @@ class BlueManage {
bool isAddEquipment = false, //
bool isReconnect = true, //
}) async {
final int knownDeviceIndex =
devicesList.indexWhere((ScanResult d) => (d.device.platformName == deviceName) || (d.advertisementData.advName == deviceName));
//
// AppLog.log("devicesList:$devicesList");
final int knownDeviceIndex = devicesList.indexWhere(
(ScanResult d) => (d.device.platformName == deviceName) || (d.advertisementData.advName == deviceName));
ScanResult? scanResult; //使
if (knownDeviceIndex >= 0) {
@ -541,6 +552,7 @@ class BlueManage {
bluetoothConnectDevice = devicesList[knownDeviceIndex].device;
scanResult = devicesList[knownDeviceIndex];
// AppLog.log('bluetoothConnectDevice: $bluetoothConnectDevice scanResult:$scanResult');
_initGetMtuSubscription();
_initListenConnectionState();
@ -552,13 +564,87 @@ class BlueManage {
upload: false);
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);
}
//
Future<void> doNotSearchBLE(String masAdds, ConnectStateCallBack connectStateCallBack, {bool isAddEquipment = false}) async {
Future<void> doNotSearchBLE(String masAdds, ConnectStateCallBack connectStateCallBack,
{bool isAddEquipment = false}) async {
await FlutterBluePlus.stopScan();
if (bluetoothConnectDevice == null || bluetoothConnectDevice?.remoteId.str != masAdds) {
@ -566,7 +652,9 @@ class BlueManage {
_initGetMtuSubscription();
_initListenConnectionState();
BuglyTool.uploadException(
message: '直接给蓝牙设备写入 上传记录当前方法是doNotSearchBLE', detail: '直接给蓝牙设备写入 通过fromId方法创建一个BluetoothDevice masAdds$masAdds', upload: false);
message: '直接给蓝牙设备写入 上传记录当前方法是doNotSearchBLE',
detail: '直接给蓝牙设备写入 通过fromId方法创建一个BluetoothDevice masAdds$masAdds',
upload: false);
} else {
BuglyTool.uploadException(
message: '直接给蓝牙设备写入 上传记录当前方法是doNotSearchBLE',
@ -585,10 +673,7 @@ class BlueManage {
int attempt = 0;
while (attempt < maxAttempts) {
try {
await bluetoothConnectDevice.connect(
timeout: 5.seconds,
mtu: 512,
);
await bluetoothConnectDevice.connect(timeout: 5.seconds);
break; // If the connection is successful, break the loop
} catch (e) {
AppLog.log('连接失败 重连了: $e');
@ -621,10 +706,6 @@ class BlueManage {
_subScribeToCharacteristic(characteristic);
bluetoothConnectionState = BluetoothConnectionState.connected;
connectStateCallBack(bluetoothConnectionState!);
if (Platform.isAndroid) {
await bluetoothConnectDevice.requestMtu(512);
}
BuglyTool.uploadException(
message: '订阅成功 上传记录当前方法是bluetoothDeviceConnect',
detail: '发现服务,连接成功,订阅数据 bluetoothDeviceConnect:${bluetoothConnectDevice.toString()} ',
@ -651,7 +732,9 @@ class BlueManage {
connectStateCallBack(bluetoothConnectionState!);
AppLog.log('发现设备时失败 e:$e bluetoothConnectionState:$bluetoothConnectionState');
BuglyTool.uploadException(
message: '发现服务时失败', detail: '发现服务时报错原因e$e bluetoothDeviceConnect:${bluetoothConnectDevice.toString()}', upload: false);
message: '发现服务时失败',
detail: '发现服务时报错原因e$e bluetoothDeviceConnect:${bluetoothConnectDevice.toString()}',
upload: false);
rethrow;
}
}
@ -721,24 +804,12 @@ class BlueManage {
for (final BluetoothCharacteristic characteristic in service.characteristics) {
if (characteristic.characteristicUuid == _characteristicIdWrite) {
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;
const int maxRetries = 3;
const int retryDelayMs = 500;
final List<int> valueList = value;
AppLog.log('发送数据时当前的mtuSize是:${_mtuSize}');
final List subData = splitList(valueList, _mtuSize!);
for (int i = 0; i < subData.length; i++) {
@ -814,12 +885,14 @@ class BlueManage {
_mtuSize = 20; // MTU为默认值
if (bluetoothConnectionState == BluetoothConnectionState.connected) {
AppLog.log('请求断开蓝牙连接');
//
await bluetoothConnectDevice!.disconnect(timeout: 1);
await bluetoothConnectDevice!.disconnect(timeout: 3);
AppLog.log('断开连接成功');
}
} on Exception catch (e, _) {
AppLog.log('断开连接失败: $e');
} finally {
bluetoothConnectionState = BluetoothConnectionState.disconnected;
}
}

View File

@ -1,74 +0,0 @@
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

@ -1,106 +0,0 @@
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,11 +27,6 @@ class EventSendModel {
Uuid? serviceId;
Uuid? characteristicId;
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'];
switch (deviceType) {
case DeviceType.blue:
t = ['758824', '75', '768824', '76', '24'];
t = ['758824', '75', '768824', '76','24'];
break;
case DeviceType.gateway:
t = ['758825', '25'];
t = ['758825','25'];
break;
}
return t;
@ -53,8 +53,6 @@ enum CommandType {
gatewayGetWifiList, //wifi列表 0x30F6
gatewayGetWifiListResult, //wifi列表结果 0x30F7
gatewayGetStatus, // 0x30F8
readRegisterKey, // 0x30A7
sendAuthorizationCode, // 0x30A6
generalExtendedCommond, // = 0x3030
gecChangeAdministratorPassword, // - = 2
@ -247,16 +245,6 @@ extension ExtensionCommandType on CommandType {
type = CommandType.gatewayGetStatus;
}
break;
case 0x30A6:
{
type = CommandType.sendAuthorizationCode;
}
break;
case 0x30A7:
{
type = CommandType.readRegisterKey;
}
break;
default:
{
type = CommandType.readStarLockStatusInfo;
@ -365,12 +353,6 @@ extension ExtensionCommandType on CommandType {
case CommandType.setLockCurrentVoicePacket:
type = 0x30A5;
break;
case CommandType.sendAuthorizationCode:
type = 0x30A6;
break;
case CommandType.readRegisterKey:
type = 0x30A7;
break;
default:
type = 0x300A;
break;
@ -510,12 +492,6 @@ extension ExtensionCommandType on CommandType {
case 0x30A5:
t = '设置锁当前语音包';
break;
case 0x30A6:
t = '发送授权码';
break;
case 0x30A7:
t = '读取注册密钥';
break;
default:
t = '读星锁状态信息';
break;

View File

@ -16,12 +16,10 @@ 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_processOtaUpgrade.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_readSupportFunctionsWithParameters.dart';
import 'package:star_lock/blue/io_protocol/io_readVoicePackageFinalResult.dart';
import 'package:star_lock/blue/io_protocol/io_referEventRecordTime.dart';
import 'package:star_lock/blue/io_protocol/io_sendAuthorizationCode.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_setVoicePackageFinalResult.dart';
@ -333,18 +331,6 @@ class CommandReciverManager {
SetVoicePackageFinalResultReply.parseData(commandType, data);
}
break;
case CommandType.readRegisterKey:
{
reply =
SenderReadRegisterKeyCommandReply.parseData(commandType, data);
}
break;
case CommandType.sendAuthorizationCode:
{
reply =
SenderAuthorizationCodeCommandReply.parseData(commandType, data);
}
break;
case CommandType.generalExtendedCommond:
{
//

View File

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

View File

@ -6,8 +6,6 @@ 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_processOtaUpgrade.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_getStatus.dart';
@ -1111,7 +1109,10 @@ class IoSenderManage {
//ota
static void senderProcessOtaUpgradeCommand(
{required int? index, required int? size, required List<int>? data, CommandSendCallBack? callBack}) {
{required int? index,
required int? size,
required List<int>? data,
CommandSendCallBack? callBack}) {
CommandSenderManager().managerSendData(
command: ProcessOtaUpgradeCommand(
index: index,
@ -1320,7 +1321,8 @@ class IoSenderManage {
}
// wifi列表
static void gatewayGetWifiCommand({required String? userID, CommandSendCallBack? callBack}) {
static void gatewayGetWifiCommand(
{required String? userID, CommandSendCallBack? callBack}) {
CommandSenderManager().managerSendData(
command: GatewayGetWifiCommand(
userID: userID,
@ -1337,51 +1339,21 @@ class IoSenderManage {
CommandSendCallBack? callBack}) {
CommandSenderManager().managerSendData(
command: GatewayConfiguringWifiCommand(
ssid: ssid, password: password, gatewayConfigurationStr: gatewayConfigurationStr),
ssid: ssid,
password: password,
gatewayConfigurationStr: gatewayConfigurationStr),
isBeforeAddUser: true,
callBack: callBack);
}
//
static void gatewayGetStatusCommand(
{required String? lockID, required String? userID, CommandSendCallBack? callBack}) {
{required String? lockID,
required String? userID,
CommandSendCallBack? callBack}) {
CommandSenderManager().managerSendData(
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,
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,
);
command: GatewayGetStatusCommand(lockID: lockID, userID: userID),
isBeforeAddUser: true,
callBack: callBack);
}
}

View File

@ -45,229 +45,272 @@ class _StarLockLoginPageState extends State<StarLockLoginPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: const Color(0xFFFFFFFF),
appBar: TitleAppBar(
barTitle: '登录'.tr,
haveBack: false,
backgroundColor: AppColors.mainColor,
actionsList: <Widget>[
if (state.isChina == true)
IconButton(
onPressed: () {
WechatManageTool.getAppInfo(CustomerTool.openCustomerService);
},
icon: const Icon(
Icons.support_agent,
color: Colors.white,
)),
TextButton(
child: Text(
'注册'.tr,
style: TextStyle(color: Colors.white, fontSize: 24.sp),
),
onPressed: () async {
final data = await Get.toNamed(Routers.starLockRegisterPage);
if (data != null) {
state.emailOrPhoneController.text = data['phoneOrEmailStr'];
logic.checkNext(state.emailOrPhoneController);
state.pwdController.text = data['pwd'];
logic.checkNext(state.pwdController);
setState(() {});
}
},
),
],
),
body: GestureDetector(
onTap: () {
FocusScope.of(context).unfocus();
},
child: ListView(
padding: EdgeInsets.only(top: 120.h, left: 40.w, right: 40.w),
children: <Widget>[
Container(
padding: EdgeInsets.all(10.w),
child: Center(child: Image.asset('images/icon_main_sky_1024.png', width: 110.w, height: 110.w))),
SizedBox(height: 50.w),
Obx(() => CommonItem(
leftTitel: '你所在的国家/地区'.tr,
rightTitle: '',
isHaveLine: true,
isPadding: false,
isHaveRightWidget: true,
isHaveDirection: true,
rightWidget: Text(
'${state.countryName} +${state.countryCode.value}',
textAlign: TextAlign.end,
style: TextStyle(fontSize: 22.sp, color: AppColors.darkGrayTextColor),
),
action: () async {
final result = await Get.toNamed(Routers.selectCountryRegionPage);
if (result != null) {
result as Map<String, dynamic>;
state.countryCode.value = result['code'];
state.countryKey.value = result['countryName'];
logic.checkIpAction();
}
resizeToAvoidBottomInset: false,
backgroundColor: const Color(0xFFFFFFFF),
appBar: TitleAppBar(
barTitle: '登录'.tr,
haveBack: false,
backgroundColor: AppColors.mainColor,
actionsList: <Widget>[
if (state.isChina == true)
IconButton(
onPressed: () {
WechatManageTool.getAppInfo(
CustomerTool.openCustomerService);
},
)),
LoginInput(
focusNode: logic.state.emailOrPhoneFocusNode,
controller: state.emailOrPhoneController,
onchangeAction: (v) {
logic.checkNext(state.emailOrPhoneController);
},
leftWidget: Padding(
padding: EdgeInsets.only(top: 30.w, bottom: 20.w, right: 5.w, left: 5.w),
child: Image.asset(
'images/icon_login_account.png',
width: 36.w,
height: 36.w,
),
),
hintText: '请输入手机号或者邮箱'.tr,
// keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
// FilteringTextInputFormatter.allow(RegExp('[0-9]')),
LengthLimitingTextInputFormatter(30),
FilteringTextInputFormatter.singleLineFormatter
]),
SizedBox(height: 10.h),
LoginInput(
focusNode: logic.state.pwdFocusNode,
controller: state.pwdController,
onchangeAction: (v) {
logic.checkNext(state.pwdController);
},
isPwd: true,
// isSuffixIcon: 2,
leftWidget: Padding(
padding: EdgeInsets.only(top: 30.w, bottom: 20.w, right: 5.w, left: 5.w),
child: Image.asset(
'images/icon_login_password.png',
width: 36.w,
height: 36.w,
),
),
hintText: '请输入密码'.tr,
inputFormatters: <TextInputFormatter>[
LengthLimitingTextInputFormatter(20),
]),
// SizedBox(height: 15.h),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Obx(() => GestureDetector(
onTap: () {
state.agree.value = !state.agree.value;
logic.changeAgreeState();
},
child: Container(
// color: Colors.red,
padding: EdgeInsets.only(left: 5.w, top: 20.w, right: 10.w, bottom: 20.h),
child: Image.asset(
state.agree.value ? 'images/icon_round_select.png' : 'images/icon_round_unSelect.png',
width: 35.w,
height: 35.w,
),
))),
// SizedBox(
// width: 5.w,
// ),
Flexible(
child: RichText(
text: TextSpan(
text: '我已阅读并同意'.tr,
style: TextStyle(color: const Color(0xff333333), fontSize: 20.sp),
children: <InlineSpan>[
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: GestureDetector(
child:
Text('${'用户协议'.tr}', style: TextStyle(color: AppColors.mainColor, fontSize: 20.sp)),
onTap: () {
Get.toNamed(Routers.webviewShowPage, arguments: <String, String>{
'url': XSConstantMacro.userAgreementURL,
'title': '用户协议'.tr
});
},
)),
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: GestureDetector(
child:
Text('${'隐私政策'.tr}', style: TextStyle(color: AppColors.mainColor, fontSize: 20.sp)),
onTap: () {
Get.toNamed(Routers.webviewShowPage, arguments: <String, String>{
'url': XSConstantMacro.privacyPolicyURL,
'title': '隐私政策'.tr
});
},
)),
],
icon: const Icon(
Icons.support_agent,
color: Colors.white,
)),
)
],
),
SizedBox(height: 50.w),
Obx(() => SubmitBtn(
btnName: '登录'.tr,
fontSize: 28.sp,
borderRadius: 20.w,
padding: EdgeInsets.only(top: 25.w, bottom: 25.w),
isDisabled: state.canNext.value,
onClick: state.canNext.value
? () {
if (state.agree.value == false) {
logic.showToast('请先同意用户协议及隐私政策'.tr);
return;
} else {
logic.login();
}
}
: null)),
// SizedBox(height: 20.w),
// Obx(() => Visibility(
// visible: state.isCheckVerifyEnable.value,
// child: SubmitBtn(
// btnName: '一键登录',
// fontSize: 28.sp,
// borderRadius: 20.w,
// padding: EdgeInsets.only(top: 25.w, bottom: 25.w),
// // isDisabled: state.canNext.value,
// onClick: () {
// if (state.agree.value == false) {
// logic.showToast('请先同意用户协议及隐私政策'.tr);
// return;
// } else {
// logic.oneClickLoginAction();
// }
// }),
// )),
SizedBox(height: 50.w),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
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: () {
Navigator.pushNamed(context, Routers.starLockForgetPasswordPage);
},
),
],
TextButton(
child: Text(
'注册'.tr,
style: TextStyle(color: Colors.white, fontSize: 24.sp),
),
onPressed: () async {
final data = await Get.toNamed(Routers.starLockRegisterPage);
if (data != null) {
state.emailOrPhoneController.text = data['phoneOrEmailStr'];
logic.checkNext(state.emailOrPhoneController);
state.pwdController.text = data['pwd'];
logic.checkNext(state.pwdController);
setState(() {});
}
},
),
],
),
),
);
body: GestureDetector(
onTap: (){
FocusScope.of(context).unfocus();
},
child: ListView(
padding: EdgeInsets.only(top: 120.h, left: 40.w, right: 40.w),
children: <Widget>[
Container(
padding: EdgeInsets.all(10.w),
child: Center(
child: Image.asset('images/icon_main_sky_1024.png',
width: 110.w, height: 110.w))),
SizedBox(height: 50.w),
Obx(() => CommonItem(
leftTitel: '你所在的国家/地区'.tr,
rightTitle: '',
isHaveLine: true,
isPadding: false,
isHaveRightWidget: true,
isHaveDirection: true,
rightWidget: Text(
'${state.countryName} +${state.countryCode.value}',
textAlign: TextAlign.end,
style: TextStyle(
fontSize: 22.sp, color: AppColors.darkGrayTextColor),
),
action: () async {
final result =
await Get.toNamed(Routers.selectCountryRegionPage);
if (result != null) {
result as Map<String, dynamic>;
state.countryCode.value = result['code'];
state.countryKey.value = result['countryName'];
logic.checkIpAction();
}
},
)),
LoginInput(
focusNode: logic.state.emailOrPhoneFocusNode,
controller: state.emailOrPhoneController,
onchangeAction: (v) {
logic.checkNext(state.emailOrPhoneController);
},
leftWidget: Padding(
padding: EdgeInsets.only(
top: 30.w, bottom: 20.w, right: 5.w, left: 5.w),
child: Image.asset(
'images/icon_login_account.png',
width: 36.w,
height: 36.w,
),
),
hintText: '请输入手机号或者邮箱'.tr,
// keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
// FilteringTextInputFormatter.allow(RegExp('[0-9]')),
LengthLimitingTextInputFormatter(30),
FilteringTextInputFormatter.singleLineFormatter
]),
SizedBox(height: 10.h),
LoginInput(
focusNode: logic.state.pwdFocusNode,
controller: state.pwdController,
onchangeAction: (v) {
logic.checkNext(state.pwdController);
},
isPwd: true,
// isSuffixIcon: 2,
leftWidget: Padding(
padding: EdgeInsets.only(
top: 30.w, bottom: 20.w, right: 5.w, left: 5.w),
child: Image.asset(
'images/icon_login_password.png',
width: 36.w,
height: 36.w,
),
),
hintText: '请输入密码'.tr,
inputFormatters: <TextInputFormatter>[
LengthLimitingTextInputFormatter(20),
]),
// SizedBox(height: 15.h),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Obx(() => GestureDetector(
onTap: () {
state.agree.value = !state.agree.value;
logic.changeAgreeState();
},
child: Container(
// color: Colors.red,
padding: EdgeInsets.only(
left: 5.w, top: 20.w, right: 10.w, bottom: 20.h),
child: Image.asset(
state.agree.value
? 'images/icon_round_select.png'
: 'images/icon_round_unSelect.png',
width: 35.w,
height: 35.w,
),
))),
// SizedBox(
// width: 5.w,
// ),
Flexible(
child: RichText(
text: TextSpan(
text: '我已阅读并同意'.tr,
style: TextStyle(
color: const Color(0xff333333), fontSize: 20.sp),
children: <InlineSpan>[
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: GestureDetector(
child: Text('${'用户协议'.tr}',
style: TextStyle(
color: AppColors.mainColor,
fontSize: 20.sp)),
onTap: () {
Get.toNamed(Routers.webviewShowPage,
arguments: <String, String>{
'url': XSConstantMacro.userAgreementURL,
'title': '用户协议'.tr
});
},
)),
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: GestureDetector(
child: Text('${'隐私政策'.tr}',
style: TextStyle(
color: AppColors.mainColor,
fontSize: 20.sp)),
onTap: () {
Get.toNamed(Routers.webviewShowPage,
arguments: <String, String>{
'url': XSConstantMacro.privacyPolicyURL,
'title': '隐私政策'.tr
});
},
)),
],
)),
)
],
),
SizedBox(height: 50.w),
Obx(() => SubmitBtn(
btnName: '登录'.tr,
fontSize: 28.sp,
borderRadius: 20.w,
padding: EdgeInsets.only(top: 25.w, bottom: 25.w),
isDisabled: state.canNext.value,
onClick: state.canNext.value
? () {
if (state.agree.value == false) {
logic.showToast('请先同意用户协议及隐私政策'.tr);
return;
} else {
logic.login();
}
}
: null)),
// SizedBox(height: 20.w),
// Obx(() => Visibility(
// visible: state.isCheckVerifyEnable.value,
// child: SubmitBtn(
// btnName: '一键登录',
// fontSize: 28.sp,
// borderRadius: 20.w,
// padding: EdgeInsets.only(top: 25.w, bottom: 25.w),
// // isDisabled: state.canNext.value,
// onClick: () {
// if (state.agree.value == false) {
// logic.showToast('请先同意用户协议及隐私政策'.tr);
// return;
// } else {
// logic.oneClickLoginAction();
// }
// }),
// )),
SizedBox(height: 50.w),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
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: () {
Navigator.pushNamed(
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(
@ -308,7 +351,8 @@ class _StarLockLoginPageState extends State<StarLockLoginPage> {
inputFormatters: inputFormatters,
decoration: InputDecoration(
//
contentPadding: const EdgeInsets.only(top: 8.0, left: -19.0, right: -15.0, bottom: 8.0),
contentPadding: const EdgeInsets.only(
top: 8.0, left: -19.0, right: -15.0, bottom: 8.0),
labelText: label,
labelStyle: TextStyle(fontSize: 22.sp),
hintStyle: TextStyle(fontSize: 22.sp),

View File

@ -101,7 +101,6 @@ class StarLockRegisterLogic extends BaseGetXController {
if (entity.errorCode!.codeIsSuccessful) {
if (entity.data!.abbreviation != 'CN') {
showToast('当前国家不支持手机验证码注册,请使用邮箱进行注册'.tr);
state.isIphoneType.value = false;
return;
}
if (state.countryName.value != entity.data!.name) {
@ -150,7 +149,7 @@ class StarLockRegisterLogic extends BaseGetXController {
}
@override
void onReady() async {
void onReady() {
super.onReady();
XSConstantMacro().getDeviceInfoData().then((Map<String, dynamic> data) {
@ -159,7 +158,5 @@ class StarLockRegisterLogic extends BaseGetXController {
//
AppLog.log('获取设备信息时出错: $error');
});
await checkIpAction();
}
}

View File

@ -31,45 +31,44 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: const Color(0xFFFFFFFF),
appBar: TitleAppBar(barTitle: '注册'.tr, haveBack: true, backgroundColor: AppColors.mainColor),
body: GestureDetector(
onTap: () {
FocusScope.of(context).unfocus();
},
child: ListView(
padding: EdgeInsets.only(top: 40.h, left: 40.w, right: 40.w),
children: <Widget>[
topSelectCountryAndRegionWidget(),
middleTFWidget(),
Obx(() {
return SubmitBtn(
btnName: '注册'.tr,
// backgroundColorList: state.canSub.value ? [AppColors.mainColor] :[Colors.grey],
fontSize: 30.sp,
borderRadius: 20.w,
padding: EdgeInsets.only(top: 25.w, bottom: 25.w),
isDisabled: state.canSub.value,
onClick: state.canSub.value
? () {
if (state.agree.value == false) {
logic.showToast('请先同意用户协议及隐私政策'.tr);
return;
} else {
logic.register();
resizeToAvoidBottomInset: false,
backgroundColor: const Color(0xFFFFFFFF),
appBar: TitleAppBar(barTitle: '注册'.tr, haveBack: true, backgroundColor: AppColors.mainColor),
body: GestureDetector(
onTap: () {
FocusScope.of(context).unfocus();
},
child: ListView(
padding: EdgeInsets.only(top: 40.h, left: 40.w, right: 40.w),
children: <Widget>[
topSelectCountryAndRegionWidget(),
middleTFWidget(),
Obx(() {
return SubmitBtn(
btnName: '注册'.tr,
// backgroundColorList: state.canSub.value ? [AppColors.mainColor] :[Colors.grey],
fontSize: 30.sp,
borderRadius: 20.w,
padding: EdgeInsets.only(top: 25.w, bottom: 25.w),
isDisabled: state.canSub.value,
onClick: state.canSub.value
? () {
if (state.agree.value == false) {
logic.showToast('请先同意用户协议及隐私政策'.tr);
return;
} else {
logic.register();
}
}
}
: null);
}),
SizedBox(
height: 20.h,
),
_buildBottomAgreement()
],
),
),
);
: null);
}),
SizedBox(
height: 20.h,
),
_buildBottomAgreement()
],
),
));
}
Widget topSelectCountryAndRegionWidget() {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +0,0 @@
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

@ -1,90 +0,0 @@
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

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

View File

@ -553,19 +553,6 @@ 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
Obx(() => Visibility(

View File

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

View File

@ -257,7 +257,7 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
}
break;
default:
// showToast('获取设备型号失败'.tr);
showToast('获取设备型号失败'.tr);
break;
}
}

View File

@ -1,317 +1,40 @@
import 'dart:async';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:get/get.dart';
import 'package:star_lock/app_settings/app_settings.dart';
import 'package:star_lock/blue/blue_manage.dart';
import 'package:star_lock/blue/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/network/api_repository.dart';
import 'package:star_lock/network/start_company_api.dart';
import 'package:star_lock/tools/baseGetXController.dart';
import 'package:star_lock/tools/storage.dart';
class ThirdPartyPlatformLogic extends BaseGetXController {
ThirdPartyPlatformState state = ThirdPartyPlatformState();
//
StreamSubscription<Reply>? _replySubscription;
void savePlatFormSetting() {
// showEasyLoading();
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
void onReady() async {
// TODO: implement onReady
super.onReady();
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();
}
},
);
getActivateInfo();
}
@override
void dispose() {
dismissEasyLoading();
//
_replySubscription?.cancel();
_replySubscription = null;
//
AppLog.log('ThirdPartyPlatformLogic disposed, subscription cancelled');
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,7 +17,8 @@ class ThirdPartyPlatformPage extends StatefulWidget {
class _ThirdPartyPlatformPageState extends State<ThirdPartyPlatformPage> {
final ThirdPartyPlatformLogic logic = Get.put(ThirdPartyPlatformLogic());
final ThirdPartyPlatformState state = Get.find<ThirdPartyPlatformLogic>().state;
final ThirdPartyPlatformState state =
Get.find<ThirdPartyPlatformLogic>().state;
@override
Widget build(BuildContext context) {
@ -45,125 +46,52 @@ class _ThirdPartyPlatformPageState extends State<ThirdPartyPlatformPage> {
}
Widget _buildBody() {
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,
),
),
),
return ListView.builder(
itemCount: state.platFormSet.length,
itemBuilder: (BuildContext context, int index) {
// itemCount - 1
final isLastItem = index == state.platFormSet.length - 1;
Positioned(
left: 0,
right: 0,
top: 620.h,
bottom: 0,
child: ListView.builder(
itemCount: state.platFormSet.length,
itemBuilder: (BuildContext context, int index) {
// itemCount - 1
final isLastItem = index == state.platFormSet.length - 1;
// platFormSet RxList<Platform>
final platform = state.platFormSet.value[index];
return CommonItem(
leftTitel: state.platFormSet.value[index],
rightTitle: '',
isHaveLine: !isLastItem,
// 线
isHaveDirection: false,
isHaveRightWidget: true,
rightWidget: Obx(
() => Radio<String>(
// Radio 使 id
value: platform,
// selectPlatFormIndex id
groupValue: state.platFormSet.value[state.selectPlatFormIndex.value],
//
activeColor: AppColors.mainColor,
// Radio
onChanged: (value) {
if (value != null) {
setState(() {
// id
final newIndex = state.platFormSet.value.indexWhere((p) => p == value);
if (newIndex != -1) {
state.selectPlatFormIndex.value = newIndex;
}
});
}
},
),
),
action: () {
setState(() {
state.selectPlatFormIndex.value = index;
});
},
);
},
shrinkWrap: true,
physics: const AlwaysScrollableScrollPhysics(),
),
),
],
),
),
// platFormSet RxList<Platform>
final platform = state.platFormSet.value[index];
return CommonItem(
leftTitel: state.platFormSet.value[index],
rightTitle: '',
isHaveLine: !isLastItem,
// 线
isHaveDirection: false,
isHaveRightWidget: true,
rightWidget: Radio<String>(
// Radio 使 id
value: platform,
// selectPlatFormIndex id
groupValue:
state.platFormSet.value[state.selectPlatFormIndex.value],
//
activeColor: AppColors.mainColor,
// Radio
onChanged: (value) {
if (value != null) {
setState(() {
// id
final newIndex =
state.platFormSet.value.indexWhere((p) => p == value);
if (newIndex != -1) {
state.selectPlatFormIndex.value = newIndex;
}
});
}
},
),
action: () {
setState(() {
state.selectPlatFormIndex.value = index;
});
},
);
},
shrinkWrap: true,
physics: const AlwaysScrollableScrollPhysics(),
);
}
}

View File

@ -1,8 +1,6 @@
import 'dart:ui';
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/translations/app_dept.dart';
@ -13,23 +11,15 @@ class ThirdPartyPlatformState {
}
Rx<LockSetInfoData> lockSetInfoData = LockSetInfoData().obs;
int differentialTime = 0; // UTC+0
// UI
final RxList<String> platFormSet = List.of({
'锁通通'.tr,
'涂鸦智能'.tr,
'Matter'.tr,
'Matter'.tr ,
}).obs;
// UI
final RxList<TppSupportInfo> tppSupportList = RxList<TppSupportInfo>([]);
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];
state.uploadPasswordDataList.addAll(reply.data.sublist(9, reply.data.length));
if (dataLength == 10 || dataLength == 9) {
if (dataLength == 10) {
// 10
state.uploadPasswordPage = state.uploadPasswordPage + 1;
@ -128,7 +128,7 @@ class UploadDataLogic extends BaseGetXController {
final int dataLength = reply.data[8];
state.uploadCardDataList.addAll(reply.data.sublist(9, reply.data.length));
if (dataLength == 10 || dataLength == 9) {
if (dataLength == 10) {
// 10
state.uploadCardPage = state.uploadCardPage + 1;
@ -175,7 +175,7 @@ class UploadDataLogic extends BaseGetXController {
final int dataLength = reply.data[8];
state.uploadFingerprintDataList.addAll(reply.data.sublist(9, reply.data.length));
if (dataLength == 10 || dataLength == 9) {
if (dataLength == 10) {
// 10
state.uploadFingerprintPage = state.uploadFingerprintPage + 1;
@ -222,7 +222,7 @@ class UploadDataLogic extends BaseGetXController {
final int dataLength = reply.data[8];
state.uploadFaceDataList.addAll(reply.data.sublist(9, reply.data.length));
if (dataLength == 10 || dataLength == 9) {
if (dataLength == 10) {
// 10
state.uploadFacePage = state.uploadFacePage + 1;
@ -269,7 +269,7 @@ class UploadDataLogic extends BaseGetXController {
final int dataLength = reply.data[8];
state.uploadPalmVeinDataList.addAll(reply.data.sublist(9, reply.data.length));
if (dataLength == 10 || dataLength == 9) {
if (dataLength == 10) {
// 10
state.uploadPalmVeinPage = state.uploadPalmVeinPage + 1;
@ -316,7 +316,7 @@ class UploadDataLogic extends BaseGetXController {
final int dataLength = reply.data[8];
state.uploadRemoteControlDataList.addAll(reply.data.sublist(9, reply.data.length));
if (dataLength == 10 || dataLength == 9) {
if (dataLength == 10) {
// 10
state.uploadRemoteControlPage = state.uploadRemoteControlPage + 1;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -22,16 +22,17 @@ class GatewayConfigurationWifiLogic extends BaseGetXController {
final GatewayConfigurationWifiState state = GatewayConfigurationWifiState();
Future<void> gatewayDistributionNetwork() async {
final LoginEntity entity = await ApiRepository.to.gatewayDistributionNetwork(
gatewayName: state.gatewayNameTF.text,
gatewayMac: state.gatewayModel.mac,
serialNumber: state.gatewayModel.serialNum,
gatewayType: 2,
networkName: state.wifiNameTF.text,
networkMac: state.gatewayModel.wifiMac,
version: state.gatewayModel.gatewayVersion,
gatewayJson: jsonDecode(state.gatewayJson),
timeout: 60);
final LoginEntity entity = await ApiRepository.to
.gatewayDistributionNetwork(
gatewayName: state.gatewayNameTF.text,
gatewayMac: state.gatewayModel.mac,
serialNumber: state.gatewayModel.serialNum,
gatewayType: 2,
networkName: state.wifiNameTF.text,
networkMac: state.gatewayModel.wifiMac,
version: state.gatewayModel.gatewayVersion,
gatewayJson: jsonDecode(state.gatewayJson),
timeout: 60);
if (entity.errorCode!.codeIsSuccessful) {
showToast('网关添加成功'.tr, something: () {
// eventBus.fire(PassCurrentLockInformationEvent(state.lockSetInfoData.value));
@ -41,35 +42,19 @@ class GatewayConfigurationWifiLogic extends BaseGetXController {
}
Future<void> getGatewayConfiguration() async {
final GetGatewayConfigurationEntity entity = await ApiRepository.to.getGatewayConfiguration(timeout: 60);
final GetGatewayConfigurationEntity entity =
await ApiRepository.to.getGatewayConfiguration(timeout: 60);
if (entity.errorCode!.codeIsSuccessful) {
String configStr = entity.data ?? '';
//
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}');
state.getGatewayConfigurationStr = entity.data ?? '';
// AppLog.log('state.getGatewayConfigurationStr:${state.getGatewayConfigurationStr}');
}
}
//
late StreamSubscription<Reply> _replySubscription;
void _initReplySubscription() {
_replySubscription = EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
_replySubscription =
EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
// WIFI配网
// if(reply is GatewayConfiguringWifiReply) {
// _replySenderConfiguringWifi(reply);
@ -111,7 +96,8 @@ class GatewayConfigurationWifiLogic extends BaseGetXController {
cancelBlueConnetctToastTimer();
dismissEasyLoading();
final int secretKeyJsonLength = (reply.data[3] << 8) + reply.data[4];
final List<int> secretKeyList = reply.data.sublist(5, 5 + secretKeyJsonLength);
final List<int> secretKeyList =
reply.data.sublist(5, 5 + secretKeyJsonLength);
state.gatewayJson = utf8String(secretKeyList);
gatewayDistributionNetwork();
@ -127,7 +113,8 @@ class GatewayConfigurationWifiLogic extends BaseGetXController {
// wifi
Future<void> senderConfiguringWifiAction() async {
AppLog.log('state.getGatewayConfigurationStr:${state.getGatewayConfigurationStr}');
AppLog.log(
'state.getGatewayConfigurationStr:${state.getGatewayConfigurationStr}');
if (state.wifiNameTF.text.isEmpty) {
showToast('请输入wifi名称'.tr);
return;
@ -155,7 +142,8 @@ class GatewayConfigurationWifiLogic extends BaseGetXController {
dismissEasyLoading();
state.sureBtnState.value = 0;
});
BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async {
BlueManage().blueSendData(BlueManage().connectDeviceName,
(BluetoothConnectionState connectionState) async {
if (connectionState == BluetoothConnectionState.connected) {
IoSenderManage.gatewayConfiguringWifiCommand(
ssid: state.wifiNameTF.text,
@ -174,7 +162,6 @@ class GatewayConfigurationWifiLogic extends BaseGetXController {
}
final NetworkInfo _networkInfo = NetworkInfo();
Future<String> getWifiName() async {
String ssid = '';
ssid = (await _networkInfo.getWifiName())!;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -29,12 +29,15 @@ class TalkViewNativeDecodePage extends StatefulWidget {
const TalkViewNativeDecodePage({Key? key}) : super(key: key);
@override
State<TalkViewNativeDecodePage> createState() => _TalkViewNativeDecodePageState();
State<TalkViewNativeDecodePage> createState() =>
_TalkViewNativeDecodePageState();
}
class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> with TickerProviderStateMixin {
class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage>
with TickerProviderStateMixin {
final TalkViewNativeDecodeLogic logic = Get.put(TalkViewNativeDecodeLogic());
final TalkViewNativeDecodeState state = Get.find<TalkViewNativeDecodeLogic>().state;
final TalkViewNativeDecodeState state =
Get.find<TalkViewNativeDecodeLogic>().state;
final startChartManage = StartChartManage();
@override
@ -66,48 +69,66 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
// false 退
return false;
},
child: Container(
child: SizedBox(
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;
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/
if (state.isLoading.isTrue || state.textureId.value == null) {
return Image.asset(
'images/main/monitorBg.png',
width: 1.sw,
height: 1.sh,
width: screenWidth,
height: screenHeight,
fit: BoxFit.cover,
);
} else {
return Positioned(
top: 0,
left: 0,
right: 0,
return Positioned.fill(
child: PopScope(
canPop: false,
child: RepaintBoundary(
key: state.globalKey,
child: RotatedBox(
// 使RotatedBox
quarterTurns: startChartManage.rotateAngle ~/ 90,
child: state.isFullScreen.isFalse
? AspectRatio(
aspectRatio: StartChartManage().videoWidth / StartChartManage().videoHeight,
child: Texture(
child: SizedBox.expand(
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,
),
)
: Texture(
textureId: state.textureId.value!,
filterQuality: FilterQuality.medium,
),
)
: Texture(
textureId: state.textureId.value!,
filterQuality: FilterQuality.medium,
),
),
),
),
),
@ -130,14 +151,19 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
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');
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),
style: TextStyle(
fontSize: 26.sp, color: Colors.white),
),
],
);
@ -151,7 +177,9 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
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)),
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.2),
borderRadius: BorderRadius.circular(20.h)),
child: Column(
children: <Widget>[
SizedBox(height: 20.h),
@ -163,7 +191,9 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
),
),
),
Obx(() => state.isLoading.isTrue ? buildRotationTransition() : Container()),
Obx(() => state.isLoading.isTrue
? buildRotationTransition()
: Container()),
Obx(() => state.isLongPressing.value
? Positioned(
top: 80.h,
@ -183,7 +213,8 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
SizedBox(width: 10.w),
Text(
'正在说话...'.tr,
style: TextStyle(fontSize: 20.sp, color: Colors.white),
style: TextStyle(
fontSize: 20.sp, color: Colors.white),
),
],
),
@ -215,8 +246,10 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
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'))),
? const AssetImage(
'images/main/icon_lockDetail_monitoringOpenVoice.png')
: const AssetImage(
'images/main/icon_lockDetail_monitoringCloseVoice.png'))),
),
),
SizedBox(width: 50.w),
@ -231,7 +264,11 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
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')),
child: Image(
width: 40.w,
height: 40.w,
image: const AssetImage(
'images/main/icon_lockDetail_monitoringScreenshot.png')),
),
),
SizedBox(width: 50.w),
@ -256,7 +293,8 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
width: 40.w,
height: 40.w,
fit: BoxFit.fill,
image: const AssetImage('images/main/icon_lockDetail_monitoringScreenRecording.png'),
image: const AssetImage(
'images/main/icon_lockDetail_monitoringScreenRecording.png'),
),
),
),
@ -292,8 +330,13 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
Text(
q,
style: TextStyle(
color: state.currentQuality.value == q ? AppColors.mainColor : Colors.black,
fontWeight: state.currentQuality.value == q ? FontWeight.bold : FontWeight.normal,
color: state.currentQuality.value == q
? AppColors.mainColor
: Colors.black,
fontWeight:
state.currentQuality.value == q
? FontWeight.bold
: FontWeight.normal,
fontSize: 28.sp,
),
),
@ -309,7 +352,8 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
);
},
child: Container(
child: Icon(Icons.high_quality_outlined, color: Colors.white, size: 38.w),
child: Icon(Icons.high_quality_outlined,
color: Colors.white, size: 38.w),
),
),
Visibility(
@ -333,56 +377,61 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
}
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();
},
)
]);
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() {

View File

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

View File

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