Merge branch 'develop_liyi' of code-internal.star-lock.cn:StarlockTeam/app-starlock into develop_liyi
# Conflicts: # pubspec.yaml
This commit is contained in:
commit
2ee6782714
@ -20,6 +20,7 @@ variables:
|
|||||||
- if: $CI_COMMIT_BRANCH == "release"
|
- if: $CI_COMMIT_BRANCH == "release"
|
||||||
- if: $CI_COMMIT_BRANCH =~ /feat_[a-zA-Z]+/
|
- if: $CI_COMMIT_BRANCH =~ /feat_[a-zA-Z]+/
|
||||||
- if: $CI_COMMIT_BRANCH == "canary_release"
|
- if: $CI_COMMIT_BRANCH == "canary_release"
|
||||||
|
- if: $CI_COMMIT_BRANCH == "develop_liyi"
|
||||||
- if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z]+\.[0-9]+)?$/
|
- if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z]+\.[0-9]+)?$/
|
||||||
|
|
||||||
.notify_rule:
|
.notify_rule:
|
||||||
|
|||||||
@ -78,6 +78,13 @@ android {
|
|||||||
keyAlias = 'upload'
|
keyAlias = 'upload'
|
||||||
keyPassword 'xhj8872'
|
keyPassword 'xhj8872'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xhj_bundle {
|
||||||
|
storeFile file("xhj_bundle.jks")
|
||||||
|
storePassword 'xhj8872'
|
||||||
|
keyAlias = 'xhj'
|
||||||
|
keyPassword 'xhj8872'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----- BEGIN flavorDimensions (autogenerated by flutter_flavorizr) -----
|
// ----- BEGIN flavorDimensions (autogenerated by flutter_flavorizr) -----
|
||||||
@ -135,6 +142,16 @@ android {
|
|||||||
manifestPlaceholders.JPUSH_PKGNAME = "com.xhjcn.lock"
|
manifestPlaceholders.JPUSH_PKGNAME = "com.xhjcn.lock"
|
||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules-xhj.pro'
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules-xhj.pro'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xhj_bundle {
|
||||||
|
dimension "flavor-type"
|
||||||
|
applicationId "ltd.xhjcn.lock"
|
||||||
|
signingConfig signingConfigs.xhj_bundle
|
||||||
|
resValue "string", "app_name", "Star Lock"
|
||||||
|
manifestPlaceholders.JPUSH_PKGNAME = "ltd.xhjcn.lock"
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules-xhj.pro'
|
||||||
|
}
|
||||||
|
|
||||||
xhj_pre {
|
xhj_pre {
|
||||||
dimension "flavor-type"
|
dimension "flavor-type"
|
||||||
applicationId "com.xhjcn.lock.pre"
|
applicationId "com.xhjcn.lock.pre"
|
||||||
|
|||||||
48
android/app/src/sky_dev/google-services.json
Normal file
48
android/app/src/sky_dev/google-services.json
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"project_info": {
|
||||||
|
"project_number": "281500445726",
|
||||||
|
"project_id": "skychip2023-ecdff",
|
||||||
|
"storage_bucket": "skychip2023-ecdff.firebasestorage.app"
|
||||||
|
},
|
||||||
|
"client": [
|
||||||
|
{
|
||||||
|
"client_info": {
|
||||||
|
"mobilesdk_app_id": "1:281500445726:android:ddf52ac7b7f83cf5c4d20f",
|
||||||
|
"android_client_info": {
|
||||||
|
"package_name": "com.skychip.lock.dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"oauth_client": [],
|
||||||
|
"api_key": [
|
||||||
|
{
|
||||||
|
"current_key": "AIzaSyC-3-ABWuy9LrYyAw_KxDRto4DanQ0sq9g"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": {
|
||||||
|
"appinvite_service": {
|
||||||
|
"other_platform_oauth_client": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"client_info": {
|
||||||
|
"mobilesdk_app_id": "1:281500445726:android:468195b9cc68dd6cc4d20f",
|
||||||
|
"android_client_info": {
|
||||||
|
"package_name": "com.starlock.lock.local"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"oauth_client": [],
|
||||||
|
"api_key": [
|
||||||
|
{
|
||||||
|
"current_key": "AIzaSyC-3-ABWuy9LrYyAw_KxDRto4DanQ0sq9g"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": {
|
||||||
|
"appinvite_service": {
|
||||||
|
"other_platform_oauth_client": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"configuration_version": "1"
|
||||||
|
}
|
||||||
48
android/app/src/sky_pre/google-services.json
Normal file
48
android/app/src/sky_pre/google-services.json
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"project_info": {
|
||||||
|
"project_number": "281500445726",
|
||||||
|
"project_id": "skychip2023-ecdff",
|
||||||
|
"storage_bucket": "skychip2023-ecdff.firebasestorage.app"
|
||||||
|
},
|
||||||
|
"client": [
|
||||||
|
{
|
||||||
|
"client_info": {
|
||||||
|
"mobilesdk_app_id": "1:281500445726:android:ddf52ac7b7f83cf5c4d",
|
||||||
|
"android_client_info": {
|
||||||
|
"package_name": "com.skychip.lock.pre"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"oauth_client": [],
|
||||||
|
"api_key": [
|
||||||
|
{
|
||||||
|
"current_key": "AIzaSyC-3-ABWuy9LrYyAw_KxDRto4DanQ"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": {
|
||||||
|
"appinvite_service": {
|
||||||
|
"other_platform_oauth_client": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"client_info": {
|
||||||
|
"mobilesdk_app_id": "1:281500445726:android:468195b9cc68dd6cc",
|
||||||
|
"android_client_info": {
|
||||||
|
"package_name": "com.starlock.lock.local"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"oauth_client": [],
|
||||||
|
"api_key": [
|
||||||
|
{
|
||||||
|
"current_key": "AIzaSyC-3-ABWuy9LrYyAw_KxDRto4DanQ0sq9g"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": {
|
||||||
|
"appinvite_service": {
|
||||||
|
"other_platform_oauth_client": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"configuration_version": "1"
|
||||||
|
}
|
||||||
48
android/app/src/xhj_dev/google-services.json
Normal file
48
android/app/src/xhj_dev/google-services.json
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"project_info": {
|
||||||
|
"project_number": "28150044todo",
|
||||||
|
"project_id": "skychip2023-etodo",
|
||||||
|
"storage_bucket": "skychip2023-etodo.firebasestorage.app"
|
||||||
|
},
|
||||||
|
"client": [
|
||||||
|
{
|
||||||
|
"client_info": {
|
||||||
|
"mobilesdk_app_id": "1:281500445726:android:ddf52ac7b7f83cf5c4todo",
|
||||||
|
"android_client_info": {
|
||||||
|
"package_name": "com.xhjcn.lock"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"oauth_client": [],
|
||||||
|
"api_key": [
|
||||||
|
{
|
||||||
|
"current_key": "AIzaSyC-3-ABWuy9LrYyAw_KxDRto4DanQ0todo"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": {
|
||||||
|
"appinvite_service": {
|
||||||
|
"other_platform_oauth_client": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"client_info": {
|
||||||
|
"mobilesdk_app_id": "1:281500445726:android:468195b9cc68dd6cc4todo",
|
||||||
|
"android_client_info": {
|
||||||
|
"package_name": "com.xhjcn.lock.local"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"oauth_client": [],
|
||||||
|
"api_key": [
|
||||||
|
{
|
||||||
|
"current_key": "AIzaSyC-3-ABWuy9LrYyAw_KxDRto4Dank9todo"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": {
|
||||||
|
"appinvite_service": {
|
||||||
|
"other_platform_oauth_client": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"configuration_version": "1"
|
||||||
|
}
|
||||||
48
android/app/src/xhj_pre/google-services.json
Normal file
48
android/app/src/xhj_pre/google-services.json
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"project_info": {
|
||||||
|
"project_number": "28150044todo",
|
||||||
|
"project_id": "skychip2023-etodo",
|
||||||
|
"storage_bucket": "skychip2023-etodo.firebasestorage.app"
|
||||||
|
},
|
||||||
|
"client": [
|
||||||
|
{
|
||||||
|
"client_info": {
|
||||||
|
"mobilesdk_app_id": "1:281500445726:android:ddf52ac7b7f83cf5c4todo",
|
||||||
|
"android_client_info": {
|
||||||
|
"package_name": "com.xhjcn.lock"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"oauth_client": [],
|
||||||
|
"api_key": [
|
||||||
|
{
|
||||||
|
"current_key": "AIzaSyC-3-ABWuy9LrYyAw_KxDRto4DanQ0todo"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": {
|
||||||
|
"appinvite_service": {
|
||||||
|
"other_platform_oauth_client": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"client_info": {
|
||||||
|
"mobilesdk_app_id": "1:281500445726:android:468195b9cc68dd6cc4todo",
|
||||||
|
"android_client_info": {
|
||||||
|
"package_name": "com.xhjcn.lock.local"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"oauth_client": [],
|
||||||
|
"api_key": [
|
||||||
|
{
|
||||||
|
"current_key": "AIzaSyC-3-ABWuy9LrYyAw_KxDRto4Dank9todo"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": {
|
||||||
|
"appinvite_service": {
|
||||||
|
"other_platform_oauth_client": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"configuration_version": "1"
|
||||||
|
}
|
||||||
BIN
android/app/xhj_bundle.jks
Normal file
BIN
android/app/xhj_bundle.jks
Normal file
Binary file not shown.
@ -18,7 +18,7 @@ elif [[ $ENV_BUILD_TAG =~ $regex ]]; then
|
|||||||
echo "===build release===$ENV_BUILD_TAG"
|
echo "===build release===$ENV_BUILD_TAG"
|
||||||
bundle exec fastlane release_apk flavor:xhj --verbose
|
bundle exec fastlane release_apk flavor:xhj --verbose
|
||||||
bundle exec fastlane release_apk flavor:sky --verbose
|
bundle exec fastlane release_apk flavor:sky --verbose
|
||||||
bundle exec fastlane release_bundle flavor:xhj --verbose
|
bundle exec fastlane release_bundle flavor:xhj_bundle --verbose
|
||||||
bundle exec fastlane release_bundle flavor:sky --verbose
|
bundle exec fastlane release_bundle flavor:sky --verbose
|
||||||
elif [[ "${ENV_BUILD_BRANCH}" == "develop" ]]; then
|
elif [[ "${ENV_BUILD_BRANCH}" == "develop" ]]; then
|
||||||
echo "===build dev===${NEXT_VERSION}"
|
echo "===build dev===${NEXT_VERSION}"
|
||||||
|
|||||||
@ -2,4 +2,5 @@ distributionBase=GRADLE_USER_HOME
|
|||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
|
#distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
|
||||||
|
distributionUrl=https://mirrors.cloud.tencent.com/gradle/gradle-7.4-all.zip
|
||||||
|
|||||||
@ -23,7 +23,7 @@ elif [[ "${ENV_BUILD_BRANCH}" == "develop" ]]; then
|
|||||||
echo "===build dev===${NEXT_VERSION}"
|
echo "===build dev===${NEXT_VERSION}"
|
||||||
bundle exec fastlane beta flavor:xhj env:Dev --verbose
|
bundle exec fastlane beta flavor:xhj env:Dev --verbose
|
||||||
bundle exec fastlane beta flavor:sky env:Dev --verbose
|
bundle exec fastlane beta flavor:sky env:Dev --verbose
|
||||||
elif [[ "${ENV_BUILD_BRANCH}" == "release" ]] || [[ "${ENV_BUILD_BRANCH}" == "feat_devops" ]] ; then
|
elif [[ "${ENV_BUILD_BRANCH}" == "release" ]] || [[ "${ENV_BUILD_BRANCH}" == "feat_devops" ]] || [[ "${ENV_BUILD_BRANCH}" == "develop_liyi" ]] ; then
|
||||||
echo "===build pre===${NEXT_VERSION}"
|
echo "===build pre===${NEXT_VERSION}"
|
||||||
bundle exec fastlane beta flavor:xhj env:Pre --verbose
|
bundle exec fastlane beta flavor:xhj env:Pre --verbose
|
||||||
bundle exec fastlane beta flavor:sky env:Pre --verbose
|
bundle exec fastlane beta flavor:sky env:Pre --verbose
|
||||||
|
|||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "اتبع النظام",
|
"跟随系统": "اتبع النظام",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "بعد إعادة الضبط ، سيتم حذف بصمات القفل. هل أنت متأكد أنك تريد إعادة ضبطه ؟",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "بعد إعادة الضبط ، سيتم حذف بصمات القفل. هل أنت متأكد أنك تريد إعادة ضبطه ؟",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "بعد إعادة الضبط ، سيتم حذف جهاز التحكم عن بعد للقفل. هل تريد إعادة ضبطه ؟"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "بعد إعادة الضبط ، سيتم حذف جهاز التحكم عن بعد للقفل. هل تريد إعادة ضبطه ؟",
|
||||||
|
"版本说明": "تعليمات الإصدار"
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Следете система",
|
"跟随系统": "Следете система",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "След нулиране, пръстовите отпечатъци на заключването ще бъдат изтрити. Сигурен ли сте, че искате да го нулирате?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "След нулиране, пръстовите отпечатъци на заключването ще бъдат изтрити. Сигурен ли сте, че искате да го нулирате?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "След нулиране, дистанционното управление на ключалката ще бъде изтрито. Искате ли да го нулирате?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "След нулиране, дистанционното управление на ключалката ще бъде изтрито. Искате ли да го нулирате?",
|
||||||
|
"版本说明": "Обяснение на версията"
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "এক্ফক্লোসিস্টেম",
|
"跟随系统": "এক্ফক্লোসিস্টেম",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "ব্যান্ডোটারট্রাসেট, thelock'sferprinতা?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "ব্যান্ডোটারট্রাসেট, thelock'sferprinতা?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "ব্যান্ডোটারপ্রাসেট, নিয়ন্ত্রণের নিয়ন্ত্রণ। ডোডো ডাইভান্টটুরে?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "ব্যান্ডোটারপ্রাসেট, নিয়ন্ত্রণের নিয়ন্ত্রণ। ডোডো ডাইভান্টটুরে?",
|
||||||
|
"版本说明": "ভার্সনপরিচিতি",
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Sledovat systém",
|
"跟随系统": "Sledovat systém",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Po resetování budou otisky prstů zámku odstraněny. Opravdu ho chcete obnovit?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Po resetování budou otisky prstů zámku odstraněny. Opravdu ho chcete obnovit?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Po resetu bude dálkové ovládání zámku odstraněno. Chcete ho obnovit?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Po resetu bude dálkové ovládání zámku odstraněno. Chcete ho obnovit?",
|
||||||
|
"版本说明": "Verze"
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Følg systemet",
|
"跟随系统": "Følg systemet",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Efter nulstilling vil låsens fingeraftryk blive slettet. Er du sikker på at du vil nulstille den?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Efter nulstilling vil låsens fingeraftryk blive slettet. Er du sikker på at du vil nulstille den?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Efter nulstilling, fjernbetjeningen af låsen vil blive slettet. Vil du nulstille den?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Efter nulstilling, fjernbetjeningen af låsen vil blive slettet. Vil du nulstille den?",
|
||||||
|
"版本说明": "Versionsbeskrivelse",
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "System folgen",
|
"跟随系统": "System folgen",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Nach dem Zurücksetzen werden die Finger abdrücke des Schlosses gelöscht. Sind Sie sicher, dass Sie es zurücksetzen wollen?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Nach dem Zurücksetzen werden die Finger abdrücke des Schlosses gelöscht. Sind Sie sicher, dass Sie es zurücksetzen wollen?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Nach dem Zurücksetzen wird die Fernbedienung des Schlosses gelöscht. Willst du es zurücksetzen?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Nach dem Zurücksetzen wird die Fernbedienung des Schlosses gelöscht. Willst du es zurücksetzen?",
|
||||||
|
"版本说明": "Versionsbeschreibung"
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Ακολουθήστε το σύστημα",
|
"跟随系统": "Ακολουθήστε το σύστημα",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Μετά την επαναφορά, τα αποτυπώματα της κλειδαριάς θα διαγραφούν. Είστε σίγουροι ότι θέλετε να το επαναφέρετε;",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Μετά την επαναφορά, τα αποτυπώματα της κλειδαριάς θα διαγραφούν. Είστε σίγουροι ότι θέλετε να το επαναφέρετε;",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Μετά την επαναφορά, το τηλεχειριστήριο της κλειδαριάς θα διαγραφεί. Θέλεις να το επαναφέρεις;"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Μετά την επαναφορά, το τηλεχειριστήριο της κλειδαριάς θα διαγραφεί. Θέλεις να το επαναφέρεις;",
|
||||||
|
"版本说明": "Περιγραφή έκδοσης",
|
||||||
}
|
}
|
||||||
@ -1121,5 +1121,12 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Follow system",
|
"跟随系统": "Follow system",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "After reset, the lock's fingerprints will be deleted. Are you sure you want to reset it?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "After reset, the lock's fingerprints will be deleted. Are you sure you want to reset it?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "After reset, the remote control of the lock will be deleted. Do you want to reset it?"
|
"通话未接通,已挂断": "Call not connected, hung up",
|
||||||
|
"通话异常中断": "Abnormal call interruption",
|
||||||
|
"通话连接失败": "Call connection failed",
|
||||||
|
"已挂断": "Hanging up",
|
||||||
|
"正在说话...": "Talking now...",
|
||||||
|
"下载完成,请到相册查看": "Download completed, please go to the album to view",
|
||||||
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "After reset, the remote control of the lock will be deleted. Do you want to reset it?",
|
||||||
|
"版本说明": "Version description"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Seguir sistema",
|
"跟随系统": "Seguir sistema",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Después de restablecer, se eliminarán las huellas dactilares del bloqueo. ¿Está seguro de que desea restablecerlo?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Después de restablecer, se eliminarán las huellas dactilares del bloqueo. ¿Está seguro de que desea restablecerlo?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Después del reinicio, se eliminará el control remoto de la cerradura. ¿Quieres resetearlo?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Después del reinicio, se eliminará el control remoto de la cerradura. ¿Quieres resetearlo?",
|
||||||
|
"版本说明": "Instrucciones de versión"
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Süsteemi jälgimine",
|
"跟随系统": "Süsteemi jälgimine",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Pärast lähtestamist kustutatakse luku sõrmejäljed. Kas tõesti soovid see lähtestada?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Pärast lähtestamist kustutatakse luku sõrmejäljed. Kas tõesti soovid see lähtestada?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Pärast lähtestamist kustutatakse luku kaugjuhtimine. Kas sa tahad seda lähtestada?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Pärast lähtestamist kustutatakse luku kaugjuhtimine. Kas sa tahad seda lähtestada?",
|
||||||
|
"版本说明": "Versiooniteave",
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Seuraa järjestelmää",
|
"跟随系统": "Seuraa järjestelmää",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Lukon sormenjäljet poistetaan. Haluatko varmasti nollataa sen?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Lukon sormenjäljet poistetaan. Haluatko varmasti nollataa sen?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Nollauksen jälkeen lukon kaukosäädin poistetaan. Haluatko palauttaa sen?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Nollauksen jälkeen lukon kaukosäädin poistetaan. Haluatko palauttaa sen?",
|
||||||
|
"版本说明": "Versio",
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Suivre le système",
|
"跟随系统": "Suivre le système",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Après réinitialisation, les empreintes digitales de la serrure seront supprimées. Êtes-vous sûr de vouloir le réinitialiser?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Après réinitialisation, les empreintes digitales de la serrure seront supprimées. Êtes-vous sûr de vouloir le réinitialiser?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Après réinitialisation, la télécommande du verrou sera supprimée. Voulez-vous le réinitialiser?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Après réinitialisation, la télécommande du verrou sera supprimée. Voulez-vous le réinitialiser?",
|
||||||
|
"版本说明": "Explication de la version",
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "מערכת מעקב",
|
"跟随系统": "מערכת מעקב",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "לאחר איפוס, טביעות האצבעות של המנעול יימחקו. אתה בטוח שברצונך לאפס את זה?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "לאחר איפוס, טביעות האצבעות של המנעול יימחקו. אתה בטוח שברצונך לאפס את זה?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "לאחר איפוס, השליטה מרחוק של המנעול יימחק. אתה רוצה לאפס את זה?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "לאחר איפוס, השליטה מרחוק של המנעול יימחק. אתה רוצה לאפס את זה?",
|
||||||
|
"版本说明": "המידע על גרסה",
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "跟隨系統",
|
"跟随系统": "跟隨系統",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "重置之後,鎖嘅指紋將被刪除。 你確定要重置它啊?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "重置之後,鎖嘅指紋將被刪除。 你確定要重置它啊?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "重置之後,鎖嘅遙控器將被刪除。 是否要重置它?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "重置之後,鎖嘅遙控器將被刪除。 是否要重置它?",
|
||||||
|
"版本说明": "版本說明"
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Prati sistem:",
|
"跟随系统": "Prati sistem:",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Nakon resetovanja, otisci brave će biti izbrisani. Jeste li sigurni da ga želite resetirati?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Nakon resetovanja, otisci brave će biti izbrisani. Jeste li sigurni da ga želite resetirati?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Nakon resetovanja, daljinski upravljač brave će biti izbrisan. Hoæeš da ga resetuješ?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Nakon resetovanja, daljinski upravljač brave će biti izbrisan. Hoæeš da ga resetuješ?",
|
||||||
|
"版本说明": "Informacije o verziji",
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Follow system",
|
"跟随系统": "Follow system",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "A reset után a zár ujjlenyomatai törlődnek. Biztos vagy benne, hogy vissza szeretné állítani?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "A reset után a zár ujjlenyomatai törlődnek. Biztos vagy benne, hogy vissza szeretné állítani?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "A reset után a zár távirányítója törlődik. Szeretné visszaállítani?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "A reset után a zár távirányítója törlődik. Szeretné visszaállítani?",
|
||||||
|
"版本说明": "Versió leírás",
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Sistem mengikuti",
|
"跟随系统": "Sistem mengikuti",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Setelah mengulang, sidik jari kunci akan dihapus. Yakin ingin meresetnya?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Setelah mengulang, sidik jari kunci akan dihapus. Yakin ingin meresetnya?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Setelah reset, remote control kunci akan dihapus. Ingin mengatur ulang?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Setelah reset, remote control kunci akan dihapus. Ingin mengatur ulang?",
|
||||||
|
"版本说明": "Catatan versi",
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Seguire il sistema",
|
"跟随系统": "Seguire il sistema",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Dopo il reset, le impronte digitali del lucchetto verranno cancellate. Sei sicuro di volerlo resettare?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Dopo il reset, le impronte digitali del lucchetto verranno cancellate. Sei sicuro di volerlo resettare?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Dopo il reset, il telecomando del lucchetto verrà eliminato. Vuoi resettarlo?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Dopo il reset, il telecomando del lucchetto verrà eliminato. Vuoi resettarlo?",
|
||||||
|
"版本说明": "Versione"
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "システムに従う",
|
"跟随系统": "システムに従う",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "リセット後、ロックの指紋は削除されます。リセットしてもよろしいですか。",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "リセット後、ロックの指紋は削除されます。リセットしてもよろしいですか。",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "リセット後、ロックのリモコンが削除されます。リセットしますか?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "リセット後、ロックのリモコンが削除されます。リセットしますか?",
|
||||||
|
"版本说明": "バージョン説明",
|
||||||
}
|
}
|
||||||
@ -1121,5 +1121,12 @@
|
|||||||
"分简称": "分简称",
|
"分简称": "分简称",
|
||||||
"跟随系统": "跟随系统",
|
"跟随系统": "跟随系统",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "重置后,该锁的指纹都将被删除哦,确认要重置吗?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "重置后,该锁的指纹都将被删除哦,确认要重置吗?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "重置后,该锁的遥控都将被删除哦,确认要重置吗?"
|
"通话未接通,已挂断": "通话未接通,已挂断",
|
||||||
|
"通话异常中断": "通话异常中断",
|
||||||
|
"通话连接失败": "通话连接失败",
|
||||||
|
"已挂断": "已挂断",
|
||||||
|
"正在说话...": "正在说话...",
|
||||||
|
"下载完成,请到相册查看": "下载完成,请到相册查看",
|
||||||
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "重置后,该锁的遥控都将被删除哦,确认要重置吗?",
|
||||||
|
"版本说明": "版本说明"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Жүйені қолдану",
|
"跟随系统": "Жүйені қолдану",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Қайта ысырып тастау Шынымен ысырып тастауды қалайсыз ба?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Қайта ысырып тастау Шынымен ысырып тастауды қалайсыз ба?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Қайта ысырып ысырып тасымалдауын өшіріледі. Оны ысырып тастауды қалайсыз ба?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Қайта ысырып ысырып тасымалдауын өшіріледі. Оны ысырып тастауды қалайсыз ба?",
|
||||||
|
"版本说明": "Версиятын көрсету",
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "시스템을 따르십시오",
|
"跟随系统": "시스템을 따르십시오",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "재설정 후 잠금 장치의 지문이 삭제됩니다. 당신은 그것을 재설정 하시겠습니까?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "재설정 후 잠금 장치의 지문이 삭제됩니다. 당신은 그것을 재설정 하시겠습니까?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "재설정 후 잠금 장치의 리모컨이 삭제됩니다. 당신은 그것을 재설정 하시겠습니까?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "재설정 후 잠금 장치의 리모컨이 삭제됩니다. 당신은 그것을 재설정 하시겠습니까?",
|
||||||
|
"版本说明": "버전 설명",
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Sekti sistema",
|
"跟随系统": "Sekti sistema",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Po reset užrakto pirštų atspaudai bus ištrinti. Ar tikrai norite jį atkurti?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Po reset užrakto pirštų atspaudai bus ištrinti. Ar tikrai norite jį atkurti?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Po reset, nuotolinis valdymo pultas užraktas bus ištrintas. Ar norite jį atkurti?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Po reset, nuotolinis valdymo pultas užraktas bus ištrintas. Ar norite jį atkurti?",
|
||||||
|
"版本说明": "Versijos aprašymas",
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Ikut system",
|
"跟随系统": "Ikut system",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Selepas menetapkan semula, cap jari kunci akan dipadamkan. Adakah anda pasti anda mahu menetapkan semula?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Selepas menetapkan semula, cap jari kunci akan dipadamkan. Adakah anda pasti anda mahu menetapkan semula?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Selepas menetapkan semula, kawalan jauh kunci akan dipadamkan. Adakah anda mahu menetapkan semula?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Selepas menetapkan semula, kawalan jauh kunci akan dipadamkan. Adakah anda mahu menetapkan semula?",
|
||||||
|
"版本说明": "Penerangan versi",
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Systeem volgen",
|
"跟随系统": "Systeem volgen",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Na het resetten worden de vingerafdrukken van het slot verwijderd. Weet je zeker dat je het wilt resetten?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Na het resetten worden de vingerafdrukken van het slot verwijderd. Weet je zeker dat je het wilt resetten?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Na het resetten wordt de afstandsbediening van het slot verwijderd. Wilt u het resetten?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Na het resetten wordt de afstandsbediening van het slot verwijderd. Wilt u het resetten?",
|
||||||
|
"版本说明": "Versieomschrijving",
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Śledź system",
|
"跟随系统": "Śledź system",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Po zresetowaniu odciski palców zamka zostaną usunięte. Czy na pewno chcesz go zresetować?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Po zresetowaniu odciski palców zamka zostaną usunięte. Czy na pewno chcesz go zresetować?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Po zresetowaniu zdalne sterowanie zamkiem zostanie usunięte. Czy chcesz go zresetować?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Po zresetowaniu zdalne sterowanie zamkiem zostanie usunięte. Czy chcesz go zresetować?",
|
||||||
|
"版本说明": "Wersja",
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Siga o sistema",
|
"跟随系统": "Siga o sistema",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Após a redefinição, as impressões digitais do bloqueio serão apagadas. Tens a certeza que queres redefini-lo?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Após a redefinição, as impressões digitais do bloqueio serão apagadas. Tens a certeza que queres redefini-lo?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Após a reinicialização, o controle remoto do bloqueio será excluído. Você quer redefini-lo?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Após a reinicialização, o controle remoto do bloqueio será excluído. Você quer redefini-lo?",
|
||||||
|
"版本说明": "Descrição da versão",
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Urmează sistemul:",
|
"跟随系统": "Urmează sistemul:",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "După resetare, amprentele încuietorii vor fi şterse. Sigur doriți să-l resetați?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "După resetare, amprentele încuietorii vor fi şterse. Sigur doriți să-l resetați?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "După resetare, telecomanda de blocare va fi ştersă. Vrei să-l resetezi?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "După resetare, telecomanda de blocare va fi ştersă. Vrei să-l resetezi?",
|
||||||
|
"版本说明": "Descrierea versiunii",
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Следуйте системе",
|
"跟随系统": "Следуйте системе",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "После сброса отпечатки пальцев замка будут удалены. Вы уверены, что хотите его перезагрузить?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "После сброса отпечатки пальцев замка будут удалены. Вы уверены, что хотите его перезагрузить?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "После сброса пульт дистанционного управления замком будет удален. А вы хотите его сбросить?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "После сброса пульт дистанционного управления замком будет удален. А вы хотите его сбросить?",
|
||||||
|
"版本说明": "Объяснение версии",
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Sledovať systém",
|
"跟随系统": "Sledovať systém",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Po resetovaní budú prstové odtlačky zámku vymazané. Ste si istí, že chcete obnoviť?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Po resetovaní budú prstové odtlačky zámku vymazané. Ste si istí, že chcete obnoviť?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Po resetovaní bude diaľkové ovládanie zámku vymazané. Chcete ho obnoviť?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Po resetovaní bude diaľkové ovládanie zámku vymazané. Chcete ho obnoviť?",
|
||||||
|
"版本说明": "Popis verzie"
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Пратите систем",
|
"跟随系统": "Пратите систем",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Након ресетовања, отисци прстију браве ће бити избрисани. Да ли сте сигурни да желите да га ресетујете?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Након ресетовања, отисци прстију браве ће бити избрисани. Да ли сте сигурни да желите да га ресетујете?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Након ресетовања, даљински управљач браве ће бити избрисан. Да ли желите да га ресетујете?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Након ресетовања, даљински управљач браве ће бити избрисан. Да ли желите да га ресетујете?",
|
||||||
|
"版本说明": "Опис верзије"
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Följ system",
|
"跟随系统": "Följ system",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Efter återställd, kommer låsets fingeravtryck tas bort. Är du säker på att du vill återställa den?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Efter återställd, kommer låsets fingeravtryck tas bort. Är du säker på att du vill återställa den?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Efter återställd, fjärrkontrollen på låset tas bort. Vill du återställa den?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Efter återställd, fjärrkontrollen på låset tas bort. Vill du återställa den?",
|
||||||
|
"版本说明": "Versionsbeskrivning"
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "ระบบติดตามผล",
|
"跟随系统": "ระบบติดตามผล",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "หลังจากรีเซ็ตแล้วลายนิ้วมือของล็อคจะถูกลบออกคุณแน่ใจว่าอยากจะรีเซ็ต?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "หลังจากรีเซ็ตแล้วลายนิ้วมือของล็อคจะถูกลบออกคุณแน่ใจว่าอยากจะรีเซ็ต?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "หลังจากรีเซ็ตแล้วรีโมทคอนโทรลของล็อคจะถูกลบออกคุณต้องการรีเซ็ตไหม"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "หลังจากรีเซ็ตแล้วรีโมทคอนโทรลของล็อคจะถูกลบออกคุณต้องการรีเซ็ตไหม",
|
||||||
|
"版本说明": "คำอธิบายรุ่น"
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Sistemi takip et",
|
"跟随系统": "Sistemi takip et",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Sıfırlamadan sonra, kilidin parmak izleri silinecektir. Sıfırlamak istediğine emin misin?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Sıfırlamadan sonra, kilidin parmak izleri silinecektir. Sıfırlamak istediğine emin misin?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Sıfırladıktan sonra, kilidin uzaktan kumandası silinecektir. Sıfırlamak ister misin?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Sıfırladıktan sonra, kilidin uzaktan kumandası silinecektir. Sıfırlamak ister misin?",
|
||||||
|
"版本说明": "Sürüm açıklaması",
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "跟蹤系統",
|
"跟随系统": "跟蹤系統",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "重置後,鎖的指紋將被刪除。 是否確實要重置它?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "重置後,鎖的指紋將被刪除。 是否確實要重置它?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "重置後,鎖的遙控器將被刪除。 是否要重置它?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "重置後,鎖的遙控器將被刪除。 是否要重置它?",
|
||||||
|
"版本说明": "版本說明",
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Система стеження за",
|
"跟随系统": "Система стеження за",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Після скидання відбитки пальців замка будуть видалені. Ви впевнені, що хочете скинути налаштування?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Після скидання відбитки пальців замка будуть видалені. Ви впевнені, що хочете скинути налаштування?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Після скидання пульт дистанційного керування замком буде видалено. Хочете його скинути?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Після скидання пульт дистанційного керування замком буде видалено. Хочете його скинути?",
|
||||||
|
"版本说明": "Опис версії",
|
||||||
}
|
}
|
||||||
@ -1120,5 +1120,6 @@
|
|||||||
"分简称": "M",
|
"分简称": "M",
|
||||||
"跟随系统": "Hệ thống theo dõi",
|
"跟随系统": "Hệ thống theo dõi",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Sau khi đặt lại, dấu vân tay của khóa sẽ bị xóa. Bạn có chắc chắn muốn thiết lập lại nó?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Sau khi đặt lại, dấu vân tay của khóa sẽ bị xóa. Bạn có chắc chắn muốn thiết lập lại nó?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Sau khi đặt lại, điều khiển từ xa của khóa sẽ bị xóa. Bạn có muốn đặt lại không?"
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Sau khi đặt lại, điều khiển từ xa của khóa sẽ bị xóa. Bạn có muốn đặt lại không?",
|
||||||
|
"版本说明": "Thông tin phiên bản"
|
||||||
}
|
}
|
||||||
@ -1121,5 +1121,12 @@
|
|||||||
"分简称": "分",
|
"分简称": "分",
|
||||||
"跟随系统": "跟随系统",
|
"跟随系统": "跟随系统",
|
||||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "重置后,该锁的指纹都将被删除哦,确认要重置吗?",
|
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "重置后,该锁的指纹都将被删除哦,确认要重置吗?",
|
||||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "重置后,该锁的遥控都将被删除哦,确认要重置吗?"
|
"通话未接通,已挂断": "通话未接通,已挂断",
|
||||||
|
"通话异常中断": "通话异常中断",
|
||||||
|
"通话连接失败": "通话连接失败",
|
||||||
|
"已挂断": "已挂断",
|
||||||
|
"正在说话...": "正在说话...",
|
||||||
|
"下载完成,请到相册查看": "下载完成,请到相册查看",
|
||||||
|
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "重置后,该锁的遥控都将被删除哦,确认要重置吗?",
|
||||||
|
"版本说明": "版本说明"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -199,28 +199,28 @@ class F {
|
|||||||
switch (appFlavor) {
|
switch (appFlavor) {
|
||||||
case Flavor.local:
|
case Flavor.local:
|
||||||
return const UmengKey(
|
return const UmengKey(
|
||||||
androidKey: '671244cf80464b33f6df9648',
|
androidKey: 'local-671244cf80464b33f6df9648',
|
||||||
iosKey: '671244ae80464b33f6df9646',
|
iosKey: 'local-671244ae80464b33f6df9646',
|
||||||
channel: 'Product');
|
channel: 'Product');
|
||||||
case Flavor.dev:
|
case Flavor.dev:
|
||||||
return const UmengKey(
|
return const UmengKey(
|
||||||
androidKey: '671244cf80464b33f6df9648',
|
androidKey: 'dev-671244cf80464b33f6df9648',
|
||||||
iosKey: '671244ae80464b33f6df9646',
|
iosKey: 'dev-671244ae80464b33f6df9646',
|
||||||
channel: 'Product');
|
channel: 'Product');
|
||||||
case Flavor.pre:
|
case Flavor.pre:
|
||||||
return const UmengKey(
|
return const UmengKey(
|
||||||
androidKey: '671244cf80464b33f6df9648',
|
androidKey: 'pre-671244cf80464b33f6df9648',
|
||||||
iosKey: '671244ae80464b33f6df9646',
|
iosKey: 'pre-671244ae80464b33f6df9646',
|
||||||
channel: 'Product');
|
channel: 'Product');
|
||||||
case Flavor.sky_dev:
|
case Flavor.sky_dev:
|
||||||
return const UmengKey(
|
return const UmengKey(
|
||||||
androidKey: '671244cf80464b33f6df9648',
|
androidKey: 'sky_dev-671244cf80464b33f6df9648',
|
||||||
iosKey: '671244ae80464b33f6df9646',
|
iosKey: 'sky_dev-671244ae80464b33f6df9646',
|
||||||
channel: 'Product');
|
channel: 'Product');
|
||||||
case Flavor.sky_pre:
|
case Flavor.sky_pre:
|
||||||
return const UmengKey(
|
return const UmengKey(
|
||||||
androidKey: '671244cf80464b33f6df9648',
|
androidKey: 'sky_pre-671244cf80464b33f6df9648',
|
||||||
iosKey: '671244ae80464b33f6df9646',
|
iosKey: 'sky_pre-671244ae80464b33f6df9646',
|
||||||
channel: 'Product');
|
channel: 'Product');
|
||||||
case Flavor.sky:
|
case Flavor.sky:
|
||||||
return const UmengKey(
|
return const UmengKey(
|
||||||
@ -229,13 +229,13 @@ class F {
|
|||||||
channel: 'Product');
|
channel: 'Product');
|
||||||
case Flavor.xhj_dev:
|
case Flavor.xhj_dev:
|
||||||
return const UmengKey(
|
return const UmengKey(
|
||||||
androidKey: '671244cf80464b33f6df9648',
|
androidKey: 'xhj_dev-671244cf80464b33f6df9648',
|
||||||
iosKey: '671244ae80464b33f6df9646',
|
iosKey: 'xhj_dev-671244ae80464b33f6df9646',
|
||||||
channel: 'Product');
|
channel: 'Product');
|
||||||
case Flavor.xhj_pre:
|
case Flavor.xhj_pre:
|
||||||
return const UmengKey(
|
return const UmengKey(
|
||||||
androidKey: '671244cf80464b33f6df9648',
|
androidKey: 'xhj_pre-671244cf80464b33f6df9648',
|
||||||
iosKey: '671244ae80464b33f6df9646',
|
iosKey: 'xhj_pre-671244ae80464b33f6df9646',
|
||||||
channel: 'Product');
|
channel: 'Product');
|
||||||
case Flavor.xhj:
|
case Flavor.xhj:
|
||||||
return const UmengKey(
|
return const UmengKey(
|
||||||
@ -244,8 +244,8 @@ class F {
|
|||||||
channel: 'Product');
|
channel: 'Product');
|
||||||
default:
|
default:
|
||||||
return const UmengKey(
|
return const UmengKey(
|
||||||
androidKey: '671244cf80464b33f6df9648',
|
androidKey: 'default-671244cf80464b33f6df9648',
|
||||||
iosKey: '671244ae80464b33f6df9646',
|
iosKey: 'default-671244ae80464b33f6df9646',
|
||||||
channel: 'Product');
|
channel: 'Product');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,10 +29,12 @@ class Data {
|
|||||||
Data.fromJson(Map<String, dynamic> json) {
|
Data.fromJson(Map<String, dynamic> json) {
|
||||||
wechatServiceUrl = json['wechat_service_url'];
|
wechatServiceUrl = json['wechat_service_url'];
|
||||||
appSiteUrl = json['app_site_url'];
|
appSiteUrl = json['app_site_url'];
|
||||||
|
appVersionHistoryUrl = json['appVersionHistoryUrl'];
|
||||||
}
|
}
|
||||||
|
|
||||||
String? wechatServiceUrl;
|
String? wechatServiceUrl;
|
||||||
String? appSiteUrl;
|
String? appSiteUrl;
|
||||||
|
String? appVersionHistoryUrl;
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final Map<String, dynamic> data = <String, dynamic>{};
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_state.dart';
|
|||||||
import 'package:star_lock/main/lockDetail/doorLockLog/exportRecordDialog/exportRecordDialog_page.dart';
|
import 'package:star_lock/main/lockDetail/doorLockLog/exportRecordDialog/exportRecordDialog_page.dart';
|
||||||
import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart';
|
import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart';
|
||||||
import 'package:star_lock/main/lockDetail/videoLog/widget/full_screenImage_page.dart';
|
import 'package:star_lock/main/lockDetail/videoLog/widget/full_screenImage_page.dart';
|
||||||
import 'package:star_lock/main/lockDetail/videoLog/widget/video_thumbnail.dart';
|
import 'package:star_lock/main/lockDetail/videoLog/widget/video_thumbnail_image.dart';
|
||||||
import 'package:star_lock/tools/EasyRefreshTool.dart';
|
import 'package:star_lock/tools/EasyRefreshTool.dart';
|
||||||
import 'package:star_lock/tools/advancedCalendar/src/widget.dart';
|
import 'package:star_lock/tools/advancedCalendar/src/widget.dart';
|
||||||
import 'package:star_lock/tools/commonDataManage.dart';
|
import 'package:star_lock/tools/commonDataManage.dart';
|
||||||
@ -399,13 +399,27 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_buildVideoItem(RecordListData recordData) {
|
_buildVideoItem(RecordListData recordData) {
|
||||||
return VideoThumbnail(videoUrl: recordData.videoUrl!);
|
return VideoThumbnailImage(videoUrl: recordData.videoUrl!);
|
||||||
}
|
}
|
||||||
|
|
||||||
_buildImageItem(RecordListData recordData) {
|
_buildImageItem(RecordListData recordData) {
|
||||||
return Image.network(
|
return RotatedBox(
|
||||||
|
quarterTurns: -1,
|
||||||
|
child: Image.network(
|
||||||
recordData.imagesUrl!,
|
recordData.imagesUrl!,
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
|
errorBuilder:
|
||||||
|
(BuildContext context, Object error, StackTrace? stackTrace) {
|
||||||
|
// 图片加载失败时显示错误图片
|
||||||
|
return RotatedBox(
|
||||||
|
quarterTurns: -1,
|
||||||
|
child: Image.asset(
|
||||||
|
'images/icon_unHaveData.png', // 错误图片路径
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import 'dart:io';
|
|||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
||||||
|
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:network_info_plus/network_info_plus.dart';
|
import 'package:network_info_plus/network_info_plus.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
@ -151,11 +152,6 @@ class ConfiguringWifiLogic extends BaseGetXController {
|
|||||||
}
|
}
|
||||||
state.sureBtnState.value = 1;
|
state.sureBtnState.value = 1;
|
||||||
|
|
||||||
showBlueConnetctToastTimer(action: () {
|
|
||||||
dismissEasyLoading();
|
|
||||||
state.sureBtnState.value = 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
final GetGatewayConfigurationEntity entity =
|
final GetGatewayConfigurationEntity entity =
|
||||||
await ApiRepository.to.getGatewayConfiguration(timeout: 60);
|
await ApiRepository.to.getGatewayConfiguration(timeout: 60);
|
||||||
if (entity.errorCode!.codeIsSuccessful) {
|
if (entity.errorCode!.codeIsSuccessful) {
|
||||||
@ -191,6 +187,7 @@ class ConfiguringWifiLogic extends BaseGetXController {
|
|||||||
// 如果为空,则直接赋值
|
// 如果为空,则直接赋值
|
||||||
state.getGatewayConfigurationStr = "{\"userPeerld\": \"$appPeerId\"}";
|
state.getGatewayConfigurationStr = "{\"userPeerld\": \"$appPeerId\"}";
|
||||||
}
|
}
|
||||||
|
|
||||||
BlueManage().blueSendData(BlueManage().connectDeviceName,
|
BlueManage().blueSendData(BlueManage().connectDeviceName,
|
||||||
(BluetoothConnectionState connectionState) async {
|
(BluetoothConnectionState connectionState) async {
|
||||||
if (connectionState == BluetoothConnectionState.connected) {
|
if (connectionState == BluetoothConnectionState.connected) {
|
||||||
@ -199,11 +196,7 @@ class ConfiguringWifiLogic extends BaseGetXController {
|
|||||||
password: state.wifiPWDController.text,
|
password: state.wifiPWDController.text,
|
||||||
gatewayConfigurationStr: state.getGatewayConfigurationStr,
|
gatewayConfigurationStr: state.getGatewayConfigurationStr,
|
||||||
);
|
);
|
||||||
} else if (connectionState == BluetoothConnectionState.disconnected) {
|
EasyLoading.show();
|
||||||
state.sureBtnState.value = 0;
|
|
||||||
if (state.ifCurrentScreen.value == true) {
|
|
||||||
showBlueConnetctToast();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, isAddEquipment: true);
|
}, isAddEquipment: true);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,10 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:image_gallery_saver/image_gallery_saver.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart';
|
import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart';
|
||||||
import 'package:star_lock/network/api_repository.dart';
|
import 'package:star_lock/network/api_repository.dart';
|
||||||
import 'package:star_lock/tools/baseGetXController.dart';
|
import 'package:star_lock/tools/baseGetXController.dart';
|
||||||
@ -9,18 +15,20 @@ class EditVideoLogLogic extends BaseGetXController {
|
|||||||
EditVideoLogState state = EditVideoLogState();
|
EditVideoLogState state = EditVideoLogState();
|
||||||
|
|
||||||
Future<void> deleteLockCloudStorageList() async {
|
Future<void> deleteLockCloudStorageList() async {
|
||||||
final VersionUndateEntity entity = await ApiRepository.to.deleteLockCloudStorageList(
|
final VersionUndateEntity entity =
|
||||||
|
await ApiRepository.to.deleteLockCloudStorageList(
|
||||||
recordIds: state.selectVideoLogList.value.map((e) => e.recordId).toList(),
|
recordIds: state.selectVideoLogList.value.map((e) => e.recordId).toList(),
|
||||||
);
|
);
|
||||||
if (entity.errorCode!.codeIsSuccessful) {
|
if (entity.errorCode!.codeIsSuccessful) {
|
||||||
state.selectVideoLogList.value.clear();
|
|
||||||
showToast('删除成功'.tr);
|
showToast('删除成功'.tr);
|
||||||
getLockCloudStorageList();
|
await getLockCloudStorageList();
|
||||||
|
state.selectVideoLogList.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> getLockCloudStorageList() async {
|
Future<void> getLockCloudStorageList() async {
|
||||||
final VideoLogEntity entity = await ApiRepository.to.getLockCloudStorageList(
|
final VideoLogEntity entity =
|
||||||
|
await ApiRepository.to.getLockCloudStorageList(
|
||||||
lockId: state.getLockId.value,
|
lockId: state.getLockId.value,
|
||||||
);
|
);
|
||||||
if (entity.errorCode!.codeIsSuccessful) {
|
if (entity.errorCode!.codeIsSuccessful) {
|
||||||
@ -28,4 +36,59 @@ class EditVideoLogLogic extends BaseGetXController {
|
|||||||
state.videoLogList.refresh();
|
state.videoLogList.refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> downloadAndSaveToGallery(String url, String fileName) async {
|
||||||
|
try {
|
||||||
|
// 请求存储权限
|
||||||
|
if (await _requestPermission()) {
|
||||||
|
final dio = Dio();
|
||||||
|
final directory = await getTemporaryDirectory();
|
||||||
|
final filePath = '${directory.path}/$fileName';
|
||||||
|
|
||||||
|
// 下载文件
|
||||||
|
await dio.download(
|
||||||
|
url,
|
||||||
|
filePath,
|
||||||
|
onReceiveProgress: (received, total) {
|
||||||
|
if (total != -1) {
|
||||||
|
final progress = (received / total) * 100;
|
||||||
|
print('下载进度: $progress%');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// 保存到图库
|
||||||
|
if (fileName.endsWith('.jpg') || fileName.endsWith('.png')) {
|
||||||
|
// 保存图片
|
||||||
|
final result = await ImageGallerySaver.saveFile(filePath);
|
||||||
|
if (result['isSuccess']) {
|
||||||
|
print('图片已保存到图库');
|
||||||
|
} else {
|
||||||
|
print('图片保存失败');
|
||||||
|
}
|
||||||
|
} else if (fileName.endsWith('.mp4')) {
|
||||||
|
// 保存视频
|
||||||
|
final result = await ImageGallerySaver.saveFile(filePath);
|
||||||
|
if (result['isSuccess']) {
|
||||||
|
print('视频已保存到图库');
|
||||||
|
} else {
|
||||||
|
print('视频保存失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除临时文件
|
||||||
|
await File(filePath).delete();
|
||||||
|
} else {
|
||||||
|
print('存储权限被拒绝');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print('下载或保存文件失败: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 请求存储权限
|
||||||
|
Future<bool> _requestPermission() async {
|
||||||
|
final status = await Permission.storage.request();
|
||||||
|
return status.isGranted;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:star_lock/appRouters.dart';
|
import 'package:star_lock/appRouters.dart';
|
||||||
import 'package:star_lock/main/lockDetail/videoLog/editVideoLog/editVideoLog_state.dart';
|
import 'package:star_lock/main/lockDetail/videoLog/editVideoLog/editVideoLog_state.dart';
|
||||||
import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart';
|
import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart';
|
||||||
|
import 'package:star_lock/main/lockDetail/videoLog/widget/full_screenImage_page.dart';
|
||||||
|
import 'package:star_lock/main/lockDetail/videoLog/widget/video_thumbnail_image.dart';
|
||||||
import 'package:star_lock/tools/dateTool.dart';
|
import 'package:star_lock/tools/dateTool.dart';
|
||||||
|
|
||||||
import '../../../../app_settings/app_colors.dart';
|
import '../../../../app_settings/app_colors.dart';
|
||||||
@ -97,6 +99,7 @@ class _EditVideoLogPageState extends State<EditVideoLogPage> {
|
|||||||
|
|
||||||
double itemW = (1.sw - 15.w * 4) / 3;
|
double itemW = (1.sw - 15.w * 4) / 3;
|
||||||
double itemH = (1.sw - 15.w * 4) / 3 + 40.h;
|
double itemH = (1.sw - 15.w * 4) / 3 + 40.h;
|
||||||
|
|
||||||
Widget mainListView(int index, CloudStorageData itemData) {
|
Widget mainListView(int index, CloudStorageData itemData) {
|
||||||
return GridView.builder(
|
return GridView.builder(
|
||||||
padding: EdgeInsets.only(left: 15.w, right: 15.w),
|
padding: EdgeInsets.only(left: 15.w, right: 15.w),
|
||||||
@ -114,99 +117,143 @@ class _EditVideoLogPageState extends State<EditVideoLogPage> {
|
|||||||
childAspectRatio: itemW / itemH),
|
childAspectRatio: itemW / itemH),
|
||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
final RecordListData recordData = itemData.recordList![index];
|
final RecordListData recordData = itemData.recordList![index];
|
||||||
return videoItem(recordData, index);
|
return videoItem(recordData);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget videoItem(RecordListData recordData, int index) {
|
// Widget videoItem(RecordListData recordData, int index) {
|
||||||
return Container(
|
// return Container(
|
||||||
width: itemW,
|
// width: itemW,
|
||||||
height: itemH,
|
// height: itemH,
|
||||||
color: Colors.white,
|
// color: Colors.white,
|
||||||
child: GestureDetector(
|
// child: GestureDetector(
|
||||||
onTap: () {
|
// onTap: () {
|
||||||
recordData.isSelect = !recordData.isSelect!;
|
// recordData.isSelect = !recordData.isSelect!;
|
||||||
if (recordData.isSelect! == true) {
|
// if (recordData.isSelect! == true) {
|
||||||
state.selectVideoLogList.add(recordData);
|
// state.selectVideoLogList.add(recordData);
|
||||||
} else {
|
// } else {
|
||||||
state.selectVideoLogList.remove(recordData);
|
// state.selectVideoLogList.remove(recordData);
|
||||||
}
|
// }
|
||||||
setState(() {});
|
// setState(() {});
|
||||||
},
|
// },
|
||||||
child: Stack(
|
// child: Stack(
|
||||||
children: <Widget>[
|
// children: <Widget>[
|
||||||
Column(
|
// Column(
|
||||||
children: <Widget>[
|
// children: <Widget>[
|
||||||
Container(
|
// Container(
|
||||||
width: itemW,
|
// width: itemW,
|
||||||
height: itemW,
|
// height: itemW,
|
||||||
margin: const EdgeInsets.all(0),
|
// margin: const EdgeInsets.all(0),
|
||||||
color: Colors.white,
|
// color: Colors.white,
|
||||||
child: ClipRRect(
|
// child: ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(10.w),
|
// borderRadius: BorderRadius.circular(10.w),
|
||||||
child: Image(
|
// child: Image(
|
||||||
fit: BoxFit.cover,
|
// fit: BoxFit.cover,
|
||||||
image: Image.network(recordData.imagesUrl ??
|
// image: Image.network(recordData.imagesUrl ??
|
||||||
'images/icon_video_placeholder.jpg')
|
// 'images/icon_video_placeholder.jpg')
|
||||||
.image),
|
// .image),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
SizedBox(height: 5.h),
|
// SizedBox(height: 5.h),
|
||||||
Text(
|
// Text(
|
||||||
DateTool()
|
// DateTool()
|
||||||
.dateToYMDHNString(recordData.operateDate.toString()),
|
// .dateToYMDHNString(recordData.operateDate.toString()),
|
||||||
textAlign: TextAlign.center,
|
// textAlign: TextAlign.center,
|
||||||
style: TextStyle(fontSize: 18.sp))
|
// style: TextStyle(fontSize: 18.sp))
|
||||||
],
|
// ],
|
||||||
),
|
// ),
|
||||||
Positioned(
|
// Positioned(
|
||||||
top: 0.w,
|
// top: 0.w,
|
||||||
right: 0.w,
|
// right: 0.w,
|
||||||
child: Image(
|
// child: Image(
|
||||||
width: 36.w,
|
// width: 36.w,
|
||||||
height: 36.w,
|
// height: 36.w,
|
||||||
image: state.selectVideoLogList.value.contains(recordData)
|
// image: state.selectVideoLogList.value.contains(recordData)
|
||||||
? const AssetImage('images/icon_round_select.png')
|
// ? const AssetImage('images/icon_round_select.png')
|
||||||
: const AssetImage('images/icon_round_unSelect.png')))
|
// : const AssetImage('images/icon_round_unSelect.png')))
|
||||||
],
|
// ],
|
||||||
)),
|
// )),
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
Widget bottomBottomBtnWidget() {
|
Widget bottomBottomBtnWidget() {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: 1.sw,
|
width: 1.sw,
|
||||||
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
|
child:
|
||||||
|
Row(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
|
||||||
bottomBtnItemWidget(
|
bottomBtnItemWidget(
|
||||||
'images/main/icon_lockDetail_monitoringDownloadVideo.png',
|
'images/main/icon_lockDetail_monitoringDownloadVideo.png',
|
||||||
'下载'.tr,
|
'下载'.tr,
|
||||||
Colors.white, () {
|
Colors.white,
|
||||||
if (state.selectVideoLogList.value.isNotEmpty) {
|
_onDownLoadClick,
|
||||||
Get.toNamed(Routers.videoLogDownLoadPage, arguments: <String, List<RecordListData>>{
|
),
|
||||||
'downloadVideoLogList': state.selectVideoLogList.value
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
logic.showToast('请选择要下载的视频');
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
SizedBox(width: 100.w),
|
SizedBox(width: 100.w),
|
||||||
bottomBtnItemWidget(
|
bottomBtnItemWidget(
|
||||||
'images/main/icon_lockDetail_monitoringDeletVideo.png',
|
'images/main/icon_lockDetail_monitoringDeletVideo.png',
|
||||||
'删除'.tr,
|
'删除'.tr,
|
||||||
AppColors.mainColor, () {
|
AppColors.mainColor,
|
||||||
if (state.selectVideoLogList.value.isNotEmpty) {
|
_onDelClick,
|
||||||
logic.deleteLockCloudStorageList();
|
)
|
||||||
} else {
|
|
||||||
logic.showToast('请选择要删除的视频'.tr);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _onDownLoadClick() async {
|
||||||
|
if (state.selectVideoLogList.value.isNotEmpty) {
|
||||||
|
double _progress = 0.0;
|
||||||
|
// 开始下载
|
||||||
|
// 显示进度条
|
||||||
|
EasyLoading.showProgress(_progress, status: '加载数据中'.tr);
|
||||||
|
|
||||||
|
// 模拟进度更新
|
||||||
|
for (int i = 0; i <= state.selectVideoLogList.length - 1; i++) {
|
||||||
|
final item = state.selectVideoLogList.value[i];
|
||||||
|
|
||||||
|
// 判断 imagesUrl 是否为空
|
||||||
|
if (item.imagesUrl != null && item.imagesUrl!.isNotEmpty) {
|
||||||
|
await logic.downloadAndSaveToGallery(item.imagesUrl!, 'image_$i.jpg');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断 videoUrl 是否为空
|
||||||
|
if (item.videoUrl != null && item.videoUrl!.isNotEmpty) {
|
||||||
|
await logic.downloadAndSaveToGallery(item.videoUrl!, 'video_$i.mp4');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新进度
|
||||||
|
_progress = (i + 1) / state.selectVideoLogList.length;
|
||||||
|
EasyLoading.showProgress(_progress, status: '加载数据中'.tr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载完成后隐藏进度条
|
||||||
|
EasyLoading.dismiss();
|
||||||
|
EasyLoading.showSuccess('下载完成,请到相册查看'.tr);
|
||||||
|
state.selectVideoLogList.clear();
|
||||||
|
setState(() {});
|
||||||
|
// Get.toNamed(Routers.videoLogDownLoadPage,
|
||||||
|
// arguments: <String, List<RecordListData>>{
|
||||||
|
// 'downloadVideoLogList': state.selectVideoLogList.value
|
||||||
|
// });
|
||||||
|
} else {
|
||||||
|
logic.showToast('请选择要下载的视频');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onDelClick() async {
|
||||||
|
if (state.selectVideoLogList.value.isNotEmpty) {
|
||||||
|
await logic.deleteLockCloudStorageList();
|
||||||
|
setState(() {});
|
||||||
|
} else {
|
||||||
|
logic.showToast('请选择要删除的视频'.tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Widget bottomBtnItemWidget(
|
Widget bottomBtnItemWidget(
|
||||||
String iconUrl, String name, Color backgroundColor, Function() onClick) {
|
String iconUrl,
|
||||||
|
String name,
|
||||||
|
Color backgroundColor,
|
||||||
|
Future<void> Function() onClick,
|
||||||
|
) {
|
||||||
final double wh = 40.w;
|
final double wh = 40.w;
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: onClick,
|
onTap: onClick,
|
||||||
@ -221,9 +268,118 @@ class _EditVideoLogPageState extends State<EditVideoLogPage> {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: Text(name,
|
child: Text(name,
|
||||||
style: TextStyle(fontSize: 22.sp),
|
style: TextStyle(fontSize: 22.sp),
|
||||||
textAlign: TextAlign.center))
|
textAlign: TextAlign.center),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget videoItem(RecordListData recordData) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
if (recordData.videoUrl != null && recordData.videoUrl!.isNotEmpty) {
|
||||||
|
Get.toNamed(Routers.videoLogDetailPage, arguments: <String, Object>{
|
||||||
|
'recordData': recordData,
|
||||||
|
'videoDataList': state.videoLogList.value
|
||||||
|
});
|
||||||
|
} else if (recordData.imagesUrl != null &&
|
||||||
|
recordData.imagesUrl!.isNotEmpty) {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => FullScreenImagePage(
|
||||||
|
imageUrl: recordData.imagesUrl!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: itemW,
|
||||||
|
height: itemH,
|
||||||
|
child: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
Container(
|
||||||
|
width: itemW,
|
||||||
|
height: itemW,
|
||||||
|
margin: const EdgeInsets.all(0),
|
||||||
|
color: Colors.white,
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(10.w),
|
||||||
|
child: _buildImageOrVideoItem(recordData),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 5.h),
|
||||||
|
Text(
|
||||||
|
DateTool()
|
||||||
|
.dateToYMDHNString(recordData.operateDate.toString()),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(fontSize: 18.sp),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
top: 0.w,
|
||||||
|
right: 0.w,
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
recordData.isSelect = !recordData.isSelect!;
|
||||||
|
if (recordData.isSelect! == true) {
|
||||||
|
state.selectVideoLogList.add(recordData);
|
||||||
|
} else {
|
||||||
|
state.selectVideoLogList.remove(recordData);
|
||||||
|
}
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
child: Image(
|
||||||
|
width: 36.w,
|
||||||
|
height: 36.w,
|
||||||
|
image: state.selectVideoLogList.value.contains(recordData)
|
||||||
|
? const AssetImage('images/icon_round_select.png')
|
||||||
|
: const AssetImage('images/icon_round_unSelect.png'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_buildImageOrVideoItem(RecordListData recordData) {
|
||||||
|
if (recordData.videoUrl != null && recordData.videoUrl!.isNotEmpty) {
|
||||||
|
return _buildVideoItem(recordData);
|
||||||
|
} else {
|
||||||
|
return _buildImageItem(recordData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_buildVideoItem(RecordListData recordData) {
|
||||||
|
return VideoThumbnailImage(videoUrl: recordData.videoUrl!);
|
||||||
|
}
|
||||||
|
|
||||||
|
_buildImageItem(RecordListData recordData) {
|
||||||
|
return RotatedBox(
|
||||||
|
quarterTurns: -1,
|
||||||
|
child: Image.network(
|
||||||
|
recordData.imagesUrl!,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
errorBuilder:
|
||||||
|
(BuildContext context, Object error, StackTrace? stackTrace) {
|
||||||
|
// 图片加载失败时显示错误图片
|
||||||
|
return RotatedBox(
|
||||||
|
quarterTurns: -1,
|
||||||
|
child: Image.asset(
|
||||||
|
'images/icon_unHaveData.png', // 错误图片路径
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
class VideoLogEntity {
|
class VideoLogEntity {
|
||||||
int? errorCode;
|
int? errorCode;
|
||||||
String? description;
|
String? description;
|
||||||
@ -61,21 +64,28 @@ class RecordListData {
|
|||||||
int? operateDate;
|
int? operateDate;
|
||||||
String? imagesUrl;
|
String? imagesUrl;
|
||||||
String? videoUrl;
|
String? videoUrl;
|
||||||
|
Uint8List? thumbnailData; // 将视频封面改为 Uint8List 类型
|
||||||
int? recordType;
|
int? recordType;
|
||||||
bool? isSelect = false;
|
bool? isSelect = false;
|
||||||
|
|
||||||
RecordListData(
|
RecordListData({
|
||||||
{this.recordId,
|
this.recordId,
|
||||||
this.operateDate,
|
this.operateDate,
|
||||||
this.imagesUrl,
|
this.imagesUrl,
|
||||||
this.videoUrl,
|
this.videoUrl,
|
||||||
this.recordType});
|
this.thumbnailData, // 视频封面数据
|
||||||
|
this.recordType,
|
||||||
|
});
|
||||||
|
|
||||||
RecordListData.fromJson(Map<String, dynamic> json) {
|
RecordListData.fromJson(Map<String, dynamic> json) {
|
||||||
recordId = json['recordId'];
|
recordId = json['recordId'];
|
||||||
operateDate = json['operateDate'];
|
operateDate = json['operateDate'];
|
||||||
imagesUrl = json['imagesUrl'];
|
imagesUrl = json['imagesUrl'];
|
||||||
videoUrl = json['videoUrl'];
|
videoUrl = json['videoUrl'];
|
||||||
|
// 如果 JSON 中包含 base64 编码的图片数据,可以解码为 Uint8List
|
||||||
|
if (json['thumbnailData'] != null) {
|
||||||
|
thumbnailData = base64Decode(json['thumbnailData']);
|
||||||
|
}
|
||||||
recordType = json['recordType'];
|
recordType = json['recordType'];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,6 +95,10 @@ class RecordListData {
|
|||||||
data['operateDate'] = operateDate;
|
data['operateDate'] = operateDate;
|
||||||
data['imagesUrl'] = imagesUrl;
|
data['imagesUrl'] = imagesUrl;
|
||||||
data['videoUrl'] = videoUrl;
|
data['videoUrl'] = videoUrl;
|
||||||
|
// 将 Uint8List 编码为 base64 字符串
|
||||||
|
if (thumbnailData != null) {
|
||||||
|
data['thumbnailData'] = base64Encode(thumbnailData!);
|
||||||
|
}
|
||||||
data['recordType'] = recordType;
|
data['recordType'] = recordType;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart';
|
||||||
import 'package:star_lock/network/api_repository.dart';
|
import 'package:star_lock/network/api_repository.dart';
|
||||||
import 'package:star_lock/tools/baseGetXController.dart';
|
import 'package:star_lock/tools/baseGetXController.dart';
|
||||||
|
|
||||||
@ -14,6 +15,15 @@ class VideoLogLogic extends BaseGetXController {
|
|||||||
);
|
);
|
||||||
if (entity.errorCode!.codeIsSuccessful) {
|
if (entity.errorCode!.codeIsSuccessful) {
|
||||||
state.videoLogList.value = entity.data!;
|
state.videoLogList.value = entity.data!;
|
||||||
|
state.videoLogList.value.forEach((element) {
|
||||||
|
// 过滤掉 imagesUrl 和 videoUrl 都为 null 或空字符串的项
|
||||||
|
element.recordList = element.recordList!
|
||||||
|
.where((record) =>
|
||||||
|
(record.imagesUrl != null && record.imagesUrl!.isNotEmpty) ||
|
||||||
|
(record.videoUrl != null && record.videoUrl!.isNotEmpty))
|
||||||
|
.toList();
|
||||||
|
});
|
||||||
|
|
||||||
state.videoLogList.refresh();
|
state.videoLogList.refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import 'package:star_lock/flavors.dart';
|
|||||||
import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart';
|
import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart';
|
||||||
import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_state.dart';
|
import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_state.dart';
|
||||||
import 'package:star_lock/main/lockDetail/videoLog/widget/full_screenImage_page.dart';
|
import 'package:star_lock/main/lockDetail/videoLog/widget/full_screenImage_page.dart';
|
||||||
import 'package:star_lock/main/lockDetail/videoLog/widget/video_thumbnail.dart';
|
import 'package:star_lock/main/lockDetail/videoLog/widget/video_thumbnail_image.dart';
|
||||||
import 'package:star_lock/tools/dateTool.dart';
|
import 'package:star_lock/tools/dateTool.dart';
|
||||||
import 'package:star_lock/tools/noData.dart';
|
import 'package:star_lock/tools/noData.dart';
|
||||||
import 'package:video_player/video_player.dart';
|
import 'package:video_player/video_player.dart';
|
||||||
@ -228,15 +228,18 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
|||||||
child: Row(
|
child: Row(
|
||||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text(state.isNavLocal.value == true ? '已下载'.tr : '全部视频'.tr,
|
Text(
|
||||||
style: TextStyle(fontSize: 26.sp, fontWeight: FontWeight.w500)),
|
state.isNavLocal.value == true ? '已下载'.tr : '全部视频'.tr,
|
||||||
|
style: TextStyle(fontSize: 26.sp, fontWeight: FontWeight.w500),
|
||||||
|
),
|
||||||
Expanded(child: SizedBox(width: 10.w)),
|
Expanded(child: SizedBox(width: 10.w)),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Image(
|
icon: Image(
|
||||||
width: 40.w,
|
width: 40.w,
|
||||||
height: 40.w,
|
height: 40.w,
|
||||||
image: const AssetImage(
|
image: const AssetImage(
|
||||||
'images/main/icon_lockDetail_monitoringEditVoice.png')),
|
'images/main/icon_lockDetail_monitoringEditVoice.png'),
|
||||||
|
),
|
||||||
iconSize: 30,
|
iconSize: 30,
|
||||||
color: Colors.black54,
|
color: Colors.black54,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
@ -338,13 +341,27 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_buildVideoItem(RecordListData recordData) {
|
_buildVideoItem(RecordListData recordData) {
|
||||||
return VideoThumbnail(videoUrl: recordData.videoUrl!);
|
return VideoThumbnailImage(videoUrl: recordData.videoUrl!);
|
||||||
}
|
}
|
||||||
|
|
||||||
_buildImageItem(RecordListData recordData) {
|
_buildImageItem(RecordListData recordData) {
|
||||||
return Image.network(
|
return RotatedBox(
|
||||||
|
quarterTurns: -1,
|
||||||
|
child: Image.network(
|
||||||
recordData.imagesUrl!,
|
recordData.imagesUrl!,
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
|
errorBuilder:
|
||||||
|
(BuildContext context, Object error, StackTrace? stackTrace) {
|
||||||
|
// 图片加载失败时显示错误图片
|
||||||
|
return RotatedBox(
|
||||||
|
quarterTurns: -1,
|
||||||
|
child: Image.asset(
|
||||||
|
'images/icon_unHaveData.png', // 错误图片路径
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -150,7 +150,8 @@ class _ControlsOverlayState extends State<ControlsOverlay> {
|
|||||||
Text(
|
Text(
|
||||||
DateTool().dateToYMDHNString(
|
DateTool().dateToYMDHNString(
|
||||||
widget.recordData.operateDate.toString()),
|
widget.recordData.operateDate.toString()),
|
||||||
style: TextStyle(color: Colors.white, fontSize: 20.sp)),
|
style: TextStyle(color: Colors.white, fontSize: 20.sp),
|
||||||
|
),
|
||||||
// Expanded(child: SizedBox(width: 10.w)),
|
// Expanded(child: SizedBox(width: 10.w)),
|
||||||
// Container(
|
// Container(
|
||||||
// width: 50.w,
|
// width: 50.w,
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
@ -7,7 +8,7 @@ import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart
|
|||||||
import 'package:star_lock/main/lockDetail/videoLog/videoLogDetail/controlsOverlay_page.dart';
|
import 'package:star_lock/main/lockDetail/videoLog/videoLogDetail/controlsOverlay_page.dart';
|
||||||
import 'package:star_lock/main/lockDetail/videoLog/videoLogDetail/videoLogDetail_state.dart';
|
import 'package:star_lock/main/lockDetail/videoLog/videoLogDetail/videoLogDetail_state.dart';
|
||||||
import 'package:star_lock/main/lockDetail/videoLog/widget/full_screenImage_page.dart';
|
import 'package:star_lock/main/lockDetail/videoLog/widget/full_screenImage_page.dart';
|
||||||
import 'package:star_lock/main/lockDetail/videoLog/widget/video_thumbnail.dart';
|
import 'package:star_lock/main/lockDetail/videoLog/widget/video_thumbnail_image.dart';
|
||||||
import 'package:star_lock/tools/dateTool.dart';
|
import 'package:star_lock/tools/dateTool.dart';
|
||||||
import 'package:video_player/video_player.dart';
|
import 'package:video_player/video_player.dart';
|
||||||
|
|
||||||
@ -72,20 +73,19 @@ class _VideoLogDetailPageState extends State<VideoLogDetailPage> {
|
|||||||
? Column(
|
? Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Container(
|
Container(
|
||||||
|
color: Colors.black,
|
||||||
height: 500.h,
|
height: 500.h,
|
||||||
decoration: BoxDecoration(color: Colors.black),
|
width: 1.sw,
|
||||||
child: AspectRatio(
|
|
||||||
aspectRatio: 16 / 9,
|
|
||||||
child: Stack(
|
child: Stack(
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
FittedBox(
|
RotatedBox(
|
||||||
child: SizedBox(
|
quarterTurns: -1,
|
||||||
width: state.videoController.value.size.width,
|
child: AspectRatio(
|
||||||
height: state.videoController.value.size.height,
|
aspectRatio: state.videoController.value.size.width /
|
||||||
|
state.videoController.value.size.height,
|
||||||
child: VideoPlayer(state.videoController),
|
child: VideoPlayer(state.videoController),
|
||||||
),
|
),
|
||||||
fit: BoxFit.cover,
|
|
||||||
),
|
),
|
||||||
ControlsOverlay(
|
ControlsOverlay(
|
||||||
controller: state.videoController,
|
controller: state.videoController,
|
||||||
@ -104,7 +104,6 @@ class _VideoLogDetailPageState extends State<VideoLogDetailPage> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
_buildOther(),
|
_buildOther(),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@ -166,13 +165,27 @@ class _VideoLogDetailPageState extends State<VideoLogDetailPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_buildVideoItem(RecordListData recordData) {
|
_buildVideoItem(RecordListData recordData) {
|
||||||
return VideoThumbnail(videoUrl: recordData.videoUrl!);
|
return VideoThumbnailImage(videoUrl: recordData.videoUrl!);
|
||||||
}
|
}
|
||||||
|
|
||||||
_buildImageItem(RecordListData recordData) {
|
_buildImageItem(RecordListData recordData) {
|
||||||
return Image.network(
|
return RotatedBox(
|
||||||
|
quarterTurns: 1,
|
||||||
|
child: Image.network(
|
||||||
recordData.imagesUrl!,
|
recordData.imagesUrl!,
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
|
errorBuilder:
|
||||||
|
(BuildContext context, Object error, StackTrace? stackTrace) {
|
||||||
|
// 图片加载失败时显示错误图片
|
||||||
|
return RotatedBox(
|
||||||
|
quarterTurns: -1,
|
||||||
|
child: Image.asset(
|
||||||
|
'images/icon_unHaveData.png', // 错误图片路径
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,11 +10,19 @@ class FullScreenImagePage extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: Container(
|
body: GestureDetector(
|
||||||
|
onTap: (){
|
||||||
|
Navigator.pop(context); // 点击图片返回
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
child: RotatedBox(
|
||||||
|
quarterTurns: -1,
|
||||||
child: PhotoView(
|
child: PhotoView(
|
||||||
imageProvider: NetworkImage(imageUrl),
|
imageProvider: NetworkImage(imageUrl),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,73 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:video_player/video_player.dart';
|
|
||||||
|
|
||||||
class VideoThumbnail extends StatefulWidget {
|
|
||||||
final String videoUrl;
|
|
||||||
|
|
||||||
VideoThumbnail({required this.videoUrl});
|
|
||||||
|
|
||||||
@override
|
|
||||||
_VideoThumbnailState createState() => _VideoThumbnailState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _VideoThumbnailState extends State<VideoThumbnail> {
|
|
||||||
late VideoPlayerController _controller;
|
|
||||||
late Future<void> _initializeVideoPlayerFuture;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
// 创建并初始化 VideoPlayerController
|
|
||||||
_controller = VideoPlayerController.network(widget.videoUrl)
|
|
||||||
..initialize().then((_) {
|
|
||||||
// 当视频控制器初始化完成后,更新UI以便显示第一帧
|
|
||||||
setState(() {});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
// 清理资源
|
|
||||||
_controller.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return GestureDetector(
|
|
||||||
// onTap: () {
|
|
||||||
// setState(() {
|
|
||||||
// if (_controller.value.isPlaying) {
|
|
||||||
// _controller.pause();
|
|
||||||
// } else {
|
|
||||||
// _controller.play();
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
child: Stack(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
// 如果视频已经初始化,则显示视频玩家
|
|
||||||
_controller.value.isInitialized
|
|
||||||
? AspectRatio(
|
|
||||||
aspectRatio: 1 / 1, // 强制正方形比例
|
|
||||||
child: FittedBox(
|
|
||||||
fit: BoxFit.cover, // 确保视频封面铺满空间
|
|
||||||
child: SizedBox(
|
|
||||||
width: _controller.value.size.width,
|
|
||||||
height: _controller.value.size.height,
|
|
||||||
child: VideoPlayer(_controller),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: Center(
|
|
||||||
child: CircularProgressIndicator(), // 加载中显示转圈
|
|
||||||
),
|
|
||||||
if (!_controller.value.isPlaying && _controller.value.isInitialized)
|
|
||||||
Icon(Icons.play_arrow_rounded,
|
|
||||||
size: 80, color: Colors.white.withOpacity(0.8)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,97 @@
|
|||||||
|
import 'dart:io'; // 导入 dart:io 以使用 File 类
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart'; // 导入 path_provider
|
||||||
|
import 'package:video_thumbnail/video_thumbnail.dart'; // 导入 video_thumbnail
|
||||||
|
|
||||||
|
class VideoThumbnailImage extends StatefulWidget {
|
||||||
|
final String videoUrl;
|
||||||
|
|
||||||
|
VideoThumbnailImage({required this.videoUrl});
|
||||||
|
|
||||||
|
@override
|
||||||
|
_VideoThumbnailState createState() => _VideoThumbnailState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _VideoThumbnailState extends State<VideoThumbnailImage> {
|
||||||
|
final Map<String, String> _thumbnailCache = {}; // 缩略图缓存
|
||||||
|
late Future<String?> _thumbnailFuture; // 用于存储缩略图生成的 Future
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_thumbnailFuture = _generateThumbnail(); // 在 initState 中初始化 Future
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成缩略图
|
||||||
|
Future<String?> _generateThumbnail() async {
|
||||||
|
try {
|
||||||
|
// 检查缓存中是否已有缩略图
|
||||||
|
if (_thumbnailCache.containsKey(widget.videoUrl)) {
|
||||||
|
return _thumbnailCache[widget.videoUrl];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取临时目录路径
|
||||||
|
final tempDir = await getTemporaryDirectory();
|
||||||
|
final thumbnailPath = await VideoThumbnail.thumbnailFile(
|
||||||
|
video: widget.videoUrl,
|
||||||
|
// 视频 URL
|
||||||
|
thumbnailPath: tempDir.path,
|
||||||
|
// 缩略图保存路径
|
||||||
|
imageFormat: ImageFormat.JPEG,
|
||||||
|
// 缩略图格式
|
||||||
|
maxHeight: 200,
|
||||||
|
// 缩略图最大高度
|
||||||
|
quality: 100, // 缩略图质量 (0-100)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 更新缓存
|
||||||
|
_thumbnailCache[widget.videoUrl] = thumbnailPath!;
|
||||||
|
return thumbnailPath;
|
||||||
|
} catch (e) {
|
||||||
|
print('Failed to generate thumbnail: $e');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return FutureBuilder<String?>(
|
||||||
|
future: _thumbnailFuture, // 生成缩略图的 Future
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
|
// 加载中显示转圈
|
||||||
|
return Center(child: CircularProgressIndicator());
|
||||||
|
} else if (snapshot.hasError || !snapshot.hasData) {
|
||||||
|
// 加载失败或没有数据时显示提示
|
||||||
|
return Image.asset(
|
||||||
|
'images/icon_unHaveData.png', // 错误图片路径
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// 加载成功,显示缩略图
|
||||||
|
final thumbnailPath = snapshot.data!;
|
||||||
|
return Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
RotatedBox(
|
||||||
|
quarterTurns: -1,
|
||||||
|
child: Image.file(
|
||||||
|
File(thumbnailPath), // 显示生成的缩略图
|
||||||
|
width: 200,
|
||||||
|
height: 200,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Icon(
|
||||||
|
Icons.play_arrow_rounded,
|
||||||
|
size: 80,
|
||||||
|
color: Colors.white.withOpacity(0.8),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,3 +1,6 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
@ -9,7 +12,9 @@ import 'package:star_lock/mine/about/about_console.dart';
|
|||||||
import '../../app_settings/app_colors.dart';
|
import '../../app_settings/app_colors.dart';
|
||||||
import '../../flavors.dart';
|
import '../../flavors.dart';
|
||||||
import '../../tools/commonItem.dart';
|
import '../../tools/commonItem.dart';
|
||||||
|
import '../../tools/storage.dart';
|
||||||
import '../../tools/titleAppBar.dart';
|
import '../../tools/titleAppBar.dart';
|
||||||
|
import '../../tools/wechat/wechatManageTool.dart';
|
||||||
|
|
||||||
class AboutPage extends StatefulWidget {
|
class AboutPage extends StatefulWidget {
|
||||||
const AboutPage({Key? key}) : super(key: key);
|
const AboutPage({Key? key}) : super(key: key);
|
||||||
@ -80,6 +85,44 @@ class _AboutPageState extends State<AboutPage> {
|
|||||||
Widget listView() {
|
Widget listView() {
|
||||||
Widget view = Column(
|
Widget view = Column(
|
||||||
children: [
|
children: [
|
||||||
|
CommonItem(
|
||||||
|
leftTitel: '版本说明'.tr,
|
||||||
|
rightTitle: '',
|
||||||
|
isHaveLine: false,
|
||||||
|
isHaveDirection: true,
|
||||||
|
action: () async {
|
||||||
|
WechatManageTool.getAppInfo(() async {
|
||||||
|
final String? appVersionHistoryBaseUrl =
|
||||||
|
await Storage.getString(appVersionHistoryUrl);
|
||||||
|
if (appVersionHistoryBaseUrl == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String brandName = '';
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
final AndroidDeviceInfo androidDeviceInfo =
|
||||||
|
await DeviceInfoPlugin().androidInfo;
|
||||||
|
brandName = androidDeviceInfo.manufacturer;
|
||||||
|
} else {
|
||||||
|
final IosDeviceInfo iosDeviceInfo =
|
||||||
|
await DeviceInfoPlugin().iosInfo;
|
||||||
|
brandName = iosDeviceInfo.systemName ?? 'ios';
|
||||||
|
}
|
||||||
|
final PackageInfo packageInfo =
|
||||||
|
await PackageInfo.fromPlatform();
|
||||||
|
Navigator.pushNamed(context, Routers.webviewShowPage,
|
||||||
|
arguments: {
|
||||||
|
'url': appVersionHistoryBaseUrl +
|
||||||
|
'?version=${packageInfo.version}&brandName=${brandName}',
|
||||||
|
'title': '版本说明'.tr
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
Divider(
|
||||||
|
height: 1,
|
||||||
|
color: AppColors.greyLineColor,
|
||||||
|
indent: 20.w,
|
||||||
|
endIndent: 20.w,
|
||||||
|
),
|
||||||
CommonItem(
|
CommonItem(
|
||||||
leftTitel: '介绍'.tr,
|
leftTitel: '介绍'.tr,
|
||||||
rightTitle: '',
|
rightTitle: '',
|
||||||
|
|||||||
@ -11,7 +11,7 @@ class StartChartApi extends BaseProvider {
|
|||||||
// 星图url
|
// 星图url
|
||||||
final String _startChartHost = 'http://sls1-scd.star-lock.cn:8080';
|
final String _startChartHost = 'http://sls1-scd.star-lock.cn:8080';
|
||||||
|
|
||||||
static StartChartApi get to => Get.find<StartChartApi>();
|
static StartChartApi get to => Get.put(StartChartApi());
|
||||||
|
|
||||||
// 星图--注册节点
|
// 星图--注册节点
|
||||||
Future<StarChartRegisterNodeEntity> starChartRegisterNode({
|
Future<StarChartRegisterNodeEntity> starChartRegisterNode({
|
||||||
@ -68,6 +68,4 @@ class StartChartApi extends BaseProvider {
|
|||||||
);
|
);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -149,122 +149,200 @@ class ScpMessage {
|
|||||||
|
|
||||||
static ScpMessage deserialize(Uint8List bytes) {
|
static ScpMessage deserialize(Uint8List bytes) {
|
||||||
final message = ScpMessage();
|
final message = ScpMessage();
|
||||||
|
final length = bytes.length;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
|
|
||||||
// String hexString =
|
// 提前检查字节数组长度是否足够
|
||||||
// bytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join();
|
if (length < 4 + 1 + 2 + 1 + 1 + 44 + 44 + 2 + 2 + 4) {
|
||||||
// // _log(text: 'result bytes hex: ${hexString}');
|
throw FormatException("Invalid message length");
|
||||||
// _log(
|
}
|
||||||
// text:
|
|
||||||
// '\n result bytes hex: ${hexString} \n payload hex: ${hexString.substring(210)}');
|
// 使用 ByteData 读取多字节数据
|
||||||
|
final byteData = ByteData.sublistView(bytes);
|
||||||
|
|
||||||
// ProtocolFlag (4 bytes)
|
// ProtocolFlag (4 bytes)
|
||||||
if (bytes.length - offset >= 4) {
|
|
||||||
message.ProtocolFlag = utf8.decode(bytes.sublist(offset, offset + 4));
|
message.ProtocolFlag = utf8.decode(bytes.sublist(offset, offset + 4));
|
||||||
offset += 4;
|
offset += 4;
|
||||||
} else {
|
|
||||||
throw FormatException("Invalid ProtocolFlag length");
|
|
||||||
}
|
|
||||||
|
|
||||||
// MessageType (1 byte)
|
// MessageType (1 byte)
|
||||||
if (bytes.length - offset >= 1) {
|
|
||||||
message.MessageType = bytes[offset];
|
message.MessageType = bytes[offset];
|
||||||
offset += 1;
|
offset += 1;
|
||||||
} else {
|
|
||||||
throw FormatException("Invalid MessageType length");
|
|
||||||
}
|
|
||||||
|
|
||||||
// MessageId (2 bytes, little-endian)
|
// MessageId (2 bytes, little-endian)
|
||||||
if (bytes.length - offset >= 2) {
|
message.MessageId = byteData.getUint16(offset, Endian.little);
|
||||||
message.MessageId = (bytes[offset + 1] << 8) | bytes[offset];
|
|
||||||
offset += 2;
|
offset += 2;
|
||||||
} else {
|
|
||||||
throw FormatException("Invalid MessageId length");
|
|
||||||
}
|
|
||||||
|
|
||||||
// SpTotal (1 byte)
|
// SpTotal (1 byte)
|
||||||
if (bytes.length - offset >= 1) {
|
|
||||||
message.SpTotal = bytes[offset];
|
message.SpTotal = bytes[offset];
|
||||||
offset += 1;
|
offset += 1;
|
||||||
} else {
|
|
||||||
throw FormatException("Invalid SpTotal length");
|
|
||||||
}
|
|
||||||
|
|
||||||
// SpIndex (1 byte)
|
// SpIndex (1 byte)
|
||||||
if (bytes.length - offset >= 1) {
|
|
||||||
message.SpIndex = bytes[offset];
|
message.SpIndex = bytes[offset];
|
||||||
offset += 1;
|
offset += 1;
|
||||||
} else {
|
|
||||||
throw FormatException("Invalid SpIndex length");
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromPeerId (字符串,长度固定为44字节)
|
// FromPeerId (44 bytes)
|
||||||
if (bytes.length - offset >= 44) {
|
|
||||||
message.FromPeerId =
|
message.FromPeerId =
|
||||||
utf8.decode(bytes.sublist(offset, offset + 44)).trimRight();
|
utf8.decode(bytes.sublist(offset, offset + 44)).trimRight();
|
||||||
offset += 44;
|
offset += 44;
|
||||||
} else {
|
|
||||||
throw FormatException("Invalid FromPeerId length");
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToPeerId (字符串,长度固定为44字节)
|
// ToPeerId (44 bytes)
|
||||||
if (bytes.length - offset >= 44) {
|
|
||||||
message.ToPeerId =
|
message.ToPeerId =
|
||||||
utf8.decode(bytes.sublist(offset, offset + 44)).trimRight();
|
utf8.decode(bytes.sublist(offset, offset + 44)).trimRight();
|
||||||
offset += 44;
|
offset += 44;
|
||||||
} else {
|
|
||||||
throw FormatException("Invalid ToPeerId length");
|
|
||||||
}
|
|
||||||
|
|
||||||
// PayloadType (2 bytes, little-endian)
|
// PayloadType (2 bytes, little-endian)
|
||||||
if (bytes.length - offset >= 2) {
|
message.PayloadType = byteData.getUint16(offset, Endian.little);
|
||||||
message.PayloadType = (bytes[offset + 1] << 8) | bytes[offset];
|
|
||||||
offset += 2;
|
offset += 2;
|
||||||
} else {
|
|
||||||
throw FormatException("Invalid PayloadType length");
|
|
||||||
}
|
|
||||||
|
|
||||||
// PayloadCRC (2 bytes, little-endian)
|
// PayloadCRC (2 bytes, little-endian)
|
||||||
if (bytes.length - offset >= 2) {
|
message.PayloadCRC = byteData.getUint16(offset, Endian.little);
|
||||||
message.PayloadCRC = (bytes[offset + 1] << 8) | bytes[offset];
|
|
||||||
offset += 2;
|
offset += 2;
|
||||||
} else {
|
|
||||||
throw FormatException("Invalid PayloadCRC length");
|
|
||||||
}
|
|
||||||
|
|
||||||
// PayloadLength (4 bytes, little-endian)
|
// PayloadLength (4 bytes, little-endian)
|
||||||
if (bytes.length - offset >= 4) {
|
message.PayloadLength = byteData.getUint32(offset, Endian.little);
|
||||||
message.PayloadLength = (bytes[offset] |
|
|
||||||
(bytes[offset + 1] << 8) |
|
|
||||||
(bytes[offset + 2] << 16) |
|
|
||||||
(bytes[offset + 3] << 24)); // 修正为 little-endian
|
|
||||||
offset += 4;
|
offset += 4;
|
||||||
} else {
|
|
||||||
throw FormatException("Invalid PayloadLength length");
|
// 检查 Payload 长度是否有效
|
||||||
|
if (message.PayloadLength == null ||
|
||||||
|
length - offset < message.PayloadLength!) {
|
||||||
|
throw FormatException("Invalid Payload or PayloadLength");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理其他类型的Payload
|
// 处理 Payload
|
||||||
if (message.PayloadLength != null &&
|
final payloadBytes = bytes.sublist(offset, offset + message.PayloadLength!);
|
||||||
bytes.length - offset >= message.PayloadLength!) {
|
|
||||||
final sublist = bytes.sublist(offset, offset + message.PayloadLength!);
|
|
||||||
offset += message.PayloadLength!;
|
offset += message.PayloadLength!;
|
||||||
message.Payload = _handlePayLoad(
|
message.Payload = _handlePayLoad(
|
||||||
payloadType: message.PayloadType ?? 0,
|
payloadType: message.PayloadType ?? 0,
|
||||||
messageType: message.MessageType ?? 0,
|
messageType: message.MessageType ?? 0,
|
||||||
byte: sublist,
|
byte: payloadBytes,
|
||||||
offset: offset,
|
offset: offset,
|
||||||
PayloadLength: message.PayloadLength,
|
PayloadLength: message.PayloadLength,
|
||||||
spIndex: message.SpIndex,
|
spIndex: message.SpIndex,
|
||||||
spTotal: message.SpTotal,
|
spTotal: message.SpTotal,
|
||||||
messageId: message.MessageId,
|
messageId: message.MessageId,
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
throw FormatException("Invalid Payload or PayloadLength");
|
|
||||||
}
|
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static ScpMessage deserialize(Uint8List bytes) {
|
||||||
|
// final message = ScpMessage();
|
||||||
|
// int offset = 0;
|
||||||
|
//
|
||||||
|
// // String hexString =
|
||||||
|
// // bytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join();
|
||||||
|
// // // _log(text: 'result bytes hex: ${hexString}');
|
||||||
|
// // _log(
|
||||||
|
// // text:
|
||||||
|
// // '\n result bytes hex: ${hexString} \n payload hex: ${hexString.substring(210)}');
|
||||||
|
//
|
||||||
|
// // ProtocolFlag (4 bytes)
|
||||||
|
// if (bytes.length - offset >= 4) {
|
||||||
|
// message.ProtocolFlag = utf8.decode(bytes.sublist(offset, offset + 4));
|
||||||
|
// offset += 4;
|
||||||
|
// } else {
|
||||||
|
// throw FormatException("Invalid ProtocolFlag length");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // MessageType (1 byte)
|
||||||
|
// if (bytes.length - offset >= 1) {
|
||||||
|
// message.MessageType = bytes[offset];
|
||||||
|
// offset += 1;
|
||||||
|
// } else {
|
||||||
|
// throw FormatException("Invalid MessageType length");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // MessageId (2 bytes, little-endian)
|
||||||
|
// if (bytes.length - offset >= 2) {
|
||||||
|
// message.MessageId = (bytes[offset + 1] << 8) | bytes[offset];
|
||||||
|
// offset += 2;
|
||||||
|
// } else {
|
||||||
|
// throw FormatException("Invalid MessageId length");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // SpTotal (1 byte)
|
||||||
|
// if (bytes.length - offset >= 1) {
|
||||||
|
// message.SpTotal = bytes[offset];
|
||||||
|
// offset += 1;
|
||||||
|
// } else {
|
||||||
|
// throw FormatException("Invalid SpTotal length");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // SpIndex (1 byte)
|
||||||
|
// if (bytes.length - offset >= 1) {
|
||||||
|
// message.SpIndex = bytes[offset];
|
||||||
|
// offset += 1;
|
||||||
|
// } else {
|
||||||
|
// throw FormatException("Invalid SpIndex length");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // FromPeerId (字符串,长度固定为44字节)
|
||||||
|
// if (bytes.length - offset >= 44) {
|
||||||
|
// message.FromPeerId =
|
||||||
|
// utf8.decode(bytes.sublist(offset, offset + 44)).trimRight();
|
||||||
|
// offset += 44;
|
||||||
|
// } else {
|
||||||
|
// throw FormatException("Invalid FromPeerId length");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // ToPeerId (字符串,长度固定为44字节)
|
||||||
|
// if (bytes.length - offset >= 44) {
|
||||||
|
// message.ToPeerId =
|
||||||
|
// utf8.decode(bytes.sublist(offset, offset + 44)).trimRight();
|
||||||
|
// offset += 44;
|
||||||
|
// } else {
|
||||||
|
// throw FormatException("Invalid ToPeerId length");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // PayloadType (2 bytes, little-endian)
|
||||||
|
// if (bytes.length - offset >= 2) {
|
||||||
|
// message.PayloadType = (bytes[offset + 1] << 8) | bytes[offset];
|
||||||
|
// offset += 2;
|
||||||
|
// } else {
|
||||||
|
// throw FormatException("Invalid PayloadType length");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // PayloadCRC (2 bytes, little-endian)
|
||||||
|
// if (bytes.length - offset >= 2) {
|
||||||
|
// message.PayloadCRC = (bytes[offset + 1] << 8) | bytes[offset];
|
||||||
|
// offset += 2;
|
||||||
|
// } else {
|
||||||
|
// throw FormatException("Invalid PayloadCRC length");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // PayloadLength (4 bytes, little-endian)
|
||||||
|
// if (bytes.length - offset >= 4) {
|
||||||
|
// message.PayloadLength = (bytes[offset] |
|
||||||
|
// (bytes[offset + 1] << 8) |
|
||||||
|
// (bytes[offset + 2] << 16) |
|
||||||
|
// (bytes[offset + 3] << 24)); // 修正为 little-endian
|
||||||
|
// offset += 4;
|
||||||
|
// } else {
|
||||||
|
// throw FormatException("Invalid PayloadLength length");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 处理其他类型的Payload
|
||||||
|
// if (message.PayloadLength != null &&
|
||||||
|
// bytes.length - offset >= message.PayloadLength!) {
|
||||||
|
// final sublist = bytes.sublist(offset, offset + message.PayloadLength!);
|
||||||
|
// offset += message.PayloadLength!;
|
||||||
|
// message.Payload = _handlePayLoad(
|
||||||
|
// payloadType: message.PayloadType ?? 0,
|
||||||
|
// messageType: message.MessageType ?? 0,
|
||||||
|
// byte: sublist,
|
||||||
|
// offset: offset,
|
||||||
|
// PayloadLength: message.PayloadLength,
|
||||||
|
// spIndex: message.SpIndex,
|
||||||
|
// spTotal: message.SpTotal,
|
||||||
|
// messageId: message.MessageId,
|
||||||
|
// );
|
||||||
|
// } else {
|
||||||
|
// throw FormatException("Invalid Payload or PayloadLength");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return message;
|
||||||
|
// }
|
||||||
|
|
||||||
// 根据不同payloadType序列化对应的payload结构体
|
// 根据不同payloadType序列化对应的payload结构体
|
||||||
static dynamic _handlePayLoad({
|
static dynamic _handlePayLoad({
|
||||||
required int payloadType,
|
required int payloadType,
|
||||||
|
|||||||
@ -29,7 +29,6 @@ class UdpTalkAcceptHandler extends ScpMessageBaseHandle
|
|||||||
// 收到同意接听回复
|
// 收到同意接听回复
|
||||||
final GenericResp genericResp = scpMessage.Payload;
|
final GenericResp genericResp = scpMessage.Payload;
|
||||||
if (checkGenericRespSuccess(genericResp)) {
|
if (checkGenericRespSuccess(genericResp)) {
|
||||||
print('收到同意接听的回复');
|
|
||||||
// 停止同意接听的重发
|
// 停止同意接听的重发
|
||||||
startChartManage.stopTalkAcceptTimer();
|
startChartManage.stopTalkAcceptTimer();
|
||||||
// 接听之后增加期望音频的接收
|
// 接听之后增加期望音频的接收
|
||||||
|
|||||||
@ -156,7 +156,7 @@ class UdpTalkDataHandler extends ScpMessageBaseHandle
|
|||||||
void _handleVideoH264(TalkData talkData) {
|
void _handleVideoH264(TalkData talkData) {
|
||||||
final TalkDataH264Frame talkDataH264Frame = TalkDataH264Frame();
|
final TalkDataH264Frame talkDataH264Frame = TalkDataH264Frame();
|
||||||
talkDataH264Frame.mergeFromBuffer(talkData.content);
|
talkDataH264Frame.mergeFromBuffer(talkData.content);
|
||||||
AppLog.log('H264 TalkData :$talkDataH264Frame');
|
// AppLog.log('H264 TalkData :$talkDataH264Frame');
|
||||||
talkDataRepository.addTalkData(talkData);
|
talkDataRepository.addTalkData(talkData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@ class UdpTalkHangUpHandler extends ScpMessageBaseHandle
|
|||||||
// // 如果不是接听中,不处理通话中挂断请求
|
// // 如果不是接听中,不处理通话中挂断请求
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
print('收到通话中挂断请求');
|
|
||||||
// 回复请求
|
// 回复请求
|
||||||
replySuccessMessage(scpMessage);
|
replySuccessMessage(scpMessage);
|
||||||
talkStatus.setHangingUpDuring();
|
talkStatus.setHangingUpDuring();
|
||||||
@ -34,7 +34,7 @@ class UdpTalkHangUpHandler extends ScpMessageBaseHandle
|
|||||||
talkePingOverTimeTimerManager.cancel();
|
talkePingOverTimeTimerManager.cancel();
|
||||||
talkDataOverTimeTimerManager.cancel();
|
talkDataOverTimeTimerManager.cancel();
|
||||||
|
|
||||||
EasyLoading.showToast('已挂断');
|
EasyLoading.showToast('已挂断'.tr);
|
||||||
Get.back();
|
Get.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -28,7 +28,7 @@ class TalkDataOverTimeTimerManager {
|
|||||||
|
|
||||||
// 超时处理函数
|
// 超时处理函数
|
||||||
static void _handleTalkeDataOverTime() {
|
static void _handleTalkeDataOverTime() {
|
||||||
EasyLoading.showToast('通话连接失败', duration: 2000.milliseconds);
|
EasyLoading.showToast('通话连接失败'.tr, duration: 2000.milliseconds);
|
||||||
// 没有通话数据,发送挂断数据
|
// 没有通话数据,发送挂断数据
|
||||||
StartChartManage().sendTalkHangupMessage();
|
StartChartManage().sendTalkHangupMessage();
|
||||||
StartChartManage().stopTalkPingMessageTimer();
|
StartChartManage().stopTalkPingMessageTimer();
|
||||||
|
|||||||
@ -28,7 +28,7 @@ class TalkePingOverTimeTimerManager {
|
|||||||
// 超时处理函数
|
// 超时处理函数
|
||||||
static void _handleTalkePingOverTime() {
|
static void _handleTalkePingOverTime() {
|
||||||
if (talkStatus.status == TalkStatus.answeredSuccessfully) {
|
if (talkStatus.status == TalkStatus.answeredSuccessfully) {
|
||||||
EasyLoading.showToast('通话异常中断', duration: 2000.milliseconds);
|
EasyLoading.showToast('通话异常中断'.tr, duration: 2000.milliseconds);
|
||||||
// 停止发送通话保持的命令
|
// 停止发送通话保持的命令
|
||||||
StartChartManage().stopTalkPingMessageTimer();
|
StartChartManage().stopTalkPingMessageTimer();
|
||||||
StartChartManage().stopTalkExpectMessageTimer();
|
StartChartManage().stopTalkExpectMessageTimer();
|
||||||
|
|||||||
@ -29,7 +29,7 @@ class TalkeRequestOverTimeTimerManager {
|
|||||||
static void _handleTalkeRequestOverTime() {
|
static void _handleTalkeRequestOverTime() {
|
||||||
if (talkStatus.status == TalkStatus.passiveCallWaitingAnswer ||
|
if (talkStatus.status == TalkStatus.passiveCallWaitingAnswer ||
|
||||||
talkStatus.status == TalkStatus.proactivelyCallWaitingAnswer) {
|
talkStatus.status == TalkStatus.proactivelyCallWaitingAnswer) {
|
||||||
EasyLoading.showToast('通话未接通,以挂断', duration: 2000.milliseconds);
|
EasyLoading.showToast('通话未接通,已挂断'.tr, duration: 2000.milliseconds);
|
||||||
// 超时未接听,发送挂断请求
|
// 超时未接听,发送挂断请求
|
||||||
StartChartManage().sendTalkRejectMessage();
|
StartChartManage().sendTalkRejectMessage();
|
||||||
talkStatus.setInitializationCompleted();
|
talkStatus.setInitializationCompleted();
|
||||||
|
|||||||
@ -50,7 +50,6 @@ class TalkViewLogic extends BaseGetXController {
|
|||||||
int audioFrameIntervalMs = 20; // 初始帧间隔设置为45毫秒(约22FPS)
|
int audioFrameIntervalMs = 20; // 初始帧间隔设置为45毫秒(约22FPS)
|
||||||
int minFrameIntervalMs = 30; // 最小帧间隔(约33 FPS)
|
int minFrameIntervalMs = 30; // 最小帧间隔(约33 FPS)
|
||||||
int maxFrameIntervalMs = 100; // 最大帧间隔(约1 FPS)
|
int maxFrameIntervalMs = 100; // 最大帧间隔(约1 FPS)
|
||||||
// int maxFrameIntervalMs = 100; // 最大帧间隔(约10 FPS)
|
|
||||||
|
|
||||||
/// 初始化音频播放器
|
/// 初始化音频播放器
|
||||||
void _initFlutterPcmSound() {
|
void _initFlutterPcmSound() {
|
||||||
@ -118,6 +117,17 @@ class TalkViewLogic extends BaseGetXController {
|
|||||||
case TalkStatus.end:
|
case TalkStatus.end:
|
||||||
_handleInvalidTalkStatus();
|
_handleInvalidTalkStatus();
|
||||||
break;
|
break;
|
||||||
|
case TalkStatus.answeredSuccessfully:
|
||||||
|
state.oneMinuteTimeTimer?.cancel(); // 取消旧定时器
|
||||||
|
state.oneMinuteTimeTimer ??=
|
||||||
|
Timer.periodic(const Duration(seconds: 1), (Timer t) {
|
||||||
|
state.oneMinuteTime.value++;
|
||||||
|
if (state.oneMinuteTime.value >= 60) {
|
||||||
|
t.cancel(); // 取消定时器
|
||||||
|
state.oneMinuteTime.value = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// 其他状态的处理
|
// 其他状态的处理
|
||||||
break;
|
break;
|
||||||
@ -160,12 +170,6 @@ class TalkViewLogic extends BaseGetXController {
|
|||||||
/// 动态调整帧间隔
|
/// 动态调整帧间隔
|
||||||
void _adjustFrameInterval() {
|
void _adjustFrameInterval() {
|
||||||
int newFrameIntervalMs = frameIntervalMs;
|
int newFrameIntervalMs = frameIntervalMs;
|
||||||
if (state.networkStatus.value == NetworkStatus.lagging) {
|
|
||||||
bufferSize = 60; // 增大缓冲区
|
|
||||||
} else {
|
|
||||||
bufferSize = 40; // 恢复默认缓冲区大小
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state.videoBuffer.length < 10 && frameIntervalMs < maxFrameIntervalMs) {
|
if (state.videoBuffer.length < 10 && frameIntervalMs < maxFrameIntervalMs) {
|
||||||
// 如果缓冲区较小且帧间隔小于最大值,则增加帧间隔
|
// 如果缓冲区较小且帧间隔小于最大值,则增加帧间隔
|
||||||
frameIntervalMs += 5;
|
frameIntervalMs += 5;
|
||||||
@ -303,7 +307,7 @@ class TalkViewLogic extends BaseGetXController {
|
|||||||
bluetoothDeviceName: BlueManage().connectDeviceName,
|
bluetoothDeviceName: BlueManage().connectDeviceName,
|
||||||
openLockCommand: messageDetail,
|
openLockCommand: messageDetail,
|
||||||
);
|
);
|
||||||
showToast('已发送开门通知');
|
showToast('正在开锁中...'.tr);
|
||||||
}
|
}
|
||||||
|
|
||||||
int _getUTCNetTime() {
|
int _getUTCNetTime() {
|
||||||
@ -442,7 +446,8 @@ class TalkViewLogic extends BaseGetXController {
|
|||||||
_syncTimer = null; // 释放定时器引用
|
_syncTimer = null; // 释放定时器引用
|
||||||
_audioTimer?.cancel();
|
_audioTimer?.cancel();
|
||||||
_audioTimer = null; // 释放定时器引用
|
_audioTimer = null; // 释放定时器引用
|
||||||
|
state.oneMinuteTimeTimer?.cancel();
|
||||||
|
state.oneMinuteTimeTimer = null;
|
||||||
stopProcessingAudio();
|
stopProcessingAudio();
|
||||||
super.onClose();
|
super.onClose();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -110,13 +110,13 @@ class _TalkViewPageState extends State<TalkViewPage>
|
|||||||
canPop: false,
|
canPop: false,
|
||||||
child: RepaintBoundary(
|
child: RepaintBoundary(
|
||||||
key: state.globalKey,
|
key: state.globalKey,
|
||||||
child: Transform.rotate(
|
child: SizedBox.expand(
|
||||||
angle:
|
child: RotatedBox(
|
||||||
state.rotateAngle.value * (pi / 180), // 旋转 90 度
|
quarterTurns: -1,
|
||||||
child: Transform.scale(
|
|
||||||
scale: scale, // 动态计算的缩放比例
|
|
||||||
child: Image.memory(
|
child: Image.memory(
|
||||||
state.listData.value,
|
state.listData.value,
|
||||||
|
width: ScreenUtil().scaleWidth,
|
||||||
|
height: ScreenUtil().scaleHeight,
|
||||||
gaplessPlayback: true,
|
gaplessPlayback: true,
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
filterQuality: FilterQuality.high,
|
filterQuality: FilterQuality.high,
|
||||||
@ -142,6 +142,34 @@ class _TalkViewPageState extends State<TalkViewPage>
|
|||||||
style: TextStyle(color: Colors.black, fontSize: 26.sp),
|
style: TextStyle(color: Colors.black, fontSize: 26.sp),
|
||||||
))
|
))
|
||||||
: Container()),
|
: Container()),
|
||||||
|
Obx(
|
||||||
|
() => state.listData.value.isNotEmpty
|
||||||
|
? 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(
|
Positioned(
|
||||||
bottom: 10.w,
|
bottom: 10.w,
|
||||||
child: Container(
|
child: Container(
|
||||||
@ -197,7 +225,7 @@ class _TalkViewPageState extends State<TalkViewPage>
|
|||||||
Icon(Icons.mic, color: Colors.white, size: 24.w),
|
Icon(Icons.mic, color: Colors.white, size: 24.w),
|
||||||
SizedBox(width: 10.w),
|
SizedBox(width: 10.w),
|
||||||
Text(
|
Text(
|
||||||
'正在说话...',
|
'正在说话...'.tr,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 20.sp, color: Colors.white),
|
fontSize: 20.sp, color: Colors.white),
|
||||||
),
|
),
|
||||||
@ -342,13 +370,13 @@ class _TalkViewPageState extends State<TalkViewPage>
|
|||||||
Colors.white,
|
Colors.white,
|
||||||
longPress: () async {
|
longPress: () async {
|
||||||
if (state.talkStatus.value == TalkStatus.answeredSuccessfully) {
|
if (state.talkStatus.value == TalkStatus.answeredSuccessfully) {
|
||||||
print('开始录音');
|
// 启动录音
|
||||||
logic.startProcessingAudio();
|
logic.startProcessingAudio();
|
||||||
state.isLongPressing.value = true;
|
state.isLongPressing.value = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
longPressUp: () async {
|
longPressUp: () async {
|
||||||
print('停止录音');
|
// 停止录音
|
||||||
logic.stopProcessingAudio();
|
logic.stopProcessingAudio();
|
||||||
state.isLongPressing.value = false;
|
state.isLongPressing.value = false;
|
||||||
},
|
},
|
||||||
@ -369,7 +397,7 @@ class _TalkViewPageState extends State<TalkViewPage>
|
|||||||
}),
|
}),
|
||||||
bottomBtnItemWidget(
|
bottomBtnItemWidget(
|
||||||
'images/main/icon_lockDetail_monitoringUnlock.png',
|
'images/main/icon_lockDetail_monitoringUnlock.png',
|
||||||
'开锁',
|
'开锁'.tr,
|
||||||
AppColors.mainColor,
|
AppColors.mainColor,
|
||||||
onClick: () {
|
onClick: () {
|
||||||
// if (UDPManage().remoteUnlock == 1) {
|
// if (UDPManage().remoteUnlock == 1) {
|
||||||
|
|||||||
@ -37,8 +37,7 @@ class TalkViewState {
|
|||||||
RxList<int> listAudioData = <int>[].obs; //得到的音频流字节数据
|
RxList<int> listAudioData = <int>[].obs; //得到的音频流字节数据
|
||||||
GlobalKey globalKey = GlobalKey();
|
GlobalKey globalKey = GlobalKey();
|
||||||
|
|
||||||
late Timer oneMinuteTimeTimer =
|
Timer? oneMinuteTimeTimer; // 定时器超过60秒关闭当前界面
|
||||||
Timer(const Duration(seconds: 1), () {}); // 定时器超过60秒关闭当前界面
|
|
||||||
RxInt oneMinuteTime = 0.obs; // 定时器秒数
|
RxInt oneMinuteTime = 0.obs; // 定时器秒数
|
||||||
|
|
||||||
// 定时器如果发送了接听的命令 而没收到回复就每秒重复发送10次
|
// 定时器如果发送了接听的命令 而没收到回复就每秒重复发送10次
|
||||||
|
|||||||
@ -36,6 +36,7 @@ const String starChartRegisterNodeInfo = 'starChartRegisterNodeInfo'; //星图
|
|||||||
const String relayInfo = 'relayInfo'; //星图中继服务器信息
|
const String relayInfo = 'relayInfo'; //星图中继服务器信息
|
||||||
const String lockNetWorkInfo = 'lockNetWorkInfo'; //锁板配网信息
|
const String lockNetWorkInfo = 'lockNetWorkInfo'; //锁板配网信息
|
||||||
|
|
||||||
|
const String appVersionHistoryUrl = 'appVersionHistoryUrl'; //是否同意隐私协议弹窗
|
||||||
class Storage {
|
class Storage {
|
||||||
factory Storage() => _instance;
|
factory Storage() => _instance;
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
|
|
||||||
|
|
||||||
import '../../login/login/app_get_version.dart';
|
import '../../login/login/app_get_version.dart';
|
||||||
import '../../network/api_repository.dart';
|
import '../../network/api_repository.dart';
|
||||||
|
import '../storage.dart';
|
||||||
import 'customer_tool.dart';
|
import 'customer_tool.dart';
|
||||||
import 'pay/wx_pay_tool.dart';
|
import 'pay/wx_pay_tool.dart';
|
||||||
|
|
||||||
@ -14,11 +13,11 @@ class WechatManageTool {
|
|||||||
// AppLog.log('AppFirstEnterHandle调用了获取App信息接口');
|
// AppLog.log('AppFirstEnterHandle调用了获取App信息接口');
|
||||||
final GetAppInfo entity = await ApiRepository.to.getAppInfo();
|
final GetAppInfo entity = await ApiRepository.to.getAppInfo();
|
||||||
if (entity.errorCode == 0) {
|
if (entity.errorCode == 0) {
|
||||||
|
Storage.setString(
|
||||||
|
appVersionHistoryUrl, entity.data?.appVersionHistoryUrl ?? '');
|
||||||
CustomerTool.init(entity.data?.wechatServiceUrl ?? '');
|
CustomerTool.init(entity.data?.wechatServiceUrl ?? '');
|
||||||
WxPayTool.setAssociationUrl(entity.data!.appSiteUrl!);
|
WxPayTool.setAssociationUrl(entity.data!.appSiteUrl!);
|
||||||
action();
|
action();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
10
pubspec.lock
10
pubspec.lock
@ -401,7 +401,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "7.0.2"
|
version: "7.0.2"
|
||||||
dio:
|
dio:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: dio
|
name: dio
|
||||||
sha256: "7d328c4d898a61efc3cd93655a0955858e29a0aa647f0f9e02d59b3bb275e2e8"
|
sha256: "7d328c4d898a61efc3cd93655a0955858e29a0aa647f0f9e02d59b3bb275e2e8"
|
||||||
@ -1785,6 +1785,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.2"
|
version: "2.3.2"
|
||||||
|
video_thumbnail:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: video_thumbnail
|
||||||
|
sha256: "3455c189d3f0bb4e3fc2236475aa84fe598b9b2d0e08f43b9761f5bc44210016"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.5.3"
|
||||||
visibility_detector:
|
visibility_detector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@ -269,7 +269,8 @@ dependencies:
|
|||||||
# 图片预览
|
# 图片预览
|
||||||
photo_view: ^0.15.0
|
photo_view: ^0.15.0
|
||||||
provider: ^6.1.2
|
provider: ^6.1.2
|
||||||
|
dio: ^4.0.6 # 网络请求库
|
||||||
|
video_thumbnail: ^0.5.3
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user