Merge branch 'release_sky' into 'master_sky'
Release sky See merge request StarlockTeam/app-starlock!229
This commit is contained in:
commit
dcd1b9a140
@ -1153,5 +1153,11 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. تمكين وظيفة الفتح عن بعد للقفل في APP (يتم إيقاف هذه الوظيفة بشكل افتراضي). إذا كان هذا الخيار غير متاح، لن يدعم القفل جوجل هوم",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. قم بتثبيت تطبيق Google Home وانقر فوق الزر زائد في الزاوية العلوية اليسرى",
|
||||
"暂无最新记录": "لا توجد حاليا أحدث السجلات المتاحة",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "الرجاء تحويل هاتفك إلى \"واي فاي 2.4\" للاتصال اليدوي"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "الرجاء تحويل هاتفك إلى \"واي فاي 2.4\" للاتصال اليدوي",
|
||||
"第三方平台设置": "الطرف الثالث منصة الإعداد",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "قفل مجموعة صوت",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "ذكر صوت",
|
||||
"女声": "صوت بنات"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. Активирайте функцията за дистанционно отключване на ключалката в приложението (тази функция е изключена по подразбиране). Ако тази опция не е налице, заключването няма да поддържа Google Home",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. Инсталирайте приложението Google Home и щракнете върху бутона плюс в горния ляв ъгъл",
|
||||
"暂无最新记录": "В момента няма най-новите налични записи",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Моля, превключете телефона си на 2.4G WiFi за ръчно свързване"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Моля, превключете телефона си на 2.4G WiFi за ръчно свързване",
|
||||
"语音包设置": "Настройки на гласовите пакети",
|
||||
"第三方平台设置": "Настройки на платформи на трети страни",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Заключване на настройките на гласовия пакет",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "Мъжки глас",
|
||||
"女声": "Женски глас"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. অ্যাপে লকের রিমোট আনলকিং ফাংশন সক্ষম করুন (এই ফাংশনটি ডিফল্টরূপে বন্ধ রয়েছে)। যদি এই বিকল্পটি উপলভ্য না হয় তবে লকটি গুগল হোম সমর্থন করবে না",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "গুগল হোম অ্যাপ্লিকেশনটি ইনস্টল করুন এবং উপরের বাম কোণে প্লাস বোতামটি ক্লিক করুন",
|
||||
"暂无最新记录": "বর্তমানে কোনও সাম্প্রতিকতম রেকর্ড সুলভ নেই",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "ম্যানুয়াল সংযোগের জন্য দয়া করে আপনার ফোনটি 2.4 জি ওয়াইফাইতে স্যুইচ করুন"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "ম্যানুয়াল সংযোগের জন্য দয়া করে আপনার ফোনটি 2.4 জি ওয়াইফাইতে স্যুইচ করুন",
|
||||
"语音包设置": "ভয়েস প্যাকেজ সেটিংস",
|
||||
"第三方平台设置": "তৃতীয় পক্ষের প্ল্যাটফর্ম সেটিংস",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "ভয়েস প্যাকেজ সেটিংস লক করুন",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "পুরুষের কণ্ঠ",
|
||||
"女声": "নারী কণ্ঠ"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. Povolte funkci dálkového odemykání zámku v APP (tato funkce je ve výchozím nastavení vypnutá). Pokud tato možnost není k dispozici, zámek nebude podporovat Google Home",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. Nainstalujte aplikaci Google Home a klikněte na tlačítko plus v levém horním rohu",
|
||||
"暂无最新记录": "Momentálně nejsou k dispozici žádné nejnovější záznamy",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Přepněte prosím svůj telefon na 2.4G WiFi pro ruční připojení"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Přepněte prosím svůj telefon na 2.4G WiFi pro ruční připojení",
|
||||
"语音包设置": "Nastavení hlasového balíčku",
|
||||
"第三方平台设置": "Nastavení platformy třetích stran",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Zamknout nastavení hlasového balíčku",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "Mužský hlas",
|
||||
"女声": "Ženský hlas"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. Aktiver fjernoplåsningsfunktionen for låsen i APP'en (denne funktion er slået fra som standard). Hvis denne mulighed ikke er tilgængelig, understøtter låsen ikke Google Home",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. Installer Google Home-appen, og klik på plusknappen i øverste venstre hjørne",
|
||||
"暂无最新记录": "Der er i øjeblikket ingen nyeste optegnelser tilgængelige",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Skift venligst din telefon til 2.4G WiFi for manuel forbindelse"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Skift venligst din telefon til 2.4G WiFi for manuel forbindelse",
|
||||
"语音包设置": "Indstillinger af stemmepakke",
|
||||
"第三方平台设置": "Indstillinger af tredjepartsplatforme",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Lås stemmepakkeindstillinger",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "Mandlige stemmer",
|
||||
"女声": "Kvindelige stemmer"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. Entsichern in einer APP, die ein schloss öffnet (standard abschalten) Wenn diese option nicht verfügbar ist, wird das schloss google nicht unterstützen",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. Installiert die google-app und klicken auf den knopf hinzufügen in der oberen linken ecke",
|
||||
"暂无最新记录": "Wir haben keine neuen daten",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Wenn manuelle verbindung hergestellt wird, schalten sie das handy auf 2,4 G WiFi"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Wenn manuelle verbindung hergestellt wird, schalten sie das handy auf 2,4 G WiFi",
|
||||
"语音包设置": "Sprachpaketeinstellungen",
|
||||
"第三方平台设置": "Einstellungen von Drittanbieterplattformen",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Sperren von Sprachpaketeinstellungen",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "Männliche Stimme",
|
||||
"女声": "Frauenstimme"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. Ενεργοποιήστε τη λειτουργία απομακρυσμένου ξεκλειδώματος της κλειδαριάς στην εφαρμογή (αυτή η λειτουργία είναι απενεργοποιημένη από προεπιλογή). Εάν αυτή η επιλογή δεν είναι διαθέσιμη, το κλείδωμα δεν θα υποστηρίζει το Google Home",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. Εγκαταστήστε την εφαρμογή Google Home και κάντε κλικ στο κουμπί συν στην επάνω αριστερή γωνία",
|
||||
"暂无最新记录": "Προς το παρόν δεν υπάρχουν διαθέσιμες τελευταίες εγγραφές",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Αλλάξτε το τηλέφωνό σας σε 2.4G WiFi για χειροκίνητη σύνδεση"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Αλλάξτε το τηλέφωνό σας σε 2.4G WiFi για χειροκίνητη σύνδεση",
|
||||
"语音包设置": "Ρυθμίσεις πακέτου φωνής",
|
||||
"第三方平台设置": "Ρυθμίσεις πλατφόρμας τρίτων",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Ρυθμίσεις κλειδώματος πακέτου φωνής",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "Ανδρική φωνή",
|
||||
"女声": "Γυναικεία φωνή"
|
||||
}
|
||||
@ -1159,5 +1159,12 @@
|
||||
"请确认后再继续": "Please confirm before continuing",
|
||||
"需要相机权限": "Camera permission required",
|
||||
"此功能的开启和关闭只能在锁附近通过手机蓝牙进行": "The activation and deactivation of this feature can only be done through Bluetooth on the phone near the lock",
|
||||
"网关添加成功": "Gateway added successfully"
|
||||
"网关添加成功": "Gateway added successfully",
|
||||
"语音包设置": "Voice packet settings",
|
||||
"第三方平台设置": "Third party platform settings",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Lock voice package settings",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "male voice",
|
||||
"女声": "female voice"
|
||||
}
|
||||
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. Habilitar la función de desbloqueo remoto del bloqueo en la aplicación (esta función se desactiva por defecto). Si esta opción no está disponible, el bloqueo no será compatible con Google Home",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. Instale la aplicación de Google Home y haga clic en el botón más en la esquina superior izquierda",
|
||||
"暂无最新记录": "Actualmente no hay registros más recientes disponibles",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Por favor cambia tu teléfono a 2.4G WiFi para la conexión manual"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Por favor cambia tu teléfono a 2.4G WiFi para la conexión manual",
|
||||
"语音包设置": "Configuración del paquete de voz",
|
||||
"第三方平台设置": "Configuración de la Plataforma de terceros",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Configuración del paquete de voz de bloqueo",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "Voz masculina",
|
||||
"女声": "Voz femenina"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. Lubage rakenduses APP luku kaugavamise funktsioon (see funktsioon on vaikimisi välja lülitatud). Kui see valik pole saadaval, ei toeta lukk Google Home'i",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. Installige rakendus Google Home ja klõpsake vasakus ülanurgas plussnuppu",
|
||||
"暂无最新记录": "Praegu pole uusimaid andmeid saadaval",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Käsitsi ühendamiseks lülitage telefon 2.4G WiFi-le"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Käsitsi ühendamiseks lülitage telefon 2.4G WiFi-le",
|
||||
"语音包设置": "Häälepaketi seadistused",
|
||||
"第三方平台设置": "Kolmanda osapoole platvormi seaded",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Lukustage häälepaketi seaded",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "Meeste hääl",
|
||||
"女声": "Naiste hääl"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. Ota lukon etälukituksen avaustoiminto käyttöön APP:ssa (tämä toiminto on oletuksena pois päältä). Jos tämä vaihtoehto ei ole käytettävissä, lukko ei tue Google Homea",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. Asenna Google Home -sovellus ja napsauta vasemmassa yläkulmassa olevaa pluspainiketta",
|
||||
"暂无最新记录": "Viimeisimpiä tietoja ei ole tällä hetkellä saatavilla",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Vaihda puhelimesi 2.4G WiFi-verkkoon manuaalista yhteyttä varten"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Vaihda puhelimesi 2.4G WiFi-verkkoon manuaalista yhteyttä varten",
|
||||
"语音包设置": "Äänipaketin asetukset",
|
||||
"第三方平台设置": "Kolmannen osapuolen alustan asetukset",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Lukitse äänipaketin asetukset",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "Miehen ääni",
|
||||
"女声": "Naisten ääni"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. Activez la fonction de déverrouillage à distance de la serrure dans l’application (cette fonction est désactivée par défaut). Si cette option n’est pas disponible, le verrou ne prendra pas en charge Google Home",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. Installez l’application Google Home et cliquez sur le bouton plus dans le coin supérieur gauche",
|
||||
"暂无最新记录": "Il n’y a actuellement aucun dernier enregistrement disponible",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Veuillez passer votre téléphone à 2.4G WiFi pour une connexion manuelle"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Veuillez passer votre téléphone à 2.4G WiFi pour une connexion manuelle",
|
||||
"语音包设置": "Paramètres du pack vocal",
|
||||
"第三方平台设置": "Paramètres de plate - forme tierce",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Paramètres du pack Lock Voice",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "Voix masculine",
|
||||
"女声": "Voix de femmes"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. הפעל את פונקציית ביטול הנעילה מרחוק של המנעול באפליקציה (פונקציה זו כבויה כברירת מחדל). אם אפשרות זו אינה זמינה, המנעול לא יתמוך ב-Google Home",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. התקן את אפליקציית Google Home ולחץ על כפתור הפלוס בפינה השמאלית העליונה",
|
||||
"暂无最新记录": "אין כרגע רשומות עדכניות זמינות",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "אנא העבר את הטלפון שלך ל- WiFi 2.4G לחיבור ידני"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "אנא העבר את הטלפון שלך ל- WiFi 2.4G לחיבור ידני",
|
||||
"语音包设置": "הגדרות חבילת קול",
|
||||
"第三方平台设置": "הגדרות פלטפורמות של צד שלישי",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "הגדרות חבילת קול לנעול",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "קול גבר",
|
||||
"女声": "קול נשי"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. एप्लिकेशन में लॉक का रिमोट अनलॉकिंग फ़ंक्शन सक्षम करें (यह फ़ंक्शन डिफ़ॉल्ट रूप से बंद है). यदि यह विकल्प उपलब्ध नहीं है, तो लॉक आपके गूगल होम को सपोर्ट नहीं करेगा।",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. गूगल होम ऐप को इंस्टॉल करें और ऊपरी बाएं कोने में प्लस बटन पर क्लिक करें।",
|
||||
"暂无最新记录": "वर्तमान में कोई नवीनतम रिकॉर्ड उपलब्ध नहीं हैं",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "मैन्युअल कनेक्शन के लिए कृपया अपना फोन 2.4 जी वाईफ़ाई पर स्विच करें।"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "मैन्युअल कनेक्शन के लिए कृपया अपना फोन 2.4 जी वाईफ़ाई पर स्विच करें।",
|
||||
"语音包设置": "आवाज पैकेज सेटिंग्स",
|
||||
"第三方平台设置": "तृतीय पक्ष मंच सेटिंग्स",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "आवाज पैकेज सेटिंग्स ताला लगाएँ",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "पुरुष आवाज",
|
||||
"女声": "महिला आवाज"
|
||||
}
|
||||
@ -1154,5 +1154,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2.喺APP中開啟鎖嘅遠程解鎖功能(此功能默認關閉)。 如果此選項不可用,則鎖將唔撐Google Home",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3.安裝Google Home應用,點擊左上角嘅加號掣",
|
||||
"暂无最新记录": "目前冇可用嘅最新記錄",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "請把手機切換到2.4G WiFi進行手動連接"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "請把手機切換到2.4G WiFi進行手動連接",
|
||||
"语音包设置": "語音包設定",
|
||||
"第三方平台设置": "協力廠商領獎臺設定",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "鎖語音包設定",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "男聲",
|
||||
"女声": "女聲"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. Omogućite funkciju daljinskog otključavanja brave u APP-u (ova je funkcija prema zadanim postavkama isključena). Ako ova opcija nije dostupna, zaključavanje neće podržavati Google Home",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. Instalirajte aplikaciju Google Home i kliknite gumb plus u gornjem lijevom kutu",
|
||||
"暂无最新记录": "Trenutno nema dostupnih najnovijih podataka",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Prebacite telefon na 2.4G WiFi za ručno povezivanje"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Prebacite telefon na 2.4G WiFi za ručno povezivanje",
|
||||
"语音包设置": "Postavke glasovnog paketa",
|
||||
"第三方平台设置": "Postavljanje podiuma treće strane",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Postavke zaključavanja glasovnog paketa",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "Muški glas",
|
||||
"女声": "Ženski glas"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. Engedélyezze a zár távoli feloldási funkcióját az APP-ban (ez a funkció alapértelmezés szerint ki van kapcsolva). Ha ez az opció nem érhető el, a zár nem támogatja a Google Home szolgáltatást",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. Telepítse a Google Home alkalmazást, és kattintson a plusz gombra a bal felső sarokban",
|
||||
"暂无最新记录": "Jelenleg nem állnak rendelkezésre legfrissebb rekordok",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Kérjük, kapcsolja át telefonját 2.4G WiFi-re a kézi csatlakozáshoz"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Kérjük, kapcsolja át telefonját 2.4G WiFi-re a kézi csatlakozáshoz",
|
||||
"语音包设置": "Hangcsomag beállításai",
|
||||
"第三方平台设置": "Harmadik fél platformjának beállítása",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Hangcsomag zárolási beállításai",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "Férfi hang",
|
||||
"女声": "női hang"
|
||||
}
|
||||
@ -1159,5 +1159,12 @@
|
||||
"请确认后再继续": "Խնդրում ենք հաստատել շարունակելուց առաջ",
|
||||
"需要相机权限": "Պահանջվում է տեսախցիկի թույլտվություն",
|
||||
"此功能的开启和关闭只能在锁附近通过手机蓝牙进行": "Այս գործառույթի ակտիվացումը եւ ապաակտիվացումը կարելի է կատարել միայն կողպեքի մոտ գտնվող հեռախոսի Bluetooth-ի միջոցով",
|
||||
"网关添加成功": "Gateway հաջողությամբ ավելացվել է"
|
||||
"网关添加成功": "Gateway հաջողությամբ ավելացվել է",
|
||||
"语音包设置": "Ձայնային փաթեթի պարամետրեր",
|
||||
"第三方平台设置": "Երրորդ կողմի հարթակի կարգավորումներ",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Փակել ձայնային փաթեթի պարամետրերը",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "տղամարդկանց ձայն",
|
||||
"女声": "կանանց ձայն"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. Aktifkan fungsi kunci pengunci jarak jauh di aplikasi (fungsi ini dimatikan secara standar). Jika opsi ini tidak tersedia, kunci tidak akan mendukung Google Home",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. Instal aplikasi Google Home dan klik tombol plus di sudut kiri atas",
|
||||
"暂无最新记录": "Saat ini tidak ada catatan terbaru yang tersedia",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Silahkan beralih ke 2.4G WiFi untuk koneksi manual"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Silahkan beralih ke 2.4G WiFi untuk koneksi manual",
|
||||
"语音包设置": "Pengaturan paket suara",
|
||||
"第三方平台设置": "Platform pihak ketiga diatur",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Mengunci paket suara",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "6 tahun sebelumnya",
|
||||
"女声": "Suara wanita"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. Abilita la funzione di sblocco remoto del lock nella APP (questa funzione è disattivata in modo predefinito). Se questa opzione non è disponibile, il lock non supporta Google Home",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. Installa l’applicazione Home di Google e fai clic sul pulsante più nell’angolo in alto a sinistra",
|
||||
"暂无最新记录": "Attualmente non sono disponibili dati più recenti",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Passa il telefono a 2,4g WiFi per la connessione manuale"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Passa il telefono a 2,4g WiFi per la connessione manuale",
|
||||
"语音包设置": "Impostazioni pacchetto vocalea",
|
||||
"第三方平台设置": "Impostazioni di piattaforme di terze parti",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Impostazioni pacchetto vocale blocco",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "voce maschile",
|
||||
"女声": "voce femminile"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. アプリでロックのリモートロック解除機能を有効にします(この機能はデフォルトでオフになっています)。このオプションが利用できない場合、ロックはgoogle homeをサポートしません",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. google homeアプリをインストールし、左上隅のプラスボタンをクリックします",
|
||||
"暂无最新记录": "最新の記録は残っていない",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "手動接続のため、携帯電話を2.4 g wifiに切り替えてください"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "手動接続のため、携帯電話を2.4 g wifiに切り替えてください",
|
||||
"语音包设置": "ボイスパックの設定",
|
||||
"第三方平台设置": "サードパーティ製プラットフォームの設定",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "ロック音声パケット設定",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "男声",
|
||||
"女声": "女声"
|
||||
}
|
||||
@ -1159,5 +1159,12 @@
|
||||
"请确认后再继续": "გაგრძელებამდე გთხოვთ დაადასტუროთ",
|
||||
"需要相机权限": "კამერის ნებართვა საჭიროა",
|
||||
"此功能的开启和关闭只能在锁附近通过手机蓝牙进行": "ამ ფუნქციის გააქტიურება და დეაქტივაცია შეიძლება გაკეთდეს მხოლოდ Bluetooth– ის საშუალებით ტელეფონით დაბლოკვის მახლობლად",
|
||||
"网关添加成功": "კარიბჭე წარმატებით დაემატა"
|
||||
"网关添加成功": "კარიბჭე წარმატებით დაემატა",
|
||||
"语音包设置": "ხმის პაკეტის პარამეტრები",
|
||||
"第三方平台设置": "მესამე მხარის პლატფორმის პარამეტრები",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "ხმის პაკეტის პარამეტრები",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "მამაკაცის ხმა",
|
||||
"女声": "ქალის ხმა"
|
||||
}
|
||||
@ -1101,7 +1101,7 @@
|
||||
"支持的国家": "支持的国家",
|
||||
"支持的国家值": "美国、加拿大、英国、澳大利亚、印度、德国、法国、意大利、西班牙、日本",
|
||||
"操作流程": "操作流程",
|
||||
"操作流程值":"1 用智能锁APP添加锁和网关\n\n2 在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Alexa \n\n3 在Alexa中添加Skill,并用智能锁APP的账号和密码进行授权。授权成功后就可以发现账号下的设备\n\n4 在Alexa app里找到锁,开启语音开锁的功能,并设置语言密码\n\n5 可以通过Alexa操作锁了",
|
||||
"操作流程值": "1 用智能锁APP添加锁和网关\n\n2 在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Alexa \n\n3 在Alexa中添加Skill,并用智能锁APP的账号和密码进行授权。授权成功后就可以发现账号下的设备\n\n4 在Alexa app里找到锁,开启语音开锁的功能,并设置语言密码\n\n5 可以通过Alexa操作锁了",
|
||||
"Google Home": "Google Home",
|
||||
"Action name": "Action name",
|
||||
"ScienerSmart": "ScienerSmart",
|
||||
@ -1164,5 +1164,12 @@
|
||||
"请确认后再继续": "请确认后再继续",
|
||||
"需要相机权限": "需要相机权限",
|
||||
"此功能的开启和关闭只能在锁附近通过手机蓝牙进行": "此功能的开启和关闭只能在锁附近通过手机蓝牙进行",
|
||||
"网关添加成功": "网关添加成功"
|
||||
"网关添加成功": "网关添加成功",
|
||||
"第三方平台设置": "第三方平台设置",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "锁语音包设置",
|
||||
"语音包设置": "语音包设置",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "男声",
|
||||
"女声": "女声"
|
||||
}
|
||||
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. APP бағдарламасында құлыпты қашықтан ашу функциясын қосу (бұл функция әдепкі бойынша өшіріледі). Егер бұл параметр қол жетімді болмаса, бұғаттау Google Home-ды қолдамайды",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. Google Home бағдарламасын орнатып, жоғарғы сол жақ бұрыштағы қосу түймешігін басыңыз",
|
||||
"暂无最新记录": "Қазіргі уақытта қол жетімді соңғы жазбалар жоқ",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Телефонды қолмен қосу үшін 2.4G WiFi бағдарламасына ауыстыруыңызды сұраймыз"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Телефонды қолмен қосу үшін 2.4G WiFi бағдарламасына ауыстыруыңызды сұраймыз",
|
||||
"语音包设置": "Дауыстық бума параметрлері",
|
||||
"第三方平台设置": "Үшінші тарап платформасының параметрлері",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Дауыстық бума параметрлерін құлыптау",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "ер дауысы",
|
||||
"女声": "Әйел дауысы"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. 앱에서 잠금의 원격 잠금 해제 기능을 활성화합니다 (이 기능은 기본적으로 꺼져 있습니다).이 옵션을 사용할 수 없는 경우 잠금은 Google Home을 지원하지 않습니다",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. 구글 홈 앱을 설치하고 왼쪽 상단 모서리에 있는 더하기 버튼을 클릭합니다",
|
||||
"暂无最新记录": "현재 사용 가능한 최신 레코드가 없습니다",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "수동 연결을 위해 핸드폰을 2.4G WiFi로 바꿔주세요"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "수동 연결을 위해 핸드폰을 2.4G WiFi로 바꿔주세요",
|
||||
"语音包设置": "음성 팩 설정",
|
||||
"第三方平台设置": "타사 플랫폼 설정",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "음성팩 설정 잠금",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "남성",
|
||||
"女声": "여성 목소리"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. Įjunkite užrakto nuotolinio atrakinimo funkciją APP (ši funkcija yra išjungta pagal numatytuosius nustatymus). Jei ši parinktis nepasiekiama, užraktas nepalaikys \"Google Home\"",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. Įdiekite \"Google Home\" programą ir spustelėkite pliuso mygtuką viršutiniame kairiajame kampe",
|
||||
"暂无最新记录": "Šiuo metu nėra naujausių įrašų",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Perjunkite telefoną į 2.4G WiFi, kad galėtumėte prisijungti rankiniu būdu"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Perjunkite telefoną į 2.4G WiFi, kad galėtumėte prisijungti rankiniu būdu",
|
||||
"语音包设置": "Balso paketo nustatymai",
|
||||
"第三方平台设置": "Trečiosios šalies platformos nustatymai",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Balso paketo nustatymų užrakinimas",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "vyriškas balsas",
|
||||
"女声": "Moteriškas balsas"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. Dayakan fungsi buka kunci jauh kunci dalam APP (fungsi ini dimatikan secara lalai). Jika pilihan ini tidak tersedia, kunci tidak akan menyokong Google Home",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. Pasang apl Google Home dan klik butang tambah di penjuru kiri sebelah atas",
|
||||
"暂无最新记录": "Pada masa ini tiada rekod terkini tersedia",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Sila tukar telefon anda kepada WiFi 2.4G untuk sambungan manual"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Sila tukar telefon anda kepada WiFi 2.4G untuk sambungan manual",
|
||||
"语音包设置": "Balso paketo nustatymai",
|
||||
"第三方平台设置": "Trečiosios šalies platformos nustatymai",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Balso paketo nustatymų užrakinimas",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "vyriškas balsas",
|
||||
"女声": "Moteriškas balsas"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. Open het slot op afstand in de APP (standaard uitgeschakeld). Als deze optie niet beschikbaar is, wordt google Home niet ondersteund",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. Installeer de google home-app en klik op de plus-knop in de linkerbovenhoek",
|
||||
"暂无最新记录": "Er zijn momenteel geen recente gegevens beschikbaar",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Stel uw telefoon in op 2. 4g WiFi bij handmatige verbinding"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Stel uw telefoon in op 2. 4g WiFi bij handmatige verbinding",
|
||||
"语音包设置": "Voice Pack-instellingen",
|
||||
"第三方平台设置": "Instellingen voor platforms van derden",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Instellingen voor spraakpakket vergrendelen",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "mannelijke stem",
|
||||
"女声": "Vrouwelijke stem"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. Włącz funkcję zdalnego odblokowywania zamka w aplikacji (ta funkcja jest domyślnie wyłączona). Jeśli ta opcja nie jest dostępna, zamek nie będzie obsługiwał Google Home",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. Zainstaluj aplikację Google Home i kliknij przycisk plusa w lewym górnym rogu",
|
||||
"暂无最新记录": "Obecnie nie ma dostępnych najnowszych rekordów",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Przełącz telefon na 2.4G Wi-Fi, aby uzyskać ręczne połączenie"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Przełącz telefon na 2.4G Wi-Fi, aby uzyskać ręczne połączenie",
|
||||
"语音包设置": "Ustawienia pakietu głosowego",
|
||||
"第三方平台设置": "Ustawienia platformy stron trzecich",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Ustawienia blokowania pakietu głosowego",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "Mężczyzna",
|
||||
"女声": "Głos kobiecy"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. Ative a função de desbloqueio remoto da fechadura no APP (esta função está desativada por padrão). Se esta opção não estiver disponível, o bloqueio não será compatível com o Google Home",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. Instale o aplicativo Google Home e clique no botão de adição no canto superior esquerdo",
|
||||
"暂无最新记录": "Atualmente não há registros mais recentes disponíveis",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Mude seu telefone para WiFi 2.4G para conexão manual"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Mude seu telefone para WiFi 2.4G para conexão manual",
|
||||
"语音包设置": "Configurações do pacote de voz",
|
||||
"第三方平台设置": "Configurações de plataformas de terceiros",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Configurações do pacote de voz bloqueada",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "Voz masculina",
|
||||
"女声": "voz feminina"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. Activați funcția de deblocare de la distanță a încuietorului în aplicație (această funcție este dezactivată în mod implicit). Dacă această opțiune nu este disponibilă, blocarea nu va accepta Google Home",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. Instalați aplicația Google Home și faceți clic pe butonul plus din colțul din stânga sus",
|
||||
"暂无最新记录": "În prezent nu există cele mai recente înregistrări disponibile",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Vă rugăm să comutați telefonul la WiFi 2.4G pentru conectarea manuală"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Vă rugăm să comutați telefonul la WiFi 2.4G pentru conectarea manuală",
|
||||
"语音包设置": "Setări pachet vocal",
|
||||
"第三方平台设置": "Setarea platformei terțelor părți",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Configurarea pachetului vocal de blocare",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "vocea bărbatului",
|
||||
"女声": "Voce feminină"
|
||||
}
|
||||
@ -1157,5 +1157,12 @@
|
||||
"请确保网络是2.4GHz Wi-Fi": "Убедитесь, что сеть имеет 2,4 ГГц Wi - Fi",
|
||||
"已选": "Выбранные",
|
||||
"是否要远程开锁": "Нужно ли удалённо открывать замок",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Пожалуйста, переключите телефон на 2.4G WiFi для ручного подключения"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Пожалуйста, переключите телефон на 2.4G WiFi для ручного подключения",
|
||||
"语音包设置": "Настройка голосового пакета",
|
||||
"第三方平台设置": "Настройка платформы третьей стороны",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Запустить настройки голосового пакета",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "Мужской голос",
|
||||
"女声": "Женские голоса"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. Povoľte funkciu diaľkového odomykania zámku v aplikácii APP (táto funkcia je predvolene vypnutá). Ak táto možnosť nie je k dispozícii, zámok nebude podporovať Google Home",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. Nainštalujte si aplikáciu Google Home a kliknite na tlačidlo plus v ľavom hornom rohu",
|
||||
"暂无最新记录": "Momentálne nie sú k dispozícii žiadne najnovšie záznamy",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Pre manuálne pripojenie prepnite telefón na 2.4G WiFi"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Pre manuálne pripojenie prepnite telefón na 2.4G WiFi",
|
||||
"语音包设置": "Nastavenie hlasového balíka",
|
||||
"第三方平台设置": "Nastavenie platformy tretích strán",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Zamknutie nastavení hlasového balíka",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "mužský hlas",
|
||||
"女声": "Ženský hlas"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2 . Омогућите функцију даљинског откључавања браве у АПП-у (ова функција је подразумевано искључена). Ако ова опција није доступна, брава неће подржати Гоогле Хоме",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3 . Инсталирајте апликацију Гоогле Хоме и кликните на дугме плус у горњем левом углу",
|
||||
"暂无最新记录": "Тренутно нема доступних најновијих података",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Пребаците телефон на КСНУМКСГ ВиФи за ручно повезивање"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Пребаците телефон на КСНУМКСГ ВиФи за ручно повезивање",
|
||||
"语音包设置": "Подешавања гласовног пакета",
|
||||
"第三方平台设置": "Подешавања платформе трећих страна",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Закључајте подешавања говорног пакета",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "мушки глас",
|
||||
"女声": "женски глас"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. Aktivera fjärrupplåsningsfunktionen för låset i APP (den här funktionen är avstängd som standard). Om det här alternativet inte är tillgängligt kommer låset inte att stödja Google Home",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. Installera Google Home-appen och klicka på plusknappen i det övre vänstra hörnet",
|
||||
"暂无最新记录": "Det finns för närvarande inga senaste poster tillgängliga",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Byt din telefon till 2.4G WiFi för manuell anslutning"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Byt din telefon till 2.4G WiFi för manuell anslutning",
|
||||
"语音包设置": "Inställningar för röstpaket",
|
||||
"第三方平台设置": "Inställningar för tredjepartsplattformar",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Lås inställningar för röstpaket",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "Mänsklig röst",
|
||||
"女声": "Kvinnlig röst"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. เปิดใช้งานฟังก์ชันการปลดล็อคระยะไกลของการล็อคในแอพ (ฟังก์ชันนี้ จะถูกปิดโดยค่าเริ่มต้น) หากไม่มีตัวเลือกนี้ การล็อคจะไม่สนับสนุนกูเกิ้ลโฮม",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. ติดตั้ง googlehome แอพ และคลิกปุ่มบวก ที่มุมบนซ้าย",
|
||||
"暂无最新记录": "ปัจจุบันยังไม่มีบันทึกล่าสุด ที่มีอยู่",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "กรุณาเปลี่ยนโทรศัพท์เป็น 2.4 GWiFi สำหรับการเชื่อมต่อด้วยตนเอง"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "กรุณาเปลี่ยนโทรศัพท์เป็น 2.4 GWiFi สำหรับการเชื่อมต่อด้วยตนเอง",
|
||||
"语音包设置": "การตั้งค่าแพ็กเกจเสียง",
|
||||
"第三方平台设置": "การตั้งค่าแพลตฟอร์มของบุคคลที่สาม",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "ล็อคการตั้งค่า Voice Pack",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "เสียงผู้ชาย",
|
||||
"女声": "เสียงผู้หญิง"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. APP'de kilidin uzaktan kilit açma işlevini etkinleştirin (bu işlev varsayılan olarak kapalıdır). Bu seçenek mevcut değilse, kilit Google Home'u desteklemeyecektir",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. Google Home uygulamasını yükleyin ve sol üst köşedeki artı düğmesini tıklayın",
|
||||
"暂无最新记录": "Şu anda en son kayıt mevcut değil",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Manuel bağlantı için lütfen telefonunuzu 2.4G WiFi'ye getirin"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Manuel bağlantı için lütfen telefonunuzu 2.4G WiFi'ye getirin",
|
||||
"语音包设置": "Ses Paketi Ayarları",
|
||||
"第三方平台设置": "Üçüncü Taraf Platform Ayarları",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Ses Paketi Ayarlarını Kilitle",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "Erkek Sesi",
|
||||
"女声": "Kadın Sesi"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. 在APP中開啓鎖的遠程開鎖功能(默認關閉)。如果這個選項不可用,鎖將不支持谷歌Home",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. 安裝谷歌Home應用程序並單擊左上角的加號按鈕",
|
||||
"暂无最新记录": "目前沒有最新的記錄",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "手動連接時請將手機調至2.4G WiFi"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "手動連接時請將手機調至2.4G WiFi",
|
||||
"语音包设置": "語音包設定",
|
||||
"第三方平台设置": "協力廠商領獎臺設定",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "鎖語音包設定",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "男聲",
|
||||
"女声": "女聲"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. Увімкніть функцію дистанційного розблокування замка в APP (ця функція вимкнена за замовчуванням). Якщо ця опція недоступна, замок не підтримуватиме Google Home",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. Встановіть програму Google Home і натисніть кнопку плюс у верхньому лівому кутку",
|
||||
"暂无最新记录": "Наразі немає останніх доступних записів",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Будь ласка, перемкніть свій телефон на 2.4G WiFi для ручного підключення"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Будь ласка, перемкніть свій телефон на 2.4G WiFi для ручного підключення",
|
||||
"语音包设置": "Параметри голосового пакету",
|
||||
"第三方平台设置": "Налаштування платформи третьої сторони",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Параметри блокування голосового пакету",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "Чоловічий голос",
|
||||
"女声": "жіночий голос"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. اے پی پی میں لاک کے ریموٹ ان لاکنگ فنکشن کو فعال کریں (یہ فنکشن ڈیفالٹ طور پر بند ہے)۔ اگر یہ آپشن دستیاب نہیں ہے تو ، لاک گوگل ہوم کو سپورٹ نہیں کرے گا۔",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. گوگل ہوم ایپ انسٹال کریں اور اوپری بائیں کونے میں پلس بٹن پر کلک کریں۔",
|
||||
"暂无最新记录": "فی الحال کوئی تازہ ترین ریکارڈ دستیاب نہیں ہے",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "براہ کرم دستی کنکشن کے لئے اپنے فون کو 2.4 جی وائی فائی پر سوئچ کریں"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "براہ کرم دستی کنکشن کے لئے اپنے فون کو 2.4 جی وائی فائی پر سوئچ کریں",
|
||||
"语音包设置": "صوتی پیکیج ترتیبات",
|
||||
"第三方平台设置": "تھرڈ پارٹی پلیٹ فارم کی ترتیبات",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "صوتی پیکیج کی ترتیبات لاک کریں",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "مردوں کی آواز",
|
||||
"女声": "خواتین کی آواز"
|
||||
}
|
||||
@ -1153,5 +1153,12 @@
|
||||
"2.在APP里开启锁的远程开锁功能(这个功能默认是关闭的)。如果没有这个选项,则锁不支持Google Home": "2. Kích hoạt chức năng mở khóa từ xa trong ứng dụng (chức năng này bị tắt theo mặc định). Nếu tùy chọn này không có sẵn, khóa sẽ không hỗ trợ Google Home",
|
||||
"3.安装Google Home APP,点击左上角的加号按钮": "3. Cài đặt ứng dụng Google Home và nhấn nút Plus ở góc trên bên trái",
|
||||
"暂无最新记录": "Hiện tại không có hồ sơ mới nhất",
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Vui lòng chuyển điện thoại sang 2.4G WiFi để kết nối bằng tay"
|
||||
"请将手机切换至2.4G WiFi进行手动连接": "Vui lòng chuyển điện thoại sang 2.4G WiFi để kết nối bằng tay",
|
||||
"语音包设置": "Thiết lập gói thoại",
|
||||
"第三方平台设置": "Cài đặt nền tảng của bên thứ ba",
|
||||
"涂鸦智能": "Tuya Smart",
|
||||
"锁语音包设置": "Khóa cài đặt gói thoại",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "Giọng nam",
|
||||
"女声": "Giọng nữ"
|
||||
}
|
||||
@ -1166,5 +1166,12 @@
|
||||
"请确认后再继续": "请确认后再继续",
|
||||
"需要相机权限": "需要相机权限",
|
||||
"一键登录": "一键登录",
|
||||
"网关添加成功": "网关添加成功"
|
||||
"网关添加成功": "网关添加成功",
|
||||
"第三方平台设置": "第三方平台设置",
|
||||
"涂鸦智能": "涂鸦智能",
|
||||
"锁语音包设置": "锁语音包设置",
|
||||
"语音包设置": "语音包设置",
|
||||
"(中国台湾)": "(中国台湾)",
|
||||
"男声": "男声",
|
||||
"女声": "女声"
|
||||
}
|
||||
|
||||
@ -71,21 +71,45 @@ class FirebaseHelper {
|
||||
}
|
||||
|
||||
Future<void> initSdk() async {
|
||||
FirebaseAnalytics.instance.setAnalyticsCollectionEnabled(true);
|
||||
const bool isProductVmMode = bool.fromEnvironment('dart.vm.product');
|
||||
if (F.isProductionEnv &&
|
||||
isProductVmMode &&
|
||||
defaultTargetPlatform == TargetPlatform.android) {
|
||||
FirebaseAnalytics.instance.setAnalyticsCollectionEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> login(String userId) async {
|
||||
FirebaseAnalytics.instance.setUserId(id: userId);
|
||||
const bool isProductVmMode = bool.fromEnvironment('dart.vm.product');
|
||||
if (F.isProductionEnv &&
|
||||
isProductVmMode &&
|
||||
defaultTargetPlatform == TargetPlatform.android) {
|
||||
FirebaseAnalytics.instance.setUserId(id: userId);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> trackEvent(
|
||||
String eventName, Map<String, Object>? parameters) async {
|
||||
FirebaseAnalytics.instance
|
||||
.logEvent(name: eventName, parameters: parameters);
|
||||
String eventName,
|
||||
Map<String, Object>? parameters,
|
||||
) async {
|
||||
const bool isProductVmMode = bool.fromEnvironment('dart.vm.product');
|
||||
if (F.isProductionEnv &&
|
||||
isProductVmMode &&
|
||||
defaultTargetPlatform == TargetPlatform.android) {
|
||||
FirebaseAnalytics.instance.logEvent(
|
||||
name: eventName,
|
||||
parameters: parameters,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> logout() async {
|
||||
FirebaseAnalytics.instance.setUserId(id: '');
|
||||
const bool isProductVmMode = bool.fromEnvironment('dart.vm.product');
|
||||
if (F.isProductionEnv &&
|
||||
isProductVmMode &&
|
||||
defaultTargetPlatform == TargetPlatform.android) {
|
||||
FirebaseAnalytics.instance.setUserId(id: '');
|
||||
}
|
||||
}
|
||||
}
|
||||
//</com>
|
||||
|
||||
@ -26,6 +26,8 @@ import 'package:star_lock/main/lockDetail/lockSet/faceUnlock/faceUnlock_page.dar
|
||||
import 'package:star_lock/main/lockDetail/lockSet/liveVideo/liveVideo_page.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockSet/motorPower/motorPower_page.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockSet/openDoorDirection/openDoorDirection_page.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockSet/speechLanguageSettings/speech_language_settings_page.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockSet/thirdPartyPlatform/third_party_platform_page.dart';
|
||||
import 'package:star_lock/main/lockDetail/messageWarn/addFamily/addFamily_page.dart';
|
||||
import 'package:star_lock/main/lockDetail/messageWarn/lockUser/lockUser_page.dart';
|
||||
import 'package:star_lock/main/lockDetail/messageWarn/msgNotification/coerceOpenDoor/coerceFingerprint/coerceFingerprint_page.dart';
|
||||
@ -41,6 +43,7 @@ import 'package:star_lock/main/lockDetail/palm/palmList/palmList_page.dart';
|
||||
import 'package:star_lock/main/lockDetail/passwordKey/passwordKeyDetailChangeDate/passwordKeyDetailChangeDate_page.dart';
|
||||
import 'package:star_lock/main/lockMian/lockMain/xhj/lockMain_xhj_page.dart';
|
||||
import 'package:star_lock/mine/about/webviewShow_page.dart';
|
||||
import 'package:star_lock/mine/addLock/lock_voice_setting/lock_voice_setting_page.dart';
|
||||
import 'package:star_lock/mine/mine/safeVerify/safeVerify_page.dart';
|
||||
import 'package:star_lock/mine/minePersonInfo/minePersonInfoEmail/mineBindPhoneOrEmail_page.dart';
|
||||
import 'package:star_lock/mine/minePersonInfo/minePersonInfoPage/minePersonInfo_entity.dart';
|
||||
@ -59,6 +62,7 @@ import 'package:star_lock/mine/mineSet/transferSmartLock/selectBranch/selectBran
|
||||
import 'package:star_lock/mine/mineSet/transferSmartLock/transferSmartLockList/transferSmartLock_page.dart';
|
||||
import 'package:star_lock/mine/valueAddedServices/advancedFeaturesWeb/advancedFeaturesWeb_page.dart';
|
||||
import 'package:star_lock/mine/valueAddedServices/advancedFunctionRecord/advancedFunctionRecord_page.dart';
|
||||
import 'package:star_lock/mine/valueAddedServices/cloudStorage/cloud_storage_page.dart';
|
||||
import 'package:star_lock/mine/valueAddedServices/valueAddedServicesRecord/value_added_services_record_page.dart';
|
||||
import 'package:star_lock/talk/starChart/views/guide/permission_guidance_page.dart';
|
||||
import 'package:star_lock/talk/starChart/views/native/talk_view_native_decode_page.dart';
|
||||
@ -368,6 +372,8 @@ abstract class Routers {
|
||||
'/valueAddedServicesRecordPage'; // 增值服务-记录
|
||||
static const String valueAddedServicesHighFunctionPage =
|
||||
'/ValueAddedServicesHighFunctionPage'; // 增值服务-高级功能
|
||||
static const String valueAddedCloudStoragePage =
|
||||
'/valueAddedCloudStoragePage'; // 增值服务-云存
|
||||
static const String valueAddedServicesBuyPage =
|
||||
'/ValueAddedServicesBuyPage'; // 增值服务-购买服务
|
||||
static const String customSMSTemplateListPage =
|
||||
@ -436,6 +442,10 @@ abstract class Routers {
|
||||
'/AddLockSelectCountryPage'; // 演示模式锁设置页
|
||||
static const String faceUnlockPage = '/faceUnlockPage'; //面容开锁设置
|
||||
static const String motorPowerPage = '/motorPowerPage'; //电机功率设置
|
||||
static const String speechLanguageSettingsPage =
|
||||
'/speechLanguageSettingsPage'; //锁语音包设置
|
||||
static const String thirdPartyPlatformPage =
|
||||
'/thirdPartyPlatformPage'; //第三方平台设置
|
||||
static const String openDoorDirectionPage = '/openDoorDirectionPage'; //开门方向设置
|
||||
static const String catEyeWorkModePage = '/catEyeWorkModePage'; //猫眼工作模式
|
||||
static const String msgNotificationPage = '/msgNotificationPage'; //消息提醒
|
||||
@ -521,6 +531,7 @@ abstract class Routers {
|
||||
'/imageTransmissionView'; //星图对讲页面(图传)
|
||||
static const String permissionGuidancePage =
|
||||
'/permissionGuidancePage'; // 锁屏权限通知引导页面
|
||||
static const String lockVoiceSettingPage = '/lockVoiceSetting'; // 锁屏权限通知引导页面
|
||||
}
|
||||
|
||||
abstract class AppRouters {
|
||||
@ -904,6 +915,10 @@ abstract class AppRouters {
|
||||
name: Routers.valueAddedServicesHighFunctionPage,
|
||||
page: () => const ValueAddedServicesHighFunctionPage(),
|
||||
),
|
||||
GetPage<dynamic>(
|
||||
name: Routers.valueAddedCloudStoragePage,
|
||||
page: () => const CloudStoragePage(),
|
||||
),
|
||||
GetPage<dynamic>(
|
||||
name: Routers.customSMSTemplateListPage,
|
||||
page: () => const CustomSMSTemplateListPage(),
|
||||
@ -1024,6 +1039,9 @@ abstract class AppRouters {
|
||||
name: Routers.faceUnlockPage, page: () => const FaceUnlockPage()),
|
||||
GetPage<dynamic>(
|
||||
name: Routers.motorPowerPage, page: () => const MotorPowerPage()),
|
||||
GetPage<dynamic>(
|
||||
name: Routers.speechLanguageSettingsPage,
|
||||
page: () => const SpeechLanguageSettingsPage()),
|
||||
GetPage<dynamic>(
|
||||
name: Routers.openDoorDirectionPage,
|
||||
page: () => const OpenDoorDirectionPage()),
|
||||
@ -1201,6 +1219,11 @@ abstract class AppRouters {
|
||||
GetPage<dynamic>(
|
||||
name: Routers.permissionGuidancePage,
|
||||
page: () => PermissionGuidancePage()),
|
||||
GetPage<dynamic>(
|
||||
name: Routers.lockVoiceSettingPage, page: () => LockVoiceSetting()),
|
||||
GetPage<dynamic>(
|
||||
name: Routers.thirdPartyPlatformPage,
|
||||
page: () => ThirdPartyPlatformPage()),
|
||||
// 插件播放页面
|
||||
// GetPage<dynamic>(name: Routers.h264View, page: () => H264WebView()), // webview播放页面
|
||||
];
|
||||
|
||||
@ -348,21 +348,43 @@ class BlueManage {
|
||||
} else {
|
||||
// 128位,判断前8位的第3、第4位
|
||||
if (cleanUuid.length >= 32) {
|
||||
final String thirdAndFourth = cleanUuid.substring(2, 4); // 索引2和3
|
||||
for (final prefix in prefixes) {
|
||||
if (thirdAndFourth == prefix) {
|
||||
if (isSingle) {
|
||||
return true; // isSingle为true,前缀匹配即返回true
|
||||
} else {
|
||||
// 判断配对状态(带横杠UUID的第31、32位,从1开始计数)
|
||||
if (cleanUuid.length >= 32) {
|
||||
String pairStatus =
|
||||
cleanUuid.substring(30, 32); // 第31、32位(从1开始计数)
|
||||
// 00=未配对,01=已配对
|
||||
if (pairStatus == '00') {
|
||||
return true; // 未配对才返回true
|
||||
if (deviceType == DeviceType.blue) {
|
||||
final String thirdAndFourth = cleanUuid.substring(6, 8); // 索引2和3
|
||||
for (final prefix in prefixes) {
|
||||
if (thirdAndFourth == prefix) {
|
||||
if (isSingle) {
|
||||
return true; // isSingle为true,前缀匹配即返回true
|
||||
} else {
|
||||
// 判断配对状态(带横杠UUID的第31、32位,从1开始计数)
|
||||
if (cleanUuid.length >= 32) {
|
||||
String pairStatus =
|
||||
cleanUuid.substring(30, 32); // 第31、32位(从1开始计数)
|
||||
// 00=未配对,01=已配对
|
||||
if (pairStatus == '00') {
|
||||
return true; // 未配对才返回true
|
||||
}
|
||||
// 已配对(01)不返回true,继续判断下一个uuid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (deviceType == DeviceType.gateway) {
|
||||
final String thirdAndFourth = cleanUuid.substring(6, 8); // 索引2和3
|
||||
for (final prefix in prefixes) {
|
||||
if (thirdAndFourth == prefix) {
|
||||
if (isSingle) {
|
||||
return true; // isSingle为true,前缀匹配即返回true
|
||||
} else {
|
||||
// 判断配对状态(带横杠UUID的第31、32位,从1开始计数)
|
||||
if (cleanUuid.length >= 32) {
|
||||
String pairStatus =
|
||||
cleanUuid.substring(30, 32); // 第31、32位(从1开始计数)
|
||||
// 00=未配对,01=已配对
|
||||
if (pairStatus == '00') {
|
||||
return true; // 未配对才返回true
|
||||
}
|
||||
// 已配对(01)不返回true,继续判断下一个uuid
|
||||
}
|
||||
// 已配对(01)不返回true,继续判断下一个uuid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
48
lib/blue/io_protocol/io_getDeviceModel.dart
Normal file
48
lib/blue/io_protocol/io_getDeviceModel.dart
Normal file
@ -0,0 +1,48 @@
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import '../io_reply.dart';
|
||||
import '../io_sender.dart';
|
||||
import '../io_tool/io_tool.dart';
|
||||
import '../io_type.dart';
|
||||
|
||||
class GetDeviceModelCommand extends SenderProtocol {
|
||||
GetDeviceModelCommand({
|
||||
this.lockID,
|
||||
}) : super(CommandType.getDeviceModel);
|
||||
String? lockID;
|
||||
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'GetDeviceModelCommand{lockID: $lockID}';
|
||||
}
|
||||
|
||||
@override
|
||||
List<int> messageDetail() {
|
||||
List<int> data = [];
|
||||
|
||||
// 指令类型
|
||||
final int type = commandType!.typeValue;
|
||||
final double typeDouble = type / 256;
|
||||
final int type1 = typeDouble.toInt();
|
||||
final int type2 = type % 256;
|
||||
data.add(type1);
|
||||
data.add(type2);
|
||||
|
||||
final int length = utf8.encode(lockID!).length;
|
||||
data.addAll(utf8.encode(lockID!));
|
||||
data = getFixedLengthList(data, 40 - length);
|
||||
|
||||
printLog(data);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class GetDeviceModelReply extends Reply {
|
||||
GetDeviceModelReply.parseData(CommandType commandType, List<int> dataDetail)
|
||||
: super.parseData(commandType, dataDetail) {
|
||||
status = dataDetail[2];
|
||||
data = dataDetail;
|
||||
}
|
||||
}
|
||||
163
lib/blue/io_protocol/io_voicePackageConfigure.dart
Normal file
163
lib/blue/io_protocol/io_voicePackageConfigure.dart
Normal file
@ -0,0 +1,163 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:crypto/crypto.dart' as crypto;
|
||||
|
||||
import '../io_reply.dart';
|
||||
import '../io_sender.dart';
|
||||
import '../io_tool/io_tool.dart';
|
||||
import '../io_type.dart';
|
||||
import '../sm4Encipher/sm4.dart';
|
||||
|
||||
//oat升级
|
||||
class VoicePackageConfigure extends SenderProtocol {
|
||||
VoicePackageConfigure(
|
||||
{this.lockID,
|
||||
this.userID,
|
||||
this.keyID,
|
||||
this.platform,
|
||||
this.product,
|
||||
this.fwSize,
|
||||
this.fwMD5,
|
||||
this.needAuthor,
|
||||
this.signKey,
|
||||
this.privateKey,
|
||||
this.token,
|
||||
this.encrypt = true})
|
||||
: super(CommandType.startVoicePackageConfigure);
|
||||
String? lockID;
|
||||
String? userID;
|
||||
String? keyID;
|
||||
int? platform;
|
||||
int? product;
|
||||
int? fwSize;
|
||||
String? fwMD5;
|
||||
int? needAuthor;
|
||||
List<int>? signKey;
|
||||
List<int>? privateKey;
|
||||
List<int>? token;
|
||||
bool encrypt;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'VoicePackageConfigure{lockID: $lockID, userID: $userID, '
|
||||
'keyID: $keyID, platform: $platform, product: $product, '
|
||||
' fwSize: $fwSize, '
|
||||
'fwMD5: $fwMD5, needAuthor: $needAuthor, signKey: $signKey, '
|
||||
'privateKey: $privateKey, token: $token}';
|
||||
}
|
||||
|
||||
@override
|
||||
int identifierValue() {
|
||||
if (encrypt) {
|
||||
return super.identifierValue();
|
||||
} else {
|
||||
return 0x20;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
List<int> messageDetail() {
|
||||
List<int> data = <int>[];
|
||||
List<int> ebcData = <int>[];
|
||||
|
||||
// 指令类型
|
||||
final int type = commandType!.typeValue;
|
||||
final double typeDouble = type / 256;
|
||||
final int type1 = typeDouble.toInt();
|
||||
final int type2 = type % 256;
|
||||
data.add(type1);
|
||||
data.add(type2);
|
||||
|
||||
// 锁id 40
|
||||
final int lockIDLength = utf8.encode(lockID!).length;
|
||||
data.addAll(utf8.encode(lockID!));
|
||||
data = getFixedLengthList(data, 40 - lockIDLength);
|
||||
|
||||
//userID 20
|
||||
final int userIDLength = utf8.encode(userID!).length;
|
||||
data.addAll(utf8.encode(userID!));
|
||||
data = getFixedLengthList(data, 20 - userIDLength);
|
||||
|
||||
//platform 2
|
||||
final int platform0 = (platform! & 0xFF00) >> 8;
|
||||
final int platform1 = platform! & 0xFF;
|
||||
data.add(platform0);
|
||||
data.add(platform1);
|
||||
|
||||
//product 2
|
||||
data.addAll(<int>[0, 1]); //先默认是 01
|
||||
|
||||
|
||||
//fwSize 4
|
||||
final ByteData bytes = ByteData(4); // 创建一个长度为4的字节数据
|
||||
bytes.setInt32(0, fwSize!);
|
||||
final List<int> byteList = bytes.buffer.asUint8List();
|
||||
data.addAll(byteList);
|
||||
|
||||
// 创建一个16字节的字节数组
|
||||
final Uint8List result = Uint8List(16);
|
||||
// 将每个十六进制字符转换为4位二进制数据,并将其存储到结果字节数组中
|
||||
for (int i = 0; i < fwMD5!.length; i += 2) {
|
||||
final String hex = fwMD5!.substring(i, i + 2);
|
||||
final int byteValue = int.parse(hex, radix: 16);
|
||||
result[i ~/ 2] = byteValue;
|
||||
}
|
||||
data.addAll(result);
|
||||
// token 长度4 首次请求 Token 填 0,如果锁需要鉴权 操作者身份,则会分配动态口令并在应答消息中返回,二次请求时带上。 当token失效或者第一次发送的时候token为0
|
||||
data.addAll(token!);
|
||||
if (needAuthor == 0) {
|
||||
//AuthCodeLen 1
|
||||
data.add(0);
|
||||
} else {
|
||||
final List<int> authCodeData = <int>[];
|
||||
|
||||
//KeyID
|
||||
authCodeData.addAll(utf8.encode(keyID!));
|
||||
|
||||
//UserID
|
||||
authCodeData.addAll(utf8.encode(userID!));
|
||||
|
||||
//token 4 首次请求 Token 填 0,如果锁需要鉴权操作者身份,则会分配动态口令并在应答消息中返回,二次请求时带上。
|
||||
authCodeData.addAll(token ?? <int>[]);
|
||||
|
||||
authCodeData.addAll(signKey ?? <int>[]);
|
||||
|
||||
// 把KeyID、authUserID、时间戳、公钥通过md5加密之后就是authCode
|
||||
final crypto.Digest authCode = crypto.md5.convert(authCodeData);
|
||||
|
||||
data.add(authCode.bytes.length);
|
||||
data.addAll(authCode.bytes);
|
||||
}
|
||||
|
||||
if ((data.length % 16) != 0) {
|
||||
final int add = 16 - data.length % 16;
|
||||
for (int i = 0; i < add; i++) {
|
||||
data.add(0);
|
||||
}
|
||||
}
|
||||
printLog(data);
|
||||
|
||||
if (encrypt) {
|
||||
// 拿到数据之后通过LockId进行SM4 ECB加密 key:544d485f633335373034383064613864
|
||||
ebcData = SM4.encrypt(data, key: privateKey, mode: SM4CryptoMode.ECB);
|
||||
return ebcData;
|
||||
} else {
|
||||
data.add(0);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class VoicePackageConfigureReply extends Reply {
|
||||
VoicePackageConfigureReply.parseData(
|
||||
CommandType commandType, List<int> dataDetail)
|
||||
: super.parseData(commandType, dataDetail) {
|
||||
data = dataDetail;
|
||||
token = data.sublist(2, 6);
|
||||
status = data[6];
|
||||
errorWithStstus(status);
|
||||
}
|
||||
|
||||
List<int> token = <int>[];
|
||||
}
|
||||
73
lib/blue/io_protocol/io_voicePackageConfigureProcess.dart
Normal file
73
lib/blue/io_protocol/io_voicePackageConfigureProcess.dart
Normal file
@ -0,0 +1,73 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import '../io_reply.dart';
|
||||
import '../io_sender.dart';
|
||||
import '../io_type.dart';
|
||||
|
||||
//oat升级
|
||||
class VoicePackageConfigureProcess extends SenderProtocol {
|
||||
VoicePackageConfigureProcess({
|
||||
this.index,
|
||||
this.size,
|
||||
this.data,
|
||||
}) : super(CommandType.voicePackageConfigureProcess);
|
||||
int? index;
|
||||
int? size;
|
||||
List<int>? data;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'VoicePackageConfigureProcess{index: $index, size: $size, data: $data}';
|
||||
}
|
||||
|
||||
@override
|
||||
List<int> messageDetail() {
|
||||
final List<int> data = [];
|
||||
|
||||
// 指令类型
|
||||
final int type = commandType!.typeValue;
|
||||
final double typeDouble = type / 256;
|
||||
final int type1 = typeDouble.toInt();
|
||||
final int type2 = type % 256;
|
||||
data.add(type1);
|
||||
data.add(type2);
|
||||
|
||||
//index 2
|
||||
final ByteData indexBytes = ByteData(2); // 创建一个长度为4的字节数据
|
||||
indexBytes.setInt16(0, index!);
|
||||
final List<int> indexList = indexBytes.buffer.asUint8List();
|
||||
data.addAll(indexList);
|
||||
|
||||
//size 2
|
||||
final ByteData bytes = ByteData(2); // 创建一个长度为4的字节数据
|
||||
bytes.setInt16(0, size!);
|
||||
final List<int> byteList = bytes.buffer.asUint8List();
|
||||
data.addAll(byteList);
|
||||
|
||||
data.addAll(this.data!);
|
||||
|
||||
printLog(data);
|
||||
//不加密
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class VoicePackageConfigureProcessReply extends Reply {
|
||||
VoicePackageConfigureProcessReply.parseData(
|
||||
CommandType commandType, List<int> dataDetail)
|
||||
: super.parseData(commandType, dataDetail) {
|
||||
data = dataDetail;
|
||||
status = data[2];
|
||||
errorWithStstus(status);
|
||||
}
|
||||
}
|
||||
|
||||
class VoicePackageConfigureConfirmationReply extends Reply {
|
||||
VoicePackageConfigureConfirmationReply.parseData(
|
||||
CommandType commandType, List<int> dataDetail)
|
||||
: super.parseData(commandType, dataDetail) {
|
||||
data = dataDetail;
|
||||
status = data[2];
|
||||
errorWithStstus(status);
|
||||
}
|
||||
}
|
||||
@ -288,16 +288,27 @@ String asciiString(List<int> codeUnits) {
|
||||
}
|
||||
|
||||
String utf8String(List<int> codeUnits) {
|
||||
codeUnits.reversed;
|
||||
final List<int> uniqueList = <int>[];
|
||||
for (int i = 0; i < codeUnits.length; i++) {
|
||||
if (codeUnits[i] != 0) {
|
||||
uniqueList.add(codeUnits[i]);
|
||||
}
|
||||
try {
|
||||
// 只去除结尾的0(常见填充方式)
|
||||
int realLen = codeUnits.indexWhere((b) => b == 0);
|
||||
List<int> validBytes = (realLen == -1) ? codeUnits : codeUnits.sublist(0, realLen);
|
||||
return utf8.decode(validBytes);
|
||||
} catch (e) {
|
||||
// 容错处理
|
||||
return '';
|
||||
}
|
||||
uniqueList.reversed;
|
||||
return utf8.decode(uniqueList).toString();
|
||||
}
|
||||
// String utf8String(List<int> codeUnits) {
|
||||
// codeUnits.reversed;
|
||||
// final List<int> uniqueList = <int>[];
|
||||
// for (int i = 0; i < codeUnits.length; i++) {
|
||||
// if (codeUnits[i] != 0) {
|
||||
// uniqueList.add(codeUnits[i]);
|
||||
// }
|
||||
// }
|
||||
// uniqueList.reversed;
|
||||
// return utf8.decode(uniqueList).toString();
|
||||
// }
|
||||
|
||||
bool compareTwoList({List<int>? list1, List<int>? list2}) {
|
||||
if (list1!.length != list2!.length) {
|
||||
|
||||
@ -9,10 +9,10 @@ List<String> getDeviceType(DeviceType deviceType) {
|
||||
List<String> t = ['758824'];
|
||||
switch (deviceType) {
|
||||
case DeviceType.blue:
|
||||
t = ['758824', '75', '768824', '76'];
|
||||
t = ['758824', '75', '768824', '76','24'];
|
||||
break;
|
||||
case DeviceType.gateway:
|
||||
t = ['758825'];
|
||||
t = ['758825','25'];
|
||||
break;
|
||||
}
|
||||
return t;
|
||||
@ -41,6 +41,10 @@ enum CommandType {
|
||||
startOATUpgrade, //OTA升级开始 0x30E0
|
||||
processOTAUpgrade, //OTA升级过程 0x30E1
|
||||
confirmationOTAUpgrade, //OTA升级确认 0x30E2
|
||||
startVoicePackageConfigure, //语音包配置开始 0x30A1
|
||||
voicePackageConfigureProcess, //语音包配置过程 0x30A2
|
||||
voicePackageConfigureConfirmation, //语音包配置确认 0x30A3
|
||||
getDeviceModel, //获取设备型号 0x30A4
|
||||
|
||||
gatewayConfiguringWifi, //网关配网 0x30F4
|
||||
gatewayConfiguringWifiResult, //网关配网结果 0x30F5
|
||||
@ -189,6 +193,26 @@ extension ExtensionCommandType on CommandType {
|
||||
type = CommandType.confirmationOTAUpgrade;
|
||||
}
|
||||
break;
|
||||
case 0x30A1:
|
||||
{
|
||||
type = CommandType.startVoicePackageConfigure;
|
||||
}
|
||||
break;
|
||||
case 0x30A2:
|
||||
{
|
||||
type = CommandType.voicePackageConfigureProcess;
|
||||
}
|
||||
break;
|
||||
case 0x30A3:
|
||||
{
|
||||
type = CommandType.voicePackageConfigureConfirmation;
|
||||
}
|
||||
break;
|
||||
case 0x30A4:
|
||||
{
|
||||
type = CommandType.getDeviceModel;
|
||||
}
|
||||
break;
|
||||
case 0x30F4:
|
||||
{
|
||||
type = CommandType.gatewayConfiguringWifi;
|
||||
@ -307,6 +331,18 @@ extension ExtensionCommandType on CommandType {
|
||||
case CommandType.gatewayGetStatus:
|
||||
type = 0x30F8;
|
||||
break;
|
||||
case CommandType.startVoicePackageConfigure:
|
||||
type = 0x30A1;
|
||||
break;
|
||||
case CommandType.voicePackageConfigureProcess:
|
||||
type = 0x30A2;
|
||||
break;
|
||||
case CommandType.voicePackageConfigureConfirmation:
|
||||
type = 0x30A3;
|
||||
break;
|
||||
case CommandType.getDeviceModel:
|
||||
type = 0x30A4;
|
||||
break;
|
||||
default:
|
||||
type = 0x300A;
|
||||
break;
|
||||
@ -322,9 +358,11 @@ extension ExtensionCommandType on CommandType {
|
||||
switch (this) {
|
||||
case CommandType.getLockPublicKey:
|
||||
case CommandType.processOTAUpgrade:
|
||||
case CommandType.voicePackageConfigureProcess:
|
||||
case CommandType.gatewayGetWifiList:
|
||||
case CommandType.gatewayConfiguringWifi:
|
||||
case CommandType.gatewayGetStatus:
|
||||
case CommandType.getDeviceModel:
|
||||
//不加密
|
||||
type = 0x20;
|
||||
break;
|
||||
@ -428,6 +466,18 @@ extension ExtensionCommandType on CommandType {
|
||||
case 0x30F8:
|
||||
t = '获取网关状态';
|
||||
break;
|
||||
case 0x30A1:
|
||||
t = '语音包配置开始';
|
||||
break;
|
||||
case 0x30A2:
|
||||
t = '语音包配置过程';
|
||||
break;
|
||||
case 0x30A3:
|
||||
t = '语音包配置确认';
|
||||
break;
|
||||
case 0x30A4:
|
||||
t = '获取设备型号';
|
||||
break;
|
||||
default:
|
||||
t = '读星锁状态信息';
|
||||
break;
|
||||
|
||||
@ -12,6 +12,7 @@ import 'package:star_lock/blue/io_protocol/io_cleanUpUsers.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_deletUser.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_editUser.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_factoryDataReset.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_getDeviceModel.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_otaUpgrade.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_processOtaUpgrade.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_readAdminPassword.dart';
|
||||
@ -21,6 +22,8 @@ import 'package:star_lock/blue/io_protocol/io_referEventRecordTime.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_setSupportFunctionsNoParameters.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_setSupportFunctionsWithParameters.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_timing.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_voicePackageConfigure.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_voicePackageConfigureProcess.dart';
|
||||
|
||||
import '../tools/storage.dart';
|
||||
import 'io_gateway/io_gateway_getStatus.dart';
|
||||
@ -292,6 +295,28 @@ class CommandReciverManager {
|
||||
reply = GatewayGetStatusReply.parseData(commandType, data);
|
||||
}
|
||||
break;
|
||||
case CommandType.getDeviceModel:
|
||||
{
|
||||
reply = GetDeviceModelReply.parseData(commandType, data);
|
||||
}
|
||||
break;
|
||||
case CommandType.startVoicePackageConfigure:
|
||||
{
|
||||
reply = VoicePackageConfigureReply.parseData(commandType, data);
|
||||
}
|
||||
break;
|
||||
case CommandType.voicePackageConfigureProcess:
|
||||
{
|
||||
reply =
|
||||
VoicePackageConfigureProcessReply.parseData(commandType, data);
|
||||
}
|
||||
break;
|
||||
case CommandType.voicePackageConfigureConfirmation:
|
||||
{
|
||||
reply = VoicePackageConfigureConfirmationReply.parseData(
|
||||
commandType, data);
|
||||
}
|
||||
break;
|
||||
case CommandType.generalExtendedCommond:
|
||||
{
|
||||
// 子命令类型
|
||||
|
||||
@ -90,6 +90,7 @@ class XSConstantMacro {
|
||||
static int webBuyTypeVip = 3; //VIP购买
|
||||
static int webBuyTypeAuth = 4; //实名购买
|
||||
static int webBuyTypeShop = 5; //商城购买
|
||||
static int webBuyTypeCloudStorage = 6; //云存购买
|
||||
|
||||
//设备类型信息
|
||||
Future<Map<String, dynamic>> getDeviceInfoData() async {
|
||||
|
||||
@ -783,7 +783,7 @@ class LockDetailLogic extends BaseGetXController {
|
||||
// }
|
||||
|
||||
/// 发送监控消息
|
||||
void sendMonitorMessage() {
|
||||
void sendMonitorMessage() async {
|
||||
final catEyeConfig = state.keyInfos.value.lockSetting?.catEyeConfig ?? [];
|
||||
final network = state.keyInfos.value.network;
|
||||
if (catEyeConfig.isNotEmpty &&
|
||||
@ -840,24 +840,48 @@ class LockDetailLogic extends BaseGetXController {
|
||||
state.DetailLockInfo = eventBus
|
||||
.on<PassCurrentLockInformationEvent>()
|
||||
.listen((PassCurrentLockInformationEvent event) {
|
||||
if (event.lockSetInfoData.lockSettingInfo != null &&
|
||||
event.lockSetInfoData.lockSettingInfo!.catEyeConfig != null &&
|
||||
event.lockSetInfoData.lockSettingInfo!.catEyeConfig!.length > 0) {
|
||||
if (state.keyInfos.value.lockSetting!.catEyeConfig == null ||
|
||||
state.keyInfos.value.lockSetting!.catEyeConfig!.length == 0) {
|
||||
state.keyInfos.value.lockSetting!.catEyeConfig!.add(CatEyeConfig(
|
||||
// 提取重复表达式为局部变量,避免多次解包
|
||||
final lockSettingInfo = event.lockSetInfoData.lockSettingInfo;
|
||||
final lockBasicInfo = event.lockSetInfoData.lockBasicInfo;
|
||||
final networkInfo = lockBasicInfo?.networkInfo;
|
||||
final targetCatEyeConfig = lockSettingInfo?.catEyeConfig;
|
||||
|
||||
if (lockBasicInfo != null && networkInfo != null) {
|
||||
state.keyInfos.value.network?.peerId = networkInfo.peerId;
|
||||
state.keyInfos.value.network?.wifiName = networkInfo.wifiName;
|
||||
}
|
||||
|
||||
// 检查前置条件:事件数据有效且 catEyeConfig 非空且非空列表
|
||||
if (lockSettingInfo != null &&
|
||||
targetCatEyeConfig != null &&
|
||||
targetCatEyeConfig.isNotEmpty) {
|
||||
// 当前状态的 catEyeConfig
|
||||
final stateCatEyeConfig =
|
||||
state.keyInfos.value.lockSetting?.catEyeConfig;
|
||||
|
||||
// 如果状态中的 catEyeConfig 为空或空列表,则初始化默认配置
|
||||
if (stateCatEyeConfig == null || stateCatEyeConfig.isEmpty) {
|
||||
state.keyInfos.value.lockSetting?.catEyeConfig ??= [];
|
||||
state.keyInfos.value.lockSetting!.catEyeConfig!.add(
|
||||
CatEyeConfig(
|
||||
catEyeMode: 0,
|
||||
catEyeModeConfig: CatEyeModeConfig(
|
||||
realTimeMode: 0,
|
||||
recordEndTime: 0,
|
||||
recordMode: 0,
|
||||
recordStartTime: 0,
|
||||
recordTime: '0',
|
||||
detectionDistance: '0')));
|
||||
realTimeMode: 0,
|
||||
recordEndTime: 0,
|
||||
recordMode: 0,
|
||||
recordStartTime: 0,
|
||||
recordTime: '0',
|
||||
detectionDistance: '0',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
state.keyInfos.value.lockSetting!.catEyeConfig![0].catEyeMode = event
|
||||
.lockSetInfoData.lockSettingInfo!.catEyeConfig![0].catEyeMode ??
|
||||
1;
|
||||
|
||||
// 更新 catEyeMode,使用空值合并提供默认值 1
|
||||
state.keyInfos.value.lockSetting!.catEyeConfig![0].catEyeMode =
|
||||
targetCatEyeConfig[0].catEyeMode ?? 1;
|
||||
|
||||
// 刷新状态
|
||||
state.keyInfos.refresh();
|
||||
}
|
||||
});
|
||||
|
||||
296
lib/main/lockDetail/lockDetail/passthrough_item.dart
Normal file
296
lib/main/lockDetail/lockDetail/passthrough_item.dart
Normal file
@ -0,0 +1,296 @@
|
||||
// 音色项类
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class TimbreItem {
|
||||
final String timbre;
|
||||
final String name;
|
||||
final String timbrePackUrl;
|
||||
final int isFemale;
|
||||
|
||||
TimbreItem({
|
||||
required this.timbre,
|
||||
required this.name,
|
||||
required this.timbrePackUrl,
|
||||
required this.isFemale,
|
||||
});
|
||||
|
||||
factory TimbreItem.fromJson(Map<String, dynamic> json) {
|
||||
return TimbreItem(
|
||||
timbre: json['timbre'] ?? '',
|
||||
name: json['name'] ?? '',
|
||||
timbrePackUrl: json['timbrePackUrl'] ?? '',
|
||||
isFemale: json['isFemale'] ?? 0,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'timbre': timbre,
|
||||
'name': name,
|
||||
'timbrePackUrl': timbrePackUrl,
|
||||
'isFemale': isFemale,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'TimbreItem{timbre: $timbre, name: $name, timbrePackUrl: '
|
||||
'$timbrePackUrl},isFemale: $isFemale}';
|
||||
}
|
||||
}
|
||||
|
||||
// 透传项主类
|
||||
class PassthroughItem {
|
||||
final String lang;
|
||||
final String langText;
|
||||
final String name;
|
||||
final List<TimbreItem> timbres;
|
||||
|
||||
PassthroughItem({
|
||||
required this.lang,
|
||||
required this.timbres,
|
||||
required this.langText,
|
||||
required this.name,
|
||||
});
|
||||
|
||||
factory PassthroughItem.fromJson(Map<String, dynamic> json) {
|
||||
var timbresJson = json['timbres'] as List<dynamic>?;
|
||||
List<TimbreItem> timbresList = timbresJson != null
|
||||
? timbresJson
|
||||
.map((e) => TimbreItem.fromJson(e as Map<String, dynamic>))
|
||||
.toList()
|
||||
: <TimbreItem>[];
|
||||
return PassthroughItem(
|
||||
lang: json['lang'] ?? '',
|
||||
langText: json['langText'] ?? '',
|
||||
name: json['name'] ?? '',
|
||||
timbres: timbresList,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'lang': lang,
|
||||
'langText': langText,
|
||||
'name': name,
|
||||
'timbres': timbres.map((e) => e.toJson()).toList(),
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'PassthroughItem{lang: $lang, name: $name, timbres: $timbres, '
|
||||
'langText: '
|
||||
'$langText}';
|
||||
}
|
||||
}
|
||||
|
||||
class PassthroughListResponse {
|
||||
PassthroughListResponse({
|
||||
this.description,
|
||||
this.errorCode,
|
||||
this.data,
|
||||
this.errorMsg,
|
||||
});
|
||||
|
||||
String? description;
|
||||
int? errorCode;
|
||||
List<PassthroughItem>? data;
|
||||
String? errorMsg;
|
||||
|
||||
PassthroughListResponse.fromJson(dynamic json) {
|
||||
description = json['description'];
|
||||
errorCode = json['errorCode'];
|
||||
if (json['data'] != null && json['data'] is List) {
|
||||
data = (json['data'] as List)
|
||||
.map((e) => PassthroughItem.fromJson(e as Map<String, dynamic>))
|
||||
.toList();
|
||||
} else {
|
||||
data = null;
|
||||
}
|
||||
errorMsg = json['errorMsg'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final map = <String, dynamic>{};
|
||||
map['description'] = description;
|
||||
map['errorCode'] = errorCode;
|
||||
if (data != null) {
|
||||
map['data'] = data!.map((e) => e.toJson()).toList();
|
||||
}
|
||||
map['errorMsg'] = errorMsg;
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
/// 工具方法:通过语言编码获取本地化文本
|
||||
/// 例如:'zh_CN' -> '简体中文'.tr,'en_US' -> '英文'.tr
|
||||
class PassthroughLangHelper {
|
||||
static String getLangText(String langCode) {
|
||||
switch (langCode.toLowerCase()) {
|
||||
case 'zh_cn':
|
||||
return '简体中文'.tr;
|
||||
case 'zh_tw':
|
||||
return '繁体中文(中国台湾)'.tr;
|
||||
case 'zh_hk':
|
||||
return '繁体中文(中国香港)'.tr;
|
||||
case 'en_us':
|
||||
return '英文'.tr;
|
||||
case 'fr_fr':
|
||||
return '法语'.tr;
|
||||
case 'ru_ru':
|
||||
return '俄语'.tr;
|
||||
case 'de_de':
|
||||
return '德语'.tr;
|
||||
case 'ja_jp':
|
||||
return '日语'.tr;
|
||||
case 'ko_kr':
|
||||
return '韩语'.tr;
|
||||
case 'it_it':
|
||||
return '意大利语'.tr;
|
||||
case 'pt_pt':
|
||||
return '葡萄牙语'.tr;
|
||||
case 'es_es':
|
||||
return '西班牙语'.tr;
|
||||
case 'ar_sa':
|
||||
return '阿拉伯语'.tr;
|
||||
case 'vi_vn':
|
||||
return '越南语'.tr;
|
||||
case 'ms_my':
|
||||
return '马来语'.tr;
|
||||
case 'nl_nl':
|
||||
return '荷兰语'.tr;
|
||||
case 'ro_ro':
|
||||
return '罗马尼亚语'.tr;
|
||||
case 'lt_lt':
|
||||
return '立陶宛语'.tr;
|
||||
case 'sv_se':
|
||||
return '瑞典语'.tr;
|
||||
case 'et_ee':
|
||||
return '爱沙尼亚语'.tr;
|
||||
case 'pl_pl':
|
||||
return '波兰语'.tr;
|
||||
case 'sk_sk':
|
||||
return '斯洛伐克语'.tr;
|
||||
case 'cs_cz':
|
||||
return '捷克语'.tr;
|
||||
case 'el_gr':
|
||||
return '希腊语'.tr;
|
||||
case 'he_il':
|
||||
return '希伯来语'.tr;
|
||||
case 'sr_rs':
|
||||
return '塞尔维亚语'.tr;
|
||||
case 'tr_tr':
|
||||
return '土耳其语'.tr;
|
||||
case 'hu_hu':
|
||||
return '匈牙利语'.tr;
|
||||
case 'bg_bg':
|
||||
return '保加利亚语'.tr;
|
||||
case 'kk_kz':
|
||||
return '哈萨克斯坦语'.tr;
|
||||
case 'bn_bd':
|
||||
return '孟加拉语'.tr;
|
||||
case 'hr_hr':
|
||||
return '克罗地亚语'.tr;
|
||||
case 'th_th':
|
||||
return '泰语'.tr;
|
||||
case 'id_id':
|
||||
return '印度尼西亚语'.tr;
|
||||
case 'fi_fi':
|
||||
return '芬兰语'.tr;
|
||||
case 'da_dk':
|
||||
return '丹麦语'.tr;
|
||||
case 'uk_ua':
|
||||
return '乌克兰语'.tr;
|
||||
case 'hi_in':
|
||||
return '印地语'.tr;
|
||||
case 'ur_pk':
|
||||
return '乌尔都语'.tr;
|
||||
case 'hy_am':
|
||||
return '亚美尼亚语'.tr;
|
||||
case 'ka_ge':
|
||||
return '格鲁吉亚语'.tr;
|
||||
default:
|
||||
return '未知语言'.tr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ValidityPeriodResponse {
|
||||
ValidityPeriodResponse({
|
||||
this.description,
|
||||
this.errorCode,
|
||||
this.data,
|
||||
this.errorMsg,
|
||||
});
|
||||
|
||||
String? description;
|
||||
int? errorCode;
|
||||
ValidityPeriod? data;
|
||||
String? errorMsg;
|
||||
|
||||
ValidityPeriodResponse.fromJson(dynamic json) {
|
||||
description = json['description'];
|
||||
errorCode = json['errorCode'];
|
||||
if (json['data'] != null) {
|
||||
data = ValidityPeriod.fromJson(json['data']);
|
||||
} else {
|
||||
data = null;
|
||||
}
|
||||
errorMsg = json['errorMsg'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final map = <String, dynamic>{};
|
||||
map['description'] = description;
|
||||
map['errorCode'] = errorCode;
|
||||
if (data != null) {
|
||||
map['data'] = data!.toJson();
|
||||
}
|
||||
map['errorMsg'] = errorMsg;
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
class ValidityPeriod {
|
||||
final int lockId;
|
||||
final int status;
|
||||
final String validityPeriodStart;
|
||||
final String validityPeriodEnd;
|
||||
final int rollingStorageDays;
|
||||
final int remainingDays;
|
||||
|
||||
ValidityPeriod({
|
||||
required this.lockId,
|
||||
required this.status,
|
||||
required this.validityPeriodStart,
|
||||
required this.validityPeriodEnd,
|
||||
required this.rollingStorageDays,
|
||||
required this.remainingDays,
|
||||
});
|
||||
|
||||
// 反序列化方法
|
||||
factory ValidityPeriod.fromJson(Map<String, dynamic> json) {
|
||||
return ValidityPeriod(
|
||||
lockId: json['lockId'] as int? ?? 0,
|
||||
// 默认值为 0
|
||||
status: json['status'] as int? ?? 0,
|
||||
validityPeriodStart: json['validityPeriodStart'] as String? ?? '',
|
||||
validityPeriodEnd: json['validityPeriodEnd'] as String? ?? '',
|
||||
rollingStorageDays: json['rollingStorageDays'] as int? ?? 0,
|
||||
remainingDays: json['remainingDays'] as int? ?? 0,
|
||||
);
|
||||
}
|
||||
|
||||
// 序列化方法
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'lockId': lockId,
|
||||
'status': status,
|
||||
'validityPeriodStart': validityPeriodStart,
|
||||
'validityPeriodEnd': validityPeriodEnd,
|
||||
'rollingStorageDays': rollingStorageDays,
|
||||
'remainingDays': remainingDays,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -161,11 +161,12 @@ class ConfiguringWifiLogic extends BaseGetXController {
|
||||
|
||||
// 上报服务器 - 注意: sureBtnState 状态将在 updateNetworkInfo 方法中或其回调中完成重置
|
||||
final info = await updateNetworkInfo(
|
||||
peerId: peerId,
|
||||
wifiName: wifiName ?? '',
|
||||
secretKey: secretKey,
|
||||
deviceMac: deviceMac ?? '',
|
||||
networkMac: networkMac ?? '');
|
||||
peerId: peerId,
|
||||
wifiName: wifiName ?? '',
|
||||
secretKey: secretKey,
|
||||
deviceMac: deviceMac ?? '',
|
||||
networkMac: networkMac ?? '',
|
||||
);
|
||||
if (info.errorCode!.codeIsSuccessful) {
|
||||
// 设置锁的peerID
|
||||
StartChartManage().lockNetworkInfo = DeviceNetworkInfo(
|
||||
@ -175,6 +176,11 @@ class ConfiguringWifiLogic extends BaseGetXController {
|
||||
peerId: peerId,
|
||||
);
|
||||
|
||||
state.lockSetInfoData.value?.lockBasicInfo?.networkInfo?.peerId =
|
||||
peerId;
|
||||
state.lockSetInfoData.value?.lockBasicInfo?.networkInfo?.wifiName =
|
||||
wifiName;
|
||||
|
||||
/// 配网成功后,赋值锁的peerId
|
||||
StartChartManage().lockPeerId = peerId;
|
||||
|
||||
@ -189,7 +195,9 @@ class ConfiguringWifiLogic extends BaseGetXController {
|
||||
Get.offAllNamed(Routers.starLockMain);
|
||||
}
|
||||
eventBus.fire(SuccessfulDistributionNetwork());
|
||||
eventBus.fire(RefreshLockListInfoDataEvent(clearScanDevices: true,isUnShowLoading: true));
|
||||
eventBus.fire(RefreshLockListInfoDataEvent(
|
||||
clearScanDevices: true, isUnShowLoading: true));
|
||||
eventBus.fire(RefreshLockDetailInfoDataEvent());
|
||||
});
|
||||
|
||||
// 获取锁设置
|
||||
@ -589,7 +597,6 @@ class ConfiguringWifiLogic extends BaseGetXController {
|
||||
recordType: recordType,
|
||||
records: records,
|
||||
isUnShowLoading: true);
|
||||
|
||||
if (entity.errorCode!.codeIsSuccessful) {
|
||||
eventBus
|
||||
.fire(PassCurrentLockInformationEvent(state.lockSetInfoData.value));
|
||||
|
||||
@ -158,6 +158,7 @@ class LockFeature {
|
||||
this.isElectronicAntiLock,
|
||||
this.isVisualDoorBellCode,
|
||||
this.isDoubleLockLinkage,
|
||||
this.languageSpeech,
|
||||
});
|
||||
|
||||
LockFeature.fromJson(Map<String, dynamic> json) {
|
||||
@ -218,6 +219,7 @@ class LockFeature {
|
||||
isElectronicAntiLock = json['isElectronicAntiLock'];
|
||||
isVisualDoorBellCode = json['isVisualDoorBellCode'];
|
||||
isDoubleLockLinkage = json['isDoubleLockLinkage'];
|
||||
languageSpeech = json['languageSpeech'];
|
||||
}
|
||||
|
||||
int? password;
|
||||
@ -277,6 +279,7 @@ class LockFeature {
|
||||
int? isElectronicAntiLock;
|
||||
int? isVisualDoorBellCode;
|
||||
int? isDoubleLockLinkage;
|
||||
int? languageSpeech;
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
@ -337,6 +340,7 @@ class LockFeature {
|
||||
data['isElectronicAntiLock'] = isElectronicAntiLock;
|
||||
data['isVisualDoorBellCode'] = isVisualDoorBellCode;
|
||||
data['isDoubleLockLinkage'] = isDoubleLockLinkage;
|
||||
data['languageSpeech'] = languageSpeech;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@ -348,6 +352,8 @@ class LockBasicInfo {
|
||||
this.keyId,
|
||||
this.model,
|
||||
this.electricQuantity,
|
||||
this.hwVersion,
|
||||
this.fwVersion,
|
||||
this.electricQuantityStandby,
|
||||
this.indate,
|
||||
this.isLockOwner,
|
||||
@ -376,6 +382,8 @@ class LockBasicInfo {
|
||||
keyId = json['keyId'];
|
||||
model = json['model'];
|
||||
electricQuantity = json['electricQuantity'];
|
||||
hwVersion = json['hwVersion'];
|
||||
fwVersion = json['fwVersion'];
|
||||
electricQuantityStandby = json['electricQuantityStandby'];
|
||||
indate = json['indate'];
|
||||
isLockOwner = json['isLockOwner'];
|
||||
@ -411,6 +419,8 @@ class LockBasicInfo {
|
||||
int? keyId;
|
||||
String? model;
|
||||
int? electricQuantity;
|
||||
String? fwVersion;
|
||||
String? hwVersion;
|
||||
int? electricQuantityStandby;
|
||||
int? indate;
|
||||
int? isLockOwner;
|
||||
@ -440,6 +450,8 @@ class LockBasicInfo {
|
||||
data['keyId'] = keyId;
|
||||
data['model'] = model;
|
||||
data['electricQuantity'] = electricQuantity;
|
||||
data['hwVersion'] = hwVersion;
|
||||
data['fwVersion'] = fwVersion;
|
||||
data['electricQuantityStandby'] = electricQuantityStandby;
|
||||
data['indate'] = indate;
|
||||
data['isLockOwner'] = isLockOwner;
|
||||
@ -523,6 +535,7 @@ class LockSettingInfo {
|
||||
this.autoLightScreen,
|
||||
this.autoLightScreenTime,
|
||||
this.faceEnErrUnlock,
|
||||
this.currentVoiceTimbre,
|
||||
});
|
||||
|
||||
LockSettingInfo.fromJson(Map<String, dynamic> json) {
|
||||
@ -570,6 +583,10 @@ class LockSettingInfo {
|
||||
autoLightScreen = json['autoLightScreen'];
|
||||
autoLightScreenTime = json['autoLightScreenTime'];
|
||||
faceEnErrUnlock = json['faceEnErrUnlock'];
|
||||
if (json['currentVoiceTimbre'] != null) {
|
||||
currentVoiceTimbre =
|
||||
CurrentVoiceTimbre.fromJson(json['currentVoiceTimbre']);
|
||||
}
|
||||
}
|
||||
|
||||
int? remoteUnlock;
|
||||
@ -605,6 +622,7 @@ class LockSettingInfo {
|
||||
int? autoLightScreen; //猫眼-自动亮屏开关 0:关闭 1:开启
|
||||
int? autoLightScreenTime; //猫眼-自动亮屏时间
|
||||
int? faceEnErrUnlock;
|
||||
CurrentVoiceTimbre? currentVoiceTimbre;
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
@ -645,7 +663,9 @@ class LockSettingInfo {
|
||||
data['autoLightScreen'] = autoLightScreen;
|
||||
data['autoLightScreenTime'] = autoLightScreenTime;
|
||||
data['faceEnErrUnlock'] = faceEnErrUnlock;
|
||||
|
||||
if (currentVoiceTimbre != null) {
|
||||
data['currentVoiceTimbre'] = currentVoiceTimbre!.toJson();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@ -757,3 +777,29 @@ class CatEyeModeConfig {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class CurrentVoiceTimbre {
|
||||
String? lang;
|
||||
String? timbre;
|
||||
|
||||
CurrentVoiceTimbre({
|
||||
this.lang,
|
||||
this.timbre,
|
||||
});
|
||||
|
||||
// 将对象转换为 JSON 数据
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['lang'] = lang;
|
||||
data['timbre'] = timbre;
|
||||
return data;
|
||||
}
|
||||
|
||||
// 从 JSON 数据构造对象
|
||||
factory CurrentVoiceTimbre.fromJson(Map<String, dynamic> json) {
|
||||
return CurrentVoiceTimbre(
|
||||
timbre: json['timbre'],
|
||||
lang: json['lang'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:star_lock/apm/apm_helper.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_getDeviceModel.dart';
|
||||
import 'package:star_lock/login/login/entity/LoginEntity.dart';
|
||||
import 'package:star_lock/main/lockMian/entity/lockListInfo_entity.dart';
|
||||
|
||||
@ -680,7 +681,7 @@ class LockSetLogic extends BaseGetXController {
|
||||
updataLockSet(getTokenList);
|
||||
} else if (connectionState == BluetoothConnectionState.disconnected) {
|
||||
// cancelBlueConnetctToastTimer();
|
||||
// if(state.ifCurrentScreen.value == true){
|
||||
// if (state.ifCurrentScreen.value == true) {
|
||||
// showBlueConnetctToast();
|
||||
// }
|
||||
}
|
||||
@ -728,6 +729,7 @@ class LockSetLogic extends BaseGetXController {
|
||||
|
||||
getUpdataLockSet();
|
||||
_initReplySubscription();
|
||||
|
||||
// _scanListDiscoveredDeviceSubscriptionAction();
|
||||
}
|
||||
|
||||
@ -737,4 +739,10 @@ class LockSetLogic extends BaseGetXController {
|
||||
_passCurrentLockInformationEvent!.cancel();
|
||||
// _scanListDiscoveredDeviceSubscription.cancel();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_replySubscription.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@ -526,6 +526,33 @@ class _LockSetPageState extends State<LockSetPage>
|
||||
'lockSetInfoData': state.lockSetInfoData.value
|
||||
});
|
||||
})),
|
||||
// 锁语音包设置
|
||||
Visibility(
|
||||
visible: state.lockFeature.value.languageSpeech == 1,
|
||||
child: CommonItem(
|
||||
leftTitel: '语音包设置'.tr,
|
||||
rightTitle: '',
|
||||
isHaveLine: true,
|
||||
isHaveDirection: true,
|
||||
action: () {
|
||||
Get.toNamed(Routers.speechLanguageSettingsPage,
|
||||
arguments: <String, LockSetInfoData>{
|
||||
'lockSetInfoData': state.lockSetInfoData.value
|
||||
});
|
||||
})),
|
||||
// 锁语音包设置
|
||||
CommonItem(
|
||||
leftTitel: '第三方平台设置'.tr,
|
||||
rightTitle: '',
|
||||
isHaveLine: true,
|
||||
isHaveDirection: true,
|
||||
action: () {
|
||||
Get.toNamed(Routers.thirdPartyPlatformPage,
|
||||
arguments: <String, LockSetInfoData>{
|
||||
'lockSetInfoData': state.lockSetInfoData.value
|
||||
});
|
||||
},
|
||||
),
|
||||
// 蓝牙广播(关闭则不能使用蓝牙主动开锁)
|
||||
/* 2024-01-12 会议确定去掉“蓝牙广播” by DaisyWu
|
||||
Obx(() => Visibility(
|
||||
@ -592,7 +619,7 @@ class _LockSetPageState extends State<LockSetPage>
|
||||
state.lockFeature.value.appUnlockOnline == 1,
|
||||
child: otherItem(
|
||||
leftTitle: '开锁时是否需联网'.tr,
|
||||
isHaveLine: false,
|
||||
isHaveLine: true,
|
||||
rightWidget: _openLockNeedOnlineSwitch()),
|
||||
),
|
||||
),
|
||||
|
||||
@ -0,0 +1,464 @@
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:crypto/crypto.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:star_lock/app_settings/app_settings.dart';
|
||||
import 'package:star_lock/blue/blue_manage.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_getDeviceModel.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_otaUpgrade.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_processOtaUpgrade.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_voicePackageConfigure.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_voicePackageConfigureProcess.dart';
|
||||
import 'package:star_lock/blue/io_reply.dart';
|
||||
import 'package:star_lock/blue/io_tool/io_tool.dart';
|
||||
import 'package:star_lock/blue/io_tool/manager_event_bus.dart';
|
||||
import 'package:star_lock/login/login/entity/LoginEntity.dart';
|
||||
import 'package:star_lock/login/selectCountryRegion/common/index.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockDetail/passthrough_item.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockSet/speechLanguageSettings/speech_language_settings_state.dart';
|
||||
import 'package:star_lock/network/api_repository.dart';
|
||||
import 'package:star_lock/tools/baseGetXController.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:star_lock/tools/commonDataManage.dart';
|
||||
import 'package:star_lock/tools/eventBusEventManage.dart';
|
||||
import 'package:star_lock/tools/storage.dart';
|
||||
import 'package:star_lock/translations/app_dept.dart';
|
||||
import 'package:star_lock/translations/current_locale_tool.dart';
|
||||
|
||||
class SpeechLanguageSettingsLogic extends BaseGetXController {
|
||||
final SpeechLanguageSettingsState state = SpeechLanguageSettingsState();
|
||||
StreamSubscription<Reply>? _replySubscription;
|
||||
|
||||
// 超时定时器(用于检测是否未收到回复)
|
||||
Timer? _sendTimeoutTimer;
|
||||
|
||||
// 超时标志位(可选,防止重复处理)
|
||||
bool _isTimeout = false;
|
||||
|
||||
@override
|
||||
void onInit() async {
|
||||
super.onInit();
|
||||
_replySubscription =
|
||||
EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
|
||||
if (reply is VoicePackageConfigureReply) {
|
||||
// 语言包配置开始
|
||||
_handlerStartVoicePackageConfigure(reply);
|
||||
} else if (reply is VoicePackageConfigureProcessReply) {
|
||||
_handlerVoicePackageConfigureProcess(reply);
|
||||
} else if (reply is VoicePackageConfigureConfirmationReply) {
|
||||
handleVoiceConfigureThrottled(reply);
|
||||
}
|
||||
});
|
||||
await initList();
|
||||
}
|
||||
|
||||
/// 获取列表
|
||||
/// //{ "vendor": "XL", "model": "JL-BLE-01"}
|
||||
initList() async {
|
||||
showEasyLoading();
|
||||
try {
|
||||
final vendor = state.lockSetInfoData.value.lockBasicInfo?.vendor;
|
||||
final model = state.lockSetInfoData.value.lockBasicInfo?.model;
|
||||
|
||||
final PassthroughListResponse entity =
|
||||
await ApiRepository.to.getPassthroughList(data: {
|
||||
'vendor': vendor!,
|
||||
'model': model!,
|
||||
});
|
||||
if (entity.errorCode!.codeIsSuccessful) {
|
||||
final data = entity.data;
|
||||
final locales = appDept.deptSupportedLocales;
|
||||
state.languages.clear();
|
||||
|
||||
state.languages.add(
|
||||
PassthroughItem(
|
||||
lang: 'system',
|
||||
timbres: [],
|
||||
langText: '跟随系统'.tr,
|
||||
name: '跟随系统'.tr,
|
||||
),
|
||||
);
|
||||
|
||||
data?.forEach((element) {
|
||||
final lang = element.lang;
|
||||
if (lang == 'zh_TW') {
|
||||
// 如果是台湾的话应该显示未简体中文
|
||||
List<String> parts = lang.split('_');
|
||||
final indexOf = locales.indexOf(Locale(parts[0], parts[1]));
|
||||
final passthroughItem = PassthroughItem(
|
||||
lang: element.lang,
|
||||
timbres: element.timbres,
|
||||
langText: '简体中文'.tr + '(中国台湾)'.tr,
|
||||
name: element.name,
|
||||
);
|
||||
state.languages.add(passthroughItem);
|
||||
} else {
|
||||
List<String> parts = lang.split('_');
|
||||
final indexOf = locales.indexOf(Locale(parts[0], parts[1]));
|
||||
final passthroughItem = PassthroughItem(
|
||||
lang: element.lang,
|
||||
timbres: element.timbres,
|
||||
langText:
|
||||
ExtensionLanguageType.fromLocale(locales[indexOf]).lanTitle,
|
||||
name: element.name,
|
||||
);
|
||||
state.languages.add(passthroughItem);
|
||||
}
|
||||
});
|
||||
state.languages.refresh();
|
||||
final lang = state
|
||||
.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.lang;
|
||||
final timbre = state
|
||||
.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.timbre;
|
||||
// 传统 for 循环,直接通过索引访问
|
||||
for (int i = 0; i < state.languages.length; i++) {
|
||||
final language = state.languages[i]; // 当前元素
|
||||
if (language.lang == lang) {
|
||||
print('匹配到下标:$i,元素:$language');
|
||||
final timbres = language.timbres;
|
||||
for (int j = 0; j < timbres.length; j++) {
|
||||
final item = timbres[j];
|
||||
if (lang == language.lang && item.timbre == timbre) {
|
||||
state.selectSoundTypeIndex.value = item.isFemale;
|
||||
state.selectPassthroughListIndex.value = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('获取语音包出现错误:$e');
|
||||
} finally {
|
||||
dismissEasyLoading();
|
||||
}
|
||||
}
|
||||
|
||||
void saveSpeechLanguageSettings() async {
|
||||
var language = state.languages[state.selectPassthroughListIndex.value];
|
||||
if (language.lang == 'system') {
|
||||
// 如果选择了跟随系统
|
||||
// 系统层的语言
|
||||
// print(CurrentLocaleTool.convertLocale(Get.deviceLocale!));
|
||||
|
||||
// APP层的语言
|
||||
Locale? currentLocale = Get.locale; // 直接获取最新语言
|
||||
if (currentLocale != null) {
|
||||
final indexWhere = state.languages
|
||||
.indexWhere((element) => element.lang == currentLocale.toString());
|
||||
state.selectPassthroughListIndex.value = indexWhere;
|
||||
}
|
||||
}
|
||||
language = state.languages[state.selectPassthroughListIndex.value];
|
||||
final value = state.selectSoundTypeIndex.value;
|
||||
state.tempLangStr.value = language.lang;
|
||||
AppLog.log('下载的语言是:${state.tempLangStr}');
|
||||
language.timbres.forEach((element) async {
|
||||
if (element.isFemale == value) {
|
||||
await downloadFile(element.timbrePackUrl);
|
||||
state.tempTimbreStr.value = element.timbre;
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void changeSelectIndex(int index) {
|
||||
state.selectLanguageIndex.value = index;
|
||||
}
|
||||
|
||||
//下载语音包
|
||||
Future<void> downloadFile(String url) async {
|
||||
final http.Response response = await http.get(Uri.parse(url));
|
||||
if (response.statusCode == 200) {
|
||||
state.data = response.bodyBytes;
|
||||
sendFileToDevice(response.bodyBytes, <int>[0, 0, 0, 0]);
|
||||
}
|
||||
}
|
||||
|
||||
sendFileToDevice(Uint8List data, List<int> token) {
|
||||
showEasyLoading();
|
||||
showBlueConnetctToastTimer(action: () {
|
||||
dismissEasyLoading();
|
||||
});
|
||||
BlueManage().blueSendData(BlueManage().connectDeviceName,
|
||||
(BluetoothConnectionState deviceConnectionState) async {
|
||||
if (deviceConnectionState == BluetoothConnectionState.connected) {
|
||||
final List<String>? privateKey =
|
||||
await Storage.getStringList(saveBluePrivateKey);
|
||||
final List<int> getPrivateKeyList =
|
||||
changeStringListToIntList(privateKey!);
|
||||
final List<String>? signKey =
|
||||
await Storage.getStringList(saveBlueSignKey);
|
||||
final List<int> signKeyDataList = changeStringListToIntList(signKey!);
|
||||
final String uid = await Storage.getUid() ?? '';
|
||||
final String md5Str = md5.convert(data).toString().toUpperCase();
|
||||
BlueManage().writeCharacteristicWithResponse(
|
||||
VoicePackageConfigure(
|
||||
lockID: BlueManage().connectDeviceName,
|
||||
userID: uid,
|
||||
keyID: BlueManage().connectDeviceName,
|
||||
platform: 0,
|
||||
product: 0,
|
||||
fwSize: data.length,
|
||||
fwMD5: md5Str,
|
||||
needAuthor: 1,
|
||||
token: token,
|
||||
signKey: signKeyDataList,
|
||||
privateKey: getPrivateKeyList)
|
||||
.packageData(),
|
||||
);
|
||||
} else if (deviceConnectionState ==
|
||||
BluetoothConnectionState.disconnected) {
|
||||
dismissEasyLoading();
|
||||
cancelBlueConnetctToastTimer();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 发送获取型号蓝牙命令
|
||||
sendGetDeviceModelBleMessage() {
|
||||
showEasyLoading();
|
||||
showBlueConnetctToastTimer(action: () {
|
||||
dismissEasyLoading();
|
||||
});
|
||||
BlueManage().blueSendData(BlueManage().connectDeviceName,
|
||||
(BluetoothConnectionState deviceConnectionState) async {
|
||||
if (deviceConnectionState == BluetoothConnectionState.connected) {
|
||||
BlueManage().writeCharacteristicWithResponse(
|
||||
GetDeviceModelCommand(
|
||||
lockID: BlueManage().connectDeviceName,
|
||||
).packageData(),
|
||||
);
|
||||
} else if (deviceConnectionState ==
|
||||
BluetoothConnectionState.disconnected) {
|
||||
dismissEasyLoading();
|
||||
cancelBlueConnetctToastTimer();
|
||||
showBlueConnetctToast();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 开始配置语音包
|
||||
void _handlerStartVoicePackageConfigure(
|
||||
VoicePackageConfigureReply reply) async {
|
||||
final int status = reply.data[6];
|
||||
switch (status) {
|
||||
case 0x00:
|
||||
//成功
|
||||
cancelBlueConnetctToastTimer();
|
||||
|
||||
_startSendLanguageFile();
|
||||
|
||||
break;
|
||||
case 0x06:
|
||||
//无权限
|
||||
final List<int> token = reply.data.sublist(2, 6);
|
||||
print('收到token:$token');
|
||||
if (state.data != null) {
|
||||
sendFileToDevice(state.data!, token);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
showToast('获取设备型号失败'.tr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void _startSendLanguageFile() {
|
||||
if (state.data == null) return;
|
||||
state.voiceSubcontractingIndex = 0;
|
||||
state.voiceSubcontractingCount =
|
||||
(state.data!.length + state.voiceSubcontractingSize - 1) ~/
|
||||
state.voiceSubcontractingSize;
|
||||
state.progress.value = 0.0; // 开始前重置进度
|
||||
_sendNextPackage();
|
||||
}
|
||||
|
||||
void _handleSendTimeout() {
|
||||
_isTimeout = true; // 标记超时状态
|
||||
dismissEasyLoading();
|
||||
cancelBlueConnetctToastTimer();
|
||||
showBlueConnetctToast();
|
||||
|
||||
// 重置状态,避免后续错误操作
|
||||
state.voiceSubcontractingIndex = 0;
|
||||
state.voiceSubcontractingCount = 0;
|
||||
state.data = null;
|
||||
state.progress.value = 0.0;
|
||||
_isTimeout = false; // 标记超时状态
|
||||
}
|
||||
|
||||
void _sendNextPackage() async {
|
||||
// 若已超时,直接返回
|
||||
if (_isTimeout) return;
|
||||
|
||||
// 取消上一次未完成的定时器(避免重复触发)
|
||||
_sendTimeoutTimer?.cancel();
|
||||
|
||||
// 检查是否已完成所有分包发送
|
||||
if (state.voiceSubcontractingIndex >= state.voiceSubcontractingCount) {
|
||||
print('所有分包已发送完成');
|
||||
state.progress.value = 1.0;
|
||||
return;
|
||||
}
|
||||
|
||||
// 启动 3 秒超时定时器
|
||||
_sendTimeoutTimer = Timer(Duration(seconds: 3), () {
|
||||
_handleSendTimeout(); // 触发超时处理
|
||||
});
|
||||
|
||||
if (state.voiceSubcontractingIndex >= state.voiceSubcontractingCount) {
|
||||
print('所有分包已发送完成');
|
||||
state.progress.value = 1.0; // 发送完成
|
||||
// 可在此处通知UI或做后续处理
|
||||
return;
|
||||
}
|
||||
|
||||
int start = state.voiceSubcontractingIndex * state.voiceSubcontractingSize;
|
||||
int end = start + state.voiceSubcontractingSize;
|
||||
if (end > state.data!.length) end = state.data!.length;
|
||||
Uint8List packageData = state.data!.sublist(start, end);
|
||||
|
||||
// 更新分包进度
|
||||
state.progress.value =
|
||||
(state.voiceSubcontractingIndex + 1) / state.voiceSubcontractingCount;
|
||||
EasyLoading.showProgress(state.progress.value,
|
||||
status: '正在发送数据 ${(state.progress.value * 100).toStringAsFixed(0)}%');
|
||||
await _sendLanguageFileBleMessage(
|
||||
index: state.voiceSubcontractingIndex,
|
||||
data: packageData,
|
||||
);
|
||||
}
|
||||
|
||||
_sendLanguageFileBleMessage(
|
||||
{required int index, required Uint8List data}) async {
|
||||
await BlueManage().blueSendData(BlueManage().connectDeviceName,
|
||||
(BluetoothConnectionState deviceConnectionState) async {
|
||||
if (deviceConnectionState == BluetoothConnectionState.connected) {
|
||||
await BlueManage().writeCharacteristicWithResponse(
|
||||
VoicePackageConfigureProcess(
|
||||
index: index,
|
||||
size: data.length,
|
||||
data: data,
|
||||
).packageData(),
|
||||
);
|
||||
} else if (deviceConnectionState ==
|
||||
BluetoothConnectionState.disconnected) {
|
||||
dismissEasyLoading();
|
||||
cancelBlueConnetctToastTimer();
|
||||
showBlueConnetctToast();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _handlerVoicePackageConfigureProcess(
|
||||
VoicePackageConfigureProcessReply reply) {
|
||||
// 取消超时定时器(已收到回复,无需继续等待)
|
||||
_sendTimeoutTimer?.cancel();
|
||||
_isTimeout = false; // 重置超时标志
|
||||
final int status = reply.data[2];
|
||||
switch (status) {
|
||||
case 0x00:
|
||||
cancelBlueConnetctToastTimer();
|
||||
state.voiceSubcontractingIndex++;
|
||||
_sendNextPackage();
|
||||
break;
|
||||
default:
|
||||
showToast('发送分包数据不成功'.tr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() async {
|
||||
await _replySubscription?.cancel();
|
||||
_replySubscription = null;
|
||||
await BlueManage().disconnect();
|
||||
dismissEasyLoading();
|
||||
cancelBlueConnetctToastTimer();
|
||||
EasyLoading.dismiss();
|
||||
// 清理分包相关状态
|
||||
state.progress.value = 0.0;
|
||||
state.voiceSubcontractingIndex = 0;
|
||||
state.voiceSubcontractingCount = 0;
|
||||
state.data = null;
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() async {
|
||||
await _replySubscription?.cancel();
|
||||
_replySubscription = null;
|
||||
await BlueManage().disconnect();
|
||||
dismissEasyLoading();
|
||||
cancelBlueConnetctToastTimer();
|
||||
EasyLoading.dismiss();
|
||||
// 清理分包相关状态
|
||||
state.progress.value = 0.0;
|
||||
state.voiceSubcontractingIndex = 0;
|
||||
state.voiceSubcontractingCount = 0;
|
||||
state.data = null;
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
bool _isThrottled = false;
|
||||
|
||||
void handleVoiceConfigureThrottled(
|
||||
VoicePackageConfigureConfirmationReply reply,
|
||||
) {
|
||||
if (_isThrottled) return;
|
||||
|
||||
_isThrottled = true;
|
||||
|
||||
// 执行你的逻辑
|
||||
_executeLogic(reply);
|
||||
|
||||
// 设置节流时间(比如 1 秒)
|
||||
Future.delayed(Duration(seconds: 1), () {
|
||||
_isThrottled = false;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _executeLogic(
|
||||
VoicePackageConfigureConfirmationReply reply) async {
|
||||
await _handlerVoicePackageConfigureConfirmation(reply);
|
||||
}
|
||||
|
||||
_handlerVoicePackageConfigureConfirmation(
|
||||
VoicePackageConfigureConfirmationReply reply,
|
||||
) async {
|
||||
final int status = reply.data[2];
|
||||
switch (status) {
|
||||
case 0x00:
|
||||
cancelBlueConnetctToastTimer();
|
||||
final LoginEntity entity =
|
||||
await ApiRepository.to.settingCurrentVoiceTimbre(
|
||||
data: {
|
||||
'lang': state.tempLangStr.value,
|
||||
'timbre': state.tempTimbreStr.value,
|
||||
},
|
||||
lockId: state.lockSetInfoData.value.lockId!,
|
||||
);
|
||||
if (entity.errorCode!.codeIsSuccessful) {
|
||||
showSuccess('设置成功'.tr, something: () {
|
||||
state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre
|
||||
?.lang = state.tempLangStr.value;
|
||||
state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre
|
||||
?.timbre = state.tempTimbreStr.value;
|
||||
eventBus.fire(
|
||||
PassCurrentLockInformationEvent(state.lockSetInfoData.value));
|
||||
});
|
||||
}
|
||||
dismissEasyLoading();
|
||||
break;
|
||||
default:
|
||||
showToast('设置'.tr + '失败'.tr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,234 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:star_lock/app_settings/app_colors.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockDetail/passthrough_item.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockSet/speechLanguageSettings/speech_language_settings_logic.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockSet/speechLanguageSettings/speech_language_settings_state.dart';
|
||||
import 'package:star_lock/tools/EasyRefreshTool.dart';
|
||||
import 'package:star_lock/tools/commonItem.dart';
|
||||
import 'package:star_lock/tools/titleAppBar.dart';
|
||||
|
||||
class SpeechLanguageSettingsPage extends StatefulWidget {
|
||||
const SpeechLanguageSettingsPage();
|
||||
|
||||
@override
|
||||
State<SpeechLanguageSettingsPage> createState() =>
|
||||
_SpeechLanguageSettingsPageState();
|
||||
}
|
||||
|
||||
class _SpeechLanguageSettingsPageState
|
||||
extends State<SpeechLanguageSettingsPage> {
|
||||
final SpeechLanguageSettingsLogic logic =
|
||||
Get.put(SpeechLanguageSettingsLogic());
|
||||
final SpeechLanguageSettingsState state =
|
||||
Get.find<SpeechLanguageSettingsLogic>().state;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.mainBackgroundColor,
|
||||
appBar: TitleAppBar(
|
||||
barTitle: '锁语音包设置'.tr,
|
||||
haveBack: true,
|
||||
backgroundColor: AppColors.mainColor,
|
||||
actionsList: [
|
||||
TextButton(
|
||||
onPressed: logic.saveSpeechLanguageSettings,
|
||||
child: Text(
|
||||
'下载'.tr,
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 24.sp,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: Obx(
|
||||
() => ListView(
|
||||
padding: EdgeInsets.zero,
|
||||
children: [
|
||||
// 语音类型选择区
|
||||
Container(
|
||||
color: Colors.white,
|
||||
child: Column(
|
||||
children: List.generate(
|
||||
state.soundTypeList.length,
|
||||
(index) {
|
||||
final isLastItem = index == state.soundTypeList.length - 1;
|
||||
final soundType = state.soundTypeList.value[index];
|
||||
return CommonItem(
|
||||
leftTitel: soundType,
|
||||
rightTitle: '',
|
||||
isHaveLine: !isLastItem,
|
||||
isHaveDirection: false,
|
||||
isHaveRightWidget: true,
|
||||
rightWidget: Radio<String>(
|
||||
value: soundType,
|
||||
groupValue: state.soundTypeList
|
||||
.value[state.selectSoundTypeIndex.value],
|
||||
activeColor: AppColors.mainColor,
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
final newIndex = state.soundTypeList.value
|
||||
.indexWhere((p) => p == value);
|
||||
if (newIndex != -1) {
|
||||
state.selectSoundTypeIndex.value = newIndex;
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
action: () {
|
||||
state.selectSoundTypeIndex.value = index;
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 8.h,
|
||||
),
|
||||
// 语言包列表区
|
||||
Container(
|
||||
color: Colors.transparent,
|
||||
child: Column(
|
||||
children: List.generate(
|
||||
state.languages.length,
|
||||
(index) {
|
||||
final item = state.languages[index];
|
||||
return CommonItem(
|
||||
leftTitel: item.langText,
|
||||
rightTitle: '',
|
||||
isHaveLine: true,
|
||||
isHaveDirection: false,
|
||||
isHaveRightWidget: true,
|
||||
rightWidget:
|
||||
state.selectPassthroughListIndex.value == index
|
||||
? Image(
|
||||
image: const AssetImage(
|
||||
'images/icon_item_checked.png'),
|
||||
width: 30.w,
|
||||
height: 30.w,
|
||||
fit: BoxFit.contain,
|
||||
)
|
||||
: Container(),
|
||||
action: () {
|
||||
state.selectPassthroughListIndex.value = index;
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody() {
|
||||
return Obx(
|
||||
() => SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
ListView.builder(
|
||||
itemCount: state.soundTypeList.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
// 判断是否是最后一个元素(索引等于 itemCount - 1)
|
||||
final isLastItem = index == state.soundTypeList.length - 1;
|
||||
|
||||
// 获取当前平台数据(假设 platFormSet 是 RxList<Platform>)
|
||||
final platform = state.soundTypeList.value[index];
|
||||
return CommonItem(
|
||||
leftTitel: state.soundTypeList.value[index],
|
||||
rightTitle: '',
|
||||
isHaveLine: !isLastItem,
|
||||
// 最后一个元素不显示分割线(取反)
|
||||
isHaveDirection: false,
|
||||
isHaveRightWidget: true,
|
||||
rightWidget: Radio<String>(
|
||||
// Radio 的值:使用平台的唯一标识(如 id)
|
||||
value: platform,
|
||||
// 当前选中的值:与 selectPlatFormIndex 关联的 id
|
||||
groupValue: state.soundTypeList
|
||||
.value[state.selectSoundTypeIndex.value],
|
||||
// 选中颜色(可选,默认主题色)
|
||||
activeColor: AppColors.mainColor,
|
||||
// 点击 Radio 时回调(更新选中索引)
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
setState(() {
|
||||
// 找到当前选中平台的索引(根据 id 匹配)
|
||||
final newIndex = state.soundTypeList.value
|
||||
.indexWhere((p) => p == value);
|
||||
if (newIndex != -1) {
|
||||
state.selectSoundTypeIndex.value = newIndex;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
action: () {
|
||||
setState(() {
|
||||
state.selectSoundTypeIndex.value = index;
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics() //add this line,
|
||||
),
|
||||
Column(
|
||||
children: _buildList(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _buildList() {
|
||||
final appLocalLanguages = state.languages;
|
||||
return List.generate(
|
||||
appLocalLanguages.length,
|
||||
(index) => _buildItem(
|
||||
appLocalLanguages[index],
|
||||
index,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
if (EasyLoading.isShow) {
|
||||
EasyLoading.dismiss(animation: true);
|
||||
}
|
||||
}
|
||||
|
||||
_buildItem(PassthroughItem item, index) {
|
||||
return CommonItem(
|
||||
leftTitel: item.langText,
|
||||
rightTitle: '',
|
||||
isHaveLine: true,
|
||||
isHaveDirection: false,
|
||||
isHaveRightWidget: true,
|
||||
rightWidget: state.selectPassthroughListIndex.value == index
|
||||
? Image(
|
||||
image: const AssetImage('images/icon_item_checked.png'),
|
||||
width: 30.w,
|
||||
height: 30.w,
|
||||
fit: BoxFit.contain,
|
||||
)
|
||||
: Container(),
|
||||
action: () {
|
||||
state.selectPassthroughListIndex.value = index;
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockDetail/passthrough_item.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockSet/lockSet/lockSetInfo_entity.dart';
|
||||
import 'package:star_lock/translations/app_dept.dart';
|
||||
|
||||
class SpeechLanguageSettingsState {
|
||||
SpeechLanguageSettingsState() {
|
||||
final map = Get.arguments;
|
||||
lockSetInfoData.value = map['lockSetInfoData'];
|
||||
}
|
||||
|
||||
|
||||
|
||||
Rx<LockSetInfoData> lockSetInfoData = LockSetInfoData().obs;
|
||||
|
||||
// 选中的语音包列表下标
|
||||
RxInt selectPassthroughListIndex = 0.obs;
|
||||
|
||||
// 选中的语音下标
|
||||
RxInt selectLanguageIndex = 0.obs;
|
||||
|
||||
final RxList<PassthroughItem> languages = <PassthroughItem>[].obs;
|
||||
|
||||
RxBool otaUpdateIng = false.obs;
|
||||
RxDouble otaProgress = 0.00.obs;
|
||||
RxString deviceModel = '2403'.obs;
|
||||
Uint8List? data;
|
||||
|
||||
// 语音包最大大小
|
||||
int voiceSubcontractingSize = 256;
|
||||
|
||||
// 总数据包数量
|
||||
int voiceSubcontractingCount = 0;
|
||||
|
||||
// 数据包序列号
|
||||
int voiceSubcontractingIndex = 0;
|
||||
|
||||
// 分包发送进度(0.0~1.0)
|
||||
RxDouble progress = 0.0.obs;
|
||||
|
||||
RxInt selectedValue = 1.obs;
|
||||
|
||||
// 响应式字符串集合(自动触发 UI 更新)
|
||||
final RxList<String> soundTypeList = List.of({
|
||||
'男声'.tr,
|
||||
'女声'.tr,
|
||||
}).obs;
|
||||
|
||||
RxInt selectSoundTypeIndex = 0.obs;
|
||||
|
||||
|
||||
RxString tempLangStr=''.obs;
|
||||
RxString tempTimbreStr=''.obs;
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockSet/thirdPartyPlatform/third_party_platform_state.dart';
|
||||
import 'package:star_lock/tools/baseGetXController.dart';
|
||||
|
||||
class ThirdPartyPlatformLogic extends BaseGetXController {
|
||||
ThirdPartyPlatformState state = ThirdPartyPlatformState();
|
||||
|
||||
void savePlatFormSetting() {
|
||||
// showEasyLoading();
|
||||
showToast('功能待开放'.tr);
|
||||
// dismissEasyLoading();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
dismissEasyLoading();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,97 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:star_lock/app_settings/app_colors.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockSet/thirdPartyPlatform/third_party_platform_logic.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockSet/thirdPartyPlatform/third_party_platform_state.dart';
|
||||
import 'package:star_lock/tools/commonItem.dart';
|
||||
import 'package:star_lock/tools/titleAppBar.dart';
|
||||
|
||||
class ThirdPartyPlatformPage extends StatefulWidget {
|
||||
const ThirdPartyPlatformPage();
|
||||
|
||||
@override
|
||||
State<ThirdPartyPlatformPage> createState() => _ThirdPartyPlatformPageState();
|
||||
}
|
||||
|
||||
class _ThirdPartyPlatformPageState extends State<ThirdPartyPlatformPage> {
|
||||
final ThirdPartyPlatformLogic logic = Get.put(ThirdPartyPlatformLogic());
|
||||
final ThirdPartyPlatformState state =
|
||||
Get.find<ThirdPartyPlatformLogic>().state;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: TitleAppBar(
|
||||
barTitle: '第三方平台设置'.tr,
|
||||
haveBack: true,
|
||||
backgroundColor: AppColors.mainColor,
|
||||
actionsList: [
|
||||
TextButton(
|
||||
onPressed: logic.savePlatFormSetting,
|
||||
child: Text(
|
||||
'保存'.tr,
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 24.sp,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: _buildBody(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody() {
|
||||
return ListView.builder(
|
||||
itemCount: state.platFormSet.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
// 判断是否是最后一个元素(索引等于 itemCount - 1)
|
||||
final isLastItem = index == state.platFormSet.length - 1;
|
||||
|
||||
// 获取当前平台数据(假设 platFormSet 是 RxList<Platform>)
|
||||
final platform = state.platFormSet.value[index];
|
||||
return CommonItem(
|
||||
leftTitel: state.platFormSet.value[index],
|
||||
rightTitle: '',
|
||||
isHaveLine: !isLastItem,
|
||||
// 最后一个元素不显示分割线(取反)
|
||||
isHaveDirection: false,
|
||||
isHaveRightWidget: true,
|
||||
rightWidget: Radio<String>(
|
||||
// Radio 的值:使用平台的唯一标识(如 id)
|
||||
value: platform,
|
||||
// 当前选中的值:与 selectPlatFormIndex 关联的 id
|
||||
groupValue:
|
||||
state.platFormSet.value[state.selectPlatFormIndex.value],
|
||||
// 选中颜色(可选,默认主题色)
|
||||
activeColor: AppColors.mainColor,
|
||||
// 点击 Radio 时回调(更新选中索引)
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
setState(() {
|
||||
// 找到当前选中平台的索引(根据 id 匹配)
|
||||
final newIndex =
|
||||
state.platFormSet.value.indexWhere((p) => p == value);
|
||||
if (newIndex != -1) {
|
||||
state.selectPlatFormIndex.value = newIndex;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
action: () {
|
||||
setState(() {
|
||||
state.selectPlatFormIndex.value = index;
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
shrinkWrap: true,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:get/get.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockSet/lockSet/lockSetInfo_entity.dart';
|
||||
import 'package:star_lock/translations/app_dept.dart';
|
||||
|
||||
class ThirdPartyPlatformState {
|
||||
ThirdPartyPlatformState() {
|
||||
final map = Get.arguments;
|
||||
lockSetInfoData.value = map['lockSetInfoData'];
|
||||
}
|
||||
|
||||
Rx<LockSetInfoData> lockSetInfoData = LockSetInfoData().obs;
|
||||
|
||||
// 响应式字符串集合(自动触发 UI 更新)
|
||||
final RxList<String> platFormSet = List.of({
|
||||
'锁通通'.tr,
|
||||
'涂鸦智能'.tr,
|
||||
}).obs;
|
||||
|
||||
RxInt selectPlatFormIndex = 0.obs;
|
||||
|
||||
|
||||
}
|
||||
@ -1,8 +1,8 @@
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:fluwx/fluwx.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:star_lock/flavors.dart';
|
||||
import 'package:star_lock/main/lockDetail/passwordKey/passwordKeyDetail/passwordKeyDetail_logic.dart';
|
||||
@ -84,8 +84,8 @@ class _PasswordKeyDetailPageState extends State<PasswordKeyDetailPage>
|
||||
// showCupertinoAlertDialog(
|
||||
// context, state.inputNameController);
|
||||
// })),
|
||||
Obx(() => lockDataListItem('姓名'.tr,
|
||||
state.keyboardPwdName.value, () {
|
||||
Obx(() =>
|
||||
lockDataListItem('姓名'.tr, state.keyboardPwdName.value, () {
|
||||
showCupertinoAlertDialog(
|
||||
context, state.inputNameController);
|
||||
})),
|
||||
@ -436,7 +436,18 @@ class _PasswordKeyDetailPageState extends State<PasswordKeyDetailPage>
|
||||
final String pwdShareStr = logic.getShareContentStr();
|
||||
switch (itemIndex) {
|
||||
case 0: //微信好友
|
||||
NativeInteractionTool().loadNativeShare(shareText: pwdShareStr);
|
||||
Fluwx fluwx = Fluwx();
|
||||
fluwx.registerApi(
|
||||
appId: F.wechatAppInfo.wechatAppId,
|
||||
universalLink: F.wechatAppInfo.universalLink,
|
||||
);
|
||||
fluwx.share(
|
||||
WeChatShareTextModel(
|
||||
pwdShareStr,
|
||||
scene: WeChatScene.session,
|
||||
),
|
||||
);
|
||||
// NativeInteractionTool().loadNativeShare(shareText: pwdShareStr);
|
||||
break;
|
||||
case 1: //短信
|
||||
case 2: //邮件
|
||||
|
||||
@ -3,9 +3,11 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:fluwx/fluwx.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:star_lock/app_settings/app_colors.dart';
|
||||
import 'package:star_lock/app_settings/app_settings.dart';
|
||||
import 'package:star_lock/flavors.dart';
|
||||
import 'package:star_lock/main/lockDetail/passwordKey/passwordKey_perpetual/passwordKey_perpetual_logic.dart';
|
||||
import 'package:star_lock/main/lockDetail/passwordKey/passwordKey_perpetual/passwordKey_perpetual_state.dart';
|
||||
import 'package:star_lock/tools/commonDataManage.dart';
|
||||
@ -859,7 +861,18 @@ class _PasswordKeyPerpetualPageState extends State<PasswordKeyPerpetualPage>
|
||||
final String pwdShareStr = logic.getShareContentStr();
|
||||
switch (itemIndex) {
|
||||
case 0: //微信好友
|
||||
NativeInteractionTool().loadNativeShare(shareText: pwdShareStr);
|
||||
Fluwx fluwx = Fluwx();
|
||||
fluwx.registerApi(
|
||||
appId: F.wechatAppInfo.wechatAppId,
|
||||
universalLink: F.wechatAppInfo.universalLink,
|
||||
);
|
||||
fluwx.share(
|
||||
WeChatShareTextModel(
|
||||
pwdShareStr,
|
||||
scene: WeChatScene.session,
|
||||
),
|
||||
);
|
||||
// NativeInteractionTool().loadNativeShare(shareText: pwdShareStr);
|
||||
break;
|
||||
case 1: //短信
|
||||
case 2: //邮件
|
||||
|
||||
@ -2,8 +2,12 @@ import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:get/get.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:star_lock/appRouters.dart';
|
||||
import 'package:star_lock/common/XSConstantMacro/XSConstantMacro.dart';
|
||||
import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart';
|
||||
import 'package:star_lock/mine/valueAddedServices/advancedFeaturesWeb/advancedFeaturesWeb_entity.dart';
|
||||
import 'package:star_lock/network/api_repository.dart';
|
||||
import 'package:star_lock/tools/baseGetXController.dart';
|
||||
|
||||
@ -142,10 +146,45 @@ class VideoLogLogic extends BaseGetXController {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
onReady() {
|
||||
super.onReady();
|
||||
getLockPassthroughInfo() async {
|
||||
showEasyLoading();
|
||||
try {
|
||||
var entity = await ApiRepository.to.getValidityPeriodInfo(
|
||||
lockId: state.getLockId.value,
|
||||
);
|
||||
if (entity.errorCode!.codeIsSuccessful) {
|
||||
state.validityPeriodInfo.value = entity.data!;
|
||||
}
|
||||
} catch (e) {
|
||||
} finally {
|
||||
dismissEasyLoading();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onInit() async {
|
||||
await getLockPassthroughInfo();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
@override
|
||||
onReady() async {
|
||||
super.onReady();
|
||||
getLockCloudStorageList();
|
||||
}
|
||||
|
||||
getWebPlayUrl() async {
|
||||
final AdvancedFeaturesWebEntity entity =
|
||||
await ApiRepository.to.getServicePackageBuyUrl();
|
||||
if (entity.errorCode!.codeIsSuccessful) {
|
||||
state.cloudStorageWebViewUrl.value = entity.data!.cloudStorage!;
|
||||
final uploadReportBuyRequest = await ApiRepository.to
|
||||
.uploadReportBuyRequest(lockId: state.getLockId.value);
|
||||
if (uploadReportBuyRequest.errorCode!.codeIsSuccessful) {
|
||||
Get.toNamed(Routers.advancedFeaturesWebPage, arguments: <String, int>{
|
||||
'webBuyType': XSConstantMacro.webBuyTypeCloudStorage,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,7 +26,9 @@ class VideoLogPage extends StatefulWidget {
|
||||
|
||||
class _VideoLogPageState extends State<VideoLogPage> {
|
||||
final VideoLogLogic logic = Get.put(VideoLogLogic());
|
||||
final VideoLogState state = Get.find<VideoLogLogic>().state;
|
||||
final VideoLogState state = Get
|
||||
.find<VideoLogLogic>()
|
||||
.state;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -54,64 +56,66 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
||||
// title加编辑按钮
|
||||
editVideoTip(),
|
||||
Obx(
|
||||
() => Visibility(
|
||||
visible: !state.isNavLocal.value,
|
||||
child: state.videoLogList.length > 0
|
||||
? Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: state.videoLogList.length,
|
||||
itemBuilder: (BuildContext c, int index) {
|
||||
final CloudStorageData item =
|
||||
state.videoLogList[index];
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
margin: EdgeInsets.only(
|
||||
left: 20.w, top: 15.w, bottom: 15.w),
|
||||
child: Row(children: <Widget>[
|
||||
Text(item.date ?? '',
|
||||
style: TextStyle(fontSize: 20.sp)),
|
||||
])),
|
||||
mainListView(index, item)
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
: _buildNotData(),
|
||||
),
|
||||
() =>
|
||||
Visibility(
|
||||
visible: !state.isNavLocal.value,
|
||||
child: state.videoLogList.length > 0
|
||||
? Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: state.videoLogList.length,
|
||||
itemBuilder: (BuildContext c, int index) {
|
||||
final CloudStorageData item =
|
||||
state.videoLogList[index];
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
margin: EdgeInsets.only(
|
||||
left: 20.w, top: 15.w, bottom: 15.w),
|
||||
child: Row(children: <Widget>[
|
||||
Text(item.date ?? '',
|
||||
style: TextStyle(fontSize: 20.sp)),
|
||||
])),
|
||||
mainListView(index, item)
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
: _buildNotData(),
|
||||
),
|
||||
),
|
||||
// 本地顶部
|
||||
Obx(
|
||||
() => Visibility(
|
||||
visible: state.isNavLocal.value,
|
||||
child: state.lockVideoList.length > 0
|
||||
? Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: state.lockVideoList.length,
|
||||
itemBuilder: (BuildContext c, int index) {
|
||||
final CloudStorageData item =
|
||||
state.lockVideoList[index];
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
margin: EdgeInsets.only(
|
||||
left: 20.w, top: 15.w, bottom: 15.w),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Text(item.date ?? '',
|
||||
style: TextStyle(fontSize: 20.sp)),
|
||||
],
|
||||
),
|
||||
() =>
|
||||
Visibility(
|
||||
visible: state.isNavLocal.value,
|
||||
child: state.lockVideoList.length > 0
|
||||
? Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: state.lockVideoList.length,
|
||||
itemBuilder: (BuildContext c, int index) {
|
||||
final CloudStorageData item =
|
||||
state.lockVideoList[index];
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
margin: EdgeInsets.only(
|
||||
left: 20.w, top: 15.w, bottom: 15.w),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Text(item.date ?? '',
|
||||
style: TextStyle(fontSize: 20.sp)),
|
||||
],
|
||||
),
|
||||
lockMainListView(index, item)
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
: _buildNotData(),
|
||||
),
|
||||
),
|
||||
lockMainListView(index, item)
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
: _buildNotData(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -157,13 +161,14 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
||||
// logic.clearDownloads();
|
||||
});
|
||||
},
|
||||
child: Obx(() => Text('云存'.tr,
|
||||
style: state.isNavLocal.value == true
|
||||
? TextStyle(
|
||||
child: Obx(() =>
|
||||
Text('云存'.tr,
|
||||
style: state.isNavLocal.value == true
|
||||
? TextStyle(
|
||||
color: Colors.grey,
|
||||
fontSize: 26.sp,
|
||||
fontWeight: FontWeight.w600)
|
||||
: TextStyle(
|
||||
: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 28.sp,
|
||||
fontWeight: FontWeight.w600)))),
|
||||
@ -175,18 +180,19 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
||||
});
|
||||
},
|
||||
child: Obx(
|
||||
() => Text(
|
||||
'已下载'.tr,
|
||||
style: state.isNavLocal.value == true
|
||||
? TextStyle(
|
||||
() =>
|
||||
Text(
|
||||
'已下载'.tr,
|
||||
style: state.isNavLocal.value == true
|
||||
? TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 28.sp,
|
||||
fontWeight: FontWeight.w600)
|
||||
: TextStyle(
|
||||
: TextStyle(
|
||||
color: Colors.grey,
|
||||
fontSize: 26.sp,
|
||||
fontWeight: FontWeight.w600),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -197,41 +203,120 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
||||
// 云存顶部视频
|
||||
Widget vipTip() {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Get.toNamed(Routers.valueAddedServicesHighFunctionPage);
|
||||
onTap: () async {
|
||||
await logic.getWebPlayUrl();
|
||||
// Get.toNamed(Routers.valueAddedCloudStoragePage);
|
||||
// Get.toNamed(Routers.valueAddedServicesHighFunctionPage);
|
||||
},
|
||||
child: Container(
|
||||
// height: 150.h,
|
||||
margin: EdgeInsets.all(15.w),
|
||||
padding:
|
||||
EdgeInsets.only(left: 20.w, top: 20.w, bottom: 20.w, right: 10.w),
|
||||
EdgeInsets.only(left: 20.w, top: 20.w, bottom: 20.w, right: 10.w),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF6F7F8),
|
||||
borderRadius: BorderRadius.circular(20.h)),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text('3天滚动储存'.tr, style: TextStyle(fontSize: 24.sp)),
|
||||
SizedBox(height: 10.h),
|
||||
Text("${F.navTitle}${"已为本设备免费提供3大滚动视频储存服务".tr}",
|
||||
style: TextStyle(fontSize: 22.sp, color: Colors.grey)),
|
||||
],
|
||||
)),
|
||||
SizedBox(width: 15.w),
|
||||
Text('去升级'.tr, style: TextStyle(fontSize: 22.sp)),
|
||||
Image(
|
||||
width: 40.w,
|
||||
height: 24.w,
|
||||
image: const AssetImage('images/icon_right_black.png'))
|
||||
],
|
||||
child: Obx(
|
||||
() =>
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text('3天滚动储存'.tr,
|
||||
style: TextStyle(fontSize: 24.sp)),
|
||||
SizedBox(height: 10.h),
|
||||
Text("${F
|
||||
.navTitle}${"已为本设备免费提供3大滚动视频储存服务"
|
||||
.tr}",
|
||||
style:
|
||||
TextStyle(fontSize: 22.sp, color: Colors
|
||||
.grey)),
|
||||
],
|
||||
)),
|
||||
SizedBox(width: 15.w),
|
||||
Text('去升级'.tr, style: TextStyle(fontSize: 22.sp)),
|
||||
Image(
|
||||
width: 40.w,
|
||||
height: 24.w,
|
||||
image: const AssetImage(
|
||||
'images/icon_right_black.png'))
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 16.h,
|
||||
),
|
||||
Text(
|
||||
'云存服务状态:${_handlerValidityPeriodStatsText()}',
|
||||
style: TextStyle(
|
||||
fontSize: 24.sp,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 8.h,
|
||||
),
|
||||
Visibility(
|
||||
visible: state.validityPeriodInfo.value != null &&
|
||||
state.validityPeriodInfo.value?.status == 1,
|
||||
child: Text(
|
||||
'过期时间:${state.validityPeriodInfo.value
|
||||
?.validityPeriodEnd}',
|
||||
style: TextStyle(
|
||||
fontSize: 24.sp,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 8.h,
|
||||
),
|
||||
Visibility(
|
||||
visible: state.validityPeriodInfo.value != null &&
|
||||
state.validityPeriodInfo.value?.status == 1,
|
||||
child: Text(
|
||||
'滚动存储天数:${state.validityPeriodInfo.value?.rollingStorageDays} 天',
|
||||
style: TextStyle(
|
||||
fontSize: 24.sp,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 8.h,
|
||||
),
|
||||
Visibility(
|
||||
visible: state.validityPeriodInfo.value != null &&
|
||||
state.validityPeriodInfo.value?.status == 1,
|
||||
child: Text(
|
||||
'剩余天数:${state.validityPeriodInfo.value
|
||||
?.remainingDays} 天',
|
||||
style: TextStyle(
|
||||
fontSize: 24.sp,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_handlerValidityPeriodStatsText() {
|
||||
if (state.validityPeriodInfo.value == null) {
|
||||
return '';
|
||||
}
|
||||
if (state.validityPeriodInfo.value?.status == 1) {
|
||||
return '已开通'.tr;
|
||||
} else if (state.validityPeriodInfo.value?.status == 2) {
|
||||
return '已过期'.tr;
|
||||
} else {
|
||||
return '未开通'.tr;
|
||||
}
|
||||
}
|
||||
|
||||
// 本地顶部
|
||||
Widget localTip() {
|
||||
return GestureDetector(
|
||||
@ -244,7 +329,7 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
||||
// height: 130.h,
|
||||
margin: EdgeInsets.all(15.w),
|
||||
padding:
|
||||
EdgeInsets.only(left: 20.w, top: 30.w, bottom: 30.w, right: 10.w),
|
||||
EdgeInsets.only(left: 20.w, top: 30.w, bottom: 30.w, right: 10.w),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF6F7F8),
|
||||
borderRadius: BorderRadius.circular(20.h)),
|
||||
@ -252,15 +337,15 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
// SizedBox(height: 20.h),
|
||||
Text('下载列表'.tr, style: TextStyle(fontSize: 24.sp)),
|
||||
SizedBox(height: 15.h),
|
||||
Text('暂无下载内容'.tr,
|
||||
style: TextStyle(fontSize: 22.sp, color: Colors.grey)),
|
||||
],
|
||||
)),
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
// SizedBox(height: 20.h),
|
||||
Text('下载列表'.tr, style: TextStyle(fontSize: 24.sp)),
|
||||
SizedBox(height: 15.h),
|
||||
Text('暂无下载内容'.tr,
|
||||
style: TextStyle(fontSize: 22.sp, color: Colors.grey)),
|
||||
],
|
||||
)),
|
||||
SizedBox(width: 15.w),
|
||||
// Text("去升级", style: TextStyle(fontSize: 24.sp)),
|
||||
Image(
|
||||
@ -334,7 +419,7 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
//横轴元素个数
|
||||
//横轴元素个数
|
||||
crossAxisCount: 3,
|
||||
//纵轴间距
|
||||
mainAxisSpacing: 15.w,
|
||||
@ -356,7 +441,7 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
//横轴元素个数
|
||||
//横轴元素个数
|
||||
crossAxisCount: 3,
|
||||
//纵轴间距
|
||||
mainAxisSpacing: 15.w,
|
||||
@ -384,9 +469,10 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => FullScreenImagePage(
|
||||
imageUrl: recordData.imagesUrl!,
|
||||
),
|
||||
builder: (context) =>
|
||||
FullScreenImagePage(
|
||||
imageUrl: recordData.imagesUrl!,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:get/get.dart';
|
||||
import 'package:get/get_rx/get_rx.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockDetail/passthrough_item.dart';
|
||||
import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart';
|
||||
|
||||
class VideoLogState {
|
||||
@ -17,4 +19,8 @@ class VideoLogState {
|
||||
getLockId.value = map['lockId'];
|
||||
}
|
||||
}
|
||||
|
||||
// 声明响应式变量
|
||||
final validityPeriodInfo = Rx<ValidityPeriod?>(null);
|
||||
RxString cloudStorageWebViewUrl = ''.obs;
|
||||
}
|
||||
|
||||
@ -16,6 +16,5 @@ class VideoLogDetailState {
|
||||
if (map['videoDataList'] != null) {
|
||||
videoLogList.value = map['videoDataList'];
|
||||
}
|
||||
print('object');
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,419 @@
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:crypto/crypto.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:star_lock/appRouters.dart';
|
||||
import 'package:star_lock/app_settings/app_colors.dart';
|
||||
import 'package:star_lock/blue/blue_manage.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_getDeviceModel.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_voicePackageConfigure.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_voicePackageConfigureProcess.dart';
|
||||
import 'package:star_lock/blue/io_reply.dart';
|
||||
import 'package:star_lock/blue/io_tool/io_tool.dart';
|
||||
import 'package:star_lock/blue/io_tool/manager_event_bus.dart';
|
||||
import 'package:star_lock/login/login/entity/LoginEntity.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockDetail/passthrough_item.dart';
|
||||
import 'package:star_lock/mine/addLock/lock_voice_setting/lock_voice_setting_state.dart';
|
||||
import 'package:star_lock/network/api_repository.dart';
|
||||
import 'package:star_lock/tools/baseGetXController.dart';
|
||||
import 'package:star_lock/tools/eventBusEventManage.dart';
|
||||
import 'package:star_lock/tools/showTipView.dart';
|
||||
import 'package:star_lock/tools/storage.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:star_lock/translations/app_dept.dart';
|
||||
|
||||
class LockVoiceSettingLogic extends BaseGetXController {
|
||||
LockVoiceSettingState state = LockVoiceSettingState();
|
||||
StreamSubscription<Reply>? _replySubscription;
|
||||
bool _isThrottled = false;
|
||||
// 超时定时器(用于检测是否未收到回复)
|
||||
Timer? _sendTimeoutTimer;
|
||||
|
||||
// 超时标志位(可选,防止重复处理)
|
||||
bool _isTimeout = false;
|
||||
|
||||
@override
|
||||
void onInit() async {
|
||||
super.onInit();
|
||||
_replySubscription =
|
||||
EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
|
||||
if (reply is VoicePackageConfigureReply) {
|
||||
// 语言包配置开始
|
||||
_handlerStartVoicePackageConfigure(reply);
|
||||
} else if (reply is VoicePackageConfigureProcessReply) {
|
||||
_handlerVoicePackageConfigureProcess(reply);
|
||||
} else if (reply is VoicePackageConfigureConfirmationReply) {
|
||||
handleVoiceConfigureThrottled(reply);
|
||||
}
|
||||
});
|
||||
initList();
|
||||
}
|
||||
|
||||
void handleVoiceConfigureThrottled(
|
||||
VoicePackageConfigureConfirmationReply reply,
|
||||
) {
|
||||
if (_isThrottled) return;
|
||||
|
||||
_isThrottled = true;
|
||||
|
||||
// 执行你的逻辑
|
||||
_executeLogic(reply);
|
||||
|
||||
// 设置节流时间(比如 1 秒)
|
||||
Future.delayed(Duration(seconds: 1), () {
|
||||
_isThrottled = false;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _executeLogic(
|
||||
VoicePackageConfigureConfirmationReply reply) async {
|
||||
final LoginEntity entity = await ApiRepository.to.settingCurrentVoiceTimbre(
|
||||
data: {
|
||||
'lang': state.tempLangStr.value,
|
||||
'timbre': state.tempTimbreStr.value,
|
||||
},
|
||||
lockId: state.lockSetInfoData.value.lockId!,
|
||||
);
|
||||
if (entity.errorCode!.codeIsSuccessful) {
|
||||
showSuccess('设置成功'.tr, something: () {
|
||||
state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.lang =
|
||||
state.tempLangStr.value;
|
||||
state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre
|
||||
?.timbre = state.tempTimbreStr.value;
|
||||
|
||||
eventBus
|
||||
.fire(PassCurrentLockInformationEvent(state.lockSetInfoData.value));
|
||||
Get.offAllNamed(Routers.starLockMain);
|
||||
});
|
||||
}
|
||||
dismissEasyLoading();
|
||||
}
|
||||
|
||||
void saveSpeechLanguageSettings() async {
|
||||
var language = state.languages[state.selectPassthroughListIndex.value];
|
||||
if (language.lang == 'system') {
|
||||
// 如果选择了跟随系统
|
||||
// 系统层的语言
|
||||
// print(CurrentLocaleTool.convertLocale(Get.deviceLocale!));
|
||||
|
||||
// APP层的语言
|
||||
Locale? currentLocale = Get.locale; // 直接获取最新语言
|
||||
if (currentLocale != null) {
|
||||
final indexWhere = state.languages
|
||||
.indexWhere((element) => element.lang == currentLocale.toString());
|
||||
state.selectPassthroughListIndex.value = indexWhere;
|
||||
}
|
||||
}
|
||||
language = state.languages[state.selectPassthroughListIndex.value];
|
||||
final value = state.selectSoundTypeIndex.value;
|
||||
state.tempLangStr.value = language.lang;
|
||||
language.timbres.forEach((element) async {
|
||||
if (element.isFemale == value) {
|
||||
await downloadFile(element.timbrePackUrl);
|
||||
state.tempTimbreStr.value = element.timbre;
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//下载语音包
|
||||
Future<void> downloadFile(String url) async {
|
||||
final http.Response response = await http.get(Uri.parse(url));
|
||||
if (response.statusCode == 200) {
|
||||
state.data = response.bodyBytes;
|
||||
sendFileToDevice(response.bodyBytes, <int>[0, 0, 0, 0]);
|
||||
}
|
||||
}
|
||||
|
||||
sendFileToDevice(Uint8List data, List<int> token) {
|
||||
showEasyLoading();
|
||||
showBlueConnetctToastTimer(action: () {
|
||||
dismissEasyLoading();
|
||||
});
|
||||
BlueManage().blueSendData(BlueManage().connectDeviceName,
|
||||
(BluetoothConnectionState deviceConnectionState) async {
|
||||
if (deviceConnectionState == BluetoothConnectionState.connected) {
|
||||
final List<String>? privateKey =
|
||||
await Storage.getStringList(saveBluePrivateKey);
|
||||
final List<int> getPrivateKeyList =
|
||||
changeStringListToIntList(privateKey!);
|
||||
final List<String>? signKey =
|
||||
await Storage.getStringList(saveBlueSignKey);
|
||||
final List<int> signKeyDataList = changeStringListToIntList(signKey!);
|
||||
final String uid = await Storage.getUid() ?? '';
|
||||
final String md5Str = md5.convert(data).toString().toUpperCase();
|
||||
BlueManage().writeCharacteristicWithResponse(
|
||||
VoicePackageConfigure(
|
||||
lockID: BlueManage().connectDeviceName,
|
||||
userID: uid,
|
||||
keyID: BlueManage().connectDeviceName,
|
||||
platform: 0,
|
||||
product: 0,
|
||||
fwSize: data.length,
|
||||
fwMD5: md5Str,
|
||||
needAuthor: 1,
|
||||
token: token,
|
||||
signKey: signKeyDataList,
|
||||
privateKey: getPrivateKeyList)
|
||||
.packageData(),
|
||||
);
|
||||
} else if (deviceConnectionState ==
|
||||
BluetoothConnectionState.disconnected) {
|
||||
dismissEasyLoading();
|
||||
cancelBlueConnetctToastTimer();
|
||||
// 延迟1秒后重试(避免频繁请求)
|
||||
Future.delayed(const Duration(seconds: 2), () {
|
||||
// 递归调用自身,重试次数+1
|
||||
sendFileToDevice(data, token);
|
||||
});
|
||||
|
||||
// showBlueConnetctToast();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _handlerVoicePackageConfigureProcess(
|
||||
VoicePackageConfigureProcessReply reply) {
|
||||
// 取消超时定时器(已收到回复,无需继续等待)
|
||||
_sendTimeoutTimer?.cancel();
|
||||
_isTimeout = false; // 重置超时标志
|
||||
final int status = reply.data[2];
|
||||
switch (status) {
|
||||
case 0x00:
|
||||
cancelBlueConnetctToastTimer();
|
||||
state.voiceSubcontractingIndex++;
|
||||
_sendNextPackage();
|
||||
break;
|
||||
default:
|
||||
showToast('发送分包数据不成功'.tr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 开始配置语音包
|
||||
void _handlerStartVoicePackageConfigure(
|
||||
VoicePackageConfigureReply reply) async {
|
||||
final int status = reply.data[6];
|
||||
switch (status) {
|
||||
case 0x00:
|
||||
//成功
|
||||
cancelBlueConnetctToastTimer();
|
||||
|
||||
_startSendLanguageFile();
|
||||
|
||||
break;
|
||||
case 0x06:
|
||||
//无权限
|
||||
final List<int> token = reply.data.sublist(2, 6);
|
||||
if (state.data != null) {
|
||||
sendFileToDevice(state.data!, token);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
showToast('获取设备型号失败'.tr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取列表
|
||||
initList() async {
|
||||
showEasyLoading();
|
||||
try {
|
||||
final vendor = state.lockSetInfoData.value.lockBasicInfo?.vendor;
|
||||
final model = state.lockSetInfoData.value.lockBasicInfo?.model;
|
||||
|
||||
final PassthroughListResponse entity =
|
||||
await ApiRepository.to.getPassthroughList(data: {
|
||||
'vendor': vendor!,
|
||||
'model': model!,
|
||||
});
|
||||
if (entity.errorCode!.codeIsSuccessful) {
|
||||
final data = entity.data;
|
||||
final locales = appDept.deptSupportedLocales;
|
||||
state.languages.clear();
|
||||
|
||||
state.languages.add(
|
||||
PassthroughItem(
|
||||
lang: 'system',
|
||||
timbres: [],
|
||||
langText: '跟随系统'.tr,
|
||||
name: '跟随系统'.tr,
|
||||
),
|
||||
);
|
||||
|
||||
data?.forEach((element) {
|
||||
final lang = element.lang;
|
||||
List<String> parts = lang.split('_');
|
||||
final indexOf = locales.indexOf(Locale(parts[0], parts[1]));
|
||||
final passthroughItem = PassthroughItem(
|
||||
lang: element.lang,
|
||||
timbres: element.timbres,
|
||||
langText:
|
||||
ExtensionLanguageType.fromLocale(locales[indexOf]).lanTitle,
|
||||
name: element.name,
|
||||
);
|
||||
state.languages.add(passthroughItem);
|
||||
});
|
||||
state.languages.refresh();
|
||||
final lang = state
|
||||
.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.lang;
|
||||
final timbre = state
|
||||
.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.timbre;
|
||||
state.languages.value.forEach((element) {
|
||||
final timbres = element.timbres;
|
||||
timbres.forEach((item) {
|
||||
if (lang == element.lang && item.timbre == timbre) {
|
||||
state.selectSoundTypeIndex.value = item.isFemale;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('获取语音包出现错误:$e');
|
||||
} finally {
|
||||
dismissEasyLoading();
|
||||
}
|
||||
}
|
||||
|
||||
// 发送获取型号蓝牙命令
|
||||
sendGetDeviceModelBleMessage() {
|
||||
showEasyLoading();
|
||||
showBlueConnetctToastTimer(action: () {
|
||||
dismissEasyLoading();
|
||||
});
|
||||
BlueManage().blueSendData(
|
||||
BlueManage().connectDeviceName,
|
||||
(BluetoothConnectionState deviceConnectionState) async {
|
||||
if (deviceConnectionState == BluetoothConnectionState.connected) {
|
||||
BlueManage().writeCharacteristicWithResponse(
|
||||
GetDeviceModelCommand(
|
||||
lockID: BlueManage().connectDeviceName,
|
||||
).packageData(),
|
||||
);
|
||||
} else if (deviceConnectionState ==
|
||||
BluetoothConnectionState.disconnected) {
|
||||
dismissEasyLoading();
|
||||
cancelBlueConnetctToastTimer();
|
||||
showBlueConnetctToast();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _startSendLanguageFile() {
|
||||
if (state.data == null) return;
|
||||
state.voiceSubcontractingIndex = 0;
|
||||
state.voiceSubcontractingCount =
|
||||
(state.data!.length + state.voiceSubcontractingSize - 1) ~/
|
||||
state.voiceSubcontractingSize;
|
||||
state.progress.value = 0.0; // 开始前重置进度
|
||||
_sendNextPackage();
|
||||
}
|
||||
void _handleSendTimeout() {
|
||||
_isTimeout = true; // 标记超时状态
|
||||
dismissEasyLoading();
|
||||
cancelBlueConnetctToastTimer();
|
||||
showBlueConnetctToast();
|
||||
|
||||
// 重置状态,避免后续错误操作
|
||||
state.voiceSubcontractingIndex = 0;
|
||||
state.voiceSubcontractingCount = 0;
|
||||
state.data = null;
|
||||
state.progress.value = 0.0;
|
||||
_isTimeout = false; // 标记超时状态
|
||||
}
|
||||
|
||||
void _sendNextPackage() {
|
||||
// 若已超时,直接返回
|
||||
if (_isTimeout) return;
|
||||
|
||||
// 取消上一次未完成的定时器(避免重复触发)
|
||||
_sendTimeoutTimer?.cancel();
|
||||
|
||||
if (state.voiceSubcontractingIndex >= state.voiceSubcontractingCount) {
|
||||
print('所有分包已发送完成');
|
||||
state.progress.value = 1.0; // 发送完成
|
||||
// 可在此处通知UI或做后续处理
|
||||
return;
|
||||
}
|
||||
|
||||
// 启动 3 秒超时定时器
|
||||
_sendTimeoutTimer = Timer(Duration(seconds: 3), () {
|
||||
_handleSendTimeout(); // 触发超时处理
|
||||
});
|
||||
|
||||
|
||||
int start = state.voiceSubcontractingIndex * state.voiceSubcontractingSize;
|
||||
int end = start + state.voiceSubcontractingSize;
|
||||
if (end > state.data!.length) end = state.data!.length;
|
||||
Uint8List packageData = state.data!.sublist(start, end);
|
||||
|
||||
// 更新分包进度
|
||||
state.progress.value =
|
||||
(state.voiceSubcontractingIndex + 1) / state.voiceSubcontractingCount;
|
||||
EasyLoading.showProgress(state.progress.value,
|
||||
status: '正在发送数据 ${(state.progress.value * 100).toStringAsFixed(0)}%');
|
||||
_sendLanguageFileBleMessage(
|
||||
index: state.voiceSubcontractingIndex,
|
||||
data: packageData,
|
||||
);
|
||||
}
|
||||
|
||||
_sendLanguageFileBleMessage({required int index, required Uint8List data}) {
|
||||
BlueManage().blueSendData(BlueManage().connectDeviceName,
|
||||
(BluetoothConnectionState deviceConnectionState) async {
|
||||
if (deviceConnectionState == BluetoothConnectionState.connected) {
|
||||
BlueManage().writeCharacteristicWithResponse(
|
||||
VoicePackageConfigureProcess(
|
||||
index: index,
|
||||
size: data.length,
|
||||
data: data,
|
||||
).packageData(),
|
||||
);
|
||||
} else if (deviceConnectionState ==
|
||||
BluetoothConnectionState.disconnected) {
|
||||
dismissEasyLoading();
|
||||
cancelBlueConnetctToastTimer();
|
||||
// showBlueConnetctToast();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() async {
|
||||
await _replySubscription?.cancel();
|
||||
_replySubscription = null;
|
||||
await BlueManage().disconnect();
|
||||
dismissEasyLoading();
|
||||
cancelBlueConnetctToastTimer();
|
||||
EasyLoading.dismiss();
|
||||
// 清理分包相关状态
|
||||
state.progress.value = 0.0;
|
||||
state.voiceSubcontractingIndex = 0;
|
||||
state.voiceSubcontractingCount = 0;
|
||||
state.data = null;
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() async {
|
||||
await _replySubscription?.cancel();
|
||||
_replySubscription = null;
|
||||
await BlueManage().disconnect();
|
||||
dismissEasyLoading();
|
||||
cancelBlueConnetctToastTimer();
|
||||
EasyLoading.dismiss();
|
||||
// 清理分包相关状态
|
||||
state.progress.value = 0.0;
|
||||
state.voiceSubcontractingIndex = 0;
|
||||
state.voiceSubcontractingCount = 0;
|
||||
state.data = null;
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
183
lib/mine/addLock/lock_voice_setting/lock_voice_setting_page.dart
Normal file
183
lib/mine/addLock/lock_voice_setting/lock_voice_setting_page.dart
Normal file
@ -0,0 +1,183 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:get/get_utils/get_utils.dart';
|
||||
import 'package:star_lock/appRouters.dart';
|
||||
import 'package:star_lock/app_settings/app_colors.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockDetail/passthrough_item.dart';
|
||||
import 'package:star_lock/mine/addLock/lock_voice_setting/lock_voice_setting_logic.dart';
|
||||
import 'package:star_lock/mine/addLock/lock_voice_setting/lock_voice_setting_state.dart';
|
||||
import 'package:star_lock/tools/EasyRefreshTool.dart';
|
||||
import 'package:star_lock/tools/commonItem.dart';
|
||||
import 'package:star_lock/tools/eventBusEventManage.dart';
|
||||
import 'package:star_lock/tools/titleAppBar.dart';
|
||||
|
||||
class LockVoiceSetting extends StatefulWidget {
|
||||
const LockVoiceSetting();
|
||||
|
||||
@override
|
||||
State<LockVoiceSetting> createState() => _LockVoiceSettingState();
|
||||
}
|
||||
|
||||
class _LockVoiceSettingState extends State<LockVoiceSetting> {
|
||||
final LockVoiceSettingLogic logic = Get.put(LockVoiceSettingLogic());
|
||||
final LockVoiceSettingState state = Get.find<LockVoiceSettingLogic>().state;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return WillPopScope(
|
||||
onWillPop: () async {
|
||||
return false;
|
||||
},
|
||||
child: Scaffold(
|
||||
backgroundColor: AppColors.mainBackgroundColor,
|
||||
appBar: TitleAppBar(
|
||||
barTitle: '锁语音包设置'.tr,
|
||||
haveBack: false,
|
||||
haveOtherLeftWidget: true,
|
||||
leftWidget: TextButton(
|
||||
onPressed: () {
|
||||
eventBus
|
||||
.fire(RefreshLockListInfoDataEvent(isUnShowLoading: true));
|
||||
Get.offAllNamed(Routers.starLockMain);
|
||||
},
|
||||
child: Text(
|
||||
'跳过'.tr,
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 24.sp,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
backgroundColor: AppColors.mainColor,
|
||||
actionsList: [
|
||||
TextButton(
|
||||
onPressed: logic.saveSpeechLanguageSettings,
|
||||
child: Text(
|
||||
'下载'.tr,
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 24.sp,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: _buildBody(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody() {
|
||||
return Obx(
|
||||
() => SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
width: 1.sw,
|
||||
decoration: BoxDecoration(color: Colors.white),
|
||||
child: ListView.builder(
|
||||
itemCount: state.soundTypeList.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
// 判断是否是最后一个元素(索引等于 itemCount - 1)
|
||||
final isLastItem = index == state.soundTypeList.length - 1;
|
||||
|
||||
// 获取当前平台数据(假设 platFormSet 是 RxList<Platform>)
|
||||
final platform = state.soundTypeList.value[index];
|
||||
return CommonItem(
|
||||
leftTitel: state.soundTypeList.value[index],
|
||||
rightTitle: '',
|
||||
isHaveLine: !isLastItem,
|
||||
// 最后一个元素不显示分割线(取反)
|
||||
isHaveDirection: false,
|
||||
isHaveRightWidget: true,
|
||||
rightWidget: Radio<String>(
|
||||
// Radio 的值:使用平台的唯一标识(如 id)
|
||||
value: platform,
|
||||
// 当前选中的值:与 selectPlatFormIndex 关联的 id
|
||||
groupValue: state.soundTypeList
|
||||
.value[state.selectSoundTypeIndex.value],
|
||||
// 选中颜色(可选,默认主题色)
|
||||
activeColor: AppColors.mainColor,
|
||||
// 点击 Radio 时回调(更新选中索引)
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
setState(() {
|
||||
// 找到当前选中平台的索引(根据 id 匹配)
|
||||
final newIndex = state.soundTypeList.value
|
||||
.indexWhere((p) => p == value);
|
||||
if (newIndex != -1) {
|
||||
state.selectSoundTypeIndex.value = newIndex;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
action: () {
|
||||
setState(() {
|
||||
state.selectSoundTypeIndex.value = index;
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
shrinkWrap: true,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 8.h,
|
||||
),
|
||||
Column(
|
||||
children: _buildList(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _buildList() {
|
||||
final appLocalLanguages = state.languages;
|
||||
return List.generate(
|
||||
appLocalLanguages.length,
|
||||
(index) => _buildItem(
|
||||
appLocalLanguages[index],
|
||||
index,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_buildItem(PassthroughItem passthroughItem, index) {
|
||||
return CommonItem(
|
||||
leftTitel: passthroughItem.langText,
|
||||
rightTitle: '',
|
||||
isHaveLine: true,
|
||||
isHaveDirection: false,
|
||||
isHaveRightWidget: true,
|
||||
rightWidget: state.selectPassthroughListIndex.value == index
|
||||
? Image(
|
||||
image: const AssetImage('images/icon_item_checked.png'),
|
||||
width: 30.w,
|
||||
height: 30.w,
|
||||
fit: BoxFit.contain,
|
||||
)
|
||||
: Container(),
|
||||
action: () {
|
||||
state.selectPassthroughListIndex.value = index;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// TODO: implement dispose
|
||||
super.dispose();
|
||||
if (EasyLoading.isShow) {
|
||||
EasyLoading.dismiss(animation: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:get/get.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockDetail/passthrough_item.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockSet/lockSet/lockSetInfo_entity.dart';
|
||||
import 'package:star_lock/translations/app_dept.dart';
|
||||
|
||||
class LockVoiceSettingState {
|
||||
LockVoiceSettingState() {
|
||||
final map = Get.arguments;
|
||||
lockSetInfoData.value = map['lockSetInfoData'];
|
||||
|
||||
lockBasicInfo.value = lockSetInfoData.value.lockBasicInfo!;
|
||||
}
|
||||
|
||||
Rx<LockSetInfoData> lockSetInfoData = LockSetInfoData().obs;
|
||||
Rx<LockBasicInfo> lockBasicInfo = LockBasicInfo().obs;
|
||||
|
||||
|
||||
|
||||
// 选中的语音包列表下标
|
||||
RxInt selectPassthroughListIndex = 0.obs;
|
||||
|
||||
// 选中的语音下标
|
||||
RxInt selectLanguageIndex = 0.obs;
|
||||
|
||||
final RxList<PassthroughItem> languages = <PassthroughItem>[].obs;
|
||||
|
||||
Map<int, String> languageSpeechDeviceTypeMapping = {0: '2403'};
|
||||
|
||||
RxBool otaUpdateIng = false.obs;
|
||||
RxDouble otaProgress = 0.00.obs;
|
||||
RxString deviceModel = '2403'.obs;
|
||||
Uint8List? data;
|
||||
|
||||
// 语音包最大大小
|
||||
int voiceSubcontractingSize = 256;
|
||||
|
||||
// 总数据包数量
|
||||
int voiceSubcontractingCount = 0;
|
||||
|
||||
// 数据包序列号
|
||||
int voiceSubcontractingIndex = 0;
|
||||
|
||||
// 分包发送进度(0.0~1.0)
|
||||
RxDouble progress = 0.0.obs;
|
||||
// 响应式字符串集合(自动触发 UI 更新)
|
||||
final RxList<String> soundTypeList = List.of({
|
||||
'男声'.tr,
|
||||
'女声'.tr,
|
||||
}).obs;
|
||||
|
||||
RxInt selectSoundTypeIndex = 1.obs;
|
||||
RxString tempLangStr=''.obs;
|
||||
RxString tempTimbreStr=''.obs;
|
||||
}
|
||||
@ -337,17 +337,15 @@ class NearbyLockLogic extends BaseGetXController {
|
||||
// 'featureSettingValue': state.featureSettingValue,
|
||||
// 'featureSettingParams': state.featureSettingParams,
|
||||
// });
|
||||
Get.toNamed(Routers.saveLockPage,
|
||||
arguments: <String, Object?>{
|
||||
'addressInfo': {},
|
||||
'pwdTimestamp': state.timestampValue * 1000,
|
||||
'lockInfo': state.lockInfo,
|
||||
'featureValue': state.featureValue,
|
||||
'featureSettingValue': state.featureSettingValue,
|
||||
'featureSettingParams': state.featureSettingParams,
|
||||
'isFromMap': 0,
|
||||
});
|
||||
|
||||
Get.toNamed(Routers.saveLockPage, arguments: <String, Object?>{
|
||||
'addressInfo': {},
|
||||
'pwdTimestamp': state.timestampValue * 1000,
|
||||
'lockInfo': state.lockInfo,
|
||||
'featureValue': state.featureValue,
|
||||
'featureSettingValue': state.featureSettingValue,
|
||||
'featureSettingParams': state.featureSettingParams,
|
||||
'isFromMap': 0,
|
||||
});
|
||||
|
||||
break;
|
||||
case 0x06:
|
||||
|
||||
@ -486,7 +486,6 @@ class SaveLockLogic extends BaseGetXController {
|
||||
// }
|
||||
|
||||
void backAction() async {
|
||||
|
||||
// BlueManage().disconnect();
|
||||
|
||||
// 查询锁设置信息
|
||||
@ -502,13 +501,19 @@ class SaveLockLogic extends BaseGetXController {
|
||||
'lockSetInfoData': state.lockSetInfoData.value,
|
||||
'pageName': 'saveLock'
|
||||
});
|
||||
} else if (state.lockSetInfoData.value.lockFeature?.languageSpeech == 1) {
|
||||
Get.toNamed(Routers.lockVoiceSettingPage, arguments: {
|
||||
'lockSetInfoData': state.lockSetInfoData.value,
|
||||
'pageName': 'saveLock'
|
||||
});
|
||||
} else {
|
||||
eventBus.fire(RefreshLockListInfoDataEvent(clearScanDevices: true,isUnShowLoading: true));
|
||||
eventBus.fire(RefreshLockListInfoDataEvent(
|
||||
clearScanDevices: true, isUnShowLoading: true));
|
||||
Future<void>.delayed(const Duration(seconds: 1), () {
|
||||
// Get.close(state.isFromMap == 1
|
||||
// ? (CommonDataManage().seletLockType == 0 ? 4 : 5)
|
||||
// : (CommonDataManage().seletLockType == 0 ? 5 : 6));
|
||||
Get.until((route) => route.isFirst);
|
||||
Get.until((route) => route.isFirst);
|
||||
});
|
||||
//刚刚配对完,需要对开锁页锁死 2 秒
|
||||
Future<void>.delayed(const Duration(milliseconds: 200), () {
|
||||
@ -520,7 +525,8 @@ class SaveLockLogic extends BaseGetXController {
|
||||
});
|
||||
}
|
||||
} else {
|
||||
eventBus.fire(RefreshLockListInfoDataEvent(clearScanDevices: true,isUnShowLoading: true));
|
||||
eventBus.fire(RefreshLockListInfoDataEvent(
|
||||
clearScanDevices: true, isUnShowLoading: true));
|
||||
Future<void>.delayed(const Duration(seconds: 1), () {
|
||||
// Get.close(state.isFromMap == 1
|
||||
// ? (CommonDataManage().seletLockType == 0 ? 4 : 5)
|
||||
|
||||
@ -84,17 +84,17 @@ class _SelectLockTypePageState extends State<SelectLockTypePage>
|
||||
arguments: <String, int>{'getLockType': 1});
|
||||
}),
|
||||
// if (!F.isLite)
|
||||
lockTypeItem('images/lockType/lockType_NFCLock.png', 'NFC无源锁'.tr, () {
|
||||
CommonDataManage().seletLockType = 2;
|
||||
// Navigator.pushNamed(context, Routers.addLockPage);
|
||||
logic.getNearByLimits();
|
||||
}),
|
||||
lockTypeItem('images/lockType/lockType_NFCLock.png', 'NFC无源锁'.tr, () {
|
||||
CommonDataManage().seletLockType = 2;
|
||||
// Navigator.pushNamed(context, Routers.addLockPage);
|
||||
logic.getNearByLimits();
|
||||
}),
|
||||
// if (!F.isLite)
|
||||
lockTypeItem('images/lockType/lockType_padlock.png', '挂锁'.tr, () {
|
||||
CommonDataManage().seletLockType = 3;
|
||||
// Navigator.pushNamed(context, Routers.addLockPage);
|
||||
logic.getNearByLimits();
|
||||
}),
|
||||
lockTypeItem('images/lockType/lockType_padlock.png', '挂锁'.tr, () {
|
||||
CommonDataManage().seletLockType = 3;
|
||||
// Navigator.pushNamed(context, Routers.addLockPage);
|
||||
logic.getNearByLimits();
|
||||
}),
|
||||
lockTypeItem('images/lockType/lockType_safeLock.png', '保险箱锁'.tr, () {
|
||||
CommonDataManage().seletLockType = 4;
|
||||
Navigator.pushNamed(context, Routers.addLockPage,
|
||||
@ -223,9 +223,16 @@ class _SelectLockTypePageState extends State<SelectLockTypePage>
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(lockTypeTitle,
|
||||
style: TextStyle(
|
||||
fontSize: 22.sp, color: AppColors.blackColor)),
|
||||
Text(
|
||||
lockTypeTitle,
|
||||
maxLines: 2, // 最大行数
|
||||
overflow: TextOverflow.ellipsis, // 超出显示省略号
|
||||
softWrap: true, // 自动换行
|
||||
style: TextStyle(
|
||||
fontSize: 22.sp,
|
||||
color: AppColors.blackColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@ -25,6 +25,7 @@ class SelectGatewayListLogic extends BaseGetXController {
|
||||
|
||||
// 监听设备返回的数据
|
||||
late StreamSubscription<Reply> _replySubscription;
|
||||
|
||||
void _initReplySubscription() {
|
||||
_replySubscription =
|
||||
EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
|
||||
@ -35,7 +36,6 @@ class SelectGatewayListLogic extends BaseGetXController {
|
||||
});
|
||||
}
|
||||
|
||||
// WIFI配网结果
|
||||
Future<void> _replyGatewayGetStatusReply(Reply reply) async {
|
||||
final int status = reply.data[2];
|
||||
|
||||
@ -99,7 +99,7 @@ class SelectGatewayListLogic extends BaseGetXController {
|
||||
void startScanBlueList() {
|
||||
state.devices.clear();
|
||||
BlueManage().startScan(2000, DeviceType.gateway, (List<ScanResult> list) {
|
||||
AppLog.log('ScanResultList:$list');
|
||||
// AppLog.log('ScanResultList:$list');
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
final ScanResult device = list[i];
|
||||
// if ((device.advertisementData.serviceUuids.isNotEmpty
|
||||
@ -211,7 +211,12 @@ class SelectGatewayListLogic extends BaseGetXController {
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
_replySubscription.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
@override
|
||||
void onClose() {
|
||||
_replySubscription.cancel();
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,12 +32,16 @@ class Data {
|
||||
String? vipBuyUrl;
|
||||
String? cloudauthBuyUrl;
|
||||
String? shopList;
|
||||
String? cloudStorage;
|
||||
String? valueAddServiceLimitFree;
|
||||
|
||||
Data(
|
||||
{this.smsBuyUrl,
|
||||
this.emailBuyUrl,
|
||||
this.vipBuyUrl,
|
||||
this.cloudauthBuyUrl,
|
||||
this.cloudStorage,
|
||||
this.valueAddServiceLimitFree,
|
||||
this.shopList});
|
||||
|
||||
Data.fromJson(Map<String, dynamic> json) {
|
||||
@ -46,6 +50,8 @@ class Data {
|
||||
vipBuyUrl = json['vip_buy_url'];
|
||||
cloudauthBuyUrl = json['cloudauth_buy_url'];
|
||||
shopList = json['shopList'];
|
||||
cloudStorage = json['cloud_storage'];
|
||||
valueAddServiceLimitFree = json['value_add_service_limit_free'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
@ -55,6 +61,8 @@ class Data {
|
||||
data['vip_buy_url'] = vipBuyUrl;
|
||||
data['cloudauth_buy_url'] = cloudauthBuyUrl;
|
||||
data['shopList'] = shopList;
|
||||
data['cloud_storage'] = cloudStorage;
|
||||
data['value_add_service_limit_free'] = valueAddServiceLimitFree;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,6 +40,9 @@ class AdvancedFeaturesWebLogic extends BaseGetXController {
|
||||
} else if (state.webBuyType.value == XSConstantMacro.webBuyTypeShop) {
|
||||
state.webBuyUrl.value = entity.data!.shopList!;
|
||||
state.webBuyTitle.value = '商城购买'.tr;
|
||||
}else if (state.webBuyType.value == XSConstantMacro.webBuyTypeCloudStorage) {
|
||||
state.webBuyUrl.value = entity.data!.cloudStorage!;
|
||||
state.webBuyTitle.value = '云存购买'.tr;
|
||||
}
|
||||
|
||||
state.webBuyView.setNavigationDelegate(
|
||||
|
||||
@ -19,6 +19,8 @@ class AdvancedFeaturesWebState {
|
||||
webBuyTitle.value = '邮件购买'.tr;
|
||||
} else if (webBuyType.value == XSConstantMacro.webBuyTypeShop) {
|
||||
webBuyTitle.value = '商城购买'.tr;
|
||||
}else if (webBuyType.value == XSConstantMacro.webBuyTypeCloudStorage) {
|
||||
webBuyTitle.value = '云存购买'.tr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
import 'package:star_lock/mine/valueAddedServices/cloudStorage/cloud_storage_state.dart';
|
||||
import 'package:star_lock/tools/baseGetXController.dart';
|
||||
|
||||
class CloudStorageLogic extends BaseGetXController {
|
||||
CloudStorageState state = CloudStorageState();
|
||||
}
|
||||
150
lib/mine/valueAddedServices/cloudStorage/cloud_storage_page.dart
Normal file
150
lib/mine/valueAddedServices/cloudStorage/cloud_storage_page.dart
Normal file
@ -0,0 +1,150 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:star_lock/app_settings/app_colors.dart';
|
||||
import 'package:star_lock/mine/valueAddedServices/cloudStorage/cloud_storage_logic.dart';
|
||||
import 'package:star_lock/mine/valueAddedServices/cloudStorage/cloud_storage_state.dart';
|
||||
import 'package:star_lock/tools/titleAppBar.dart';
|
||||
|
||||
class CloudStoragePage extends StatefulWidget {
|
||||
const CloudStoragePage();
|
||||
|
||||
@override
|
||||
State<CloudStoragePage> createState() => _CloudStoragePageState();
|
||||
}
|
||||
|
||||
class _CloudStoragePageState extends State<CloudStoragePage> {
|
||||
final CloudStorageLogic logic = Get.put(CloudStorageLogic());
|
||||
final CloudStorageState state = Get.find<CloudStorageLogic>().state;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: TitleAppBar(
|
||||
barTitle: '云存储购买'.tr,
|
||||
haveBack: true,
|
||||
iconColor: Colors.black,
|
||||
titleColor: Colors.black,
|
||||
backgroundColor: Colors.white,
|
||||
),
|
||||
body: SafeArea(
|
||||
child: _buildBody(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody() {
|
||||
return Container(
|
||||
decoration: const BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.center,
|
||||
colors: [Color(0xFFC5F0E7), Color(0xFFF7F7F7)],
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
// 购买套餐选项卡
|
||||
_buildPurchasePackage()
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPurchasePackage() {
|
||||
return Container(
|
||||
width: 1.sw,
|
||||
margin: EdgeInsets.symmetric(
|
||||
vertical: 12.h,
|
||||
horizontal: 14.w,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF7F7F7),
|
||||
borderRadius: BorderRadiusDirectional.all(
|
||||
Radius.circular(16.r),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
_buildTabs(),
|
||||
_buildTabContent(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTabs() {
|
||||
return Obx(
|
||||
() => Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: List.generate(
|
||||
state.tabs.length,
|
||||
(int index) => _buildTabItem(index),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTabItem(int index) {
|
||||
return Expanded(
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
state.selectedIndex.value = index;
|
||||
},
|
||||
child: Container(
|
||||
height: 68.h,
|
||||
decoration: BoxDecoration(
|
||||
color: _isSelectTabBgColor(index),
|
||||
borderRadius: BorderRadiusDirectional.only(
|
||||
topStart: Radius.circular(16.r),
|
||||
topEnd: Radius.circular(16.r),
|
||||
),
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
state.tabs[index],
|
||||
style: _isSelectTabTitle(index),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
TextStyle _isSelectTabTitle(int index) {
|
||||
if (state.selectedIndex.value == index) {
|
||||
return TextStyle(
|
||||
color: const Color(0xFF040404),
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 28.sp,
|
||||
);
|
||||
}
|
||||
return TextStyle(
|
||||
color: const Color(0xFF8F8F8F),
|
||||
fontSize: 28.sp,
|
||||
);
|
||||
}
|
||||
|
||||
Color _isSelectTabBgColor(int index) {
|
||||
if (state.selectedIndex.value == index) {
|
||||
return Colors.white;
|
||||
}
|
||||
return const Color(0xFFF7F7F7);
|
||||
}
|
||||
|
||||
Widget _buildTabContent() {
|
||||
return Container(
|
||||
width: 1.sw,
|
||||
padding: EdgeInsets.symmetric(
|
||||
vertical: 12.h,
|
||||
horizontal: 14.w,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
),
|
||||
child: Text('asd'),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class CloudStorageState {
|
||||
// 选中的索引
|
||||
RxInt selectedIndex = 0.obs;
|
||||
|
||||
// 选项卡标题
|
||||
final List<String> tabs = ['7天滚动存储', '30天滚动存储'];
|
||||
final List<Map<String, dynamic>> tabContent = [
|
||||
{'title': '连续包月', 'price': '1', 'price2': '188', 'discount': '立省188元'},
|
||||
{'title': '连续包月', 'price': '1', 'price2': '188', 'discount': '立省188元'}
|
||||
];
|
||||
}
|
||||
@ -265,6 +265,8 @@ abstract class Api {
|
||||
final String getServiceUserPackageURL =
|
||||
'/v2/service/getUserPackage'; //获取增值服务用户余量包
|
||||
|
||||
final String getValidityPeriodInfoURL = '/passthrough';
|
||||
//获取云存储服务信息
|
||||
final String getlockCloudStorageListURL = '/lockCloudStorage/list'; //获取云存列表
|
||||
final String deleteLockCloudStorageURL = '/lockCloudStorage/delete'; //删除云存
|
||||
|
||||
@ -298,4 +300,9 @@ abstract class Api {
|
||||
'/SL-A-1.0/peer/nslookup'; // 星图--解析对端信息
|
||||
final String bindUserStarchartURL =
|
||||
'/userStarchart/bindUserStarchart'; // 绑定星图配置
|
||||
final String getPassthroughListURL = '/passthrough'; // 获取语音列表
|
||||
final String updateCurrentVoiceTimbre =
|
||||
'/lockSetting/updateLockSetting'; // 设置语音包
|
||||
final String reportBuyRequestURL =
|
||||
'/service/reportBuyRequest'; // 上报增值服务购买请求
|
||||
}
|
||||
|
||||
@ -2400,6 +2400,22 @@ class ApiProvider extends BaseProvider {
|
||||
'searchStr': searchStr
|
||||
}));
|
||||
|
||||
// 获取云存列表
|
||||
Future<Response> getValidityPeriodInfo(
|
||||
int lockId, {
|
||||
String request_method = 'POST',
|
||||
String request_uri = '/api/v1/cloudStorage/getStorageServiceInfo',
|
||||
required Map<String, dynamic> post_args,
|
||||
}) =>
|
||||
post(
|
||||
getValidityPeriodInfoURL.toUrl,
|
||||
jsonEncode({
|
||||
'lockId': lockId,
|
||||
'request_method': request_method,
|
||||
'request_uri': request_uri,
|
||||
'post_args': post_args,
|
||||
}));
|
||||
|
||||
// 获取云存列表
|
||||
Future<Response> getLockCloudStorageList(int lockId) =>
|
||||
post(getlockCloudStorageListURL.toUrl, jsonEncode({'lockId': lockId}));
|
||||
@ -2773,6 +2789,55 @@ class ApiProvider extends BaseProvider {
|
||||
isShowNetworkErrorMsg: false,
|
||||
isShowErrMsg: false,
|
||||
isUnShowLoading: true);
|
||||
|
||||
/// 获取设备配网信息
|
||||
Future<Response> getPassthroughList(
|
||||
String requestMethod,
|
||||
String requestUri,
|
||||
Map<String, String> data,
|
||||
) =>
|
||||
post(
|
||||
getPassthroughListURL.toUrl,
|
||||
jsonEncode({
|
||||
'request_method': requestMethod,
|
||||
'request_uri': requestUri,
|
||||
'post_args': data,
|
||||
}),
|
||||
isShowNetworkErrorMsg: false,
|
||||
isShowErrMsg: false,
|
||||
isUnShowLoading: true);
|
||||
|
||||
/// 设置语音包
|
||||
Future<Response> settingCurrentVoiceTimbre(
|
||||
int lockId,
|
||||
Map<String, String> data,
|
||||
) =>
|
||||
post(
|
||||
updateCurrentVoiceTimbre.toUrl,
|
||||
jsonEncode({
|
||||
'lockId': lockId,
|
||||
'currentVoiceTimbre': data,
|
||||
}),
|
||||
isShowNetworkErrorMsg: false,
|
||||
isShowErrMsg: false,
|
||||
isUnShowLoading: true);
|
||||
|
||||
/// 设置语音包
|
||||
Future<Response> reportBuyRequest(
|
||||
int lockId,
|
||||
String type,
|
||||
) =>
|
||||
post(
|
||||
reportBuyRequestURL.toUrl,
|
||||
jsonEncode({
|
||||
'lockId': lockId,
|
||||
'type': type,
|
||||
}),
|
||||
isShowNetworkErrorMsg: false,
|
||||
isShowErrMsg: false,
|
||||
isUnShowLoading: true);
|
||||
|
||||
|
||||
}
|
||||
|
||||
extension ExtensionString on String {
|
||||
|
||||
@ -13,6 +13,7 @@ import 'package:star_lock/main/lockDetail/electronicKey/sendEmailNotification/se
|
||||
import 'package:star_lock/main/lockDetail/face/addFace/addFace_entity.dart';
|
||||
import 'package:star_lock/main/lockDetail/fingerprint/fingerprintList/fingerprint_entity.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockDetail/device_network_info.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockDetail/passthrough_item.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockSet/basicInformation/basicInformation/KeyDetailEntity.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockSet/lockEscalation/updateLockInfo_entity.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockSet/lockEscalation/version_entity.dart';
|
||||
@ -2435,6 +2436,30 @@ class ApiRepository {
|
||||
return CoerceFingerprintListEntity.fromJson(res.body);
|
||||
}
|
||||
|
||||
// 获取云存储服务信息
|
||||
Future<ValidityPeriodResponse> getValidityPeriodInfo({
|
||||
required int lockId,
|
||||
}) async {
|
||||
Map<String, dynamic> post_args = Map.of({'lockId': lockId});
|
||||
final res = await apiProvider.getValidityPeriodInfo(
|
||||
lockId,
|
||||
post_args: post_args,
|
||||
);
|
||||
return ValidityPeriodResponse.fromJson(res.body);
|
||||
}
|
||||
|
||||
// 上报增值服务购买请求
|
||||
Future<LoginEntity> uploadReportBuyRequest({
|
||||
required int lockId,
|
||||
String type = 'cloud_storage',
|
||||
}) async {
|
||||
final res = await apiProvider.reportBuyRequest(
|
||||
lockId,
|
||||
type,
|
||||
);
|
||||
return LoginEntity.fromJson(res.body);
|
||||
}
|
||||
|
||||
// 获取云存列表
|
||||
Future<VideoLogEntity> getLockCloudStorageList({required int lockId}) async {
|
||||
final res = await apiProvider.getLockCloudStorageList(lockId);
|
||||
@ -2770,4 +2795,30 @@ class ApiRepository {
|
||||
);
|
||||
return DeviceNetwork.fromJson(res.body);
|
||||
}
|
||||
|
||||
// 获取语音列表
|
||||
Future<PassthroughListResponse> getPassthroughList({
|
||||
String requestMethod = 'POST',
|
||||
String requestUri = '/api/v1/voice/packs',
|
||||
required Map<String, String> data,
|
||||
}) async {
|
||||
final res = await apiProvider.getPassthroughList(
|
||||
requestMethod,
|
||||
requestUri,
|
||||
data,
|
||||
);
|
||||
return PassthroughListResponse.fromJson(res.body);
|
||||
}
|
||||
|
||||
// 设置语音
|
||||
Future<LoginEntity> settingCurrentVoiceTimbre({
|
||||
required int lockId,
|
||||
required Map<String, String> data,
|
||||
}) async {
|
||||
final res = await apiProvider.settingCurrentVoiceTimbre(
|
||||
lockId,
|
||||
data,
|
||||
);
|
||||
return LoginEntity.fromJson(res.body);
|
||||
}
|
||||
}
|
||||
|
||||
@ -277,7 +277,6 @@ class MessageCommand {
|
||||
int? SpTotal,
|
||||
int? SpIndex,
|
||||
}) {
|
||||
|
||||
final payload = talkData.writeToBuffer();
|
||||
ScpMessage message = ScpMessage(
|
||||
ProtocolFlag: ProtocolFlagConstant.scp01,
|
||||
|
||||
@ -630,6 +630,7 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
||||
|
||||
// 重置期望数据
|
||||
StartChartManage().reSetDefaultTalkExpect();
|
||||
StartChartManage().stopTalkExpectMessageTimer();
|
||||
VideoDecodePlugin.releaseDecoder();
|
||||
|
||||
// 取消批处理定时器
|
||||
|
||||
@ -40,6 +40,7 @@ const String lockNetWorkInfo = 'lockNetWorkInfo'; //锁板配网信息
|
||||
|
||||
const String appVersionHistoryUrl = 'appVersionHistoryUrl'; //是否同意隐私协议弹窗
|
||||
const String voipToken = 'voipToken'; //是否同意隐私协议弹窗
|
||||
const String deviceModel = 'deviceModel'; //设备型号
|
||||
|
||||
class Storage {
|
||||
factory Storage() => _instance;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user