Merge branch 'develop_sky' into 'release_sky'

Develop sky

See merge request StarlockTeam/app-starlock!271
This commit is contained in:
李仪 2025-09-03 09:20:35 +00:00
commit c9683b4cba
60 changed files with 43810 additions and 43335 deletions

View File

@ -1160,5 +1160,11 @@
"锁语音包设置": "قفل مجموعة صوت", "锁语音包设置": "قفل مجموعة صوت",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "ذكر صوت", "男声": "ذكر صوت",
"女声": "صوت بنات" "女声": "صوت بنات",
"您的图像和视频数据仅保留": "يتم الاحتفاظ ببيانات الصور والفيديو فقط",
"后图像和视频数据将会失效,开通": "بعد ذلك ، ستكون بيانات الصورة والفيديو غير صالحة ويتم تنشيطها",
"云存会员": "عضوية التخزين السحابي",
"服务,图像视频信息随心存!": "معلومات الخدمة والصور والفيديو في قلبك!",
"图像": "صورة",
"视频": "فيديو"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "Заключване на настройките на гласовия пакет", "锁语音包设置": "Заключване на настройките на гласовия пакет",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Мъжки глас", "男声": "Мъжки глас",
"女声": "Женски глас" "女声": "Женски глас",
"您的图像和视频数据仅保留": "Данните ви за изображения и видеоклипове се запазват само",
"后图像和视频数据将会失效,开通": "След това данните за изображението и видеото ще бъдат невалидни и активирани",
"云存会员": "Членство в Cloud Storage",
"服务,图像视频信息随心存!": "Информацията за обслужване, изображения и видео са във вашето сърце!",
"图像": "изображение",
"视频": "Видео"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "ভয়েস প্যাকেজ সেটিংস লক করুন", "锁语音包设置": "ভয়েস প্যাকেজ সেটিংস লক করুন",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "পুরুষের কণ্ঠ", "男声": "পুরুষের কণ্ঠ",
"女声": "নারী কণ্ঠ" "女声": "নারী কণ্ঠ",
"您的图像和视频数据仅保留": "আপনার চিত্র এবং ভিডিও ডেটা কেবল ধরে রাখা হয়",
"后图像和视频数据将会失效,开通": "এর পরে, চিত্র এবং ভিডিও ডেটা অবৈধ এবং সক্রিয় হবে",
"云存会员": "ক্লাউড স্টোরেজ সদস্যতা",
"服务,图像视频信息随心存!": "পরিষেবা, চিত্র এবং ভিডিও তথ্য আপনার হৃদয়ে!",
"图像": "প্রতিচ্ছবি",
"视频": "ভিডিও"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "Zamknout nastavení hlasového balíčku", "锁语音包设置": "Zamknout nastavení hlasového balíčku",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Mužský hlas", "男声": "Mužský hlas",
"女声": "Ženský hlas" "女声": "Ženský hlas",
"您的图像和视频数据仅保留": "Uchovávají se pouze vaše obrazová data a data videí",
"后图像和视频数据将会失效,开通": "Poté budou obrazová a video data neplatná a aktivovaná",
"云存会员": "Členství v cloudovém úložišti",
"服务,图像视频信息随心存!": "Servis, obrazové a video informace jsou na prvním místě!",
"图像": "obraz",
"视频": "Video"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "Lås stemmepakkeindstillinger", "锁语音包设置": "Lås stemmepakkeindstillinger",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Mandlige stemmer", "男声": "Mandlige stemmer",
"女声": "Kvindelige stemmer" "女声": "Kvindelige stemmer",
"您的图像和视频数据仅保留": "Dine billed- og videodata opbevares kun",
"后图像和视频数据将会失效,开通": "Derefter vil billed- og videodataene være ugyldige og aktiveret",
"云存会员": "Medlemskab af Cloud Storage",
"服务,图像视频信息随心存!": "Service-, billed- og videoinformation er i dit hjerte!",
"图像": "billede",
"视频": "Video"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "Sperren von Sprachpaketeinstellungen", "锁语音包设置": "Sperren von Sprachpaketeinstellungen",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Männliche Stimme", "男声": "Männliche Stimme",
"女声": "Frauenstimme" "女声": "Frauenstimme",
"您的图像和视频数据仅保留": "Ihre Bild- und Videodaten werden nur dann aufbewahrt",
"后图像和视频数据将会失效,开通": "Danach sind die Bild- und Videodaten ungültig und aktiviert",
"云存会员": "Cloud-Speicher-Mitgliedschaft",
"服务,图像视频信息随心存!": "Service-, Bild- und Videoinformationen liegen Ihnen am Herzen!",
"图像": "Bild",
"视频": "Video"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "Ρυθμίσεις κλειδώματος πακέτου φωνής", "锁语音包设置": "Ρυθμίσεις κλειδώματος πακέτου φωνής",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Ανδρική φωνή", "男声": "Ανδρική φωνή",
"女声": "Γυναικεία φωνή" "女声": "Γυναικεία φωνή",
"您的图像和视频数据仅保留": "Τα δεδομένα εικόνας και βίντεο διατηρούνται μόνο",
"后图像和视频数据将会失效,开通": "Μετά από αυτό, τα δεδομένα εικόνας και βίντεο θα είναι άκυρα και θα ενεργοποιηθούν",
"云存会员": "Συνδρομή Cloud Storage",
"服务,图像视频信息随心存!": "Οι πληροφορίες εξυπηρέτησης, εικόνας και βίντεο είναι στην καρδιά σας!",
"图像": "εικόνα",
"视频": "Βίντεο"
} }

View File

@ -1167,5 +1167,11 @@
"锁语音包设置": "Lock voice package settings", "锁语音包设置": "Lock voice package settings",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "male voice", "男声": "male voice",
"女声": "female voice" "女声": "female voice",
"您的图像和视频数据仅保留": "Your image and video data is only retained",
"后图像和视频数据将会失效,开通": "After that, the image and video data will be invalid and activated",
"云存会员": "Cloud Storage Membership",
"服务,图像视频信息随心存!": "Service, image and video information are at your heart!",
"图像": "image",
"视频": "Video"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "Configuración del paquete de voz de bloqueo", "锁语音包设置": "Configuración del paquete de voz de bloqueo",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Voz masculina", "男声": "Voz masculina",
"女声": "Voz femenina" "女声": "Voz femenina",
"您的图像和视频数据仅保留": "Solo se conservan los datos de imagen y vídeo",
"后图像和视频数据将会失效,开通": "Después de eso, los datos de imagen y video no serán válidos y se activarán",
"云存会员": "Membresía de almacenamiento en la nube",
"服务,图像视频信息随心存!": "¡La información de servicio, imagen y video está en su corazón!",
"图像": "imagen",
"视频": "Vídeo"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "Lukustage häälepaketi seaded", "锁语音包设置": "Lukustage häälepaketi seaded",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Meeste hääl", "男声": "Meeste hääl",
"女声": "Naiste hääl" "女声": "Naiste hääl",
"您的图像和视频数据仅保留": "Teie pildi- ja videoandmeid säilitatakse ainult",
"后图像和视频数据将会失效,开通": "Pärast seda on pildi- ja videoandmed kehtetud ja aktiveeritud",
"云存会员": "Pilvesalvestuse liikmelisus",
"服务,图像视频信息随心存!": "Teenindus-, pildi- ja videoteave on teie südames!",
"图像": "Piltide",
"视频": "Video"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "Lukitse äänipaketin asetukset", "锁语音包设置": "Lukitse äänipaketin asetukset",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Miehen ääni", "男声": "Miehen ääni",
"女声": "Naisten ääni" "女声": "Naisten ääni",
"您的图像和视频数据仅保留": "Kuva- ja videotietosi säilytetään vain",
"后图像和视频数据将会失效,开通": "Sen jälkeen kuva- ja videotiedot ovat virheellisiä ja aktivoituvat",
"云存会员": "Pilvitallennustilan jäsenyys",
"服务,图像视频信息随心存!": "Palvelu-, kuva- ja videotiedot ovat sydämessäsi!",
"图像": "kuva",
"视频": "Video"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "Paramètres du pack Lock Voice", "锁语音包设置": "Paramètres du pack Lock Voice",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Voix masculine", "男声": "Voix masculine",
"女声": "Voix de femmes" "女声": "Voix de femmes",
"您的图像和视频数据仅保留": "Vos données dimage et de vidéo ne sont conservées que",
"后图像和视频数据将会失效,开通": "Après cela, les données de limage et de la vidéo seront invalides et activées",
"云存会员": "Adhésion au stockage dans le cloud",
"服务,图像视频信息随心存!": "Le service, limage et les informations vidéo sont au cœur de vos préoccupations !",
"图像": "image",
"视频": "Vidéo"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "הגדרות חבילת קול לנעול", "锁语音包设置": "הגדרות חבילת קול לנעול",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "קול גבר", "男声": "קול גבר",
"女声": "קול נשי" "女声": "קול נשי",
"您的图像和视频数据仅保留": "נתוני התמונה והסרטונים נשמרים רק",
"后图像和视频数据将会失效,开通": "לאחר מכן, נתוני התמונה והווידאו לא יהיו חוקיים ויופעלו",
"云存会员": "חברות באחסון בענן",
"服务,图像视频信息随心存!": "מידע על שירות, תמונה ווידאו נמצאים בלב שלך!",
"图像": "תמונה",
"视频": "וידאו"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "आवाज पैकेज सेटिंग्स ताला लगाएँ", "锁语音包设置": "आवाज पैकेज सेटिंग्स ताला लगाएँ",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "पुरुष आवाज", "男声": "पुरुष आवाज",
"女声": "महिला आवाज" "女声": "महिला आवाज",
"您的图像和视频数据仅保留": "आपकी छवि और वीडियो डेटा केवल बनाए रखा जाता है",
"后图像和视频数据将会失效,开通": "उसके बाद, छवि और वीडियो डेटा अमान्य और सक्रिय हो जाएगा",
"云存会员": "क्लाउड स्टोरेज सदस्यता",
"服务,图像视频信息随心存!": "सेवा, छवि और वीडियो जानकारी आपके दिल में हैं!",
"图像": "प्रतिबिंब",
"视频": "वीडियो"
} }

View File

@ -1162,5 +1162,11 @@
"锁语音包设置": "鎖語音包設定", "锁语音包设置": "鎖語音包設定",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "男聲", "男声": "男聲",
"女声": "女聲" "女声": "女聲",
"您的图像和视频数据仅保留": "您的圖像和視頻數據僅保留",
"后图像和视频数据将会失效,开通": "后圖像和視頻數據將會失效,開通",
"云存会员": "雲存會員",
"服务,图像视频信息随心存!": "服務,圖像視頻資訊隨心存!",
"图像": "圖像",
"视频": "視頻"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "Postavke zaključavanja glasovnog paketa", "锁语音包设置": "Postavke zaključavanja glasovnog paketa",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Muški glas", "男声": "Muški glas",
"女声": "Ženski glas" "女声": "Ženski glas",
"您的图像和视频数据仅保留": "Vaši podaci o slici i videozapisu zadržavaju se samo",
"后图像和视频数据将会失效,开通": "Nakon toga, slikovni i video podaci bit će nevažeći i aktivirani",
"云存会员": "Članstvo u pohrani u oblaku",
"服务,图像视频信息随心存!": "Informacije o usluzi, slikama i videozapisima su vam u srcu!",
"图像": "slika",
"视频": "Video"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "Hangcsomag zárolási beállításai", "锁语音包设置": "Hangcsomag zárolási beállításai",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Férfi hang", "男声": "Férfi hang",
"女声": "női hang" "女声": "női hang",
"您的图像和视频数据仅保留": "A kép- és videóadatokat csak a rendszer őrzi meg",
"后图像和视频数据将会失效,开通": "Ezt követően a kép- és videóadatok érvénytelenek lesznek és aktiválódnak",
"云存会员": "Felhőalapú tárolási tagság",
"服务,图像视频信息随心存!": "A szolgáltatás, a képi és videós információk a szívedben vannak!",
"图像": "kép",
"视频": "Video"
} }

View File

@ -1167,5 +1167,11 @@
"锁语音包设置": "Փակել ձայնային փաթեթի պարամետրերը", "锁语音包设置": "Փակել ձայնային փաթեթի պարամետրերը",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "տղամարդկանց ձայն", "男声": "տղամարդկանց ձայն",
"女声": "կանանց ձայն" "女声": "կանանց ձայն",
"您的图像和视频数据仅保留": "Ձեր պատկերի եւ վիդեո տվյալները պահպանվում են միայն",
"后图像和视频数据将会失效,开通": "Դրանից հետո պատկերի եւ վիդեո տվյալները կլինեն անվավեր եւ կակտիվացվեն",
"云存会员": "Cloud Storage Membership",
"服务,图像视频信息随心存!": "Ծառայությունը, պատկերը եւ վիդեո տեղեկատվությունը ձեր սրտում են:",
"图像": "Պատկերասրահ",
"视频": "Տեսանյութ"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "Mengunci paket suara", "锁语音包设置": "Mengunci paket suara",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "6 tahun sebelumnya", "男声": "6 tahun sebelumnya",
"女声": "Suara wanita" "女声": "Suara wanita",
"您的图像和视频数据仅保留": "Data gambar dan video Anda hanya disimpan",
"后图像和视频数据将会失效,开通": "Setelah itu, data gambar dan video akan tidak valid dan diaktifkan",
"云存会员": "Keanggotaan Cloud Storage",
"服务,图像视频信息随心存!": "Informasi layanan, gambar, dan video adalah inti Anda!",
"图像": "citra",
"视频": "Video"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "Impostazioni pacchetto vocale blocco", "锁语音包设置": "Impostazioni pacchetto vocale blocco",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "voce maschile", "男声": "voce maschile",
"女声": "voce femminile" "女声": "voce femminile",
"您的图像和视频数据仅保留": "I dati delle immagini e dei video vengono conservati solo",
"后图像和视频数据将会失效,开通": "Successivamente, i dati dell'immagine e del video non saranno più validi e attivati",
"云存会员": "Iscrizione al cloud storage",
"服务,图像视频信息随心存!": "Le informazioni sul servizio, le immagini e i video sono al tuo centro!",
"图像": "immagine",
"视频": "Video"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "ロック音声パケット設定", "锁语音包设置": "ロック音声パケット設定",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "男声", "男声": "男声",
"女声": "女声" "女声": "女声",
"您的图像和视频数据仅保留": "画像と動画のデータのみが保持されます",
"后图像和视频数据将会失效,开通": "その後、画像とビデオのデータは無効になり、アクティブになります",
"云存会员": "クラウドストレージメンバーシップ",
"服务,图像视频信息随心存!": "サービス、画像、ビデオ情報があなたの中心にあります!",
"图像": "画像",
"视频": "ビデオ"
} }

View File

@ -1167,5 +1167,11 @@
"锁语音包设置": "ხმის პაკეტის პარამეტრები", "锁语音包设置": "ხმის პაკეტის პარამეტრები",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "მამაკაცის ხმა", "男声": "მამაკაცის ხმა",
"女声": "ქალის ხმა" "女声": "ქალის ხმა",
"您的图像和视频数据仅保留": "თქვენი სურათი და ვიდეო მონაცემები ინახება მხოლოდ",
"后图像和视频数据将会失效,开通": "ამის შემდეგ, სურათისა და ვიდეო მონაცემები არასწორი და გააქტიურებული იქნება",
"云存会员": "Cloud Storage წევრობა",
"服务,图像视频信息随心存!": "მომსახურება, სურათი და ვიდეო ინფორმაცია თქვენს გულშია!",
"图像": "სურათი",
"视频": "ვიდეო"
} }

View File

@ -1172,5 +1172,11 @@
"语音包设置": "语音包设置", "语音包设置": "语音包设置",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "男声", "男声": "男声",
"女声": "女声" "女声": "女声",
"您的图像和视频数据仅保留": "您的图像和视频数据仅保留",
"后图像和视频数据将会失效,开通": "后图像和视频数据将会失效,开通",
"云存会员": "云存会员",
"服务,图像视频信息随心存!": "服务,图像视频信息随心存!",
"图像": "图像",
"视频": "视频"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "Дауыстық бума параметрлерін құлыптау", "锁语音包设置": "Дауыстық бума параметрлерін құлыптау",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "ер дауысы", "男声": "ер дауысы",
"女声": "Әйел дауысы" "女声": "Әйел дауысы",
"您的图像和视频数据仅保留": "Сіздің кескініңіз бен бейне деректеріңіз тек сақталады",
"后图像和视频数据将会失效,开通": "Осыдан кейін кескін мен бейне деректер жарамсыз болып, белсендіріледі",
"云存会员": "Бұлтты сақтауға мүшелік",
"服务,图像视频信息随心存!": "Қызмет, бейне және бейне ақпарат сіздің жүрегіңізде жатыр!",
"图像": "кескіні",
"视频": "Бейне"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "음성팩 설정 잠금", "锁语音包设置": "음성팩 설정 잠금",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "남성", "男声": "남성",
"女声": "여성 목소리" "女声": "여성 목소리",
"您的图像和视频数据仅保留": "이미지 및 동영상 데이터만 보존됩니다.",
"后图像和视频数据将会失效,开通": "그 후 이미지 및 비디오 데이터는 유효하지 않고 활성화됩니다",
"云存会员": "클라우드 스토리지 멤버십",
"服务,图像视频信息随心存!": "서비스, 이미지 및 비디오 정보가 당신의 중심에 있습니다!",
"图像": "이미지",
"视频": "비디오"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "Balso paketo nustatymų užrakinimas", "锁语音包设置": "Balso paketo nustatymų užrakinimas",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "vyriškas balsas", "男声": "vyriškas balsas",
"女声": "Moteriškas balsas" "女声": "Moteriškas balsas",
"您的图像和视频数据仅保留": "Vaizdo ir vaizdo įrašų duomenys saugomi tik",
"后图像和视频数据将会失效,开通": "Po to vaizdo ir vaizdo duomenys bus negaliojantys ir suaktyvinti",
"云存会员": "Debesies saugyklos narystė",
"服务,图像视频信息随心存!": "Aptarnavimas, vaizdas ir video informacija yra jūsų širdis!",
"图像": "vaizdas",
"视频": "Video"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "Balso paketo nustatymų užrakinimas", "锁语音包设置": "Balso paketo nustatymų užrakinimas",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "vyriškas balsas", "男声": "vyriškas balsas",
"女声": "Moteriškas balsas" "女声": "Moteriškas balsas",
"您的图像和视频数据仅保留": "Data imej dan video anda hanya dikekalkan",
"后图像和视频数据将会失效,开通": "Selepas itu, data imej dan video akan menjadi tidak sah dan diaktifkan",
"云存会员": "Keahlian Storan Awan",
"服务,图像视频信息随心存!": "Maklumat perkhidmatan, imej dan video adalah di hati anda!",
"图像": "Imej",
"视频": "Video"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "Instellingen voor spraakpakket vergrendelen", "锁语音包设置": "Instellingen voor spraakpakket vergrendelen",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "mannelijke stem", "男声": "mannelijke stem",
"女声": "Vrouwelijke stem" "女声": "Vrouwelijke stem",
"您的图像和视频数据仅保留": "Uw beeld- en videogegevens worden alleen bewaard",
"后图像和视频数据将会失效,开通": "Daarna zijn de afbeeldings- en videogegevens ongeldig en geactiveerd",
"云存会员": "Lidmaatschap voor cloudopslag",
"服务,图像视频信息随心存!": "Service-, beeld- en video-informatie staan bij u centraal!",
"图像": "beeld",
"视频": "Video"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "Ustawienia blokowania pakietu głosowego", "锁语音包设置": "Ustawienia blokowania pakietu głosowego",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Mężczyzna", "男声": "Mężczyzna",
"女声": "Głos kobiecy" "女声": "Głos kobiecy",
"您的图像和视频数据仅保留": "Dane obrazu i filmu są przechowywane tylko",
"后图像和视频数据将会失效,开通": "Po tym czasie dane obrazu i wideo zostaną nieważne i aktywowane",
"云存会员": "Członkostwo w usłudze Cloud Storage",
"服务,图像视频信息随心存!": "Informacje o serwisie, obrazie i wideo są w Twoim sercu!",
"图像": "obraz",
"视频": "Wideo"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "Configurações do pacote de voz bloqueada", "锁语音包设置": "Configurações do pacote de voz bloqueada",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Voz masculina", "男声": "Voz masculina",
"女声": "voz feminina" "女声": "voz feminina",
"您的图像和视频数据仅保留": "Seus dados de imagem e vídeo são retidos apenas",
"后图像和视频数据将会失效,开通": "Depois disso, os dados de imagem e vídeo serão inválidos e ativados",
"云存会员": "Associação de armazenamento em nuvem",
"服务,图像视频信息随心存!": "Informações de serviço, imagem e vídeo estão no seu coração!",
"图像": "imagem",
"视频": "Vídeo"
} }

View File

@ -1166,5 +1166,11 @@
"语音包设置": "Configurações do pacote de voz", "语音包设置": "Configurações do pacote de voz",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Macho", "男声": "Macho",
"女声": "Garota" "女声": "Garota",
"您的图像和视频数据仅保留": "Seus dados de imagem e vídeo são retidos apenas",
"后图像和视频数据将会失效,开通": "Depois disso, os dados de imagem e vídeo serão inválidos e ativados",
"云存会员": "Associação de armazenamento em nuvem",
"服务,图像视频信息随心存!": "Informações de serviço, imagem e vídeo estão no seu coração!",
"图像": "imagem",
"视频": "Vídeo"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "Configurarea pachetului vocal de blocare", "锁语音包设置": "Configurarea pachetului vocal de blocare",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "vocea bărbatului", "男声": "vocea bărbatului",
"女声": "Voce feminină" "女声": "Voce feminină",
"您的图像和视频数据仅保留": "Datele tale de imagine și video sunt păstrate numai",
"后图像和视频数据将会失效,开通": "După aceea, datele de imagine și video vor fi invalide și activate",
"云存会员": "Abonament de stocare în cloud",
"服务,图像视频信息随心存!": "Serviciile, imaginile și informațiile video sunt în centrul dumneavoastră!",
"图像": "imagine",
"视频": "Video"
} }

View File

@ -1165,5 +1165,11 @@
"锁语音包设置": "Запустить настройки голосового пакета", "锁语音包设置": "Запустить настройки голосового пакета",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Мужской голос", "男声": "Мужской голос",
"女声": "Женские голоса" "女声": "Женские голоса",
"您的图像和视频数据仅保留": "Ваши изображения и видеоданные сохраняются только",
"后图像和视频数据将会失效,开通": "После этого изображение и видео данные будут недействительными и активированы",
"云存会员": "Членство в облачном хранилище",
"服务,图像视频信息随心存!": "Сервисная, имиджевая и видеоинформация в Вашем сердце!",
"图像": "образ",
"视频": "Видео"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "Zamknutie nastavení hlasového balíka", "锁语音包设置": "Zamknutie nastavení hlasového balíka",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "mužský hlas", "男声": "mužský hlas",
"女声": "Ženský hlas" "女声": "Ženský hlas",
"您的图像和视频数据仅保留": "Vaše údaje o obrázkoch a videách sa zachovajú iba",
"后图像和视频数据将会失效,开通": "Potom budú údaje o obrázku a videu neplatné a aktivované",
"云存会员": "Členstvo v cloudovom úložisku",
"服务,图像视频信息随心存!": "Informácie o službách, obrázkoch a videách sú vo vašom srdci!",
"图像": "obraz",
"视频": "Video"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "Закључајте подешавања говорног пакета", "锁语音包设置": "Закључајте подешавања говорног пакета",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "мушки глас", "男声": "мушки глас",
"女声": "женски глас" "女声": "женски глас",
"您的图像和视频数据仅保留": "Ваши подаци о слици и видео записима се задржавају само",
"后图像和视频数据将会失效,开通": "Након тога, сликовни и видео подаци ће бити неважећи и активирани",
"云存会员": "Чланство у облаку за складиштење",
"服务,图像视频信息随心存!": "Сервис , слике и видео информације су у вашем срцу!",
"图像": "Слика",
"视频": "Пријава"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "Lås inställningar för röstpaket", "锁语音包设置": "Lås inställningar för röstpaket",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Mänsklig röst", "男声": "Mänsklig röst",
"女声": "Kvinnlig röst" "女声": "Kvinnlig röst",
"您的图像和视频数据仅保留": "Dina bild- och videodata sparas endast",
"后图像和视频数据将会失效,开通": "Efter det kommer bild- och videodata att vara ogiltiga och aktiverade",
"云存会员": "Medlemskap i molnlagring",
"服务,图像视频信息随心存!": "Service, bild- och videoinformation finns i ditt hjärta!",
"图像": "bild",
"视频": "Video"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "ล็อคการตั้งค่า Voice Pack", "锁语音包设置": "ล็อคการตั้งค่า Voice Pack",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "เสียงผู้ชาย", "男声": "เสียงผู้ชาย",
"女声": "เสียงผู้หญิง" "女声": "เสียงผู้หญิง",
"您的图像和视频数据仅保留": "ระบบจะเก็บข้อมูลรูปภาพและวิดีโอของคุณไว้เท่านั้น",
"后图像和视频数据将会失效,开通": "หลังจากนั้น ข้อมูลรูปภาพและวิดีโอจะไม่ถูกต้องและเปิดใช้งาน",
"云存会员": "สมาชิกที่เก็บข้อมูลบนคลาวด์",
"服务,图像视频信息随心存!": "ข้อมูลบริการ รูปภาพ และวิดีโออยู่ที่หัวใจของคุณ!",
"图像": "ภาพ",
"视频": "วีดิทัศน์"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "Ses Paketi Ayarlarını Kilitle", "锁语音包设置": "Ses Paketi Ayarlarını Kilitle",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Erkek Sesi", "男声": "Erkek Sesi",
"女声": "Kadın Sesi" "女声": "Kadın Sesi",
"您的图像和视频数据仅保留": "Görüntü ve video verileriniz yalnızca korunur",
"后图像和视频数据将会失效,开通": "Bundan sonra, görüntü ve video verileri geçersiz olacak ve etkinleştirilecektir",
"云存会员": "Bulut Depolama Üyeliği",
"服务,图像视频信息随心存!": "Servis, görüntü ve video bilgileri kalbinizde!",
"图像": "resim",
"视频": "Video"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "鎖語音包設定", "锁语音包设置": "鎖語音包設定",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "男聲", "男声": "男聲",
"女声": "女聲" "女声": "女聲",
"您的图像和视频数据仅保留": "您的圖像和視頻數據僅保留",
"后图像和视频数据将会失效,开通": "后圖像和視頻數據將會失效,開通",
"云存会员": "雲存會員",
"服务,图像视频信息随心存!": "服務,圖像視頻資訊隨心存!",
"图像": "圖像",
"视频": "視頻"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "Параметри блокування голосового пакету", "锁语音包设置": "Параметри блокування голосового пакету",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Чоловічий голос", "男声": "Чоловічий голос",
"女声": "жіночий голос" "女声": "жіночий голос",
"您的图像和视频数据仅保留": "Ваші зображення та відеодані зберігаються лише",
"后图像和视频数据将会失效,开通": "Після цього дані зображення та відео будуть недійсними та активованими",
"云存会员": "Членство в хмарних сховищах",
"服务,图像视频信息随心存!": "Сервіс, зображення та відео інформація у вашому серці!",
"图像": "образ",
"视频": "Відео"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "صوتی پیکیج کی ترتیبات لاک کریں", "锁语音包设置": "صوتی پیکیج کی ترتیبات لاک کریں",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "مردوں کی آواز", "男声": "مردوں کی آواز",
"女声": "خواتین کی آواز" "女声": "خواتین کی آواز",
"您的图像和视频数据仅保留": "آپ کی تصویر اور ویڈیو کا ڈیٹا صرف برقرار رکھا گیا ہے",
"后图像和视频数据将会失效,开通": "اس کے بعد ، تصویر اور ویڈیو کا ڈیٹا غیر قانونی اور فعال ہوجائے گا۔",
"云存会员": "Cloud Storage Membership",
"服务,图像视频信息随心存!": "خدمت، تصویر اور ویڈیو کی معلومات آپ کے دل میں ہیں!",
"图像": "روپ",
"视频": "ویڈیو"
} }

View File

@ -1161,5 +1161,11 @@
"锁语音包设置": "Khóa cài đặt gói thoại", "锁语音包设置": "Khóa cài đặt gói thoại",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "Giọng nam", "男声": "Giọng nam",
"女声": "Giọng nữ" "女声": "Giọng nữ",
"您的图像和视频数据仅保留": "Dữ liệu hình ảnh và video của bạn chỉ được giữ lại",
"后图像和视频数据将会失效,开通": "Sau đó, dữ liệu hình ảnh và video sẽ không hợp lệ và được kích hoạt",
"云存会员": "Tư cách thành viên lưu trữ đám mây",
"服务,图像视频信息随心存!": "Thông tin dịch vụ, hình ảnh và video là trọng tâm của bạn!",
"图像": "ảnh",
"视频": "Video"
} }

View File

@ -63,7 +63,6 @@
"授权管理员拥有操作这把锁的重要权限,请确保只发给我你信任的人": "授权管理员拥有操作这把锁的重要权限,请确保只发给我你信任的人", "授权管理员拥有操作这把锁的重要权限,请确保只发给我你信任的人": "授权管理员拥有操作这把锁的重要权限,请确保只发给我你信任的人",
"功能开启后,你将可以通过网关远程开锁。此功能的开启和关闭只能在锁附近通过手机蓝牙进行。": "功能开启后,你将可以通过网关远程开锁。此功能的开启和关闭只能在锁附近通过手机蓝牙进行。", "功能开启后,你将可以通过网关远程开锁。此功能的开启和关闭只能在锁附近通过手机蓝牙进行。": "功能开启后,你将可以通过网关远程开锁。此功能的开启和关闭只能在锁附近通过手机蓝牙进行。",
"此功能的开启和关闭只能在锁附近通过手机蓝牙进行": "此功能的开启和关闭只能在锁附近通过手机蓝牙进行", "此功能的开启和关闭只能在锁附近通过手机蓝牙进行": "此功能的开启和关闭只能在锁附近通过手机蓝牙进行",
"功能开启后,你将可以通过网关远程开锁。": "功能开启后,你将可以通过网关远程开锁。", "功能开启后,你将可以通过网关远程开锁。": "功能开启后,你将可以通过网关远程开锁。",
"排列方式": "排列方式", "排列方式": "排列方式",
"早到榜": "早到榜", "早到榜": "早到榜",
@ -1102,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", "Google Home": "Google Home",
"Action name": "Action name", "Action name": "Action name",
"ScienerSmart": "ScienerSmart", "ScienerSmart": "ScienerSmart",
@ -1174,5 +1173,11 @@
"语音包设置": "语音包设置", "语音包设置": "语音包设置",
"(中国台湾)": "(中国台湾)", "(中国台湾)": "(中国台湾)",
"男声": "男声", "男声": "男声",
"女声": "女声" "女声": "女声",
"您的图像和视频数据仅保留": "您的图像和视频数据仅保留",
"后图像和视频数据将会失效,开通": "后图像和视频数据将会失效,开通",
"云存会员": "云存会员",
"服务,图像视频信息随心存!": "服务,图像视频信息随心存!",
"图像": "图像",
"视频": "视频"
} }

View File

@ -48,7 +48,7 @@ class ReadLockCurrentVoicePacketReply extends Reply {
CommandType commandType, List<int> dataDetail) CommandType commandType, List<int> dataDetail)
: super.parseData(commandType, dataDetail) { : super.parseData(commandType, dataDetail) {
data = dataDetail; data = dataDetail;
status = data[6]; status = data[2];
errorWithStstus(status); errorWithStstus(status);
} }
} }

View File

@ -55,7 +55,7 @@ class SetVoicePackageFinalResultReply extends Reply {
CommandType commandType, List<int> dataDetail) CommandType commandType, List<int> dataDetail)
: super.parseData(commandType, dataDetail) { : super.parseData(commandType, dataDetail) {
data = dataDetail; data = dataDetail;
status = data[6]; status = data[2];
errorWithStstus(status); errorWithStstus(status);
} }
} }

View File

@ -18,9 +18,11 @@ import 'package:star_lock/blue/io_protocol/io_processOtaUpgrade.dart';
import 'package:star_lock/blue/io_protocol/io_readAdminPassword.dart'; import 'package:star_lock/blue/io_protocol/io_readAdminPassword.dart';
import 'package:star_lock/blue/io_protocol/io_readSupportFunctionsNoParameters.dart'; import 'package:star_lock/blue/io_protocol/io_readSupportFunctionsNoParameters.dart';
import 'package:star_lock/blue/io_protocol/io_readSupportFunctionsWithParameters.dart'; import 'package:star_lock/blue/io_protocol/io_readSupportFunctionsWithParameters.dart';
import 'package:star_lock/blue/io_protocol/io_readVoicePackageFinalResult.dart';
import 'package:star_lock/blue/io_protocol/io_referEventRecordTime.dart'; 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_setSupportFunctionsNoParameters.dart';
import 'package:star_lock/blue/io_protocol/io_setSupportFunctionsWithParameters.dart'; import 'package:star_lock/blue/io_protocol/io_setSupportFunctionsWithParameters.dart';
import 'package:star_lock/blue/io_protocol/io_setVoicePackageFinalResult.dart';
import 'package:star_lock/blue/io_protocol/io_timing.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_voicePackageConfigure.dart';
import 'package:star_lock/blue/io_protocol/io_voicePackageConfigureProcess.dart'; import 'package:star_lock/blue/io_protocol/io_voicePackageConfigureProcess.dart';
@ -317,6 +319,18 @@ class CommandReciverManager {
commandType, data); commandType, data);
} }
break; break;
case CommandType.readLockCurrentVoicePacket:
{
reply =
ReadLockCurrentVoicePacketReply.parseData(commandType, data);
}
break;
case CommandType.setLockCurrentVoicePacket:
{
reply =
SetVoicePackageFinalResultReply.parseData(commandType, data);
}
break;
case CommandType.generalExtendedCommond: case CommandType.generalExtendedCommond:
{ {
// //

View File

@ -125,4 +125,9 @@ class DoorLockLogDataItem {
data['recordDetailStr'] = recordDetailStr; data['recordDetailStr'] = recordDetailStr;
return data; return data;
} }
@override
String toString() {
return 'DoorLockLogDataItem{recordId: $recordId, lockId: $lockId, lockAlias: $lockAlias, recordType: $recordType, recordTypeName: $recordTypeName, username: $username, operateDate: $operateDate, imagesUrl: $imagesUrl, videoUrl: $videoUrl, headUrl: $headUrl, userid: $userid, keyboardPwd: $keyboardPwd, recordStr: $recordStr, recordDetailStr: $recordDetailStr}';
}
} }

View File

@ -3,12 +3,15 @@ import 'dart:async';
import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:star_lock/apm/apm_helper.dart'; import 'package:star_lock/apm/apm_helper.dart';
import 'package:star_lock/appRouters.dart';
import 'package:star_lock/app_settings/app_settings.dart'; import 'package:star_lock/app_settings/app_settings.dart';
import 'package:star_lock/common/XSConstantMacro/XSConstantMacro.dart';
import 'package:star_lock/main/lockDetail/doorLockLog/date_time_extensions.dart'; import 'package:star_lock/main/lockDetail/doorLockLog/date_time_extensions.dart';
import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_entity.dart'; import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_entity.dart';
import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_state.dart'; import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_state.dart';
import 'package:star_lock/main/lockDetail/lockOperatingRecord/lockOperatingRecordGetLastRecordTime_entity.dart'; import 'package:star_lock/main/lockDetail/lockOperatingRecord/lockOperatingRecordGetLastRecordTime_entity.dart';
import 'package:star_lock/mine/valueAddedServices/advancedFeaturesWeb/advancedFeaturesWeb_entity.dart';
import 'package:star_lock/tools/commonDataManage.dart'; import 'package:star_lock/tools/commonDataManage.dart';
import 'package:star_lock/tools/dateTool.dart'; import 'package:star_lock/tools/dateTool.dart';
import 'package:star_lock/tools/eventBusEventManage.dart'; import 'package:star_lock/tools/eventBusEventManage.dart';
@ -402,7 +405,20 @@ class DoorLockLogLogic extends BaseGetXController {
void refreshWeek() { void refreshWeek() {
_setWeekRange(); _setWeekRange();
} }
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.keyInfos.value.lockId!);
if (uploadReportBuyRequest.errorCode!.codeIsSuccessful) {
Get.toNamed(Routers.advancedFeaturesWebPage, arguments: <String, int>{
'webBuyType': XSConstantMacro.webBuyTypeCloudStorage,
});
}
}
}
@override @override
Future<void> onClose() async { Future<void> onClose() async {
super.onClose(); super.onClose();

View File

@ -1,4 +1,5 @@
import 'package:flustars/flustars.dart'; import 'package:flustars/flustars.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
@ -284,6 +285,17 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
return formatter.format(dateTime); return formatter.format(dateTime);
} }
bool _checkIsVideoOrImagesType(DoorLockLogDataItem item) {
final recordType = item.recordType;
switch (recordType) {
case 130:
case 220:
return true;
default:
return false;
}
}
String _buildIDByType(DoorLockLogDataItem item) { String _buildIDByType(DoorLockLogDataItem item) {
final recordType = item.recordType; final recordType = item.recordType;
switch (recordType) { switch (recordType) {
@ -407,6 +419,20 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
itemCount: state.lockLogItemList.length, itemCount: state.lockLogItemList.length,
contentsBuilder: (BuildContext context, int index) { contentsBuilder: (BuildContext context, int index) {
final DoorLockLogDataItem timelineData = state.lockLogItemList[index]; final DoorLockLogDataItem timelineData = state.lockLogItemList[index];
// 👇 videoUrl build
int? firstVideoIndex = state.lockLogItemList
.indexWhere((item) => _checkIsVideoOrImagesType(item));
bool isInvalid = _checkIsVideoOrImagesType(timelineData) &&
((timelineData.imagesUrl == null &&
timelineData.videoUrl == null) ||
(timelineData.videoUrl == '' && timelineData.imagesUrl == ''));
String typeText = '';
if (timelineData.recordType == 130) {
typeText = '图像'.tr;
} else if (timelineData.recordType == 220) {
typeText = '视频'.tr;
}
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
Get.toNamed( Get.toNamed(
@ -428,17 +454,37 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
// 使 SingleChildScrollView // 使 SingleChildScrollView
SingleChildScrollView( SingleChildScrollView(
scrollDirection: Axis.horizontal, // scrollDirection: Axis.horizontal, //
child: Text( child: RichText(
_buildIDByType(timelineData),
textAlign: TextAlign.left, textAlign: TextAlign.left,
text: TextSpan(
style: TextStyle( style: TextStyle(
color: _buildTextColorByType(timelineData), color: _buildTextColorByType(timelineData),
fontSize: 24.sp, fontSize: 24.sp,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
// children: [
TextSpan(
text: _buildIDByType(timelineData) +
(isInvalid
? '${typeText}' +
'已失效'.tr +
''
: ''),
),
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: Visibility(
visible: isInvalid,
child: Icon(
Icons.error,
size: 24.sp,
color: Colors.red,
),
),
),
],
),
maxLines: 1, maxLines: 1,
//
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
), ),
@ -455,8 +501,71 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
), ),
), ),
SizedBox( SizedBox(
height: 20.h, height: 12.h,
), ),
Visibility(
visible: _checkIsVideoOrImagesType(timelineData) &&
index == firstVideoIndex,
child: GestureDetector(
onTap: () async {
await logic.getWebPlayUrl();
},
child: Container(
padding: EdgeInsets.all(8.w),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(8.r)),
),
child: RichText(
textAlign: TextAlign.center,
text: TextSpan(
children: [
//
TextSpan(
text:
'${'您的图像和视频数据仅保留'.tr} ${state.rollingStorageDays.value} ${''.tr} ,${state.rollingStorageDays.value} ${''.tr} ${'后图像和视频数据将会失效,开通'.tr}',
style: TextStyle(
color: Colors.grey,
fontSize: 16.sp,
fontWeight: FontWeight.w600,
height: 1.8,
),
),
// 🔥
TextSpan(
text: '云存会员'.tr,
style: TextStyle(
color: AppColors.mainColor,
fontSize: 22.sp,
fontWeight: FontWeight.w800,
//
decoration: TextDecoration.underline,
decorationThickness: 1.5,
height: 1.8,
),
recognizer: TapGestureRecognizer()
..onTap = () async {
// 👉
print('点击了“云存会员”');
await logic.getWebPlayUrl();
// Navigator.push(context, MaterialPageRoute(builder: ...));
},
),
//
TextSpan(
text: '服务,图像视频信息随心存!'.tr,
style: TextStyle(
color: Colors.grey,
fontSize: 16.sp,
fontWeight: FontWeight.w600,
height: 1.8,
),
),
],
),
),
),
),
)
], ],
), ),
), ),

View File

@ -1,4 +1,5 @@
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:get/get_rx/get_rx.dart';
import 'package:star_lock/common/XSConstantMacro/XSConstantMacro.dart'; import 'package:star_lock/common/XSConstantMacro/XSConstantMacro.dart';
import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_entity.dart'; import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_entity.dart';
import 'package:star_lock/tools/advancedCalendar/src/controller.dart'; import 'package:star_lock/tools/advancedCalendar/src/controller.dart';
@ -73,4 +74,6 @@ class DoorLockLogState {
int logCountPage = 10; // int logCountPage = 10; //
Rx<DateTime> currentSelectDate = DateTime.now().obs; Rx<DateTime> currentSelectDate = DateTime.now().obs;
bool isLockReceiveResponse = false; // bool isLockReceiveResponse = false; //
RxString cloudStorageWebViewUrl = ''.obs;
RxInt rollingStorageDays = 3.obs; //
} }

View File

@ -89,27 +89,27 @@ class _CatEyeCustomModePageState extends State<CatEyeCustomModePage> {
SizedBox( SizedBox(
height: 30.h, height: 30.h,
), ),
Container( // Container(
margin: EdgeInsets.only(left: 20.w), // margin: EdgeInsets.only(left: 20.w),
child: CommonItem( // child: CommonItem(
leftTitel: '实时画面'.tr, // leftTitel: '实时画面'.tr,
rightTitle: state.realTimeMode.value, // rightTitle: state.realTimeMode.value,
isHaveLine: false, // isHaveLine: false,
isHaveDirection: true, // isHaveDirection: true,
isHaveRightWidget: false, // isHaveRightWidget: false,
action: () { // action: () {
Navigator.pushNamed(context, Routers.liveVideoPage, // Navigator.pushNamed(context, Routers.liveVideoPage,
arguments: { // arguments: {
'lockSetInfoData': state.lockSetInfoData.value, // 'lockSetInfoData': state.lockSetInfoData.value,
'catEyeConfigData': state.lockSetInfoData.value // 'catEyeConfigData': state.lockSetInfoData.value
.lockSettingInfo!.catEyeConfig!.isNotEmpty // .lockSettingInfo!.catEyeConfig!.isNotEmpty
? state.lockSetInfoData.value.lockSettingInfo! // ? state.lockSetInfoData.value.lockSettingInfo!
.catEyeConfig![0] // .catEyeConfig![0]
: null // : null
}); // });
}, // },
), // ),
) // )
], ],
), ),
), ),

View File

@ -2,6 +2,7 @@ import 'dart:async';
import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:get/get.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/blue_manage.dart';
import 'package:star_lock/blue/io_protocol/io_setSupportFunctionsWithParameters.dart'; import 'package:star_lock/blue/io_protocol/io_setSupportFunctionsWithParameters.dart';
import 'package:star_lock/blue/io_reply.dart'; import 'package:star_lock/blue/io_reply.dart';
@ -82,30 +83,31 @@ class CatEyeSetLogic extends BaseGetXController {
// //
cancelBlueConnetctToastTimer(); cancelBlueConnetctToastTimer();
dismissEasyLoading(); dismissEasyLoading();
AppLog.log('state.settingOptions.value:${state.settingOptions.value}');
switch (state.settingOptions.value) { switch (state.settingOptions.value) {
case 1: // case 1: //
{ {
updateAutoLightScreenConfig(); await updateAutoLightScreenConfig();
} }
break; break;
case 2: // case 2: //
{ {
updateStayWarnConfig(); await updateStayWarnConfig();
} }
break; break;
case 3: // case 3: //
{ {
updateAbnormalWarnConfig(); await updateAbnormalWarnConfig();
} }
break; break;
case 4: // case 4: //
{ {
updateLightScreenTimeConfig(); await updateLightScreenTimeConfig();
} }
break; break;
case 5: // case 5: //
{ {
updateCatEyeModeConfig(); await updateCatEyeModeConfig();
} }
break; break;
default: default:
@ -288,6 +290,7 @@ class CatEyeSetLogic extends BaseGetXController {
.catEyeConfig![0] .catEyeConfig![0]
.catEyeModeConfig .catEyeModeConfig
?.realTimeMode = state.catEyeConfig.value.realTimeMode; ?.realTimeMode = state.catEyeConfig.value.realTimeMode;
eventBus eventBus
.fire(PassCurrentLockInformationEvent(state.lockSetInfoData.value)); .fire(PassCurrentLockInformationEvent(state.lockSetInfoData.value));
} }
@ -456,6 +459,10 @@ class CatEyeSetLogic extends BaseGetXController {
} }
void sendBlueMessage() { void sendBlueMessage() {
showEasyLoading();
showBlueConnetctToastTimer(action: () {
dismissEasyLoading();
});
final message = _buildCatEyeSetBlueMessage(); final message = _buildCatEyeSetBlueMessage();
BlueManage().blueSendData(BlueManage().connectDeviceName, BlueManage().blueSendData(BlueManage().connectDeviceName,
(BluetoothConnectionState connectionState) async { (BluetoothConnectionState connectionState) async {

View File

@ -80,12 +80,12 @@ class _CatEyeSetPageState extends State<CatEyeSetPage> {
isHaveRightWidget: true, isHaveRightWidget: true,
rightWidget: _otherToDoSwitch(2), rightWidget: _otherToDoSwitch(2),
)), )),
Obx(() => CommonItem( // Obx(() => CommonItem(
leftTitel: '异常警告'.tr, // leftTitel: '异常警告'.tr,
rightTitle: '', // rightTitle: '',
isHaveLine: true, // isHaveLine: true,
isHaveRightWidget: true, // isHaveRightWidget: true,
rightWidget: _otherToDoSwitch(3))), // rightWidget: _otherToDoSwitch(3))),
//ToDo //ToDo
CommonItem( CommonItem(
leftTitel: '呼叫目标'.tr, leftTitel: '呼叫目标'.tr,

View File

@ -12,6 +12,7 @@ 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_getDeviceModel.dart';
import 'package:star_lock/blue/io_protocol/io_otaUpgrade.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_processOtaUpgrade.dart';
import 'package:star_lock/blue/io_protocol/io_readVoicePackageFinalResult.dart';
import 'package:star_lock/blue/io_protocol/io_setVoicePackageFinalResult.dart'; import 'package:star_lock/blue/io_protocol/io_setVoicePackageFinalResult.dart';
import 'package:star_lock/blue/io_protocol/io_voicePackageConfigure.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_protocol/io_voicePackageConfigureProcess.dart';
@ -55,9 +56,12 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
handleVoiceConfigureThrottled(reply); handleVoiceConfigureThrottled(reply);
} else if (reply is SetVoicePackageFinalResultReply) { } else if (reply is SetVoicePackageFinalResultReply) {
handleSetResult(reply); handleSetResult(reply);
} else if (reply is ReadLockCurrentVoicePacketReply) {
handleLockCurrentVoicePacketResult(reply);
} }
}); });
await initList(); await initList();
readLockLanguage();
} }
/// ///
@ -435,9 +439,24 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
_handlerVoicePackageConfigureConfirmation( _handlerVoicePackageConfigureConfirmation(
VoicePackageConfigureConfirmationReply reply, VoicePackageConfigureConfirmationReply reply,
) async { ) async {
final int status = reply.data[2]; showEasyLoading();
switch (status) { showBlueConnetctToastTimer(action: () {
case 0x00: dismissEasyLoading();
});
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: () async {
state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.lang =
state.tempLangStr.value;
state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre
?.timbre = state.tempTimbreStr.value;
await BlueManage().blueSendData(BlueManage().connectDeviceName, await BlueManage().blueSendData(BlueManage().connectDeviceName,
(BluetoothConnectionState deviceConnectionState) async { (BluetoothConnectionState deviceConnectionState) async {
if (deviceConnectionState == BluetoothConnectionState.connected) { if (deviceConnectionState == BluetoothConnectionState.connected) {
@ -454,10 +473,8 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
showBlueConnetctToast(); showBlueConnetctToast();
} }
}); });
break; await Future.delayed(Duration(seconds: 1));
default: });
showToast('设置'.tr + '失败'.tr);
break;
} }
} }
@ -466,24 +483,6 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
switch (status) { switch (status) {
case 0x00: case 0x00:
cancelBlueConnetctToastTimer(); 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(); dismissEasyLoading();
break; break;
default: default:
@ -491,4 +490,74 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
break; break;
} }
} }
void handleLockCurrentVoicePacketResult(
ReadLockCurrentVoicePacketReply reply) {
final int status = reply.data[2];
switch (status) {
case 0x00:
//
cancelBlueConnetctToastTimer();
const int languageCodeStartIndex = 3;
const int languageCodeLength = 20;
const int languageCodeEndIndex =
languageCodeStartIndex + languageCodeLength; // 23
if (reply.data.length < languageCodeEndIndex) {
throw Exception(
'Reply data is too short to contain LanguageCode. Expected at least $languageCodeEndIndex bytes, got ${reply.data.length}');
}
List<int> languageCodeBytes =
reply.data.sublist(languageCodeStartIndex, languageCodeEndIndex);
String languageCode = String.fromCharCodes(languageCodeBytes);
languageCode = languageCode.trim(); //
languageCode =
languageCode.replaceAll('\u0000', ''); // (null bytes)
if (languageCode != null && languageCode != '') {
final indexWhere = state.languages
.indexWhere((element) => element.lang == languageCode);
if (indexWhere != -1) {
print('锁板上的语言是:$languageCode,下标是:$indexWhere');
state.selectPassthroughListIndex.value = indexWhere;
}
}
dismissEasyLoading();
break;
case 0x06:
//
final List<int> token = reply.data.sublist(2, 6);
if (state.data != null) {
sendFileToDevice(state.data!, token);
}
break;
default:
break;
}
}
void readLockLanguage() async {
showEasyLoading();
showBlueConnetctToastTimer(action: () {
dismissEasyLoading();
});
await BlueManage().blueSendData(BlueManage().connectDeviceName,
(BluetoothConnectionState deviceConnectionState) async {
if (deviceConnectionState == BluetoothConnectionState.connected) {
await BlueManage().writeCharacteristicWithResponse(
ReadLockCurrentVoicePacket(
lockID: BlueManage().connectDeviceName,
).packageData(),
);
} else if (deviceConnectionState ==
BluetoothConnectionState.disconnected) {
dismissEasyLoading();
cancelBlueConnetctToastTimer();
showBlueConnetctToast();
}
});
}
} }

View File

@ -63,6 +63,12 @@ class _SpeechLanguageSettingsPageState
final soundType = state.soundTypeList.value[index]; final soundType = state.soundTypeList.value[index];
return CommonItem( return CommonItem(
leftTitel: soundType, leftTitel: soundType,
leftTitleStyle: TextStyle(
fontSize: 20.sp,
fontWeight: state.selectSoundTypeIndex.value == index
? FontWeight.bold
: null,
),
rightTitle: '', rightTitle: '',
isHaveLine: !isLastItem, isHaveLine: !isLastItem,
isHaveDirection: false, isHaveDirection: false,
@ -94,7 +100,8 @@ class _SpeechLanguageSettingsPageState
height: 8.h, height: 8.h,
), ),
// //
Container( Obx(
() => Container(
color: Colors.transparent, color: Colors.transparent,
child: Column( child: Column(
children: List.generate( children: List.generate(
@ -103,11 +110,18 @@ class _SpeechLanguageSettingsPageState
final item = state.languages[index]; final item = state.languages[index];
return CommonItem( return CommonItem(
leftTitel: item.langText, leftTitel: item.langText,
leftTitleStyle: TextStyle(
fontSize: 20.sp,
fontWeight: state.selectPassthroughListIndex.value == index
? FontWeight.bold
: null,
),
rightTitle: '', rightTitle: '',
isHaveLine: true, isHaveLine: true,
isHaveDirection: false, isHaveDirection: false,
isHaveRightWidget: true, isHaveRightWidget: true,
leftTitleMaxWidth: 0.9.sw, // leftTitleMaxWidth: 0.9.sw,
//
rightWidget: rightWidget:
state.selectPassthroughListIndex.value == index state.selectPassthroughListIndex.value == index
? Image( ? Image(
@ -126,6 +140,7 @@ class _SpeechLanguageSettingsPageState
), ),
), ),
), ),
),
], ],
), ),
), ),
@ -133,16 +148,6 @@ class _SpeechLanguageSettingsPageState
} }
List<Widget> _buildList() {
final appLocalLanguages = state.languages;
return List.generate(
appLocalLanguages.length,
(index) => _buildItem(
appLocalLanguages[index],
index,
),
);
}
@override @override
void dispose() { void dispose() {
@ -152,24 +157,4 @@ class _SpeechLanguageSettingsPageState
} }
} }
_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;
},
);
}
} }

View File

@ -12,6 +12,7 @@ import 'package:star_lock/app_settings/app_colors.dart';
import 'package:star_lock/blue/blue_manage.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_getDeviceModel.dart';
import 'package:star_lock/blue/io_protocol/io_readVoicePackageFinalResult.dart'; import 'package:star_lock/blue/io_protocol/io_readVoicePackageFinalResult.dart';
import 'package:star_lock/blue/io_protocol/io_setVoicePackageFinalResult.dart';
import 'package:star_lock/blue/io_protocol/io_voicePackageConfigure.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_protocol/io_voicePackageConfigureProcess.dart';
import 'package:star_lock/blue/io_reply.dart'; import 'package:star_lock/blue/io_reply.dart';
@ -53,6 +54,8 @@ class LockVoiceSettingLogic extends BaseGetXController {
handleVoiceConfigureThrottled(reply); handleVoiceConfigureThrottled(reply);
} else if (reply is ReadLockCurrentVoicePacketReply) { } else if (reply is ReadLockCurrentVoicePacketReply) {
handleLockCurrentVoicePacketResult(reply); handleLockCurrentVoicePacketResult(reply);
} else if (reply is SetVoicePackageFinalResultReply) {
handleSetResult(reply);
} }
}); });
initList(); initList();
@ -77,6 +80,10 @@ class LockVoiceSettingLogic extends BaseGetXController {
Future<void> _executeLogic( Future<void> _executeLogic(
VoicePackageConfigureConfirmationReply reply) async { VoicePackageConfigureConfirmationReply reply) async {
showEasyLoading();
showBlueConnetctToastTimer(action: () {
dismissEasyLoading();
});
final LoginEntity entity = await ApiRepository.to.settingCurrentVoiceTimbre( final LoginEntity entity = await ApiRepository.to.settingCurrentVoiceTimbre(
data: { data: {
'lang': state.tempLangStr.value, 'lang': state.tempLangStr.value,
@ -85,18 +92,47 @@ class LockVoiceSettingLogic extends BaseGetXController {
lockId: state.lockSetInfoData.value.lockId!, lockId: state.lockSetInfoData.value.lockId!,
); );
if (entity.errorCode!.codeIsSuccessful) { if (entity.errorCode!.codeIsSuccessful) {
showSuccess('设置成功'.tr, something: () { showSuccess('设置成功'.tr, something: () async {
state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.lang = state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.lang =
state.tempLangStr.value; state.tempLangStr.value;
state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre
?.timbre = state.tempTimbreStr.value; ?.timbre = state.tempTimbreStr.value;
await BlueManage().blueSendData(BlueManage().connectDeviceName,
(BluetoothConnectionState deviceConnectionState) async {
if (deviceConnectionState == BluetoothConnectionState.connected) {
await BlueManage().writeCharacteristicWithResponse(
SetVoicePackageFinalResult(
lockID: BlueManage().connectDeviceName,
languageCode: state.tempLangStr.value,
).packageData(),
);
} else if (deviceConnectionState ==
BluetoothConnectionState.disconnected) {
dismissEasyLoading();
cancelBlueConnetctToastTimer();
showBlueConnetctToast();
}
});
await Future.delayed(Duration(seconds: 1));
eventBus eventBus
.fire(PassCurrentLockInformationEvent(state.lockSetInfoData.value)); .fire(PassCurrentLockInformationEvent(state.lockSetInfoData.value));
Get.offAllNamed(Routers.starLockMain); Get.offAllNamed(Routers.starLockMain);
}); });
} }
}
void handleSetResult(SetVoicePackageFinalResultReply reply) async {
final int status = reply.data[2];
switch (status) {
case 0x00:
cancelBlueConnetctToastTimer();
dismissEasyLoading(); dismissEasyLoading();
break;
default:
showToast('设置'.tr + '失败'.tr);
break;
}
} }
void saveSpeechLanguageSettings() async { void saveSpeechLanguageSettings() async {
@ -201,14 +237,12 @@ class LockVoiceSettingLogic extends BaseGetXController {
// //
void _handlerStartVoicePackageConfigure( void _handlerStartVoicePackageConfigure(
VoicePackageConfigureReply reply) async { VoicePackageConfigureReply reply) async {
final int status = reply.data[3]; final int status = reply.data[6];
switch (status) { switch (status) {
case 0x00: case 0x00:
// //
cancelBlueConnetctToastTimer(); cancelBlueConnetctToastTimer();
_startSendLanguageFile(); _startSendLanguageFile();
break; break;
case 0x06: case 0x06:
// //
@ -218,7 +252,8 @@ class LockVoiceSettingLogic extends BaseGetXController {
} }
break; break;
default: default:
showToast('获取设备型号失败'.tr); dismissEasyLoading();
cancelBlueConnetctToastTimer();
break; break;
} }
} }
@ -409,6 +444,10 @@ class LockVoiceSettingLogic extends BaseGetXController {
} }
void readLockLanguage() async { void readLockLanguage() async {
showEasyLoading();
showBlueConnetctToastTimer(action: () {
dismissEasyLoading();
});
await BlueManage().blueSendData(BlueManage().connectDeviceName, await BlueManage().blueSendData(BlueManage().connectDeviceName,
(BluetoothConnectionState deviceConnectionState) async { (BluetoothConnectionState deviceConnectionState) async {
if (deviceConnectionState == BluetoothConnectionState.connected) { if (deviceConnectionState == BluetoothConnectionState.connected) {
@ -428,40 +467,42 @@ class LockVoiceSettingLogic extends BaseGetXController {
void handleLockCurrentVoicePacketResult( void handleLockCurrentVoicePacketResult(
ReadLockCurrentVoicePacketReply reply) { ReadLockCurrentVoicePacketReply reply) {
final int status = reply.data[6]; final int status = reply.data[2];
switch (status) { switch (status) {
case 0x00: case 0x00:
// //
cancelBlueConnetctToastTimer(); cancelBlueConnetctToastTimer();
// 1. LanguageCode
// CmdID (2 bytes) + Status (1 byte) = 3 bytes -> LanguageCode 3
const int languageCodeStartIndex = 3; const int languageCodeStartIndex = 3;
const int languageCodeLength = 20; const int languageCodeLength = 20;
const int languageCodeEndIndex = const int languageCodeEndIndex =
languageCodeStartIndex + languageCodeLength; // 23 languageCodeStartIndex + languageCodeLength; // 23
// 2.
if (reply.data.length < languageCodeEndIndex) { if (reply.data.length < languageCodeEndIndex) {
throw Exception( throw Exception(
'Reply data is too short to contain LanguageCode. Expected at least $languageCodeEndIndex bytes, got ${reply.data.length}'); 'Reply data is too short to contain LanguageCode. Expected at least $languageCodeEndIndex bytes, got ${reply.data.length}');
} }
// 3. LanguageCode
List<int> languageCodeBytes = List<int> languageCodeBytes =
reply.data.sublist(languageCodeStartIndex, languageCodeEndIndex); reply.data.sublist(languageCodeStartIndex, languageCodeEndIndex);
// 4.
// UTF-8 ASCII
String languageCode = String.fromCharCodes(languageCodeBytes); String languageCode = String.fromCharCodes(languageCodeBytes);
// 5. () '\0'
// 20 '\0'
languageCode = languageCode.trim(); // languageCode = languageCode.trim(); //
languageCode = languageCode =
languageCode.replaceAll('\u0000', ''); // (null bytes) languageCode.replaceAll('\u0000', ''); // (null bytes)
// 6. 使 languageCode
print('LanguageCode: $languageCode'); // : zh_CN, en_US print('LanguageCode: $languageCode'); // : zh_CN, en_US
if (languageCode != null && languageCode != '') {
final indexWhere = state.languages
.indexWhere((element) => element.lang == languageCode);
if (indexWhere != -1) {
print('锁板上的语言是:$languageCode,下标是:$indexWhere');
state.selectPassthroughListIndex.value = indexWhere;
}
}
dismissEasyLoading();
break; break;
case 0x06: case 0x06:
// //

View File

@ -96,7 +96,7 @@ class _LockVoiceSettingState extends State<LockVoiceSetting> {
return CommonItem( return CommonItem(
leftTitel: soundType, leftTitel: soundType,
leftTitleStyle: TextStyle( leftTitleStyle: TextStyle(
fontSize: 22.sp, fontSize: 20.sp,
fontWeight: state.selectSoundTypeIndex.value == index fontWeight: state.selectSoundTypeIndex.value == index
? FontWeight.bold ? FontWeight.bold
: null, : null,
@ -142,7 +142,7 @@ class _LockVoiceSettingState extends State<LockVoiceSetting> {
return CommonItem( return CommonItem(
leftTitel: item.langText, leftTitel: item.langText,
leftTitleStyle: TextStyle( leftTitleStyle: TextStyle(
fontSize: 22.sp, fontSize: 20.sp,
fontWeight: fontWeight:
state.selectPassthroughListIndex.value == index state.selectPassthroughListIndex.value == index
? FontWeight.bold ? FontWeight.bold
@ -152,7 +152,7 @@ class _LockVoiceSettingState extends State<LockVoiceSetting> {
isHaveLine: true, isHaveLine: true,
isHaveDirection: false, isHaveDirection: false,
isHaveRightWidget: true, isHaveRightWidget: true,
leftTitleMaxWidth: 0.9.sw, leftTitleMaxWidth: 0.85.sw,
rightWidget: rightWidget:
state.selectPassthroughListIndex.value == index state.selectPassthroughListIndex.value == index
? Image( ? Image(

View File

@ -110,22 +110,8 @@ class ImageTransmissionLogic extends BaseGetXController {
// //
switch (contentType) { switch (contentType) {
case TalkData_ContentTypeE.G711: case TalkData_ContentTypeE.G711:
// // //
if (_isFirstAudioFrame) { if (!state.isOpenVoice.value && state.isRecordingAudio.value) {
_startAudioTime = currentTime;
_isFirstAudioFrame = false;
}
//
final expectedTime = _startAudioTime + talkData.durationMs;
final audioDelay = currentTime - expectedTime;
//
if (audioDelay > 500) {
state.audioBuffer.clear();
if (state.isOpenVoice.value) {
_playAudioFrames();
}
return; return;
} }
if (state.audioBuffer.length >= audioBufferSize) { if (state.audioBuffer.length >= audioBufferSize) {
@ -212,7 +198,8 @@ class ImageTransmissionLogic extends BaseGetXController {
/// ///
void _playAudioData(TalkData talkData) async { void _playAudioData(TalkData talkData) async {
if (state.isOpenVoice.value) { if (state.isOpenVoice.value &&
state.isRecordingAudio.value == false) {
final list = final list =
G711().decodeAndDenoise(talkData.content, true, 8000, 300, 150); G711().decodeAndDenoise(talkData.content, true, 8000, 300, 150);
// // PCM PcmArrayInt16 // // PCM PcmArrayInt16
@ -565,7 +552,6 @@ class ImageTransmissionLogic extends BaseGetXController {
// //
Future<void> startProcessingAudio() async { Future<void> startProcessingAudio() async {
try { try {
if (await state.voiceProcessor?.hasRecordAudioPermission() ?? false) { if (await state.voiceProcessor?.hasRecordAudioPermission() ?? false) {
await state.voiceProcessor?.start(state.frameLength, state.sampleRate); await state.voiceProcessor?.start(state.frameLength, state.sampleRate);
@ -602,12 +588,23 @@ class ImageTransmissionLogic extends BaseGetXController {
} on PlatformException catch (ex) { } on PlatformException catch (ex) {
// state.errorMessage.value = 'Failed to stop recorder: $ex'; // state.errorMessage.value = 'Failed to stop recorder: $ex';
} finally { } finally {
final bool? isRecording = await state.voiceProcessor?.isRecording(); //
state.isRecordingAudio.value = isRecording!; if (_startProcessingAudioTimer != null) {
// 53200
for (int i = 0; i < 5; i++) {
_bufferedAudioFrames.addAll(List.filled(chunkSize, 0));
} }
Future.delayed(const Duration(milliseconds: 300), () {
_startProcessingAudioTimer?.cancel(); _startProcessingAudioTimer?.cancel();
_startProcessingAudioTimer = null; _startProcessingAudioTimer = null;
_bufferedAudioFrames.clear(); _bufferedAudioFrames.clear();
});
} else {
_bufferedAudioFrames.clear();
}
final bool? isRecording = await state.voiceProcessor?.isRecording();
state.isRecordingAudio.value = isRecording!;
}
} }
static const int chunkSize = 320; // 32010ms G.711 static const int chunkSize = 320; // 32010ms G.711
@ -645,38 +642,24 @@ class ImageTransmissionLogic extends BaseGetXController {
List<int> encodedData = G711Tool.encode(applyGain, 0); // 0A-law List<int> encodedData = G711Tool.encode(applyGain, 0); // 0A-law
_bufferedAudioFrames.addAll(encodedData); _bufferedAudioFrames.addAll(encodedData);
// //
if (_startProcessingAudioTimer == null && _bufferedAudioFrames.length > chunkSize) { if (_startProcessingAudioTimer == null &&
_startProcessingAudioTimer = Timer.periodic(Duration(milliseconds: intervalMs), _sendAudioChunk); _bufferedAudioFrames.length > chunkSize) {
_startProcessingAudioTimer =
Timer.periodic(Duration(milliseconds: intervalMs), _sendAudioChunk);
} }
} }
// //
void _onError(VoiceProcessorException error) { void _onError(VoiceProcessorException error) {
AppLog.log(error.message!); AppLog.log(error.message!);
} }
//
List<int> _applyGain(List<int> pcmData, double gainFactor) { List<int> _applyGain(List<int> pcmData, double gainFactor) {
List<int> result = List<int>.filled(pcmData.length, 0); return pcmData.map((sample) {
//
for (int i = 0; i < pcmData.length; i++) { int amplified = (sample * gainFactor).round();
// PCM数据通常是有符号的16位整数 return amplified.clamp(-32768, 32767);
int sample = pcmData[i]; }).toList();
//
double amplified = sample * gainFactor;
//
if (amplified > 32767) {
amplified = 32767;
} else if (amplified < -32768) {
amplified = -32768;
}
result[i] = amplified.toInt();
}
return result;
} }
} }

View File

@ -104,10 +104,10 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
codecType: 'h264', codecType: 'h264',
); );
// textureId // textureId
AppLog.log('StartChartManage().videoWidth:${StartChartManage() AppLog.log(
.videoWidth}'); 'StartChartManage().videoWidth:${StartChartManage().videoWidth}');
AppLog.log('StartChartManage().videoHeight:${StartChartManage() AppLog.log(
.videoHeight}'); 'StartChartManage().videoHeight:${StartChartManage().videoHeight}');
final textureId = await VideoDecodePlugin.initDecoder(config); final textureId = await VideoDecodePlugin.initDecoder(config);
if (textureId != null) { if (textureId != null) {
Future.microtask(() => state.textureId.value = textureId); Future.microtask(() => state.textureId.value = textureId);
@ -493,7 +493,9 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
/// ///
void _playAudioData(TalkData talkData) async { void _playAudioData(TalkData talkData) async {
if (state.isOpenVoice.value && state.isLoading.isFalse) { if (state.isOpenVoice.value &&
state.isLoading.isFalse &&
state.isRecordingAudio.value == false) {
List<int> encodedData = G711Tool.decode(talkData.content, 0); // 0A-law List<int> encodedData = G711Tool.decode(talkData.content, 0); // 0A-law
// PCM PcmArrayInt16 // PCM PcmArrayInt16
final PcmArrayInt16 fromList = PcmArrayInt16.fromList(encodedData); final PcmArrayInt16 fromList = PcmArrayInt16.fromList(encodedData);
@ -746,7 +748,6 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
// //
Future<void> startProcessingAudio() async { Future<void> startProcessingAudio() async {
try { try {
if (await state.voiceProcessor?.hasRecordAudioPermission() ?? false) { if (await state.voiceProcessor?.hasRecordAudioPermission() ?? false) {
await state.voiceProcessor?.start(state.frameLength, state.sampleRate); await state.voiceProcessor?.start(state.frameLength, state.sampleRate);
@ -783,39 +784,36 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
} on PlatformException catch (ex) { } on PlatformException catch (ex) {
// state.errorMessage.value = 'Failed to stop recorder: $ex'; // state.errorMessage.value = 'Failed to stop recorder: $ex';
} finally { } finally {
final bool? isRecording = await state.voiceProcessor?.isRecording(); //
state.isRecordingAudio.value = isRecording!; if (_startProcessingAudioTimer != null) {
// 53200
for (int i = 0; i < 5; i++) {
_bufferedAudioFrames.addAll(List.filled(chunkSize, 0));
} }
Future.delayed(const Duration(milliseconds: 300), () {
_startProcessingAudioTimer?.cancel(); _startProcessingAudioTimer?.cancel();
_startProcessingAudioTimer = null; _startProcessingAudioTimer = null;
_bufferedAudioFrames.clear(); _bufferedAudioFrames.clear();
});
} else {
_bufferedAudioFrames.clear();
}
final bool? isRecording = await state.voiceProcessor?.isRecording();
state.isRecordingAudio.value = isRecording!;
}
} }
// //
List<int> _applyGain(List<int> pcmData, double gainFactor) { List<int> _applyGain(List<int> pcmData, double gainFactor) {
List<int> result = List<int>.filled(pcmData.length, 0); return pcmData.map((sample) {
//
for (int i = 0; i < pcmData.length; i++) { int amplified = (sample * gainFactor).round();
// PCM数据通常是有符号的16位整数 return amplified.clamp(-32768, 32767);
int sample = pcmData[i]; }).toList();
//
double amplified = sample * gainFactor;
//
if (amplified > 32767) {
amplified = 32767;
} else if (amplified < -32768) {
amplified = -32768;
} }
result[i] = amplified.toInt();
}
return result;
}
static const int chunkSize = 320; // 32010ms G.711 static const int chunkSize = 320; // 32010ms G.711
static const int intervalMs = 40; // 40ms发送一次4chunk static const int intervalMs = 35; // 40ms发送一次4chunk
void _sendAudioChunk(Timer timer) async { void _sendAudioChunk(Timer timer) async {
if (_bufferedAudioFrames.length < chunkSize) { if (_bufferedAudioFrames.length < chunkSize) {
// //
@ -849,10 +847,11 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
List<int> encodedData = G711Tool.encode(applyGain, 0); // 0A-law List<int> encodedData = G711Tool.encode(applyGain, 0); // 0A-law
_bufferedAudioFrames.addAll(encodedData); _bufferedAudioFrames.addAll(encodedData);
// //
if (_startProcessingAudioTimer == null && _bufferedAudioFrames.length > chunkSize) { if (_startProcessingAudioTimer == null &&
_startProcessingAudioTimer = Timer.periodic(Duration(milliseconds: intervalMs), _sendAudioChunk); _bufferedAudioFrames.length > chunkSize) {
_startProcessingAudioTimer =
Timer.periodic(Duration(milliseconds: intervalMs), _sendAudioChunk);
} }
} }
@ -973,7 +972,8 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
// //
switch (contentType) { switch (contentType) {
case TalkData_ContentTypeE.G711: case TalkData_ContentTypeE.G711:
if (!state.isOpenVoice.value) { //
if (!state.isOpenVoice.value || state.isRecordingAudio.value) {
return; return;
} }
if (state.audioBuffer.length >= audioBufferSize) { if (state.audioBuffer.length >= audioBufferSize) {

View File

@ -109,22 +109,10 @@ class TalkViewLogic extends BaseGetXController {
// //
switch (contentType) { switch (contentType) {
case TalkData_ContentTypeE.G711: case TalkData_ContentTypeE.G711:
// // //
if (_isFirstAudioFrame) { if (!state.isOpenVoice.value || state.isRecordingAudio.value) {
_startAudioTime = currentTime; print(
_isFirstAudioFrame = false; '录音时丢弃数据:${state.isOpenVoice.value}-${state.isRecordingAudio.value}');
}
//
final expectedTime = _startAudioTime + talkData.durationMs;
final audioDelay = currentTime - expectedTime;
//
if (audioDelay > 500) {
state.audioBuffer.clear();
if (state.isOpenVoice.value) {
_playAudioFrames();
}
return; return;
} }
if (state.audioBuffer.length >= audioBufferSize) { if (state.audioBuffer.length >= audioBufferSize) {
@ -388,9 +376,11 @@ class TalkViewLogic extends BaseGetXController {
if (state.videoBuffer.isNotEmpty) { if (state.videoBuffer.isNotEmpty) {
final TalkData oldestFrame = state.videoBuffer.removeAt(0); final TalkData oldestFrame = state.videoBuffer.removeAt(0);
if (oldestFrame.content.isNotEmpty) { if (oldestFrame.content.isNotEmpty) {
state.listData.value = Uint8List.fromList(oldestFrame.content); // state.listData.value =
Uint8List.fromList(oldestFrame.content); //
final int decodeStart = DateTime.now().millisecondsSinceEpoch; final int decodeStart = DateTime.now().millisecondsSinceEpoch;
decodeImageFromList(Uint8List.fromList(oldestFrame.content)).then((ui.Image img) { decodeImageFromList(Uint8List.fromList(oldestFrame.content))
.then((ui.Image img) {
final int decodeEnd = DateTime.now().millisecondsSinceEpoch; final int decodeEnd = DateTime.now().millisecondsSinceEpoch;
state.currentImage.value = img; state.currentImage.value = img;
_renderedFrameCount++; _renderedFrameCount++;
@ -562,7 +552,6 @@ class TalkViewLogic extends BaseGetXController {
// //
Future<void> startProcessingAudio() async { Future<void> startProcessingAudio() async {
try { try {
if (await state.voiceProcessor?.hasRecordAudioPermission() ?? false) { if (await state.voiceProcessor?.hasRecordAudioPermission() ?? false) {
await state.voiceProcessor?.start(state.frameLength, state.sampleRate); await state.voiceProcessor?.start(state.frameLength, state.sampleRate);
@ -599,12 +588,23 @@ class TalkViewLogic extends BaseGetXController {
} on PlatformException catch (ex) { } on PlatformException catch (ex) {
// state.errorMessage.value = 'Failed to stop recorder: $ex'; // state.errorMessage.value = 'Failed to stop recorder: $ex';
} finally { } finally {
final bool? isRecording = await state.voiceProcessor?.isRecording(); //
state.isRecordingAudio.value = isRecording!; if (_startProcessingAudioTimer != null) {
// 53200
for (int i = 0; i < 5; i++) {
_bufferedAudioFrames.addAll(List.filled(chunkSize, 0));
} }
Future.delayed(const Duration(milliseconds: 300), () {
_startProcessingAudioTimer?.cancel(); _startProcessingAudioTimer?.cancel();
_startProcessingAudioTimer = null; _startProcessingAudioTimer = null;
_bufferedAudioFrames.clear(); _bufferedAudioFrames.clear();
});
} else {
_bufferedAudioFrames.clear();
}
final bool? isRecording = await state.voiceProcessor?.isRecording();
state.isRecordingAudio.value = isRecording!;
}
} }
static const int chunkSize = 320; // 32010ms G.711 static const int chunkSize = 320; // 32010ms G.711
@ -642,10 +642,11 @@ class TalkViewLogic extends BaseGetXController {
List<int> encodedData = G711Tool.encode(applyGain, 0); // 0A-law List<int> encodedData = G711Tool.encode(applyGain, 0); // 0A-law
_bufferedAudioFrames.addAll(encodedData); _bufferedAudioFrames.addAll(encodedData);
// //
if (_startProcessingAudioTimer == null && _bufferedAudioFrames.length > chunkSize) { if (_startProcessingAudioTimer == null &&
_startProcessingAudioTimer = Timer.periodic(Duration(milliseconds: intervalMs), _sendAudioChunk); _bufferedAudioFrames.length > chunkSize) {
_startProcessingAudioTimer =
Timer.periodic(Duration(milliseconds: intervalMs), _sendAudioChunk);
} }
} }
@ -656,25 +657,10 @@ class TalkViewLogic extends BaseGetXController {
// //
List<int> _applyGain(List<int> pcmData, double gainFactor) { List<int> _applyGain(List<int> pcmData, double gainFactor) {
List<int> result = List<int>.filled(pcmData.length, 0); return pcmData.map((sample) {
//
for (int i = 0; i < pcmData.length; i++) { int amplified = (sample * gainFactor).round();
// PCM数据通常是有符号的16位整数 return amplified.clamp(-32768, 32767);
int sample = pcmData[i]; }).toList();
//
double amplified = sample * gainFactor;
//
if (amplified > 32767) {
amplified = 32767;
} else if (amplified < -32768) {
amplified = -32768;
}
result[i] = amplified.toInt();
}
return result;
} }
} }