Merge branch 'develop_liyi' of code-internal.star-lock.cn:StarlockTeam/app-starlock into develop_liyi

# Conflicts:
#	pubspec.yaml
This commit is contained in:
“DaisyWu” 2025-01-21 15:14:22 +08:00
commit 2ee6782714
78 changed files with 1193 additions and 452 deletions

View File

@ -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:

View File

@ -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"

View 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"
}

View 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"
}

View 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"
}

View 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

Binary file not shown.

View File

@ -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}"

View File

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

View File

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

View File

@ -1120,5 +1120,6 @@
"分简称": "M",
"跟随系统": "اتبع النظام",
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "بعد إعادة الضبط ، سيتم حذف بصمات القفل. هل أنت متأكد أنك تريد إعادة ضبطه ؟",
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "بعد إعادة الضبط ، سيتم حذف جهاز التحكم عن بعد للقفل. هل تريد إعادة ضبطه ؟"
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "بعد إعادة الضبط ، سيتم حذف جهاز التحكم عن بعد للقفل. هل تريد إعادة ضبطه ؟",
"版本说明": "تعليمات الإصدار"
}

View File

@ -1120,5 +1120,6 @@
"分简称": "M",
"跟随系统": "Следете система",
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "След нулиране, пръстовите отпечатъци на заключването ще бъдат изтрити. Сигурен ли сте, че искате да го нулирате?",
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "След нулиране, дистанционното управление на ключалката ще бъде изтрито. Искате ли да го нулирате?"
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "След нулиране, дистанционното управление на ключалката ще бъде изтрито. Искате ли да го нулирате?",
"版本说明": "Обяснение на версията"
}

View File

@ -1120,5 +1120,6 @@
"分简称": "M",
"跟随系统": "এক্ফক্লোসিস্টেম",
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "ব্যান্ডোটারট্রাসেট, thelock'sferprinতা?",
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "ব্যান্ডোটারপ্রাসেট, নিয়ন্ত্রণের নিয়ন্ত্রণ। ডোডো ডাইভান্টটুরে?"
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "ব্যান্ডোটারপ্রাসেট, নিয়ন্ত্রণের নিয়ন্ত্রণ। ডোডো ডাইভান্টটুরে?",
"版本说明": "ভার্সনপরিচিতি",
}

View File

@ -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"
}

View File

@ -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",
}

View File

@ -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"
}

View File

@ -1120,5 +1120,6 @@
"分简称": "M",
"跟随系统": "Ακολουθήστε το σύστημα",
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Μετά την επαναφορά, τα αποτυπώματα της κλειδαριάς θα διαγραφούν. Είστε σίγουροι ότι θέλετε να το επαναφέρετε;",
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Μετά την επαναφορά, το τηλεχειριστήριο της κλειδαριάς θα διαγραφεί. Θέλεις να το επαναφέρεις;"
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Μετά την επαναφορά, το τηλεχειριστήριο της κλειδαριάς θα διαγραφεί. Θέλεις να το επαναφέρεις;",
"版本说明": "Περιγραφή έκδοσης",
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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",
}

View File

@ -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",
}

View File

@ -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",
}

View File

@ -1120,5 +1120,6 @@
"分简称": "M",
"跟随系统": "מערכת מעקב",
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "לאחר איפוס, טביעות האצבעות של המנעול יימחקו. אתה בטוח שברצונך לאפס את זה?",
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "לאחר איפוס, השליטה מרחוק של המנעול יימחק. אתה רוצה לאפס את זה?"
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "לאחר איפוס, השליטה מרחוק של המנעול יימחק. אתה רוצה לאפס את זה?",
"版本说明": "המידע על גרסה",
}

View File

@ -1120,5 +1120,6 @@
"分简称": "M",
"跟随系统": "跟隨系統",
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "重置之後,鎖嘅指紋將被刪除。 你確定要重置它啊?",
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "重置之後,鎖嘅遙控器將被刪除。 是否要重置它?"
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "重置之後,鎖嘅遙控器將被刪除。 是否要重置它?",
"版本说明": "版本說明"
}

View File

@ -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",
}

View File

@ -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",
}

View File

@ -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",
}

View File

@ -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"
}

View File

@ -1120,5 +1120,6 @@
"分简称": "M",
"跟随系统": "システムに従う",
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "リセット後、ロックの指紋は削除されます。リセットしてもよろしいですか。",
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "リセット後、ロックのリモコンが削除されます。リセットしますか?"
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "リセット後、ロックのリモコンが削除されます。リセットしますか?",
"版本说明": "バージョン説明",
}

View File

@ -1121,5 +1121,12 @@
"分简称": "分简称",
"跟随系统": "跟随系统",
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "重置后,该锁的指纹都将被删除哦,确认要重置吗?",
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "重置后,该锁的遥控都将被删除哦,确认要重置吗?"
"通话未接通,已挂断": "通话未接通,已挂断",
"通话异常中断": "通话异常中断",
"通话连接失败": "通话连接失败",
"已挂断": "已挂断",
"正在说话...": "正在说话...",
"下载完成,请到相册查看": "下载完成,请到相册查看",
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "重置后,该锁的遥控都将被删除哦,确认要重置吗?",
"版本说明": "版本说明"
}

View File

@ -1120,5 +1120,6 @@
"分简称": "M",
"跟随系统": "Жүйені қолдану",
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Қайта ысырып тастау Шынымен ысырып тастауды қалайсыз ба?",
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Қайта ысырып ысырып тасымалдауын өшіріледі. Оны ысырып тастауды қалайсыз ба?"
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Қайта ысырып ысырып тасымалдауын өшіріледі. Оны ысырып тастауды қалайсыз ба?",
"版本说明": "Версиятын көрсету",
}

View File

@ -1120,5 +1120,6 @@
"分简称": "M",
"跟随系统": "시스템을 따르십시오",
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "재설정 후 잠금 장치의 지문이 삭제됩니다. 당신은 그것을 재설정 하시겠습니까?",
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "재설정 후 잠금 장치의 리모컨이 삭제됩니다. 당신은 그것을 재설정 하시겠습니까?"
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "재설정 후 잠금 장치의 리모컨이 삭제됩니다. 당신은 그것을 재설정 하시겠습니까?",
"版本说明": "버전 설명",
}

View File

@ -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",
}

View File

@ -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",
}

View File

@ -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",
}

View File

@ -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",
}

View File

@ -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",
}

View File

@ -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",
}

View File

@ -1120,5 +1120,6 @@
"分简称": "M",
"跟随系统": "Следуйте системе",
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "После сброса отпечатки пальцев замка будут удалены. Вы уверены, что хотите его перезагрузить?",
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "После сброса пульт дистанционного управления замком будет удален. А вы хотите его сбросить?"
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "После сброса пульт дистанционного управления замком будет удален. А вы хотите его сбросить?",
"版本说明": "Объяснение версии",
}

View File

@ -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"
}

View File

@ -1120,5 +1120,6 @@
"分简称": "M",
"跟随系统": "Пратите систем",
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Након ресетовања, отисци прстију браве ће бити избрисани. Да ли сте сигурни да желите да га ресетујете?",
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Након ресетовања, даљински управљач браве ће бити избрисан. Да ли желите да га ресетујете?"
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Након ресетовања, даљински управљач браве ће бити избрисан. Да ли желите да га ресетујете?",
"版本说明": "Опис верзије"
}

View File

@ -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"
}

View File

@ -1120,5 +1120,6 @@
"分简称": "M",
"跟随系统": "ระบบติดตามผล",
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "หลังจากรีเซ็ตแล้วลายนิ้วมือของล็อคจะถูกลบออกคุณแน่ใจว่าอยากจะรีเซ็ต?",
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "หลังจากรีเซ็ตแล้วรีโมทคอนโทรลของล็อคจะถูกลบออกคุณต้องการรีเซ็ตไหม"
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "หลังจากรีเซ็ตแล้วรีโมทคอนโทรลของล็อคจะถูกลบออกคุณต้องการรีเซ็ตไหม",
"版本说明": "คำอธิบายรุ่น"
}

View File

@ -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ı",
}

View File

@ -1120,5 +1120,6 @@
"分简称": "M",
"跟随系统": "跟蹤系統",
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "重置後,鎖的指紋將被刪除。 是否確實要重置它?",
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "重置後,鎖的遙控器將被刪除。 是否要重置它?"
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "重置後,鎖的遙控器將被刪除。 是否要重置它?",
"版本说明": "版本說明",
}

View File

@ -1120,5 +1120,6 @@
"分简称": "M",
"跟随系统": "Система стеження за",
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "Після скидання відбитки пальців замка будуть видалені. Ви впевнені, що хочете скинути налаштування?",
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Після скидання пульт дистанційного керування замком буде видалено. Хочете його скинути?"
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "Після скидання пульт дистанційного керування замком буде видалено. Хочете його скинути?",
"版本说明": "Опис версії",
}

View File

@ -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"
}

View File

@ -1121,5 +1121,12 @@
"分简称": "分",
"跟随系统": "跟随系统",
"重置后,该锁的指纹都将被删除哦,确认要重置吗?": "重置后,该锁的指纹都将被删除哦,确认要重置吗?",
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "重置后,该锁的遥控都将被删除哦,确认要重置吗?"
"通话未接通,已挂断": "通话未接通,已挂断",
"通话异常中断": "通话异常中断",
"通话连接失败": "通话连接失败",
"已挂断": "已挂断",
"正在说话...": "正在说话...",
"下载完成,请到相册查看": "下载完成,请到相册查看",
"重置后,该锁的遥控都将被删除哦,确认要重置吗?": "重置后,该锁的遥控都将被删除哦,确认要重置吗?",
"版本说明": "版本说明"
}

View File

@ -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');
}
}

View File

@ -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>{};

View File

@ -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,
),
);
},
),
);
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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,
),
);
},
),
);
}
}

View File

@ -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;
}

View File

@ -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();
}
}

View File

@ -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,
),
);
},
),
);
}
}

View File

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

View File

@ -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,
),
);
},
),
);
}

View File

@ -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),
),
),
),
),
);
}
}

View File

@ -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)),
],
),
);
}
}

View File

@ -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),
),
],
);
}
},
);
}
}

View File

@ -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: '',

View File

@ -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;
}
}

View File

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

View File

@ -29,7 +29,6 @@ class UdpTalkAcceptHandler extends ScpMessageBaseHandle
//
final GenericResp genericResp = scpMessage.Payload;
if (checkGenericRespSuccess(genericResp)) {
print('收到同意接听的回复');
//
startChartManage.stopTalkAcceptTimer();
//

View File

@ -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);
}

View File

@ -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();
}

View File

@ -28,7 +28,7 @@ class TalkDataOverTimeTimerManager {
//
static void _handleTalkeDataOverTime() {
EasyLoading.showToast('通话连接失败', duration: 2000.milliseconds);
EasyLoading.showToast('通话连接失败'.tr, duration: 2000.milliseconds);
//
StartChartManage().sendTalkHangupMessage();
StartChartManage().stopTalkPingMessageTimer();

View File

@ -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();

View File

@ -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();

View File

@ -50,7 +50,6 @@ class TalkViewLogic extends BaseGetXController {
int audioFrameIntervalMs = 20; // 4522FPS
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();
}

View File

@ -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) {

View File

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

View File

@ -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;

View File

@ -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();
}
}
}

View File

@ -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:

View File

@ -269,7 +269,8 @@ dependencies:
# 图片预览
photo_view: ^0.15.0
provider: ^6.1.2
dio: ^4.0.6 # 网络请求库
video_thumbnail: ^0.5.3