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 =~ /feat_[a-zA-Z]+/
|
||||
- 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]+)?$/
|
||||
|
||||
.notify_rule:
|
||||
|
||||
@ -78,6 +78,13 @@ android {
|
||||
keyAlias = 'upload'
|
||||
keyPassword 'xhj8872'
|
||||
}
|
||||
|
||||
xhj_bundle {
|
||||
storeFile file("xhj_bundle.jks")
|
||||
storePassword 'xhj8872'
|
||||
keyAlias = 'xhj'
|
||||
keyPassword 'xhj8872'
|
||||
}
|
||||
}
|
||||
|
||||
// ----- BEGIN flavorDimensions (autogenerated by flutter_flavorizr) -----
|
||||
@ -135,6 +142,16 @@ android {
|
||||
manifestPlaceholders.JPUSH_PKGNAME = "com.xhjcn.lock"
|
||||
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 {
|
||||
dimension "flavor-type"
|
||||
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"
|
||||
bundle exec fastlane release_apk flavor:xhj --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
|
||||
elif [[ "${ENV_BUILD_BRANCH}" == "develop" ]]; then
|
||||
echo "===build dev===${NEXT_VERSION}"
|
||||
|
||||
@ -2,4 +2,5 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
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}"
|
||||
bundle exec fastlane beta flavor:xhj 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}"
|
||||
bundle exec fastlane beta flavor:xhj env:Pre --verbose
|
||||
bundle exec fastlane beta flavor:sky env:Pre --verbose
|
||||
|
||||
@ -1120,5 +1120,6 @@
|
||||
"分简称": "M",
|
||||
"跟随系统": "اتبع النظام",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "بعد إعادة الضبط ، سيتم حذف بصمات القفل. هل أنت متأكد أنك تريد إعادة ضبطه ؟",
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "بعد إعادة الضبط ، سيتم حذف جهاز التحكم عن بعد للقفل. هل تريد إعادة ضبطه ؟"
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "بعد إعادة الضبط ، سيتم حذف جهاز التحكم عن بعد للقفل. هل تريد إعادة ضبطه ؟",
|
||||
"版本说明": "تعليمات الإصدار"
|
||||
}
|
||||
@ -1120,5 +1120,6 @@
|
||||
"分简称": "M",
|
||||
"跟随系统": "Следете система",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "След нулиране, пръстовите отпечатъци на заключването ще бъдат изтрити. Сигурен ли сте, че искате да го нулирате?",
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "След нулиране, дистанционното управление на ключалката ще бъде изтрито. Искате ли да го нулирате?"
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "След нулиране, дистанционното управление на ключалката ще бъде изтрито. Искате ли да го нулирате?",
|
||||
"版本说明": "Обяснение на версията"
|
||||
}
|
||||
@ -1120,5 +1120,6 @@
|
||||
"分简称": "M",
|
||||
"跟随系统": "এক্ফক্লোসিস্টেম",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "ব্যান্ডোটারট্রাসেট, thelock'sferprinতা?",
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "ব্যান্ডোটারপ্রাসেট, নিয়ন্ত্রণের নিয়ন্ত্রণ। ডোডো ডাইভান্টটুরে?"
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "ব্যান্ডোটারপ্রাসেট, নিয়ন্ত্রণের নিয়ন্ত্রণ। ডোডো ডাইভান্টটুরে?",
|
||||
"版本说明": "ভার্সনপরিচিতি",
|
||||
}
|
||||
@ -1120,5 +1120,6 @@
|
||||
"分简称": "M",
|
||||
"跟随系统": "Sledovat systém",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "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",
|
||||
"跟随系统": "Følg systemet",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "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",
|
||||
"跟随系统": "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 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",
|
||||
"跟随系统": "Ακολουθήστε το σύστημα",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Μετά την επαναφορά, τα αποτυπώματα της κλειδαριάς θα διαγραφούν. Είστε σίγουροι ότι θέλετε να το επαναφέρετε;",
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Μετά την επαναφορά, το τηλεχειριστήριο της κλειδαριάς θα διαγραφεί. Θέλεις να το επαναφέρεις;"
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Μετά την επαναφορά, το τηλεχειριστήριο της κλειδαριάς θα διαγραφεί. Θέλεις να το επαναφέρεις;",
|
||||
"版本说明": "Περιγραφή έκδοσης",
|
||||
}
|
||||
@ -61,7 +61,7 @@
|
||||
"请输入员工账号": "Enter Employee's Account",
|
||||
"批量授权锁": "Grant multiple locks",
|
||||
"授权管理员拥有操作这把锁的重要权限,请确保只发给我你信任的人": "The authorized administrator will have majority permission to operate this lock.",
|
||||
"功能开启后,你将可以通过网关远程开锁。此功能的开启和关闭只能在锁附近通过手机蓝牙进行。":"This feature allows you to Unlock the Smart Lock Remotely via a Gateway.This Feature can ONLY be Turned ON or OFF via Bluetooth.",
|
||||
"功能开启后,你将可以通过网关远程开锁。此功能的开启和关闭只能在锁附近通过手机蓝牙进行。": "This feature allows you to Unlock the Smart Lock Remotely via a Gateway.This Feature can ONLY be Turned ON or OFF via Bluetooth.",
|
||||
"排列方式": "List Type",
|
||||
"早到榜": "Early List",
|
||||
"迟到榜": "Late List",
|
||||
@ -732,18 +732,18 @@
|
||||
"请选择有效日": "Please select the effective day",
|
||||
"公司名字长度不能小于 6 ": "The length of the company name cannot be less than 6",
|
||||
"已是最新版本": "No updates",
|
||||
"一":"One",
|
||||
"二":"Two",
|
||||
"三":"Three",
|
||||
"四":"Four",
|
||||
"五":"Five",
|
||||
"六":"Six",
|
||||
"日":"Sun",
|
||||
"新建短信模版":"Creat SMS template",
|
||||
"新建邮件模版":"Creat email template",
|
||||
"自定义短信模版":"SMS template",
|
||||
"自定义邮件模版":"Email template",
|
||||
"名称":"Name",
|
||||
"一": "One",
|
||||
"二": "Two",
|
||||
"三": "Three",
|
||||
"四": "Four",
|
||||
"五": "Five",
|
||||
"六": "Six",
|
||||
"日": "Sun",
|
||||
"新建短信模版": "Creat SMS template",
|
||||
"新建邮件模版": "Creat email template",
|
||||
"自定义短信模版": "SMS template",
|
||||
"自定义邮件模版": "Email template",
|
||||
"名称": "Name",
|
||||
"星星锁": "Star lock",
|
||||
"无考勤记录": "No Records",
|
||||
"大家干劲十足": "Everyone comes in time",
|
||||
@ -780,20 +780,20 @@
|
||||
"该已锁被删除": "The locked is deleted",
|
||||
"授权管理员只能查看和管理自己下发的钥匙、密码等权限": "The authorized admin can only manage passcodes,ekeys and etccreated by himself.",
|
||||
"添加授权管理员": "Create Admin",
|
||||
"导出记录":"Export records",
|
||||
"选择时间段":"Select time period",
|
||||
"导出":"Export",
|
||||
"批量导出":"Batch export",
|
||||
"读取记录":"Refresh Records",
|
||||
"设备":"Device",
|
||||
"消息":"Messages",
|
||||
"智能分析":"Intelligent analytics",
|
||||
"精准识别设备事件,过滤无效信息":"Accurately identify device events and filter out invalid information",
|
||||
"系统设置":"System settings",
|
||||
"系统的全局配置在此项内进行设置":"The global configuration of the system is set in this item",
|
||||
"导出操作记录":"Export records",
|
||||
"立即查看":"View",
|
||||
"导出成功":"Exported successfully",
|
||||
"导出记录": "Export records",
|
||||
"选择时间段": "Select time period",
|
||||
"导出": "Export",
|
||||
"批量导出": "Batch export",
|
||||
"读取记录": "Refresh Records",
|
||||
"设备": "Device",
|
||||
"消息": "Messages",
|
||||
"智能分析": "Intelligent analytics",
|
||||
"精准识别设备事件,过滤无效信息": "Accurately identify device events and filter out invalid information",
|
||||
"系统设置": "System settings",
|
||||
"系统的全局配置在此项内进行设置": "The global configuration of the system is set in this item",
|
||||
"导出操作记录": "Export records",
|
||||
"立即查看": "View",
|
||||
"导出成功": "Exported successfully",
|
||||
"发送钥匙": "Send ekey",
|
||||
"进度": "Rate",
|
||||
"失败": "Failed",
|
||||
@ -926,7 +926,7 @@
|
||||
"或发生异常事件时": "or an abnormal event occurs",
|
||||
"逗留达到10秒": "Stay for 10 seconds",
|
||||
"约1.5米": "About 1.5 meters",
|
||||
"随时":"Anytime",
|
||||
"随时": "Anytime",
|
||||
"立即录像": "Record immediately",
|
||||
"录像时机": "Video timing",
|
||||
"有人出现时录像": "Record when someone appears",
|
||||
@ -1094,7 +1094,7 @@
|
||||
"支持的国家": "Supported countries",
|
||||
"支持的国家值": "USA, Canada, UK, Australia, India, Germany, France, Italy, Spain, Japan",
|
||||
"操作流程": "Operation process",
|
||||
"操作流程值":"1 Add a lock and gateway with the Smart lock APP \n\n2 Enable the remote unlocking function of the lock in the APP (this function is turned off by default). If you do not have this option, the lock does not support Alexa \n\n3 Add skills to Alexa and authorize them with the Smart lock APP's account and password. After the authorization is successful, you can discover devices under the account \n\n4 Locate the lock in the Alexa app, turn on the voice unlock function, and set the language password \n\n5 The lock can be operated through Alexa",
|
||||
"操作流程值": "1 Add a lock and gateway with the Smart lock APP \n\n2 Enable the remote unlocking function of the lock in the APP (this function is turned off by default). If you do not have this option, the lock does not support Alexa \n\n3 Add skills to Alexa and authorize them with the Smart lock APP's account and password. After the authorization is successful, you can discover devices under the account \n\n4 Locate the lock in the Alexa app, turn on the voice unlock function, and set the language password \n\n5 The lock can be operated through Alexa",
|
||||
"Google Home": "Google Home",
|
||||
"Action name": "Action name",
|
||||
"ScienerSmart": "ScienerSmart",
|
||||
@ -1121,5 +1121,12 @@
|
||||
"分简称": "M",
|
||||
"跟随系统": "Follow system",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "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",
|
||||
"跟随系统": "Seguir sistema",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "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",
|
||||
"跟随系统": "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 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",
|
||||
"跟随系统": "Seuraa järjestelmää",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "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",
|
||||
"跟随系统": "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, 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",
|
||||
"跟随系统": "מערכת מעקב",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "לאחר איפוס, טביעות האצבעות של המנעול יימחקו. אתה בטוח שברצונך לאפס את זה?",
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "לאחר איפוס, השליטה מרחוק של המנעול יימחק. אתה רוצה לאפס את זה?"
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "לאחר איפוס, השליטה מרחוק של המנעול יימחק. אתה רוצה לאפס את זה?",
|
||||
"版本说明": "המידע על גרסה",
|
||||
}
|
||||
@ -1120,5 +1120,6 @@
|
||||
"分简称": "M",
|
||||
"跟随系统": "跟隨系統",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "重置之後,鎖嘅指紋將被刪除。 你確定要重置它啊?",
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "重置之後,鎖嘅遙控器將被刪除。 是否要重置它?"
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "重置之後,鎖嘅遙控器將被刪除。 是否要重置它?",
|
||||
"版本说明": "版本說明"
|
||||
}
|
||||
@ -1120,5 +1120,6 @@
|
||||
"分简称": "M",
|
||||
"跟随系统": "Prati sistem:",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "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",
|
||||
"跟随系统": "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 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",
|
||||
"跟随系统": "Sistem mengikuti",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "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",
|
||||
"跟随系统": "Seguire il sistema",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "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",
|
||||
"跟随系统": "システムに従う",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "リセット後、ロックの指紋は削除されます。リセットしてもよろしいですか。",
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "リセット後、ロックのリモコンが削除されます。リセットしますか?"
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "リセット後、ロックのリモコンが削除されます。リセットしますか?",
|
||||
"版本说明": "バージョン説明",
|
||||
}
|
||||
@ -1121,5 +1121,12 @@
|
||||
"分简称": "分简称",
|
||||
"跟随系统": "跟随系统",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "重置后,该锁的指纹都将被删除哦,确认要重置吗?",
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "重置后,该锁的遥控都将被删除哦,确认要重置吗?"
|
||||
"通话未接通,已挂断": "通话未接通,已挂断",
|
||||
"通话异常中断": "通话异常中断",
|
||||
"通话连接失败": "通话连接失败",
|
||||
"已挂断": "已挂断",
|
||||
"正在说话...": "正在说话...",
|
||||
"下载完成,请到相册查看": "下载完成,请到相册查看",
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "重置后,该锁的遥控都将被删除哦,确认要重置吗?",
|
||||
"版本说明": "版本说明"
|
||||
}
|
||||
|
||||
@ -1120,5 +1120,6 @@
|
||||
"分简称": "M",
|
||||
"跟随系统": "Жүйені қолдану",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Қайта ысырып тастау Шынымен ысырып тастауды қалайсыз ба?",
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Қайта ысырып ысырып тасымалдауын өшіріледі. Оны ысырып тастауды қалайсыз ба?"
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Қайта ысырып ысырып тасымалдауын өшіріледі. Оны ысырып тастауды қалайсыз ба?",
|
||||
"版本说明": "Версиятын көрсету",
|
||||
}
|
||||
@ -1120,5 +1120,6 @@
|
||||
"分简称": "M",
|
||||
"跟随系统": "시스템을 따르십시오",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "재설정 후 잠금 장치의 지문이 삭제됩니다. 당신은 그것을 재설정 하시겠습니까?",
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "재설정 후 잠금 장치의 리모컨이 삭제됩니다. 당신은 그것을 재설정 하시겠습니까?"
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "재설정 후 잠금 장치의 리모컨이 삭제됩니다. 당신은 그것을 재설정 하시겠습니까?",
|
||||
"版本说明": "버전 설명",
|
||||
}
|
||||
@ -1120,5 +1120,6 @@
|
||||
"分简称": "M",
|
||||
"跟随系统": "Sekti sistema",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "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",
|
||||
"跟随系统": "Ikut system",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "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",
|
||||
"跟随系统": "Systeem volgen",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "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",
|
||||
"跟随系统": "Śledź system",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "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",
|
||||
"跟随系统": "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 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",
|
||||
"跟随系统": "Urmează sistemul:",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "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",
|
||||
"跟随系统": "Следуйте системе",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "После сброса отпечатки пальцев замка будут удалены. Вы уверены, что хотите его перезагрузить?",
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "После сброса пульт дистанционного управления замком будет удален. А вы хотите его сбросить?"
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "После сброса пульт дистанционного управления замком будет удален. А вы хотите его сбросить?",
|
||||
"版本说明": "Объяснение версии",
|
||||
}
|
||||
@ -1120,5 +1120,6 @@
|
||||
"分简称": "M",
|
||||
"跟随系统": "Sledovať systém",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "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",
|
||||
"跟随系统": "Пратите систем",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Након ресетовања, отисци прстију браве ће бити избрисани. Да ли сте сигурни да желите да га ресетујете?",
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Након ресетовања, даљински управљач браве ће бити избрисан. Да ли желите да га ресетујете?"
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Након ресетовања, даљински управљач браве ће бити избрисан. Да ли желите да га ресетујете?",
|
||||
"版本说明": "Опис верзије"
|
||||
}
|
||||
@ -1120,5 +1120,6 @@
|
||||
"分简称": "M",
|
||||
"跟随系统": "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, 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",
|
||||
"跟随系统": "ระบบติดตามผล",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "หลังจากรีเซ็ตแล้วลายนิ้วมือของล็อคจะถูกลบออกคุณแน่ใจว่าอยากจะรีเซ็ต?",
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "หลังจากรีเซ็ตแล้วรีโมทคอนโทรลของล็อคจะถูกลบออกคุณต้องการรีเซ็ตไหม"
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "หลังจากรีเซ็ตแล้วรีโมทคอนโทรลของล็อคจะถูกลบออกคุณต้องการรีเซ็ตไหม",
|
||||
"版本说明": "คำอธิบายรุ่น"
|
||||
}
|
||||
@ -1120,5 +1120,6 @@
|
||||
"分简称": "M",
|
||||
"跟随系统": "Sistemi takip et",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "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",
|
||||
"跟随系统": "跟蹤系統",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "重置後,鎖的指紋將被刪除。 是否確實要重置它?",
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "重置後,鎖的遙控器將被刪除。 是否要重置它?"
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "重置後,鎖的遙控器將被刪除。 是否要重置它?",
|
||||
"版本说明": "版本說明",
|
||||
}
|
||||
@ -1120,5 +1120,6 @@
|
||||
"分简称": "M",
|
||||
"跟随系统": "Система стеження за",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Після скидання відбитки пальців замка будуть видалені. Ви впевнені, що хочете скинути налаштування?",
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Після скидання пульт дистанційного керування замком буде видалено. Хочете його скинути?"
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Після скидання пульт дистанційного керування замком буде видалено. Хочете його скинути?",
|
||||
"版本说明": "Опис версії",
|
||||
}
|
||||
@ -1120,5 +1120,6 @@
|
||||
"分简称": "M",
|
||||
"跟随系统": "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, đ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) {
|
||||
case Flavor.local:
|
||||
return const UmengKey(
|
||||
androidKey: '671244cf80464b33f6df9648',
|
||||
iosKey: '671244ae80464b33f6df9646',
|
||||
androidKey: 'local-671244cf80464b33f6df9648',
|
||||
iosKey: 'local-671244ae80464b33f6df9646',
|
||||
channel: 'Product');
|
||||
case Flavor.dev:
|
||||
return const UmengKey(
|
||||
androidKey: '671244cf80464b33f6df9648',
|
||||
iosKey: '671244ae80464b33f6df9646',
|
||||
androidKey: 'dev-671244cf80464b33f6df9648',
|
||||
iosKey: 'dev-671244ae80464b33f6df9646',
|
||||
channel: 'Product');
|
||||
case Flavor.pre:
|
||||
return const UmengKey(
|
||||
androidKey: '671244cf80464b33f6df9648',
|
||||
iosKey: '671244ae80464b33f6df9646',
|
||||
androidKey: 'pre-671244cf80464b33f6df9648',
|
||||
iosKey: 'pre-671244ae80464b33f6df9646',
|
||||
channel: 'Product');
|
||||
case Flavor.sky_dev:
|
||||
return const UmengKey(
|
||||
androidKey: '671244cf80464b33f6df9648',
|
||||
iosKey: '671244ae80464b33f6df9646',
|
||||
androidKey: 'sky_dev-671244cf80464b33f6df9648',
|
||||
iosKey: 'sky_dev-671244ae80464b33f6df9646',
|
||||
channel: 'Product');
|
||||
case Flavor.sky_pre:
|
||||
return const UmengKey(
|
||||
androidKey: '671244cf80464b33f6df9648',
|
||||
iosKey: '671244ae80464b33f6df9646',
|
||||
androidKey: 'sky_pre-671244cf80464b33f6df9648',
|
||||
iosKey: 'sky_pre-671244ae80464b33f6df9646',
|
||||
channel: 'Product');
|
||||
case Flavor.sky:
|
||||
return const UmengKey(
|
||||
@ -229,13 +229,13 @@ class F {
|
||||
channel: 'Product');
|
||||
case Flavor.xhj_dev:
|
||||
return const UmengKey(
|
||||
androidKey: '671244cf80464b33f6df9648',
|
||||
iosKey: '671244ae80464b33f6df9646',
|
||||
androidKey: 'xhj_dev-671244cf80464b33f6df9648',
|
||||
iosKey: 'xhj_dev-671244ae80464b33f6df9646',
|
||||
channel: 'Product');
|
||||
case Flavor.xhj_pre:
|
||||
return const UmengKey(
|
||||
androidKey: '671244cf80464b33f6df9648',
|
||||
iosKey: '671244ae80464b33f6df9646',
|
||||
androidKey: 'xhj_pre-671244cf80464b33f6df9648',
|
||||
iosKey: 'xhj_pre-671244ae80464b33f6df9646',
|
||||
channel: 'Product');
|
||||
case Flavor.xhj:
|
||||
return const UmengKey(
|
||||
@ -244,8 +244,8 @@ class F {
|
||||
channel: 'Product');
|
||||
default:
|
||||
return const UmengKey(
|
||||
androidKey: '671244cf80464b33f6df9648',
|
||||
iosKey: '671244ae80464b33f6df9646',
|
||||
androidKey: 'default-671244cf80464b33f6df9648',
|
||||
iosKey: 'default-671244ae80464b33f6df9646',
|
||||
channel: 'Product');
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,10 +29,12 @@ class Data {
|
||||
Data.fromJson(Map<String, dynamic> json) {
|
||||
wechatServiceUrl = json['wechat_service_url'];
|
||||
appSiteUrl = json['app_site_url'];
|
||||
appVersionHistoryUrl = json['appVersionHistoryUrl'];
|
||||
}
|
||||
|
||||
String? wechatServiceUrl;
|
||||
String? appSiteUrl;
|
||||
String? appVersionHistoryUrl;
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
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/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.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/advancedCalendar/src/widget.dart';
|
||||
import 'package:star_lock/tools/commonDataManage.dart';
|
||||
@ -399,13 +399,27 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
|
||||
}
|
||||
|
||||
_buildVideoItem(RecordListData recordData) {
|
||||
return VideoThumbnail(videoUrl: recordData.videoUrl!);
|
||||
return VideoThumbnailImage(videoUrl: recordData.videoUrl!);
|
||||
}
|
||||
|
||||
_buildImageItem(RecordListData recordData) {
|
||||
return Image.network(
|
||||
recordData.imagesUrl!,
|
||||
fit: BoxFit.cover,
|
||||
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,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:network_info_plus/network_info_plus.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
@ -151,11 +152,6 @@ class ConfiguringWifiLogic extends BaseGetXController {
|
||||
}
|
||||
state.sureBtnState.value = 1;
|
||||
|
||||
showBlueConnetctToastTimer(action: () {
|
||||
dismissEasyLoading();
|
||||
state.sureBtnState.value = 0;
|
||||
});
|
||||
|
||||
final GetGatewayConfigurationEntity entity =
|
||||
await ApiRepository.to.getGatewayConfiguration(timeout: 60);
|
||||
if (entity.errorCode!.codeIsSuccessful) {
|
||||
@ -191,6 +187,7 @@ class ConfiguringWifiLogic extends BaseGetXController {
|
||||
// 如果为空,则直接赋值
|
||||
state.getGatewayConfigurationStr = "{\"userPeerld\": \"$appPeerId\"}";
|
||||
}
|
||||
|
||||
BlueManage().blueSendData(BlueManage().connectDeviceName,
|
||||
(BluetoothConnectionState connectionState) async {
|
||||
if (connectionState == BluetoothConnectionState.connected) {
|
||||
@ -199,11 +196,7 @@ class ConfiguringWifiLogic extends BaseGetXController {
|
||||
password: state.wifiPWDController.text,
|
||||
gatewayConfigurationStr: state.getGatewayConfigurationStr,
|
||||
);
|
||||
} else if (connectionState == BluetoothConnectionState.disconnected) {
|
||||
state.sureBtnState.value = 0;
|
||||
if (state.ifCurrentScreen.value == true) {
|
||||
showBlueConnetctToast();
|
||||
}
|
||||
EasyLoading.show();
|
||||
}
|
||||
}, isAddEquipment: true);
|
||||
}
|
||||
|
||||
@ -1,4 +1,10 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:dio/dio.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/network/api_repository.dart';
|
||||
import 'package:star_lock/tools/baseGetXController.dart';
|
||||
@ -9,18 +15,20 @@ class EditVideoLogLogic extends BaseGetXController {
|
||||
EditVideoLogState state = EditVideoLogState();
|
||||
|
||||
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(),
|
||||
);
|
||||
if (entity.errorCode!.codeIsSuccessful) {
|
||||
state.selectVideoLogList.value.clear();
|
||||
showToast('删除成功'.tr);
|
||||
getLockCloudStorageList();
|
||||
await getLockCloudStorageList();
|
||||
state.selectVideoLogList.clear();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getLockCloudStorageList() async {
|
||||
final VideoLogEntity entity = await ApiRepository.to.getLockCloudStorageList(
|
||||
final VideoLogEntity entity =
|
||||
await ApiRepository.to.getLockCloudStorageList(
|
||||
lockId: state.getLockId.value,
|
||||
);
|
||||
if (entity.errorCode!.codeIsSuccessful) {
|
||||
@ -28,4 +36,59 @@ class EditVideoLogLogic extends BaseGetXController {
|
||||
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_easyloading/flutter_easyloading.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.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/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 '../../../../app_settings/app_colors.dart';
|
||||
@ -97,6 +99,7 @@ class _EditVideoLogPageState extends State<EditVideoLogPage> {
|
||||
|
||||
double itemW = (1.sw - 15.w * 4) / 3;
|
||||
double itemH = (1.sw - 15.w * 4) / 3 + 40.h;
|
||||
|
||||
Widget mainListView(int index, CloudStorageData itemData) {
|
||||
return GridView.builder(
|
||||
padding: EdgeInsets.only(left: 15.w, right: 15.w),
|
||||
@ -114,116 +117,269 @@ class _EditVideoLogPageState extends State<EditVideoLogPage> {
|
||||
childAspectRatio: itemW / itemH),
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final RecordListData recordData = itemData.recordList![index];
|
||||
return videoItem(recordData, index);
|
||||
return videoItem(recordData);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget videoItem(RecordListData recordData, int index) {
|
||||
return Container(
|
||||
width: itemW,
|
||||
height: itemH,
|
||||
color: Colors.white,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
recordData.isSelect = !recordData.isSelect!;
|
||||
if (recordData.isSelect! == true) {
|
||||
state.selectVideoLogList.add(recordData);
|
||||
} else {
|
||||
state.selectVideoLogList.remove(recordData);
|
||||
}
|
||||
setState(() {});
|
||||
},
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
Column(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
width: itemW,
|
||||
height: itemW,
|
||||
margin: const EdgeInsets.all(0),
|
||||
color: Colors.white,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(10.w),
|
||||
child: Image(
|
||||
fit: BoxFit.cover,
|
||||
image: Image.network(recordData.imagesUrl ??
|
||||
'images/icon_video_placeholder.jpg')
|
||||
.image),
|
||||
),
|
||||
),
|
||||
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: 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')))
|
||||
],
|
||||
)),
|
||||
);
|
||||
}
|
||||
// Widget videoItem(RecordListData recordData, int index) {
|
||||
// return Container(
|
||||
// width: itemW,
|
||||
// height: itemH,
|
||||
// color: Colors.white,
|
||||
// child: GestureDetector(
|
||||
// onTap: () {
|
||||
// recordData.isSelect = !recordData.isSelect!;
|
||||
// if (recordData.isSelect! == true) {
|
||||
// state.selectVideoLogList.add(recordData);
|
||||
// } else {
|
||||
// state.selectVideoLogList.remove(recordData);
|
||||
// }
|
||||
// setState(() {});
|
||||
// },
|
||||
// child: Stack(
|
||||
// children: <Widget>[
|
||||
// Column(
|
||||
// children: <Widget>[
|
||||
// Container(
|
||||
// width: itemW,
|
||||
// height: itemW,
|
||||
// margin: const EdgeInsets.all(0),
|
||||
// color: Colors.white,
|
||||
// child: ClipRRect(
|
||||
// borderRadius: BorderRadius.circular(10.w),
|
||||
// child: Image(
|
||||
// fit: BoxFit.cover,
|
||||
// image: Image.network(recordData.imagesUrl ??
|
||||
// 'images/icon_video_placeholder.jpg')
|
||||
// .image),
|
||||
// ),
|
||||
// ),
|
||||
// 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: 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')))
|
||||
// ],
|
||||
// )),
|
||||
// );
|
||||
// }
|
||||
|
||||
Widget bottomBottomBtnWidget() {
|
||||
return SizedBox(
|
||||
width: 1.sw,
|
||||
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
|
||||
child:
|
||||
Row(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
|
||||
bottomBtnItemWidget(
|
||||
'images/main/icon_lockDetail_monitoringDownloadVideo.png',
|
||||
'下载'.tr,
|
||||
Colors.white, () {
|
||||
if (state.selectVideoLogList.value.isNotEmpty) {
|
||||
Get.toNamed(Routers.videoLogDownLoadPage, arguments: <String, List<RecordListData>>{
|
||||
'downloadVideoLogList': state.selectVideoLogList.value
|
||||
});
|
||||
} else {
|
||||
logic.showToast('请选择要下载的视频');
|
||||
}
|
||||
}),
|
||||
'images/main/icon_lockDetail_monitoringDownloadVideo.png',
|
||||
'下载'.tr,
|
||||
Colors.white,
|
||||
_onDownLoadClick,
|
||||
),
|
||||
SizedBox(width: 100.w),
|
||||
bottomBtnItemWidget(
|
||||
'images/main/icon_lockDetail_monitoringDeletVideo.png',
|
||||
'删除'.tr,
|
||||
AppColors.mainColor, () {
|
||||
if (state.selectVideoLogList.value.isNotEmpty) {
|
||||
logic.deleteLockCloudStorageList();
|
||||
} else {
|
||||
logic.showToast('请选择要删除的视频'.tr);
|
||||
}
|
||||
})
|
||||
'images/main/icon_lockDetail_monitoringDeletVideo.png',
|
||||
'删除'.tr,
|
||||
AppColors.mainColor,
|
||||
_onDelClick,
|
||||
)
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
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(
|
||||
String iconUrl, String name, Color backgroundColor, Function() onClick) {
|
||||
String iconUrl,
|
||||
String name,
|
||||
Color backgroundColor,
|
||||
Future<void> Function() onClick,
|
||||
) {
|
||||
final double wh = 40.w;
|
||||
return GestureDetector(
|
||||
onTap: onClick,
|
||||
child: SizedBox(
|
||||
height: 140.h,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
SizedBox(height: 30.w),
|
||||
Image.asset(iconUrl, width: wh, height: wh, fit: BoxFit.fitWidth),
|
||||
SizedBox(height: 10.w),
|
||||
Expanded(
|
||||
child: Text(name,
|
||||
style: TextStyle(fontSize: 22.sp),
|
||||
textAlign: TextAlign.center))
|
||||
],
|
||||
)),
|
||||
height: 140.h,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
SizedBox(height: 30.w),
|
||||
Image.asset(iconUrl, width: wh, height: wh, fit: BoxFit.fitWidth),
|
||||
SizedBox(height: 10.w),
|
||||
Expanded(
|
||||
child: Text(name,
|
||||
style: TextStyle(fontSize: 22.sp),
|
||||
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 {
|
||||
int? errorCode;
|
||||
String? description;
|
||||
@ -61,21 +64,28 @@ class RecordListData {
|
||||
int? operateDate;
|
||||
String? imagesUrl;
|
||||
String? videoUrl;
|
||||
Uint8List? thumbnailData; // 将视频封面改为 Uint8List 类型
|
||||
int? recordType;
|
||||
bool? isSelect = false;
|
||||
|
||||
RecordListData(
|
||||
{this.recordId,
|
||||
this.operateDate,
|
||||
this.imagesUrl,
|
||||
this.videoUrl,
|
||||
this.recordType});
|
||||
RecordListData({
|
||||
this.recordId,
|
||||
this.operateDate,
|
||||
this.imagesUrl,
|
||||
this.videoUrl,
|
||||
this.thumbnailData, // 视频封面数据
|
||||
this.recordType,
|
||||
});
|
||||
|
||||
RecordListData.fromJson(Map<String, dynamic> json) {
|
||||
recordId = json['recordId'];
|
||||
operateDate = json['operateDate'];
|
||||
imagesUrl = json['imagesUrl'];
|
||||
videoUrl = json['videoUrl'];
|
||||
// 如果 JSON 中包含 base64 编码的图片数据,可以解码为 Uint8List
|
||||
if (json['thumbnailData'] != null) {
|
||||
thumbnailData = base64Decode(json['thumbnailData']);
|
||||
}
|
||||
recordType = json['recordType'];
|
||||
}
|
||||
|
||||
@ -85,6 +95,10 @@ class RecordListData {
|
||||
data['operateDate'] = operateDate;
|
||||
data['imagesUrl'] = imagesUrl;
|
||||
data['videoUrl'] = videoUrl;
|
||||
// 将 Uint8List 编码为 base64 字符串
|
||||
if (thumbnailData != null) {
|
||||
data['thumbnailData'] = base64Encode(thumbnailData!);
|
||||
}
|
||||
data['recordType'] = recordType;
|
||||
return data;
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
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/tools/baseGetXController.dart';
|
||||
|
||||
@ -14,6 +15,15 @@ class VideoLogLogic extends BaseGetXController {
|
||||
);
|
||||
if (entity.errorCode!.codeIsSuccessful) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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_state.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/noData.dart';
|
||||
import 'package:video_player/video_player.dart';
|
||||
@ -228,15 +228,18 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
||||
child: Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(state.isNavLocal.value == true ? '已下载'.tr : '全部视频'.tr,
|
||||
style: TextStyle(fontSize: 26.sp, fontWeight: FontWeight.w500)),
|
||||
Text(
|
||||
state.isNavLocal.value == true ? '已下载'.tr : '全部视频'.tr,
|
||||
style: TextStyle(fontSize: 26.sp, fontWeight: FontWeight.w500),
|
||||
),
|
||||
Expanded(child: SizedBox(width: 10.w)),
|
||||
IconButton(
|
||||
icon: Image(
|
||||
width: 40.w,
|
||||
height: 40.w,
|
||||
image: const AssetImage(
|
||||
'images/main/icon_lockDetail_monitoringEditVoice.png')),
|
||||
width: 40.w,
|
||||
height: 40.w,
|
||||
image: const AssetImage(
|
||||
'images/main/icon_lockDetail_monitoringEditVoice.png'),
|
||||
),
|
||||
iconSize: 30,
|
||||
color: Colors.black54,
|
||||
onPressed: () {
|
||||
@ -338,13 +341,27 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
||||
}
|
||||
|
||||
_buildVideoItem(RecordListData recordData) {
|
||||
return VideoThumbnail(videoUrl: recordData.videoUrl!);
|
||||
return VideoThumbnailImage(videoUrl: recordData.videoUrl!);
|
||||
}
|
||||
|
||||
_buildImageItem(RecordListData recordData) {
|
||||
return Image.network(
|
||||
recordData.imagesUrl!,
|
||||
fit: BoxFit.cover,
|
||||
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,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,9 +148,10 @@ class _ControlsOverlayState extends State<ControlsOverlay> {
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
DateTool().dateToYMDHNString(
|
||||
widget.recordData.operateDate.toString()),
|
||||
style: TextStyle(color: Colors.white, fontSize: 20.sp)),
|
||||
DateTool().dateToYMDHNString(
|
||||
widget.recordData.operateDate.toString()),
|
||||
style: TextStyle(color: Colors.white, fontSize: 20.sp),
|
||||
),
|
||||
// Expanded(child: SizedBox(width: 10.w)),
|
||||
// Container(
|
||||
// width: 50.w,
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.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/videoLogDetail_state.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:video_player/video_player.dart';
|
||||
|
||||
@ -72,37 +73,35 @@ class _VideoLogDetailPageState extends State<VideoLogDetailPage> {
|
||||
? Column(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
color: Colors.black,
|
||||
height: 500.h,
|
||||
decoration: BoxDecoration(color: Colors.black),
|
||||
child: AspectRatio(
|
||||
aspectRatio: 16 / 9,
|
||||
child: Stack(
|
||||
alignment: Alignment.bottomCenter,
|
||||
children: <Widget>[
|
||||
FittedBox(
|
||||
child: SizedBox(
|
||||
width: state.videoController.value.size.width,
|
||||
height: state.videoController.value.size.height,
|
||||
child: VideoPlayer(state.videoController),
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
width: 1.sw,
|
||||
child: Stack(
|
||||
alignment: Alignment.bottomCenter,
|
||||
children: <Widget>[
|
||||
RotatedBox(
|
||||
quarterTurns: -1,
|
||||
child: AspectRatio(
|
||||
aspectRatio: state.videoController.value.size.width /
|
||||
state.videoController.value.size.height,
|
||||
child: VideoPlayer(state.videoController),
|
||||
),
|
||||
ControlsOverlay(
|
||||
controller: state.videoController,
|
||||
recordData: state.recordData.value,
|
||||
),
|
||||
ControlsOverlay(
|
||||
controller: state.videoController,
|
||||
recordData: state.recordData.value,
|
||||
),
|
||||
if (state.videoController.value.isPlaying ||
|
||||
state.videoController.value.isBuffering)
|
||||
Container()
|
||||
else
|
||||
VideoProgressIndicator(
|
||||
state.videoController,
|
||||
colors: VideoProgressColors(
|
||||
playedColor: AppColors.mainColor),
|
||||
allowScrubbing: true,
|
||||
),
|
||||
if (state.videoController.value.isPlaying ||
|
||||
state.videoController.value.isBuffering)
|
||||
Container()
|
||||
else
|
||||
VideoProgressIndicator(
|
||||
state.videoController,
|
||||
colors: VideoProgressColors(
|
||||
playedColor: AppColors.mainColor),
|
||||
allowScrubbing: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
_buildOther(),
|
||||
@ -166,13 +165,27 @@ class _VideoLogDetailPageState extends State<VideoLogDetailPage> {
|
||||
}
|
||||
|
||||
_buildVideoItem(RecordListData recordData) {
|
||||
return VideoThumbnail(videoUrl: recordData.videoUrl!);
|
||||
return VideoThumbnailImage(videoUrl: recordData.videoUrl!);
|
||||
}
|
||||
|
||||
_buildImageItem(RecordListData recordData) {
|
||||
return Image.network(
|
||||
recordData.imagesUrl!,
|
||||
fit: BoxFit.cover,
|
||||
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,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -10,9 +10,17 @@ class FullScreenImagePage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Container(
|
||||
child: PhotoView(
|
||||
imageProvider: NetworkImage(imageUrl),
|
||||
body: GestureDetector(
|
||||
onTap: (){
|
||||
Navigator.pop(context); // 点击图片返回
|
||||
},
|
||||
child: Container(
|
||||
child: RotatedBox(
|
||||
quarterTurns: -1,
|
||||
child: PhotoView(
|
||||
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_screenutil/flutter_screenutil.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 '../../flavors.dart';
|
||||
import '../../tools/commonItem.dart';
|
||||
import '../../tools/storage.dart';
|
||||
import '../../tools/titleAppBar.dart';
|
||||
import '../../tools/wechat/wechatManageTool.dart';
|
||||
|
||||
class AboutPage extends StatefulWidget {
|
||||
const AboutPage({Key? key}) : super(key: key);
|
||||
@ -80,6 +85,44 @@ class _AboutPageState extends State<AboutPage> {
|
||||
Widget listView() {
|
||||
Widget view = Column(
|
||||
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(
|
||||
leftTitel: '介绍'.tr,
|
||||
rightTitle: '',
|
||||
|
||||
@ -11,7 +11,7 @@ class StartChartApi extends BaseProvider {
|
||||
// 星图url
|
||||
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({
|
||||
@ -68,6 +68,4 @@ class StartChartApi extends BaseProvider {
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -149,122 +149,200 @@ class ScpMessage {
|
||||
|
||||
static ScpMessage deserialize(Uint8List bytes) {
|
||||
final message = ScpMessage();
|
||||
final length = bytes.length;
|
||||
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)}');
|
||||
// 提前检查字节数组长度是否足够
|
||||
if (length < 4 + 1 + 2 + 1 + 1 + 44 + 44 + 2 + 2 + 4) {
|
||||
throw FormatException("Invalid message length");
|
||||
}
|
||||
|
||||
// 使用 ByteData 读取多字节数据
|
||||
final byteData = ByteData.sublistView(bytes);
|
||||
|
||||
// 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");
|
||||
}
|
||||
message.ProtocolFlag = utf8.decode(bytes.sublist(offset, offset + 4));
|
||||
offset += 4;
|
||||
|
||||
// MessageType (1 byte)
|
||||
if (bytes.length - offset >= 1) {
|
||||
message.MessageType = bytes[offset];
|
||||
offset += 1;
|
||||
} else {
|
||||
throw FormatException("Invalid MessageType length");
|
||||
}
|
||||
message.MessageType = bytes[offset];
|
||||
offset += 1;
|
||||
|
||||
// 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");
|
||||
}
|
||||
message.MessageId = byteData.getUint16(offset, Endian.little);
|
||||
offset += 2;
|
||||
|
||||
// SpTotal (1 byte)
|
||||
if (bytes.length - offset >= 1) {
|
||||
message.SpTotal = bytes[offset];
|
||||
offset += 1;
|
||||
} else {
|
||||
throw FormatException("Invalid SpTotal length");
|
||||
}
|
||||
message.SpTotal = bytes[offset];
|
||||
offset += 1;
|
||||
|
||||
// SpIndex (1 byte)
|
||||
if (bytes.length - offset >= 1) {
|
||||
message.SpIndex = bytes[offset];
|
||||
offset += 1;
|
||||
} else {
|
||||
throw FormatException("Invalid SpIndex length");
|
||||
}
|
||||
message.SpIndex = bytes[offset];
|
||||
offset += 1;
|
||||
|
||||
// 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");
|
||||
}
|
||||
// FromPeerId (44 bytes)
|
||||
message.FromPeerId =
|
||||
utf8.decode(bytes.sublist(offset, offset + 44)).trimRight();
|
||||
offset += 44;
|
||||
|
||||
// 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");
|
||||
}
|
||||
// ToPeerId (44 bytes)
|
||||
message.ToPeerId =
|
||||
utf8.decode(bytes.sublist(offset, offset + 44)).trimRight();
|
||||
offset += 44;
|
||||
|
||||
// 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");
|
||||
}
|
||||
message.PayloadType = byteData.getUint16(offset, Endian.little);
|
||||
offset += 2;
|
||||
|
||||
// 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");
|
||||
}
|
||||
message.PayloadCRC = byteData.getUint16(offset, Endian.little);
|
||||
offset += 2;
|
||||
|
||||
// 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");
|
||||
}
|
||||
message.PayloadLength = byteData.getUint32(offset, Endian.little);
|
||||
offset += 4;
|
||||
|
||||
// 处理其他类型的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 {
|
||||
// 检查 Payload 长度是否有效
|
||||
if (message.PayloadLength == null ||
|
||||
length - offset < message.PayloadLength!) {
|
||||
throw FormatException("Invalid Payload or PayloadLength");
|
||||
}
|
||||
|
||||
// 处理 Payload
|
||||
final payloadBytes = bytes.sublist(offset, offset + message.PayloadLength!);
|
||||
offset += message.PayloadLength!;
|
||||
message.Payload = _handlePayLoad(
|
||||
payloadType: message.PayloadType ?? 0,
|
||||
messageType: message.MessageType ?? 0,
|
||||
byte: payloadBytes,
|
||||
offset: offset,
|
||||
PayloadLength: message.PayloadLength,
|
||||
spIndex: message.SpIndex,
|
||||
spTotal: message.SpTotal,
|
||||
messageId: message.MessageId,
|
||||
);
|
||||
|
||||
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结构体
|
||||
static dynamic _handlePayLoad({
|
||||
required int payloadType,
|
||||
|
||||
@ -29,7 +29,6 @@ class UdpTalkAcceptHandler extends ScpMessageBaseHandle
|
||||
// 收到同意接听回复
|
||||
final GenericResp genericResp = scpMessage.Payload;
|
||||
if (checkGenericRespSuccess(genericResp)) {
|
||||
print('收到同意接听的回复');
|
||||
// 停止同意接听的重发
|
||||
startChartManage.stopTalkAcceptTimer();
|
||||
// 接听之后增加期望音频的接收
|
||||
|
||||
@ -156,7 +156,7 @@ class UdpTalkDataHandler extends ScpMessageBaseHandle
|
||||
void _handleVideoH264(TalkData talkData) {
|
||||
final TalkDataH264Frame talkDataH264Frame = TalkDataH264Frame();
|
||||
talkDataH264Frame.mergeFromBuffer(talkData.content);
|
||||
AppLog.log('H264 TalkData :$talkDataH264Frame');
|
||||
// AppLog.log('H264 TalkData :$talkDataH264Frame');
|
||||
talkDataRepository.addTalkData(talkData);
|
||||
}
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@ class UdpTalkHangUpHandler extends ScpMessageBaseHandle
|
||||
// // 如果不是接听中,不处理通话中挂断请求
|
||||
// return;
|
||||
// }
|
||||
print('收到通话中挂断请求');
|
||||
|
||||
// 回复请求
|
||||
replySuccessMessage(scpMessage);
|
||||
talkStatus.setHangingUpDuring();
|
||||
@ -34,7 +34,7 @@ class UdpTalkHangUpHandler extends ScpMessageBaseHandle
|
||||
talkePingOverTimeTimerManager.cancel();
|
||||
talkDataOverTimeTimerManager.cancel();
|
||||
|
||||
EasyLoading.showToast('已挂断');
|
||||
EasyLoading.showToast('已挂断'.tr);
|
||||
Get.back();
|
||||
}
|
||||
|
||||
|
||||
@ -28,7 +28,7 @@ class TalkDataOverTimeTimerManager {
|
||||
|
||||
// 超时处理函数
|
||||
static void _handleTalkeDataOverTime() {
|
||||
EasyLoading.showToast('通话连接失败', duration: 2000.milliseconds);
|
||||
EasyLoading.showToast('通话连接失败'.tr, duration: 2000.milliseconds);
|
||||
// 没有通话数据,发送挂断数据
|
||||
StartChartManage().sendTalkHangupMessage();
|
||||
StartChartManage().stopTalkPingMessageTimer();
|
||||
|
||||
@ -28,7 +28,7 @@ class TalkePingOverTimeTimerManager {
|
||||
// 超时处理函数
|
||||
static void _handleTalkePingOverTime() {
|
||||
if (talkStatus.status == TalkStatus.answeredSuccessfully) {
|
||||
EasyLoading.showToast('通话异常中断', duration: 2000.milliseconds);
|
||||
EasyLoading.showToast('通话异常中断'.tr, duration: 2000.milliseconds);
|
||||
// 停止发送通话保持的命令
|
||||
StartChartManage().stopTalkPingMessageTimer();
|
||||
StartChartManage().stopTalkExpectMessageTimer();
|
||||
|
||||
@ -29,7 +29,7 @@ class TalkeRequestOverTimeTimerManager {
|
||||
static void _handleTalkeRequestOverTime() {
|
||||
if (talkStatus.status == TalkStatus.passiveCallWaitingAnswer ||
|
||||
talkStatus.status == TalkStatus.proactivelyCallWaitingAnswer) {
|
||||
EasyLoading.showToast('通话未接通,以挂断', duration: 2000.milliseconds);
|
||||
EasyLoading.showToast('通话未接通,已挂断'.tr, duration: 2000.milliseconds);
|
||||
// 超时未接听,发送挂断请求
|
||||
StartChartManage().sendTalkRejectMessage();
|
||||
talkStatus.setInitializationCompleted();
|
||||
|
||||
@ -50,7 +50,6 @@ class TalkViewLogic extends BaseGetXController {
|
||||
int audioFrameIntervalMs = 20; // 初始帧间隔设置为45毫秒(约22FPS)
|
||||
int minFrameIntervalMs = 30; // 最小帧间隔(约33 FPS)
|
||||
int maxFrameIntervalMs = 100; // 最大帧间隔(约1 FPS)
|
||||
// int maxFrameIntervalMs = 100; // 最大帧间隔(约10 FPS)
|
||||
|
||||
/// 初始化音频播放器
|
||||
void _initFlutterPcmSound() {
|
||||
@ -118,6 +117,17 @@ class TalkViewLogic extends BaseGetXController {
|
||||
case TalkStatus.end:
|
||||
_handleInvalidTalkStatus();
|
||||
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:
|
||||
// 其他状态的处理
|
||||
break;
|
||||
@ -160,12 +170,6 @@ class TalkViewLogic extends BaseGetXController {
|
||||
/// 动态调整帧间隔
|
||||
void _adjustFrameInterval() {
|
||||
int newFrameIntervalMs = frameIntervalMs;
|
||||
if (state.networkStatus.value == NetworkStatus.lagging) {
|
||||
bufferSize = 60; // 增大缓冲区
|
||||
} else {
|
||||
bufferSize = 40; // 恢复默认缓冲区大小
|
||||
}
|
||||
|
||||
if (state.videoBuffer.length < 10 && frameIntervalMs < maxFrameIntervalMs) {
|
||||
// 如果缓冲区较小且帧间隔小于最大值,则增加帧间隔
|
||||
frameIntervalMs += 5;
|
||||
@ -303,7 +307,7 @@ class TalkViewLogic extends BaseGetXController {
|
||||
bluetoothDeviceName: BlueManage().connectDeviceName,
|
||||
openLockCommand: messageDetail,
|
||||
);
|
||||
showToast('已发送开门通知');
|
||||
showToast('正在开锁中...'.tr);
|
||||
}
|
||||
|
||||
int _getUTCNetTime() {
|
||||
@ -442,7 +446,8 @@ class TalkViewLogic extends BaseGetXController {
|
||||
_syncTimer = null; // 释放定时器引用
|
||||
_audioTimer?.cancel();
|
||||
_audioTimer = null; // 释放定时器引用
|
||||
|
||||
state.oneMinuteTimeTimer?.cancel();
|
||||
state.oneMinuteTimeTimer = null;
|
||||
stopProcessingAudio();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
@ -110,13 +110,13 @@ class _TalkViewPageState extends State<TalkViewPage>
|
||||
canPop: false,
|
||||
child: RepaintBoundary(
|
||||
key: state.globalKey,
|
||||
child: Transform.rotate(
|
||||
angle:
|
||||
state.rotateAngle.value * (pi / 180), // 旋转 90 度
|
||||
child: Transform.scale(
|
||||
scale: scale, // 动态计算的缩放比例
|
||||
child: SizedBox.expand(
|
||||
child: RotatedBox(
|
||||
quarterTurns: -1,
|
||||
child: Image.memory(
|
||||
state.listData.value,
|
||||
width: ScreenUtil().scaleWidth,
|
||||
height: ScreenUtil().scaleHeight,
|
||||
gaplessPlayback: true,
|
||||
fit: BoxFit.cover,
|
||||
filterQuality: FilterQuality.high,
|
||||
@ -142,6 +142,34 @@ class _TalkViewPageState extends State<TalkViewPage>
|
||||
style: TextStyle(color: Colors.black, fontSize: 26.sp),
|
||||
))
|
||||
: 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(
|
||||
bottom: 10.w,
|
||||
child: Container(
|
||||
@ -197,7 +225,7 @@ class _TalkViewPageState extends State<TalkViewPage>
|
||||
Icon(Icons.mic, color: Colors.white, size: 24.w),
|
||||
SizedBox(width: 10.w),
|
||||
Text(
|
||||
'正在说话...',
|
||||
'正在说话...'.tr,
|
||||
style: TextStyle(
|
||||
fontSize: 20.sp, color: Colors.white),
|
||||
),
|
||||
@ -342,13 +370,13 @@ class _TalkViewPageState extends State<TalkViewPage>
|
||||
Colors.white,
|
||||
longPress: () async {
|
||||
if (state.talkStatus.value == TalkStatus.answeredSuccessfully) {
|
||||
print('开始录音');
|
||||
// 启动录音
|
||||
logic.startProcessingAudio();
|
||||
state.isLongPressing.value = true;
|
||||
}
|
||||
},
|
||||
longPressUp: () async {
|
||||
print('停止录音');
|
||||
// 停止录音
|
||||
logic.stopProcessingAudio();
|
||||
state.isLongPressing.value = false;
|
||||
},
|
||||
@ -369,7 +397,7 @@ class _TalkViewPageState extends State<TalkViewPage>
|
||||
}),
|
||||
bottomBtnItemWidget(
|
||||
'images/main/icon_lockDetail_monitoringUnlock.png',
|
||||
'开锁',
|
||||
'开锁'.tr,
|
||||
AppColors.mainColor,
|
||||
onClick: () {
|
||||
// if (UDPManage().remoteUnlock == 1) {
|
||||
|
||||
@ -37,8 +37,7 @@ class TalkViewState {
|
||||
RxList<int> listAudioData = <int>[].obs; //得到的音频流字节数据
|
||||
GlobalKey globalKey = GlobalKey();
|
||||
|
||||
late Timer oneMinuteTimeTimer =
|
||||
Timer(const Duration(seconds: 1), () {}); // 定时器超过60秒关闭当前界面
|
||||
Timer? oneMinuteTimeTimer; // 定时器超过60秒关闭当前界面
|
||||
RxInt oneMinuteTime = 0.obs; // 定时器秒数
|
||||
|
||||
// 定时器如果发送了接听的命令 而没收到回复就每秒重复发送10次
|
||||
|
||||
@ -36,6 +36,7 @@ const String starChartRegisterNodeInfo = 'starChartRegisterNodeInfo'; //星图
|
||||
const String relayInfo = 'relayInfo'; //星图中继服务器信息
|
||||
const String lockNetWorkInfo = 'lockNetWorkInfo'; //锁板配网信息
|
||||
|
||||
const String appVersionHistoryUrl = 'appVersionHistoryUrl'; //是否同意隐私协议弹窗
|
||||
class Storage {
|
||||
factory Storage() => _instance;
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
|
||||
|
||||
import '../../login/login/app_get_version.dart';
|
||||
import '../../network/api_repository.dart';
|
||||
import '../storage.dart';
|
||||
import 'customer_tool.dart';
|
||||
import 'pay/wx_pay_tool.dart';
|
||||
|
||||
@ -13,12 +12,12 @@ class WechatManageTool {
|
||||
static Future<void> getAppInfo(void Function() action) async {
|
||||
// AppLog.log('AppFirstEnterHandle调用了获取App信息接口');
|
||||
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 ?? '');
|
||||
WxPayTool.setAssociationUrl(entity.data!.appSiteUrl!);
|
||||
action();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
10
pubspec.lock
10
pubspec.lock
@ -401,7 +401,7 @@ packages:
|
||||
source: hosted
|
||||
version: "7.0.2"
|
||||
dio:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: dio
|
||||
sha256: "7d328c4d898a61efc3cd93655a0955858e29a0aa647f0f9e02d59b3bb275e2e8"
|
||||
@ -1785,6 +1785,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@ -269,7 +269,8 @@ dependencies:
|
||||
# 图片预览
|
||||
photo_view: ^0.15.0
|
||||
provider: ^6.1.2
|
||||
|
||||
dio: ^4.0.6 # 网络请求库
|
||||
video_thumbnail: ^0.5.3
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user