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",
|
||||
"跟随系统": "Ακολουθήστε το σύστημα",
|
||||
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Μετά την επαναφορά, τα αποτυπώματα της κλειδαριάς θα διαγραφούν. Είστε σίγουροι ότι θέλετε να το επαναφέρετε;",
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Μετά την επαναφορά, το τηλεχειριστήριο της κλειδαριάς θα διαγραφεί. Θέλεις να το επαναφέρεις;"
|
||||
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Μετά την επαναφορά, το τηλεχειριστήριο της κλειδαριάς θα διαγραφεί. Θέλεις να το επαναφέρεις;",
|
||||
"版本说明": "Περιγραφή έκδοσης",
|
||||
}
|
||||
@ -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(
|
||||
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,99 +117,143 @@ 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('请选择要下载的视频');
|
||||
}
|
||||
}),
|
||||
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);
|
||||
}
|
||||
})
|
||||
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,
|
||||
@ -221,9 +268,118 @@ class _EditVideoLogPageState extends State<EditVideoLogPage> {
|
||||
Expanded(
|
||||
child: Text(name,
|
||||
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 {
|
||||
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,
|
||||
RecordListData({
|
||||
this.recordId,
|
||||
this.operateDate,
|
||||
this.imagesUrl,
|
||||
this.videoUrl,
|
||||
this.recordType});
|
||||
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')),
|
||||
'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(
|
||||
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,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -150,7 +150,8 @@ class _ControlsOverlayState extends State<ControlsOverlay> {
|
||||
Text(
|
||||
DateTool().dateToYMDHNString(
|
||||
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)),
|
||||
// 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,20 +73,19 @@ 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,
|
||||
width: 1.sw,
|
||||
child: Stack(
|
||||
alignment: Alignment.bottomCenter,
|
||||
children: <Widget>[
|
||||
FittedBox(
|
||||
child: SizedBox(
|
||||
width: state.videoController.value.size.width,
|
||||
height: state.videoController.value.size.height,
|
||||
RotatedBox(
|
||||
quarterTurns: -1,
|
||||
child: AspectRatio(
|
||||
aspectRatio: state.videoController.value.size.width /
|
||||
state.videoController.value.size.height,
|
||||
child: VideoPlayer(state.videoController),
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
ControlsOverlay(
|
||||
controller: state.videoController,
|
||||
@ -104,7 +104,6 @@ class _VideoLogDetailPageState extends State<VideoLogDetailPage> {
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
_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(
|
||||
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,11 +10,19 @@ class FullScreenImagePage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Container(
|
||||
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");
|
||||
}
|
||||
|
||||
// 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];
|
||||
message.MessageId = byteData.getUint16(offset, Endian.little);
|
||||
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) {
|
||||
// FromPeerId (44 bytes)
|
||||
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) {
|
||||
// ToPeerId (44 bytes)
|
||||
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];
|
||||
message.PayloadType = byteData.getUint16(offset, Endian.little);
|
||||
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];
|
||||
message.PayloadCRC = byteData.getUint16(offset, Endian.little);
|
||||
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
|
||||
message.PayloadLength = byteData.getUint32(offset, Endian.little);
|
||||
offset += 4;
|
||||
} else {
|
||||
throw FormatException("Invalid PayloadLength length");
|
||||
|
||||
// 检查 Payload 长度是否有效
|
||||
if (message.PayloadLength == null ||
|
||||
length - offset < message.PayloadLength!) {
|
||||
throw FormatException("Invalid Payload or PayloadLength");
|
||||
}
|
||||
|
||||
// 处理其他类型的Payload
|
||||
if (message.PayloadLength != null &&
|
||||
bytes.length - offset >= message.PayloadLength!) {
|
||||
final sublist = bytes.sublist(offset, offset + message.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: sublist,
|
||||
byte: payloadBytes,
|
||||
offset: offset,
|
||||
PayloadLength: message.PayloadLength,
|
||||
spIndex: message.SpIndex,
|
||||
spTotal: message.SpTotal,
|
||||
messageId: message.MessageId,
|
||||
);
|
||||
} else {
|
||||
throw FormatException("Invalid Payload or PayloadLength");
|
||||
}
|
||||
|
||||
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';
|
||||
|
||||
@ -14,11 +13,11 @@ class WechatManageTool {
|
||||
// AppLog.log('AppFirstEnterHandle调用了获取App信息接口');
|
||||
final GetAppInfo entity = await ApiRepository.to.getAppInfo();
|
||||
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