Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d86d3de95e | ||
|
|
968a62be62 | ||
|
|
a5e921876f | ||
|
|
28f06bdab3 | ||
|
|
68635313d4 | ||
|
|
b0bafb1904 | ||
|
|
08aebf05e9 | ||
|
|
7994d09590 | ||
|
|
cb6174cf7d | ||
|
|
46ad46323e | ||
|
|
8f8659726a | ||
|
|
f6383fb4b5 | ||
|
|
4c6535243d | ||
|
|
b814efc21f | ||
|
|
1b7d1e87c7 | ||
|
|
316968e6ea | ||
|
|
c0a2c18ec4 | ||
|
|
ca0e843d80 | ||
|
|
cc2808a1da | ||
|
|
d367921db9 | ||
|
|
14ce19872d | ||
|
|
aa885b4158 | ||
|
|
7b19980a83 | ||
|
|
a3220afc32 | ||
|
|
0e8aa9dea6 | ||
|
|
91e8d559b9 | ||
|
|
9ecbfbffc7 | ||
|
|
df04dc6065 | ||
|
|
70c4edc761 | ||
|
|
f3c12f98cc | ||
|
|
8ddb1c4201 | ||
|
|
e466270cb1 | ||
|
|
f48314bd9b | ||
|
|
23b1a28790 |
@@ -55,9 +55,9 @@
|
||||
"i18next": "^21.10.0",
|
||||
"i18next-browser-languagedetector": "^6.1.8",
|
||||
"i18next-http-backend": "^1.4.4",
|
||||
"livekit-client": "^1.11.4",
|
||||
"livekit-client": "1.12.0",
|
||||
"lodash": "^4.17.21",
|
||||
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#4b3406daa95c8f969f386341b8b632ba4a60501a",
|
||||
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#9ba44b96202e36d8bd6fbcff3222b7c70fc371d7",
|
||||
"matrix-widget-api": "^1.3.1",
|
||||
"mermaid": "^8.13.8",
|
||||
"normalize.css": "^8.0.1",
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
"Another user on this call is having an issue. In order to better diagnose these issues we'd like to collect a debug log.": "Друг потребител в този разговор има проблем. За да диагностицираме този проблем по-добре ни се иска да съберем debug логове.",
|
||||
"Audio": "Звук",
|
||||
"Avatar": "Аватар",
|
||||
"By clicking \"Join call now\", you agree to our <2>Terms and conditions</2>": "Натискайки \"Влез в разговора сега\", се съгласявате с нашите <2>Правила и условия</2>",
|
||||
"Call link copied": "Връзка към разговора бе копирана",
|
||||
"Call type menu": "Меню \"тип на разговора\"",
|
||||
"Camera": "Камера",
|
||||
|
||||
@@ -89,7 +89,6 @@
|
||||
"Create account": "Vytvořit účet",
|
||||
"Copy": "Kopírovat",
|
||||
"Call type menu": "Menu typu hovoru",
|
||||
"By clicking \"Go\", you agree to our <2>Terms and conditions</2>": "Kliknutím na \"Pokračovat\", odsouhlasíte naše <2>Terms and conditions</2>",
|
||||
"Another user on this call is having an issue. In order to better diagnose these issues we'd like to collect a debug log.": "Jiný uživatel v tomto hovoru má problémy. Abychom mohli diagnostikovat problém, rádi bychom shromáždili protokoly ladění.",
|
||||
"<0>Why not finish by setting up a password to keep your account?</0><1>You'll be able to keep your name and set an avatar for use on future calls</1>": "<0>Proč neskončit nastavením hesla, abyste mohli účet použít znovu?</0><1>Budete si moci nechat své jméno a nastavit si avatar pro budoucí hovory </1>",
|
||||
"<0>Join call now</0><1>Or</1><2>Copy call link and join later</2>": "<0>Připojit se</0><1>Or</1><2>Zkopírovat odkaz a připojit se později</2>",
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
"Another user on this call is having an issue. In order to better diagnose these issues we'd like to collect a debug log.": "Ein anderer Benutzer dieses Anrufs hat ein Problem. Um es besser diagnostizieren zu können, würden wir gerne ein Debug-Protokoll erstellen.",
|
||||
"Audio": "Audio",
|
||||
"Avatar": "Avatar",
|
||||
"By clicking \"Join call now\", you agree to our <2>Terms and conditions</2>": "Wenn du auf „Anruf beitreten“ klickst, akzeptierst du unsere <2>Geschäftsbedingungen</2>",
|
||||
"Call link copied": "Anruflink kopiert",
|
||||
"Call type menu": "Anruftyp Menü",
|
||||
"Camera": "Kamera",
|
||||
@@ -113,5 +112,9 @@
|
||||
"{{count}} stars|one": "{{count}} Stern",
|
||||
"<0>Thanks for your feedback!</0>": "<0>Danke für deine Rückmeldung!</0>",
|
||||
"{{displayName}} is presenting": "{{displayName}} präsentiert",
|
||||
"Show connection stats": "Verbindungsstatistiken zeigen"
|
||||
"Show connection stats": "Verbindungsstatistiken zeigen",
|
||||
"By clicking \"Join call now\", you agree to our <2>End User Licensing Agreement (EULA)</2>": "Mit einem Klick auf „Anruf beitreten“ akzeptierst du unseren <2>Endbenutzer-Lizenzvertrag (EULA)</2>",
|
||||
"By clicking \"Go\", you agree to our <2>End User Licensing Agreement (EULA)</2>": "Mit einem Klick auf „Los geht’s“ akzeptierst du unseren <2>Endbenutzer-Lizenzvertrag (EULA)</2>",
|
||||
"Element Call is temporarily not encrypted while we test scalability.": "Element Call ist temporär nicht verschlüsselt, während wir die Skalierbarkeit testen.",
|
||||
"This site is protected by ReCAPTCHA and the Google <2>Privacy Policy</2> and <6>Terms of Service</6> apply.<9></9>By clicking \"Register\", you agree to our <12>End User Licensing Agreement (EULA)</12>": "Diese Seite wird durch reCAPTCHA geschützt und es gelten Googles <2>Datenschutzerklärung</2> und <6>Nutzungsbedingungen</6>. <9></9>Mit einem Klick auf „Registrieren“ akzeptierst du unseren <2>Endbenutzer-Lizenzvertrag (EULA)</2>"
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
"Display name": "Display name",
|
||||
"Download debug logs": "Download debug logs",
|
||||
"Element Call Home": "Element Call Home",
|
||||
"Element Call is temporarily not encrypted while we test scalability.": "Element Call is temporarily not encrypted while we test scalability.",
|
||||
"Element Call is temporarily not end-to-end encrypted while we test scalability.": "Element Call is temporarily not end-to-end encrypted while we test scalability.",
|
||||
"Exit full screen": "Exit full screen",
|
||||
"Expose developer settings in the settings window.": "Expose developer settings in the settings window.",
|
||||
"Feedback": "Feedback",
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
"Register": "Registrarse",
|
||||
"Not registered yet? <2>Create an account</2>": "¿No estás registrado todavía? <2>Crear una cuenta</2>",
|
||||
"Login to your account": "Iniciar sesión en tu cuenta",
|
||||
"By clicking \"Go\", you agree to our <2>Terms and conditions</2>": "Al hacer clic en \"Comenzar\" aceptarás nuestros <2>Términos y condiciones</2>",
|
||||
"Yes, join call": "Si, unirse a la llamada",
|
||||
"Walkie-talkie call name": "Nombre de la llamada Walkie-talkie",
|
||||
"Walkie-talkie call": "Llamada Walkie-talkie",
|
||||
|
||||
@@ -32,13 +32,12 @@
|
||||
"Camera": "Kaamera",
|
||||
"Call type menu": "Kõnetüübi valik",
|
||||
"Call link copied": "Kõne link on kopeeritud",
|
||||
"By clicking \"Go\", you agree to our <2>Terms and conditions</2>": "Klõpsides „Jätka“nõustud sa meie <2>kasutustingimustega</2>",
|
||||
"Avatar": "Tunnuspilt",
|
||||
"Audio": "Heli",
|
||||
"Another user on this call is having an issue. In order to better diagnose these issues we'd like to collect a debug log.": "Ühel teisel selles kõnes osalejal on lahenduse kasutamisel tekkinud probleem ning selle põhjuse leidmiseks me sooviksime koguda silumislogisid.",
|
||||
"Passwords must match": "Salasõnad ei klapi",
|
||||
"Password": "Salasõna",
|
||||
"Not registered yet? <2>Create an account</2>": "Pole veel registreerunud? <2>Loo kasutajakonto</2>",
|
||||
"Not registered yet? <2>Create an account</2>": "Sa pole veel registreerunud? <2>Loo kasutajakonto</2>",
|
||||
"Not now, return to home screen": "Mitte praegu, mine tagasi avalehele",
|
||||
"No": "Ei",
|
||||
"Mute microphone": "Summuta mikrofon",
|
||||
@@ -52,7 +51,7 @@
|
||||
"Loading…": "Laadimine …",
|
||||
"Leave": "Lahku",
|
||||
"Join existing call?": "Liitu juba käimasoleva kõnega?",
|
||||
"Join call now": "Kõnega liitumine",
|
||||
"Join call now": "Liitu kõnega kohe",
|
||||
"Join call": "Kõnega liitumine",
|
||||
"Turn on camera": "Lülita kaamera sisse",
|
||||
"Turn off camera": "Lülita kaamera välja",
|
||||
@@ -113,5 +112,9 @@
|
||||
"<0>Thanks for your feedback!</0>": "<0>Täname Sind tagasiside eest!</0>",
|
||||
"<0>We'd love to hear your feedback so we can improve your experience.</0>": "<0>Meie rakenduse paremaks muutmiseks me hea meelega ootame Sinu arvamusi.</0>",
|
||||
"Show connection stats": "Näita ühenduse statistikat",
|
||||
"{{displayName}} is presenting": "{{displayName}} on esitlemas"
|
||||
"{{displayName}} is presenting": "{{displayName}} on esitlemas",
|
||||
"By clicking \"Go\", you agree to our <2>End User Licensing Agreement (EULA)</2>": "Klõpsides „Jätka“, nõustud sa meie <2>Lõppkasutaja litsentsilepinguga (EULA)</2>",
|
||||
"By clicking \"Join call now\", you agree to our <2>End User Licensing Agreement (EULA)</2>": "Klõpsides „Liitu kõnega kohe“, nõustud sa meie <2>Lõppkasutaja litsentsilepinguga (EULA)</2>",
|
||||
"Element Call is temporarily not encrypted while we test scalability.": "Seni kuni me testime skaleeritavust, siis Element Call ajutiselt pole krüptitud.",
|
||||
"This site is protected by ReCAPTCHA and the Google <2>Privacy Policy</2> and <6>Terms of Service</6> apply.<9></9>By clicking \"Register\", you agree to our <12>End User Licensing Agreement (EULA)</12>": "Selles saidis on kasutusel ReCAPTCHA ja kehtivad Google'i <2>Privaatsuspoliitika</2> ning <6>Teenusetingimused</6>.<9></9>Klõpsides „Registreeru“, sa nõustud meie <12>Lõppkasutaja litsentsilepingu (EULA) tingimustega</12>"
|
||||
}
|
||||
|
||||
@@ -45,7 +45,6 @@
|
||||
"Camera": "دوربین",
|
||||
"Call type menu": "منوی نوع تماس",
|
||||
"Call link copied": "لینک تماس کپی شد",
|
||||
"By clicking \"Go\", you agree to our <2>Terms and conditions</2>": "با کلیک بر روی برو، شما با <2>شرایط و قوانین استفاده</2> موافقت میکنید",
|
||||
"Avatar": "آواتار",
|
||||
"Audio": "صدا",
|
||||
"Another user on this call is having an issue. In order to better diagnose these issues we'd like to collect a debug log.": "کاربر دیگری در این تماس مشکلی دارد. برای تشخیص بهتر مشکل، بهتر است ما لاگ عیبیابی را جمعآوری کنیم.",
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
"Another user on this call is having an issue. In order to better diagnose these issues we'd like to collect a debug log.": "Un autre utilisateur dans cet appel a un problème. Pour nous permettre de résoudre le problème, nous aimerions récupérer un journal de débogage.",
|
||||
"Audio": "Audio",
|
||||
"Avatar": "Avatar",
|
||||
"By clicking \"Join call now\", you agree to our <2>Terms and conditions</2>": "En cliquant sur « Rejoindre l’appel » vous acceptez nos <2>conditions d’utilisation</2>",
|
||||
"Call link copied": "Lien de l’appel copié",
|
||||
"Call type menu": "Menu de type d’appel",
|
||||
"Camera": "Caméra",
|
||||
@@ -113,5 +112,8 @@
|
||||
"<0>Thanks for your feedback!</0>": "<0>Merci pour votre commentaire !</0>",
|
||||
"How did it go?": "Comment cela s’est-il passé ?",
|
||||
"{{displayName}} is presenting": "{{displayName}} est à l’écran",
|
||||
"Show connection stats": "Afficher les statistiques de la connexion"
|
||||
"Show connection stats": "Afficher les statistiques de la connexion",
|
||||
"By clicking \"Join call now\", you agree to our <2>End User Licensing Agreement (EULA)</2>": "En cliquant sur « Rejoindre l’appel maintenant », vous acceptez notre <2>Contrat de Licence Utilisateur Final (CLUF)</2>",
|
||||
"By clicking \"Go\", you agree to our <2>End User Licensing Agreement (EULA)</2>": "En cliquant sur « Commencer », vous acceptez notre <2>Contrat de Licence Utilisateur Final (CLUF)</2>",
|
||||
"This site is protected by ReCAPTCHA and the Google <2>Privacy Policy</2> and <6>Terms of Service</6> apply.<9></9>By clicking \"Register\", you agree to our <12>End User Licensing Agreement (EULA)</12>": "Ce site est protégé par ReCAPTCHA, la <2>politique de confidentialité</2> et les <6>conditions d’utilisation</6> de Google s’appliquent.<9></9>En cliquant sur « S’enregistrer » vous acceptez également notre <12>Contrat de Licence Utilisateur Final (CLUF)</12>"
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
"Your recent calls": "Panggilan Anda terkini",
|
||||
"{{names}}, {{name}}": "{{names}}, {{name}}",
|
||||
"Sending debug logs…": "Mengirimkan catatan pengawakutuan…",
|
||||
"<0>Join call now</0><1>Or</1><2>Copy call link and join later</2>": "<0>Bergabung panggilan sekarang</0><1>Atau</1><2>Salin tautan dan bergabung nanti</2>",
|
||||
"<0>Join call now</0><1>Or</1><2>Copy call link and join later</2>": "<0>Bergabung ke panggilan sekarang</0><1>Atau</1><2>Salin tautan dan bergabung nanti</2>",
|
||||
"Element Call Home": "Beranda Element Call",
|
||||
"Copy": "Salin",
|
||||
"<0>Submitting debug logs will help us track down the problem.</0>": "<0>Mengirim catatan pengawakutuan akan membantu kami melacak masalahnya.</0>",
|
||||
@@ -102,7 +102,7 @@
|
||||
"Feedback": "Masukan",
|
||||
"If you are experiencing issues or simply would like to provide some feedback, please send us a short description below.": "Jika Anda mengalami masalah atau hanya ingin memberikan masukan, silakan kirimkan kami deskripsi pendek di bawah.",
|
||||
"Submit": "Kirim",
|
||||
"Submitting…": "Mengirim",
|
||||
"Submitting…": "Mengirim…",
|
||||
"Thanks, we received your feedback!": "Terima kasih, kami telah menerima masukan Anda!",
|
||||
"Your feedback": "Masukan Anda",
|
||||
"{{displayName}}, your call has ended.": "{{displayName}}, panggilan Anda telah berakhir.",
|
||||
@@ -113,5 +113,8 @@
|
||||
"Show connection stats": "Tampilkan statistik koneksi",
|
||||
"{{displayName}} is presenting": "{{displayName}} sedang menampilkan",
|
||||
"{{count}} stars|other": "{{count}} bintang",
|
||||
"By clicking \"Go\", you agree to our <2>End User Licensing Agreement (EULA)</2>": "Dengan mengeklik \"Bergabung\", Anda menyetujui <2>"
|
||||
"By clicking \"Go\", you agree to our <2>End User Licensing Agreement (EULA)</2>": "Dengan mengeklik \"Bergabung\", Anda menyetujui <2>Perjanjian Lisensi Pengguna Akhir (EULA)</2>",
|
||||
"This site is protected by ReCAPTCHA and the Google <2>Privacy Policy</2> and <6>Terms of Service</6> apply.<9></9>By clicking \"Register\", you agree to our <12>End User Licensing Agreement (EULA)</12>": "Situs ini dilindungi oleh reCAPTCHA dan <2>Kebijakan Privasi</2> dan <6>Ketentuan Layanan</6> Google berlaku.<9></9>Dengan mengeklik \"Daftar\", Anda menyetujui <12>Perjanjian Lisensi Pengguna Akhir (EULA)</12> kami",
|
||||
"By clicking \"Join call now\", you agree to our <2>End User Licensing Agreement (EULA)</2>": "Dengan mengeklik \"Bergabung ke panggilan sekarang\", Anda menyetujui <2>Perjanjian Lisensi Pengguna Akhir (EULA)</2> kami",
|
||||
"Element Call is temporarily not encrypted while we test scalability.": "Element Call sementara tidak dienkripsi selagi kami menguji skalabilitas."
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
"<0>Oops, something's gone wrong.</0>": "<0>何かがうまく行きませんでした。</0>",
|
||||
"Camera": "カメラ",
|
||||
"Call link copied": "通話リンクをコピーしました",
|
||||
"By clicking \"Go\", you agree to our <2>Terms and conditions</2>": "「続行」をクリックすると、 <2>利用規約</2>に同意したとみなされます",
|
||||
"Avatar": "アバター",
|
||||
"Audio": "音声",
|
||||
"Confirm password": "パスワードを確認",
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
"Select an option": "Выберите вариант",
|
||||
"Other users are trying to join this call from incompatible versions. These users should ensure that they have refreshed their browsers:<1>{userLis}</1>": "Другие пользователи пытаются присоединиться с неподдерживаемых версий программы. Этим участникам надо перезагрузить браузер: <1>{userLis}</1>",
|
||||
"Grid layout menu": "Меню \"Расположение сеткой\"",
|
||||
"By clicking \"Go\", you agree to our <2>Terms and conditions</2>": "Нажимая \"Далее\", вы соглашаетесь с нашими <2>положениями и условиями</2>",
|
||||
"<0>Why not finish by setting up a password to keep your account?</0><1>You'll be able to keep your name and set an avatar for use on future calls</1>": "<0>Почему бы не задать пароль, тем самым сохранив аккаунт?</0><1>Так вы можете оставить своё имя и задать аватар для будущих звонков.</1>",
|
||||
"<0>Create an account</0> Or <2>Access as a guest</2>": "<0>Создать аккаунт</0> или <2>Зайти как гость</2>",
|
||||
"<0>Already have an account?</0><1><0>Log in</0> Or <2>Access as a guest</2></1>": "<0>Уже есть аккаунт?</0><1><0>Войти с ним</0> или <2>Зайти как гость</2></1>",
|
||||
|
||||
@@ -85,7 +85,6 @@
|
||||
"Camera": "Kamera",
|
||||
"Call type menu": "Ponuka typu hovoru",
|
||||
"Call link copied": "Odkaz na hovor skopírovaný",
|
||||
"By clicking \"Go\", you agree to our <2>Terms and conditions</2>": "Kliknutím na tlačidlo \"Prejsť\" súhlasíte s našimi <2>Podmienkami</2>",
|
||||
"Avatar": "Obrázok",
|
||||
"Audio": "Audio",
|
||||
"Another user on this call is having an issue. In order to better diagnose these issues we'd like to collect a debug log.": "Ďalší používateľ v tomto hovore má problém. Aby sme mohli lepšie diagnostikovať tieto problémy, chceli by sme získať záznam o ladení.",
|
||||
@@ -113,5 +112,9 @@
|
||||
"<0>Thanks for your feedback!</0>": "<0> Ďakujeme za vašu spätnú väzbu!</0>",
|
||||
"<0>We'd love to hear your feedback so we can improve your experience.</0>": "<0> Radi si vypočujeme vašu spätnú väzbu, aby sme mohli zlepšiť vaše skúsenosti.</0>",
|
||||
"{{displayName}} is presenting": "{{displayName}} prezentuje",
|
||||
"Show connection stats": "Zobraziť štatistiky pripojenia"
|
||||
"Show connection stats": "Zobraziť štatistiky pripojenia",
|
||||
"By clicking \"Join call now\", you agree to our <2>End User Licensing Agreement (EULA)</2>": "Kliknutím na \"Pripojiť sa k hovoru teraz\" súhlasíte s našou <2>Licenčnou zmluvou s koncovým používateľom (EULA)</2>",
|
||||
"By clicking \"Go\", you agree to our <2>End User Licensing Agreement (EULA)</2>": "Kliknutím na tlačidlo \"Prejsť\" vyjadrujete súhlas s našou <2>Licenčnou zmluvou s koncovým používateľom (EULA)</2>",
|
||||
"This site is protected by ReCAPTCHA and the Google <2>Privacy Policy</2> and <6>Terms of Service</6> apply.<9></9>By clicking \"Register\", you agree to our <12>End User Licensing Agreement (EULA)</12>": "Táto stránka je chránená systémom ReCAPTCHA a platia na ňu <2>Pravidlá ochrany osobných údajov spoločnosti Google</2> a <6>Podmienky poskytovania služieb</6>.<9></9>Kliknutím na tlačidlo \"Registrovať sa\" súhlasíte s našou <12>Licenčnou zmluvou s koncovým používateľom (EULA)</12>",
|
||||
"Element Call is temporarily not encrypted while we test scalability.": "Element Call nie je dočasne šifrovaný, kým testujeme škálovateľnosť."
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
"Another user on this call is having an issue. In order to better diagnose these issues we'd like to collect a debug log.": "Bu aramadaki başka bir kullanıcı sorun yaşıyor. Sorunu daha iyi çözebilmemiz için hata ayıklama kütüğünü almak isteriz.",
|
||||
"Audio": "Ses",
|
||||
"Avatar": "Avatar",
|
||||
"By clicking \"Join call now\", you agree to our <2>Terms and conditions</2>": "\"Şimdi katıl\"a tıklayarak, <2>hükümler ve koşullar</2>ı kabul etmiş sayılırsınız",
|
||||
"Call link copied": "Arama bağlantısı kopyalandı",
|
||||
"Call type menu": "Arama tipi menüsü",
|
||||
"Camera": "Kamera",
|
||||
|
||||
@@ -83,7 +83,6 @@
|
||||
"Camera": "Камера",
|
||||
"Call type menu": "Меню типу виклику",
|
||||
"Call link copied": "Посилання на виклик скопійовано",
|
||||
"By clicking \"Go\", you agree to our <2>Terms and conditions</2>": "Натиснувши «Далі», ви погодитеся з нашими <2>Умовами та положеннями</2>",
|
||||
"Avatar": "Аватар",
|
||||
"Audio": "Звук",
|
||||
"Another user on this call is having an issue. In order to better diagnose these issues we'd like to collect a debug log.": "Інший користувач у цьому виклику має проблему. Щоб краще визначити ці проблеми, ми хотіли б зібрати журнал налагодження.",
|
||||
@@ -113,5 +112,9 @@
|
||||
"<0>We'd love to hear your feedback so we can improve your experience.</0>": "<0>Ми будемо раді почути ваші відгуки, щоб поліпшити роботу застосунку.</0>",
|
||||
"How did it go?": "Вам усе сподобалось?",
|
||||
"{{displayName}} is presenting": "{{displayName}} представляє",
|
||||
"Show connection stats": "Показати стан з'єднання"
|
||||
"Show connection stats": "Показати стан з'єднання",
|
||||
"By clicking \"Go\", you agree to our <2>End User Licensing Agreement (EULA)</2>": "Натискаючи \"Далі\", ви погоджуєтеся з нашою <2>Ліцензійною угодою з кінцевим користувачем (EULA)</2>",
|
||||
"By clicking \"Join call now\", you agree to our <2>End User Licensing Agreement (EULA)</2>": "Натискаючи \"Приєднатися до виклику зараз\", ви погоджуєтеся з нашою <2>Ліцензійною угодою з кінцевим користувачем (EULA)</2>",
|
||||
"This site is protected by ReCAPTCHA and the Google <2>Privacy Policy</2> and <6>Terms of Service</6> apply.<9></9>By clicking \"Register\", you agree to our <12>End User Licensing Agreement (EULA)</12>": "Цей сайт захищений ReCAPTCHA і до нього застосовується <2>Політика приватності</2> і <6>Умови надання послуг</6> Google.<9></9>Натискаючи \"Зареєструватися\", ви погоджуєтеся з нашою <12>Ліцензійною угодою з кінцевим користувачем (EULA)</12>",
|
||||
"Element Call is temporarily not encrypted while we test scalability.": "Element Call тимчасово не шифрується, поки ми тестуємо масштабованість."
|
||||
}
|
||||
|
||||
@@ -93,7 +93,6 @@
|
||||
"Camera": "相機",
|
||||
"Call type menu": "通話類型選單",
|
||||
"Call link copied": "已複製通話連結",
|
||||
"By clicking \"Go\", you agree to our <2>Terms and conditions</2>": "當您按下「前往」,你也同意了我們的條款與細則",
|
||||
"Avatar": "大頭照",
|
||||
"Audio": "語音",
|
||||
"Another user on this call is having an issue. In order to better diagnose these issues we'd like to collect a debug log.": "這通對話中的另一位使用者遇到了某些問題。為了診斷問題,我們將會建立除錯紀錄。",
|
||||
@@ -113,5 +112,9 @@
|
||||
"{{displayName}}, your call has ended.": "{{displayName}},您的通話已結束。",
|
||||
"How did it go?": "進展如何?",
|
||||
"{{displayName}} is presenting": "{{displayName}} 正在展示",
|
||||
"Show connection stats": "顯示連線統計資料"
|
||||
"Show connection stats": "顯示連線統計資料",
|
||||
"By clicking \"Go\", you agree to our <2>End User Licensing Agreement (EULA)</2>": "點擊「前往」即表示您同意我們的<2>終端使用者授權協議 (EULA)</2>",
|
||||
"By clicking \"Join call now\", you agree to our <2>End User Licensing Agreement (EULA)</2>": "點擊「立刻加入通話」即表示您同意我們的<2>終端使用者授權協議 (EULA)</2>",
|
||||
"This site is protected by ReCAPTCHA and the Google <2>Privacy Policy</2> and <6>Terms of Service</6> apply.<9></9>By clicking \"Register\", you agree to our <12>End User Licensing Agreement (EULA)</12>": "此網站被 ReCAPTCHA 保護,並適用 Google 的<2>隱私權政策</2>與<6>服務條款</6>。<9></9>點擊「註冊」即表示您同意我們的<12>終端使用者授權協議 (EULA)</12>",
|
||||
"Element Call is temporarily not encrypted while we test scalability.": "在我們測試可擴展性時,Element Call 暫時未加密。"
|
||||
}
|
||||
|
||||
@@ -26,7 +26,8 @@ export const E2EEBanner = () => {
|
||||
<div className={styles.e2eeBanner}>
|
||||
<LockOffIcon width={24} height={24} />
|
||||
<Trans>
|
||||
Element Call is temporarily not encrypted while we test scalability.
|
||||
Element Call is temporarily not end-to-end encrypted while we test
|
||||
scalability.
|
||||
</Trans>
|
||||
</div>
|
||||
</Banner>
|
||||
|
||||
@@ -27,7 +27,9 @@ export const E2EELock = () => {
|
||||
const { t } = useTranslation();
|
||||
const tooltip = useCallback(
|
||||
() =>
|
||||
t("Element Call is temporarily not encrypted while we test scalability."),
|
||||
t(
|
||||
"Element Call is temporarily not end-to-end encrypted while we test scalability."
|
||||
),
|
||||
[t]
|
||||
);
|
||||
|
||||
|
||||
@@ -61,6 +61,10 @@ limitations under the License.
|
||||
outline: auto;
|
||||
}
|
||||
|
||||
.toolbarButton:disabled {
|
||||
opacity: 0.55;
|
||||
}
|
||||
|
||||
.toolbarButton,
|
||||
.toolbarButtonSecondary {
|
||||
width: 50px;
|
||||
|
||||
@@ -77,6 +77,7 @@ interface Props {
|
||||
children: Element[];
|
||||
onPress: (e: PressEvent) => void;
|
||||
onPressStart: (e: PressEvent) => void;
|
||||
disabled: boolean;
|
||||
// TODO: add all props for <Button>
|
||||
[index: string]: unknown;
|
||||
}
|
||||
|
||||
@@ -14,12 +14,12 @@ const defaultLiveKitPublishOptions: TrackPublishDefaults = {
|
||||
red: true,
|
||||
forceStereo: false,
|
||||
simulcast: true,
|
||||
videoSimulcastLayers: [VideoPresets.h180, VideoPresets.h216] as VideoPreset[],
|
||||
videoSimulcastLayers: [VideoPresets.h180, VideoPresets.h360] as VideoPreset[],
|
||||
screenShareEncoding: ScreenSharePresets.h1080fps30.encoding,
|
||||
stopMicTrackOnMute: false,
|
||||
videoCodec: "vp8",
|
||||
videoEncoding: VideoPresets.h360.encoding,
|
||||
backupCodec: { codec: "vp8", encoding: VideoPresets.h360.encoding },
|
||||
videoEncoding: VideoPresets.h720.encoding,
|
||||
backupCodec: { codec: "vp8", encoding: VideoPresets.h720.encoding },
|
||||
} as const;
|
||||
|
||||
export const defaultLiveKitOptions: RoomOptions = {
|
||||
@@ -31,7 +31,7 @@ export const defaultLiveKitOptions: RoomOptions = {
|
||||
|
||||
// capture settings
|
||||
videoCaptureDefaults: {
|
||||
resolution: VideoPresets.h360.resolution,
|
||||
resolution: VideoPresets.h720.resolution,
|
||||
},
|
||||
|
||||
// publish settings
|
||||
|
||||
@@ -341,7 +341,12 @@ export function InCallView({
|
||||
|
||||
const toggleScreensharing = useCallback(async () => {
|
||||
exitFullscreen();
|
||||
await localParticipant.setScreenShareEnabled(!isScreenShareEnabled);
|
||||
await localParticipant.setScreenShareEnabled(!isScreenShareEnabled, {
|
||||
audio: true,
|
||||
selfBrowserSurface: "include",
|
||||
surfaceSwitching: "include",
|
||||
systemAudio: "include",
|
||||
});
|
||||
}, [localParticipant, isScreenShareEnabled, exitFullscreen]);
|
||||
|
||||
let footer: JSX.Element | null;
|
||||
|
||||
@@ -28,7 +28,7 @@ import { useModalTriggerState } from "../Modal";
|
||||
import { SettingsModal } from "../settings/SettingsModal";
|
||||
import { useClient } from "../ClientContext";
|
||||
import { useMediaDevicesSwitcher } from "../livekit/useMediaDevicesSwitcher";
|
||||
import { DeviceChoices, UserChoices } from "../livekit/useLiveKit";
|
||||
import { UserChoices } from "../livekit/useLiveKit";
|
||||
import { useDefaultDevices } from "../settings/useSetting";
|
||||
|
||||
export type MatrixInfo = {
|
||||
@@ -66,10 +66,14 @@ export function VideoPreview({ matrixInfo, onUserChoicesChanged }: Props) {
|
||||
const [videoEnabled, setVideoEnabled] = useState<boolean>(true);
|
||||
const [audioEnabled, setAudioEnabled] = useState<boolean>(true);
|
||||
|
||||
// we store if the tracks are currently initializing to not show them as muted.
|
||||
// showing them as muted while they are not yet available makes the buttons flicker undesirable during startup.
|
||||
const [initializingVideo, setInitializingVideo] = useState<boolean>(true);
|
||||
const [initializingAudio, setInitializingAudio] = useState<boolean>(true);
|
||||
|
||||
// The settings are updated as soon as the device changes. We wrap the settings value in a ref to store their initial value.
|
||||
// Not changing the device options prohibits the usePreviewTracks hook to recreate the tracks.
|
||||
const initialDefaultDevices = useRef(useDefaultDevices()[0]);
|
||||
|
||||
const tracks = usePreviewTracks(
|
||||
{
|
||||
audio: { deviceId: initialDefaultDevices.current.audioinput },
|
||||
@@ -89,9 +93,10 @@ export function VideoPreview({ matrixInfo, onUserChoicesChanged }: Props) {
|
||||
tracks?.filter((t) => t.kind === Track.Kind.Audio)[0] as LocalAudioTrack,
|
||||
[tracks]
|
||||
);
|
||||
|
||||
// Only let the MediaDeviceSwitcher request permissions if a video track is already available.
|
||||
// Otherwise we would end up asking for permissions in usePreviewTracks and in useMediaDevicesSwitcher.
|
||||
const requestPermissions = !!videoTrack;
|
||||
const requestPermissions = !!audioTrack && !!videoTrack;
|
||||
const mediaSwitcher = useMediaDevicesSwitcher(
|
||||
undefined,
|
||||
{
|
||||
@@ -104,22 +109,23 @@ export function VideoPreview({ matrixInfo, onUserChoicesChanged }: Props) {
|
||||
|
||||
const videoEl = React.useRef(null);
|
||||
|
||||
// pretend the video is available until the initialization is over
|
||||
const videoAvailableAndEnabled =
|
||||
videoEnabled && (!!videoTrack || initializingVideo);
|
||||
const audioAvailableAndEnabled =
|
||||
audioEnabled && (!!videoTrack || initializingAudio);
|
||||
|
||||
useEffect(() => {
|
||||
// Effect to update the settings
|
||||
const createChoices = (
|
||||
enabled: boolean,
|
||||
deviceId?: string
|
||||
): DeviceChoices | undefined => {
|
||||
return deviceId
|
||||
? {
|
||||
selectedId: deviceId,
|
||||
enabled,
|
||||
}
|
||||
: undefined;
|
||||
};
|
||||
onUserChoicesChanged({
|
||||
video: createChoices(videoEnabled, videoIn.selectedId),
|
||||
audio: createChoices(audioEnabled, audioIn.selectedId),
|
||||
video: {
|
||||
selectedId: videoIn.selectedId,
|
||||
enabled: videoAvailableAndEnabled,
|
||||
},
|
||||
audio: {
|
||||
selectedId: audioIn.selectedId,
|
||||
enabled: audioAvailableAndEnabled,
|
||||
},
|
||||
});
|
||||
}, [
|
||||
onUserChoicesChanged,
|
||||
@@ -127,22 +133,31 @@ export function VideoPreview({ matrixInfo, onUserChoicesChanged }: Props) {
|
||||
videoEnabled,
|
||||
audioIn.selectedId,
|
||||
audioEnabled,
|
||||
videoAvailableAndEnabled,
|
||||
audioAvailableAndEnabled,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
// Effect to update the initial device selection for the ui elements based on the current preview track.
|
||||
if (!videoIn.selectedId || videoIn.selectedId == "") {
|
||||
if (videoTrack) {
|
||||
setInitializingVideo(false);
|
||||
}
|
||||
videoTrack?.getDeviceId().then((videoId) => {
|
||||
if (videoId) {
|
||||
videoIn.setSelected(videoId);
|
||||
}
|
||||
videoIn.setSelected(videoId ?? "default");
|
||||
});
|
||||
}
|
||||
if (!audioIn.selectedId || audioIn.selectedId == "") {
|
||||
if (audioTrack) {
|
||||
setInitializingAudio(false);
|
||||
}
|
||||
audioTrack?.getDeviceId().then((audioId) => {
|
||||
if (audioId) {
|
||||
audioIn.setSelected(audioId);
|
||||
}
|
||||
// getDeviceId() can return undefined for audio devices. This happens if
|
||||
// the devices list uses "default" as the device id for the current
|
||||
// device and the device set on the track also uses the deviceId
|
||||
// "default". Check `normalizeDeviceId` in `getDeviceId` for more
|
||||
// details.
|
||||
audioIn.setSelected(audioId ?? "default");
|
||||
});
|
||||
}
|
||||
}, [videoIn, audioIn, videoTrack, audioTrack]);
|
||||
@@ -158,6 +173,15 @@ export function VideoPreview({ matrixInfo, onUserChoicesChanged }: Props) {
|
||||
};
|
||||
}, [videoTrack]);
|
||||
|
||||
useEffect(() => {
|
||||
// Effect to mute/unmute video track. (This has to be done, so that the hardware camera indicator does not confuse the user)
|
||||
if (videoTrack && videoEnabled) {
|
||||
videoTrack?.unmute();
|
||||
} else if (videoTrack) {
|
||||
videoTrack?.mute();
|
||||
}
|
||||
}, [videoEnabled, videoTrack]);
|
||||
|
||||
return (
|
||||
<div className={styles.preview} ref={previewRef}>
|
||||
<video ref={videoEl} muted playsInline disablePictureInPicture />
|
||||
@@ -173,12 +197,14 @@ export function VideoPreview({ matrixInfo, onUserChoicesChanged }: Props) {
|
||||
)}
|
||||
<div className={styles.previewButtons}>
|
||||
<MicButton
|
||||
muted={!audioEnabled}
|
||||
onPress={() => setAudioEnabled(!audioEnabled)}
|
||||
muted={!audioAvailableAndEnabled}
|
||||
onPress={() => setAudioEnabled(!audioAvailableAndEnabled)}
|
||||
disabled={!audioTrack}
|
||||
/>
|
||||
<VideoButton
|
||||
muted={!videoEnabled}
|
||||
onPress={() => setVideoEnabled(!videoEnabled)}
|
||||
muted={!videoAvailableAndEnabled}
|
||||
onPress={() => setVideoEnabled(!videoAvailableAndEnabled)}
|
||||
disabled={!videoTrack}
|
||||
/>
|
||||
<SettingsButton onPress={openSettings} />
|
||||
</div>
|
||||
|
||||
@@ -46,6 +46,7 @@ import {
|
||||
MediaDevices,
|
||||
MediaDevicesState,
|
||||
} from "../livekit/useMediaDevicesSwitcher";
|
||||
import { useUrlParams } from "../UrlParams";
|
||||
|
||||
interface Props {
|
||||
mediaDevicesSwitcher?: MediaDevicesState;
|
||||
@@ -59,6 +60,8 @@ interface Props {
|
||||
export const SettingsModal = (props: Props) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { isEmbedded } = useUrlParams();
|
||||
|
||||
const [showInspector, setShowInspector] = useShowInspector();
|
||||
const [optInAnalytics, setOptInAnalytics] = useOptInAnalytics();
|
||||
const [developerSettingsTab, setDeveloperSettingsTab] =
|
||||
@@ -75,7 +78,11 @@ export const SettingsModal = (props: Props) => {
|
||||
return (
|
||||
<SelectInput
|
||||
label={caption}
|
||||
selectedKey={devices.selectedId}
|
||||
selectedKey={
|
||||
devices.selectedId === "" || !devices.selectedId
|
||||
? "default"
|
||||
: devices.selectedId
|
||||
}
|
||||
onSelectionChange={(id) => devices.setSelected(id.toString())}
|
||||
>
|
||||
{devices.available.map(({ deviceId, label }, index) => (
|
||||
@@ -147,17 +154,19 @@ export const SettingsModal = (props: Props) => {
|
||||
>
|
||||
{devices && generateDeviceSelection(devices.videoIn, t("Camera"))}
|
||||
</TabItem>
|
||||
<TabItem
|
||||
key="profile"
|
||||
title={
|
||||
<>
|
||||
<UserIcon width={15} height={15} />
|
||||
<span>{t("Profile")}</span>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<ProfileSettingsTab client={props.client} />
|
||||
</TabItem>
|
||||
{!isEmbedded && (
|
||||
<TabItem
|
||||
key="profile"
|
||||
title={
|
||||
<>
|
||||
<UserIcon width={15} height={15} />
|
||||
<span>{t("Profile")}</span>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<ProfileSettingsTab client={props.client} />
|
||||
</TabItem>
|
||||
)}
|
||||
<TabItem
|
||||
key="feedback"
|
||||
title={
|
||||
|
||||
@@ -26,7 +26,7 @@ limitations under the License.
|
||||
padding: 0;
|
||||
margin: 0 auto 24px auto;
|
||||
gap: 16px;
|
||||
overflow: scroll;
|
||||
overflow-y: auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,9 @@ import styles from "./VideoTile.module.css";
|
||||
import { ReactComponent as MicIcon } from "../icons/Mic.svg";
|
||||
import { ReactComponent as MicMutedIcon } from "../icons/MicMuted.svg";
|
||||
import { useReactiveState } from "../useReactiveState";
|
||||
import { FullscreenButton } from "../button/Button";
|
||||
import { AudioButton, FullscreenButton } from "../button/Button";
|
||||
import { useModalTriggerState } from "../Modal";
|
||||
import { VideoTileSettingsModal } from "./VideoTileSettingsModal";
|
||||
|
||||
export interface ItemData {
|
||||
id: string;
|
||||
@@ -111,10 +113,14 @@ export const VideoTile = forwardRef<HTMLDivElement, Props>(
|
||||
onToggleFullscreen(data.id);
|
||||
}, [data, onToggleFullscreen]);
|
||||
|
||||
const {
|
||||
modalState: videoTileSettingsModalState,
|
||||
modalProps: videoTileSettingsModalProps,
|
||||
} = useModalTriggerState();
|
||||
const onOptionsPress = videoTileSettingsModalState.open;
|
||||
|
||||
const toolbarButtons: JSX.Element[] = [];
|
||||
if (!sfuParticipant.isLocal) {
|
||||
// TODO local volume option, which would also go here
|
||||
|
||||
if (content === TileContent.ScreenShare) {
|
||||
toolbarButtons.push(
|
||||
<FullscreenButton
|
||||
@@ -124,6 +130,16 @@ export const VideoTile = forwardRef<HTMLDivElement, Props>(
|
||||
onPress={onFullscreen}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
// Due to the LK SDK this sadly only works for user-media atm
|
||||
toolbarButtons.push(
|
||||
<AudioButton
|
||||
key="localVolume"
|
||||
className={styles.button}
|
||||
volume={(sfuParticipant as RemoteParticipant).getVolume()}
|
||||
onPress={onOptionsPress}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,6 +198,12 @@ export const VideoTile = forwardRef<HTMLDivElement, Props>(
|
||||
: Track.Source.ScreenShare
|
||||
}
|
||||
/>
|
||||
{videoTileSettingsModalState.isOpen && !maximised && (
|
||||
<VideoTileSettingsModal
|
||||
{...videoTileSettingsModalProps}
|
||||
data={data}
|
||||
/>
|
||||
)}
|
||||
</animated.div>
|
||||
);
|
||||
}
|
||||
|
||||
120
src/video-grid/VideoTileSettingsModal.module.css
Normal file
120
src/video-grid/VideoTileSettingsModal.module.css
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
Copyright 2022 - 2023 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.videoTileSettingsModal {
|
||||
width: 700px;
|
||||
height: 316px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
margin: 27px 34px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.localVolumePercentage {
|
||||
width: 3ch;
|
||||
}
|
||||
|
||||
.localVolumeSlider[type="range"] {
|
||||
-ms-appearance: none;
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
|
||||
background-color: transparent;
|
||||
--slider-color: var(--quinary-content);
|
||||
--slider-height: 4px;
|
||||
--thumb-color: var(--accent);
|
||||
--thumb-radius: 100%;
|
||||
--thumb-size: 16px;
|
||||
--thumb-margin-top: -6px;
|
||||
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.localVolumeSlider[type="range"]::-moz-range-track {
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
|
||||
background-color: var(--slider-color);
|
||||
height: var(--slider-height);
|
||||
}
|
||||
.localVolumeSlider[type="range"]::-ms-track {
|
||||
-ms-appearance: none;
|
||||
appearance: none;
|
||||
|
||||
background-color: var(--slider-color);
|
||||
height: var(--slider-height);
|
||||
}
|
||||
.localVolumeSlider[type="range"]::-webkit-slider-runnable-track {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
|
||||
background-color: var(--slider-color);
|
||||
height: var(--slider-height);
|
||||
}
|
||||
|
||||
.localVolumeSlider[type="range"]::-moz-range-thumb {
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
|
||||
height: var(--thumb-size);
|
||||
width: var(--thumb-size);
|
||||
margin-top: var(--thumb-margin-top);
|
||||
border-radius: var(--thumb-radius);
|
||||
background: var(--thumb-color);
|
||||
}
|
||||
.localVolumeSlider[type="range"]::-ms-thumb {
|
||||
-ms-appearance: none;
|
||||
appearance: none;
|
||||
|
||||
height: var(--thumb-size);
|
||||
width: var(--thumb-size);
|
||||
margin-top: var(--thumb-margin-top);
|
||||
border-radius: var(--thumb-radius);
|
||||
background: var(--thumb-color);
|
||||
}
|
||||
.localVolumeSlider[type="range"]::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
|
||||
height: var(--thumb-size);
|
||||
width: var(--thumb-size);
|
||||
margin-top: var(--thumb-margin-top);
|
||||
border-radius: var(--thumb-radius);
|
||||
background: var(--thumb-color);
|
||||
}
|
||||
|
||||
.localVolumeSlider[type="range"]::-moz-range-progress {
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
|
||||
height: var(--slider-height);
|
||||
background: var(--thumb-color);
|
||||
}
|
||||
.localVolumeSlider[type="range"]::-ms-fill-lower {
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
|
||||
height: var(--slider-height);
|
||||
background: var(--thumb-color);
|
||||
}
|
||||
85
src/video-grid/VideoTileSettingsModal.tsx
Normal file
85
src/video-grid/VideoTileSettingsModal.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
Copyright 2022 - 2023 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { ChangeEvent, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { RemoteParticipant } from "livekit-client";
|
||||
|
||||
import { FieldRow } from "../input/Input";
|
||||
import { Modal } from "../Modal";
|
||||
import styles from "./VideoTileSettingsModal.module.css";
|
||||
import { VolumeIcon } from "../button/VolumeIcon";
|
||||
import { ItemData } from "./VideoTile";
|
||||
|
||||
interface LocalVolumeProps {
|
||||
participant: RemoteParticipant;
|
||||
}
|
||||
|
||||
const LocalVolume: React.FC<LocalVolumeProps> = ({
|
||||
participant,
|
||||
}: LocalVolumeProps) => {
|
||||
const [localVolume, setLocalVolume] = useState<number>(
|
||||
participant.getVolume()
|
||||
);
|
||||
|
||||
const onLocalVolumeChanged = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
const value: number = +event.target.value;
|
||||
setLocalVolume(value);
|
||||
participant.setVolume(value);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<FieldRow>
|
||||
<VolumeIcon volume={localVolume} />
|
||||
<input
|
||||
className={styles.localVolumeSlider}
|
||||
type="range"
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.01"
|
||||
value={localVolume}
|
||||
onChange={onLocalVolumeChanged}
|
||||
/>
|
||||
</FieldRow>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
// TODO: Extend ModalProps
|
||||
interface Props {
|
||||
data: ItemData;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export const VideoTileSettingsModal = ({ data, onClose, ...rest }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className={styles.videoTileSettingsModal}
|
||||
title={t("Local volume")}
|
||||
isDismissable
|
||||
mobileFullScreen
|
||||
onClose={onClose}
|
||||
{...rest}
|
||||
>
|
||||
<div className={styles.content}>
|
||||
<LocalVolume participant={data.sfuParticipant as RemoteParticipant} />
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
@@ -23,6 +23,7 @@ import type { MatrixClient } from "matrix-js-sdk/src/client";
|
||||
import type { IWidgetApiRequest } from "matrix-widget-api";
|
||||
import { LazyEventEmitter } from "./LazyEventEmitter";
|
||||
import { getUrlParams } from "./UrlParams";
|
||||
import { Config } from "./config/Config";
|
||||
|
||||
// Subset of the actions in matrix-react-sdk
|
||||
export enum ElementWidgetActions {
|
||||
@@ -156,9 +157,35 @@ export const widget: WidgetHelpers | null = (() => {
|
||||
timelineSupport: true,
|
||||
useE2eForGroupCall: e2eEnabled,
|
||||
fallbackICEServerAllowed: allowIceFallback,
|
||||
// XXX: The client expects the list of foci in its constructor, but we don't
|
||||
// know this until we fetch the config file. However, we can't wait to construct
|
||||
// the client object or we'll miss the 'capabilities' request from the host app.
|
||||
// As of writing this, I have made the embedded widget client send the 'contentLoaded'
|
||||
// message so that we can use the widget API in less racy mode, but we need to change
|
||||
// element-web to use waitForIFrameLoad=false. Once that change has rolled out,
|
||||
// we can just start the client after we've fetched the config.
|
||||
foci: [],
|
||||
}
|
||||
);
|
||||
const clientPromise = client.startClient().then(() => client);
|
||||
|
||||
const clientPromise = new Promise<MatrixClient>((resolve) => {
|
||||
(async () => {
|
||||
// wait for the config file to be ready (we load very early on so it might not
|
||||
// be otherwise)
|
||||
await Config.init();
|
||||
const livekit = Config.get().livekit;
|
||||
const focus = livekit?.livekit_service_url;
|
||||
// Now we've fetched the config, be evil and use the getter to inject the focus
|
||||
// into the client (see above XXX).
|
||||
if (focus) {
|
||||
client.getFoci().push({
|
||||
livekitServiceUrl: livekit.livekit_service_url,
|
||||
});
|
||||
}
|
||||
await client.startClient();
|
||||
resolve(client);
|
||||
})();
|
||||
});
|
||||
|
||||
return { api, lazyActions, client: clientPromise };
|
||||
} else {
|
||||
|
||||
30
yarn.lock
30
yarn.lock
@@ -4043,9 +4043,9 @@
|
||||
integrity sha512-HzNRZtp4eepNitP+BD6k2L6DROIDG4Q0fm4x+dwfsr6LGmROENnok75VGw40628xf+iR24WeMFcHuuBDUAzzsQ==
|
||||
|
||||
"@types/node@>=13.7.0":
|
||||
version "20.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.2.1.tgz#de559d4b33be9a808fd43372ccee822c70f39704"
|
||||
integrity sha512-DqJociPbZP1lbZ5SQPk4oag6W7AyaGMO6gSfRwq3PWl4PXTwJpRQJhDq4W0kzrg3w6tJ1SwlvGZ5uKFHY13LIg==
|
||||
version "20.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.1.tgz#a6033a8718653c50ac4962977e14d0f984d9527d"
|
||||
integrity sha512-JIzsAvJeA/5iY6Y/OxZbv1lUcc8dNSE77lb2gnBH+/PJ3lFR1Ccvgwl5JWnHAkNHcRsT0TbpVOsiMKZ1F/yyJg==
|
||||
|
||||
"@types/node@^14.0.10 || ^16.0.0", "@types/node@^14.14.20 || ^16.0.0":
|
||||
version "16.11.43"
|
||||
@@ -10715,10 +10715,10 @@ lines-and-columns@^1.1.6:
|
||||
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
|
||||
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
|
||||
|
||||
livekit-client@^1.11.4:
|
||||
version "1.11.4"
|
||||
resolved "https://registry.yarnpkg.com/livekit-client/-/livekit-client-1.11.4.tgz#e222afc111f36a28a7171755cdcfe6b8fa2ca2dc"
|
||||
integrity sha512-TX53HRrtz7ZPWLasnrUOkrGN8EL22/IDwg39uLT7aJcSBWtgKlCueQkwjW4nn7KVWRF8mv00g8WiPDE9jyS8fQ==
|
||||
livekit-client@1.12.0:
|
||||
version "1.12.0"
|
||||
resolved "https://registry.yarnpkg.com/livekit-client/-/livekit-client-1.12.0.tgz#4b4f18087331d4893adaccb148e33fe870eb9a2e"
|
||||
integrity sha512-G1KHNMSaEMXtPIKxTQt+WH/uRvhkQ0tQaZ5Kkem2CvB/5I4KPrV4DSmhBKP1P+8reHcaBBiye8V9bfpD69aHyQ==
|
||||
dependencies:
|
||||
eventemitter3 "^5.0.1"
|
||||
loglevel "^1.8.0"
|
||||
@@ -10972,9 +10972,9 @@ matrix-events-sdk@0.0.1:
|
||||
resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd"
|
||||
integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA==
|
||||
|
||||
"matrix-js-sdk@github:matrix-org/matrix-js-sdk#4b3406daa95c8f969f386341b8b632ba4a60501a":
|
||||
"matrix-js-sdk@github:matrix-org/matrix-js-sdk#9ba44b96202e36d8bd6fbcff3222b7c70fc371d7":
|
||||
version "26.0.1"
|
||||
resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/4b3406daa95c8f969f386341b8b632ba4a60501a"
|
||||
resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/9ba44b96202e36d8bd6fbcff3222b7c70fc371d7"
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.5"
|
||||
"@matrix-org/matrix-sdk-crypto-js" "^0.1.0-alpha.10"
|
||||
@@ -12653,9 +12653,9 @@ property-information@^5.0.0, property-information@^5.3.0:
|
||||
xtend "^4.0.0"
|
||||
|
||||
protobufjs@^7.0.0:
|
||||
version "7.2.3"
|
||||
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.3.tgz#01af019e40d9c6133c49acbb3ff9e30f4f0f70b2"
|
||||
integrity sha512-TtpvOqwB5Gdz/PQmOjgsrGH1nHjAQVCN7JG4A6r1sXRWESL5rNMAiRcBQlCAdKxZcAbstExQePYG8xof/JVRgg==
|
||||
version "7.2.4"
|
||||
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.4.tgz#3fc1ec0cdc89dd91aef9ba6037ba07408485c3ae"
|
||||
integrity sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ==
|
||||
dependencies:
|
||||
"@protobufjs/aspromise" "^1.1.2"
|
||||
"@protobufjs/base64" "^1.1.2"
|
||||
@@ -15403,9 +15403,9 @@ webpack@4:
|
||||
webpack-sources "^3.2.3"
|
||||
|
||||
webrtc-adapter@^8.1.1:
|
||||
version "8.2.2"
|
||||
resolved "https://registry.yarnpkg.com/webrtc-adapter/-/webrtc-adapter-8.2.2.tgz#3497a7a57905b2ec0bf804278a775a348952ca16"
|
||||
integrity sha512-jQWwqiAEAFZamWliJo0Q+dIC6ZMJ8BgCFvW/oXWVFby1Nw14dOUfPwZ3lVe4nafDXdTyCUT7xfLt5xXiioXUCQ==
|
||||
version "8.2.3"
|
||||
resolved "https://registry.yarnpkg.com/webrtc-adapter/-/webrtc-adapter-8.2.3.tgz#85e5e52ea68e808be8d6db85e338aa5c95e80022"
|
||||
integrity sha512-gnmRz++suzmvxtp3ehQts6s2JtAGPuDPjA1F3a9ckNpG1kYdYuHWYpazoAnL9FS5/B21tKlhkorbdCXat0+4xQ==
|
||||
dependencies:
|
||||
sdp "^3.2.0"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user