From cad4dbc694f53db7dea94312070572dbc6e54198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sava=20Rado=C5=A1?= Date: Wed, 9 Oct 2019 15:24:22 +0000 Subject: [PATCH 01/77] Added translation using Weblate (Serbian (latin)) --- vector/src/main/res/values-b+sr+Latn/strings.xml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 vector/src/main/res/values-b+sr+Latn/strings.xml diff --git a/vector/src/main/res/values-b+sr+Latn/strings.xml b/vector/src/main/res/values-b+sr+Latn/strings.xml new file mode 100644 index 0000000000..a6b3daec93 --- /dev/null +++ b/vector/src/main/res/values-b+sr+Latn/strings.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file From 1420f43fdcbc9ba8d93d8e75675a825b2f2cdd45 Mon Sep 17 00:00:00 2001 From: Valere Date: Wed, 9 Oct 2019 19:38:07 +0200 Subject: [PATCH 02/77] version ++ --- CHANGES.rst | 25 +++++++++++++++++++++++++ build.gradle | 4 ++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index e82f433b49..cf7977cf35 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,28 @@ +Changes in Riot 0.9.9 (2019-XX-XX) +=================================================== + +MatrixSdk 🚀: + - Upgrade to version 0.X.Y. + +Features ✨: + - + +Improvementss 🙌: + - + +Other changes: + - + +Bugfix 🐛: + - + +Translations 🗣: + - + +Build 🧱: + - + + Changes in Riot 0.9.8 (2019-10-09) =================================================== diff --git a/build.gradle b/build.gradle index 2b84392915..b5f5ff08e1 100755 --- a/build.gradle +++ b/build.gradle @@ -23,8 +23,8 @@ buildscript { // global properties used in sub modules ext { - versionCodeProp = 90800 - versionNameProp = "0.9.8" + versionCodeProp = 90900 + versionNameProp = "0.9.9-dev" versionBuild = System.getenv("BUILD_NUMBER") as Integer ?: 0 buildNumberProp = "${versionBuild}" } From 395cc5ff00733fc47529e604f715e2b37c0050c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sava=20Rado=C5=A1?= Date: Wed, 9 Oct 2019 22:22:25 +0000 Subject: [PATCH 03/77] Translated using Weblate (Serbian) Currently translated at 7.9% (95 of 1208 strings) Translation: Riot Android/Riot Android Translate-URL: https://translate.riot.im/projects/riot-android/riot-android/sr/ --- vector/src/main/res/values-sr/strings.xml | 110 +++++++++++++++++++++- 1 file changed, 108 insertions(+), 2 deletions(-) diff --git a/vector/src/main/res/values-sr/strings.xml b/vector/src/main/res/values-sr/strings.xml index a6b3daec93..5d5fb3e9f2 100644 --- a/vector/src/main/res/values-sr/strings.xml +++ b/vector/src/main/res/values-sr/strings.xml @@ -1,2 +1,108 @@ - - \ No newline at end of file + +Светла тема + Тамна тема + Црна тема + Status.im тема + + Иницијализација сервиса + Синхронизација у току… + Бучна обавештења + Тиха обавештења + + Поруке + Соба + Подешавања + Подаци о члану + Историјски + Пријава грешке + Пошаљи налепницу + Резервна копија кључева + Користи резервну копију кључева + Верификуј уређај + + Креирање резервне копије кључева се није завршило, молим сачекајте… + Изгубићете ваше шифроване поруке ако се сад одјавите + Креирање резервне копије кључева је у току. Ако се одјавите сад, изгубићете приступ вашим шифрованим порукама. + Сигурносна копија кључева би требало да буде активна на свим вашим уређајима како би избегли губитак приступа вашим шифрованим порукама. + Не желим моје шифроване поруке + Прављење резервне копије кључева у току… + Користи резервну копију кључева + Да ли сте сигурни\? + Изгубићете приступ вашим шифрованим порукама уколико не направите резервну копију кључева пре него што се одјавите. + + Учитавање… + + У реду + Откажи + Сачувај + Напусти + Остани + Пошаљи + Копирај + Пошаљи поново + Уклони + Подели + Прихвати + Прескочи + Готово + Обустави + Игнориши + Прегледај + Одбаци + + Изађи + Акције + Одјави се + Да ли сте сигурни да желите да се одјавите\? + Гласовни позив + Видео позив + Глобална претрага + Означи све као прочитано + Брзи одговор + Означи као прочитано + Отвори + Затвори + Онемогући + + Потврда + Упозорење + Грешка + + Омиљено + Људи + Собе + Позивнице + Низак приоритет + Разговори + Локални адресар + Листа корисника + Само Matrix контакти + Нема резултата + Нема подешених сервера идентитета. + + Собе + Листа соба + Нема соба + Пошаљи позивницу + Опишите ваш проблем овде + Прочитај + + Придружи се соби + Корисничко име + Направи налог + Пријави се + Одјави се + Пошаљи налепницу + Направи фотографију или видео снимак + Направи фотографију + Направи видео снимак + + Пријави се + Пријави се помоћу single sign-on + Направи налог + Прескочи + Адреса електронске поште или корисничко име + Лозинка + Нова лозинка + Корисничко име + From e9622b3139cfea4de0149befeba2ed06aea54e82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sava=20Rado=C5=A1?= Date: Wed, 9 Oct 2019 15:24:51 +0000 Subject: [PATCH 04/77] Translated using Weblate (Serbian (latin)) Currently translated at 9.8% (118 of 1208 strings) Translation: Riot Android/Riot Android Translate-URL: https://translate.riot.im/projects/riot-android/riot-android/sr_Latn/ --- .../src/main/res/values-b+sr+Latn/strings.xml | 136 +++++++++++++++++- 1 file changed, 134 insertions(+), 2 deletions(-) diff --git a/vector/src/main/res/values-b+sr+Latn/strings.xml b/vector/src/main/res/values-b+sr+Latn/strings.xml index a6b3daec93..fddc801282 100644 --- a/vector/src/main/res/values-b+sr+Latn/strings.xml +++ b/vector/src/main/res/values-b+sr+Latn/strings.xml @@ -1,2 +1,134 @@ - - \ No newline at end of file + +en + US + + Svetla Tema + Tamna Tema + Crna Tema + Status.im Tema + + Inicijalizacija servisa + Sinhronizacija u toku… + Bučna obaveštenja + Tiha obaveštenja + + Poruke + Soba + Podešavanja + Podaci o članu + Istorijski + Prijava bug-a + Pošalji nalepnicu + Rezervna kopija ključeva + Koristi rezervnu kopiju ključeva + Verifikuj uređaj + + Kreiranje rezervne kopije ključeva se nije završilo, molim sačekajte… + Izgubićete vaše šifrovane poruke ukoliko se sada odjavite + Kreiranje rezervne kopije ključeva je u toku. Ako se odjavite sada, izgubićete pristup vašim šifrovanim porukama. + Sigurnosna kopija ključeva bi trebalo da bude aktivna na svim vašim uređajima kako bi izbegli gubitak pristupa vašim šifrovanim porukama. + Ne želim moje šifrovane poruke + Pravljenje rezervne kopije ključeva u toku… + Koristi rezervnu kopiju ključeva + Da li ste sigurni\? + Izgubićete pristup vašim šifrovanim porukama ukoliko ne napravite rezervu kopiju ključeva pre nego što se odjavite. + + Učitavanje… + + U redu + Otkaži + Sačuvaj + Napusti + Ostani + Pošalji + Kopiraj + Pošalji ponovo + Ukloni + Podeli + Kasnije + Prosledi + Obriši + Preimenuj + Konferencijski poziv u toku. +\nPriključi se kao %1$s ili %2$s + Glas + Video + Nemoguća uspostava poziva, molim probajte kasnije + Neke opcije mogu nedostajati usled manjka dozvola… + Ova akcija nije moguća zbog nedosatka dozvola. + Treba vam dozvola da pozovete kako bi započeli konferencijski poziv u ovoj sobi + Nemoguća uspostava poziva + Informacije o uređaju + Konferencijski pozivi nisu podržani u šifrovanim sobama + Ipak zovi + Ipak pošalji + ili + Pošalji pozivnicu + Prihvati + Preskoči + Gotovo + Obustavi + Ignoriši + Pregledaj + Odbaci + + Izađi + Akcije + Odjavi se + Da li ste sigurni da želite da se odjavite\? + Glasovni poziv + Video poziv + Globalna pretraga + Označi sve kao pročitano + Brzi odgovor + Označi kao pročitano + Otvori + Zatvori + Onemogući + + Potvrda + Upozorenje + Greška + + Ljudi + Sobe + Pozivnice + Nizak prioritet + Lokalni adresar + Lista korisnika + Samo Matrix kontakti + Sobe + Lista soba + Nema soba + Nema javnih soba + Nema grupa + + Ako je moguće, molim opišite na engleskom. + Opišite vaš problem ovde + Korisničko ime + Napravi nalog + Prijavi se + Odjavi se + Započni novo ćaskanje + Započni glasovni poziv + Započni video poziv + + Ne pitaj ponovo + + Pošalji nalepnicu + Napravi fotografiju ili video snimak + Napravi fotografiju + Napravi video snimak + + Prijavi se + Napravi nalog + Preskoči + Lozinka + Nova lozinka + Korisničko ime + Broj telefona + Broj telefona (opciono) + Ponovi lozinku + Potvrdite vašu novu lozinku + Pogrešno korisničko ime i/ili lozinka + From e6aa25b764d9e25f6c0ed742621bc3de7f46b476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=86=A1=ED=83=9C=EC=84=AD?= Date: Fri, 11 Oct 2019 09:57:00 +0000 Subject: [PATCH 05/77] Translated using Weblate (Korean) Currently translated at 100.0% (1208 of 1208 strings) Translation: Riot Android/Riot Android Translate-URL: https://translate.riot.im/projects/riot-android/riot-android/ko/ --- vector/src/main/res/values-ko/strings.xml | 26 +++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/vector/src/main/res/values-ko/strings.xml b/vector/src/main/res/values-ko/strings.xml index 523bc83d14..2e574e4015 100644 --- a/vector/src/main/res/values-ko/strings.xml +++ b/vector/src/main/res/values-ko/strings.xml @@ -19,7 +19,7 @@ 불러오는 중… - + 취소 저장 떠나기 @@ -235,7 +235,7 @@ 전화번호가 누락되었습니다 이메일 주소나 전화번호가 누락되었습니다 옳지 않은 토큰 - 맞춤 서버 옵션을 사용하기 (고급) + 맞춤 서버 설정을 사용하기 (고급) 등록을 계속하려면 이메일을 확인하세요 API가 존재하기 전까지는 이메일과 전화번호로 한 번에 등록할 수 없습니다. 오직 전화번호만 고려됩니다. \n @@ -336,7 +336,7 @@ 음성 통화를 하려면 Riot은 마이크에 접근하는 권한이 필요합니다. " \n -\n전화를 하려면 다은 팝업에서 접근을 허용해주세요." +\n전화를 하려면 다음 팝업에서 접근을 허용해주세요." 영상 통화를 하려면 Riot은 카메라와 마이크에 접근하는 권한이 필요합니다. \n \n전화를 하려면 다음 팝업에서 접근을 허용해주세요. @@ -545,7 +545,7 @@ 버전 버전 %s 이용 약관 - 제 3자 공지 + 제 3자 고지 저작권 개인 정보 정책 @@ -661,7 +661,7 @@ 알림 소리 이 계정에서 알림 켜기 이 기기에서 알림 켜기 - 3초 동안 화면을 켬 + 3초 동안 화면을 켜기 소리 알림 설정 전화 알림 설정 조용한 알림 설정 @@ -687,7 +687,7 @@ 버전 olm 버전 이용 약관 - 제 3자 공지 + 제 3자 고지 저작권 개인 정보 정책 미디어 유지 @@ -734,7 +734,7 @@ 알림 개인 정보 Riot은 백그라운드에서 실행되어 알림을 안전하고 은밀하게 관리할 수 있습니다. 이것은 배터리 사용량에 영향을 줄 수 있습니다. 권한 부여 - 다른 옵션을 선택하세요 + 다른 설정을 선택하세요 백그라운드 연결 Riot은 신뢰가 있는 알림을 위해 낮은 영향의 백그라운드 연결을 유지해야 합니다. @@ -845,7 +845,7 @@ 누가 이 방에 접근할 수 있나요\? 누구나 - (이 옵션을 선택한 시점부터) 구성원만 + (이 설정을 선택한 시점부터) 구성원만 (초대받은 시점부터) 구성원만 (참가한 시점부터) 구성원만 @@ -931,7 +931,7 @@ 로컬 파일에서 키 가져오기 가져오기 확인된 기기로만 암호화 - 이 기기에서 확인되지 않은 기기로 절대 암호화된 메시지를 보내지 않기. + 이 기기에서 확인되지 않은 기기로 절대 암호화된 메시지를 보내지 않습니다. %1$d/%2$d 키를 성공적으로 가져왔습니다. 확인되지 않음 @@ -1036,7 +1036,7 @@ 맞춤 카메라 화면 대신 시스템 카메라를 실행합니다. 키보드 엔터 키로 메시지 보내기 음성 메시지 보내기 - 이 옵션은 메시지를 기록하기 위한 제 3자 애플리케이션이 필요합니다. + 이 설정은 메시지를 기록하기 위한 제 3자 애플리케이션이 필요합니다. 새 기기 \'%s\'을(를) 추가했습니다, 여기에는 암호화 키가 필요합니다. 새 기기에는 암호화 키가 필요합니다. @@ -1453,7 +1453,7 @@ 파일 \"%1$s\"에서 종단간 암호화 키 가져옴. Matrix SDK 버전 - 다른 제 3자 공지 + 다른 제 3자 고지 이 방을 이미 봤습니다! 빠른 리액션 @@ -1574,7 +1574,7 @@ 계정 복구 용 이메일을 설정합니다. 이메일이나 전화로 이후 알고 있는 사람들이 당신을 찾을 수 있는지 여부를 선택하는데 사용됩니다. 이 URL로는 홈서버에 접근할 수 없습니다, 확인해주세요 대체 전화 지원 서버 허용 - 홈서버가 전화를 지원하지 않는다면 %s을(를) 지원 서버롤 사용합니다 (전화하는 동안 IP 주소가 공유될 것입니다) + 홈서버가 전화를 지원하지 않는다면 %s을(를) 지원 서버로 사용합니다 (전화하는 동안 IP 주소가 공유됩니다) 이 작업을 하려면 설정에서 ID 서버를 추가하세요. 백그라운드 동기화 모드 (실험적) 배터리에 최적화됨 @@ -1592,7 +1592,7 @@ %s \n동기화는 자원 (배터리)이나 기기의 상태 (수면)에 따라 지연됩니다. 탐색 - 탐색 설정 관리하기. + 탐색 설정을 관리합니다. 공개 이름 (대화하는 사람들에게 보여집니다) 기기의 공개 이름은 대화하는 사람들에게 보여집니다 ID 서버를 사용하고 있지 않습니다 From 570c7173b5eff0ae4afe653593631cb5181ffd48 Mon Sep 17 00:00:00 2001 From: Osoitz Date: Sun, 13 Oct 2019 14:09:04 +0000 Subject: [PATCH 06/77] Translated using Weblate (Basque) Currently translated at 100.0% (1208 of 1208 strings) Translation: Riot Android/Riot Android Translate-URL: https://translate.riot.im/projects/riot-android/riot-android/eu/ --- vector/src/main/res/values-eu/strings.xml | 103 ++++++++++++++++++++-- 1 file changed, 94 insertions(+), 9 deletions(-) diff --git a/vector/src/main/res/values-eu/strings.xml b/vector/src/main/res/values-eu/strings.xml index 598b8907cc..e76f3b826c 100644 --- a/vector/src/main/res/values-eu/strings.xml +++ b/vector/src/main/res/values-eu/strings.xml @@ -414,7 +414,7 @@ Kontuan izan ekintza honek aplikazioa berrabiaraziko duela eta denbora bat behar Bigarren planoko sinkronizazioa Gaitu bigarren planoko sinkronizazioa Sinkronizazio eskaerak debora-muga gainditu du - Eskaeren arteko itxaronaldia + Sinkronizazioen arteko itxaronaldia segundo segundo @@ -441,10 +441,10 @@ Kontuan izan ekintza honek aplikazioa berrabiaraziko duela eta denbora bat behar Finkatu irakurri gabeko mezuak dituzten gelak Gailuak Erakutsi mezu guztien denbora-zigilua - Gailuaren xehetasunak + Gailuaren informazioa ID - Izena - Gailuaren izena + Izen publikoa + Aldatu izen publikoa Azkenekoz ikusia %1$s @ %2$s Eragiketa honek autentifikazio gehigarria behar du. @@ -574,9 +574,9 @@ Kontuan izan ekintza honek aplikazioa berrabiaraziko duela eta denbora bat behar Deszifratze errorea Igorlearen gailuaren informazioa - Gailuaren izena - Izena - Gailuaren IDa + Izen publikoa + Izen publikoa + IDa Gailuaren gakoa Egiaztaketa Ed25519 hatz-marka @@ -870,7 +870,7 @@ Baten bat gehitu orain? Desaktibatu kontua %1$s hasiera-zerbitzaria erabiltzen jarraitzeko erabilera baldintzak irakurri eta onartu behar dituzu. - Irakurri orain + Berrikusi orain Desaktibatu kontua Honek kontua behin betirako erabilgaitza bihurtuko du. Ezin izango duzu saioa hasi, eta ezin izango du beste inork ID hori erabili. Kontua dagoen gela guztietatik aterako da, eta kontuaren xehetasunak identitate-zerbitzaritik ezabatuko dira. Ekintza hau ezin da desegin. @@ -1048,7 +1048,7 @@ Kontuan izan ekintza honek aplikazioa berrabiaraziko duela eta denbora bat behar Onartu - Berrikusi eta onartu hasiera-zerbitzari honen politikak: + Irakurri eta onartu hasiera-zerbitzari honen baldintzak: %1$d/%2$d gako ongi inportatu dira. @@ -1612,4 +1612,89 @@ Abisua: Fitxategi hau ezabatu daiteke aplikazioa desinstalatzen bada. Ikusi edizioen historiala +Bat ere ez + Indargabetu + Deskonektatu + Berrikusi + Ukatu + + Ez da identitate-zerbitzaririk konfiguratu. + + Deiak huts egin du zerbitzaria gaizki konfiguratuta dagoelako + Eskatu zure hasiera-zerbitzariko administratzaileari (%1$s) TURN zerbitzari bat konfiguratu dezala deiak ondo funtzionatu dezaten. +\n +\nBestela, %2$s zerbitzari publikoa erabili dezakezu, baina hau ez da hain fidagarria izango, eta zure IP-a partekatuko du zerbitzari horrekin. Hau ezarpenetan aldatu dezakezu. + Saiatu %s erabiltzen + Ez galdetu berriro + + Ezarri E-mail bat kontua berreskuratzeko, eta gero aukeran zure ezagunek aurkitu zaitzaten. + Ezarri telefono bat gero aukeran zure ezagunek aurkitu zaitzaten. + Ezarri E-mail bat kontua berreskuratzeko. Erabili geroo aukeran e-maila edo telefonoa zure ezagunek aurkitu zaitzaten. + Ezarri E-mail bat kontua berreskuratzeko. Erabili geroo aukeran e-maila edo telefonoa zure ezagunek aurkitu zaitzaten. + Ezin izan da hasiera-zerbitzari bat atzitu URL honetan, egiaztatu ezazu + Baimendu lehenetsitako deien laguntzarako zerbitzaria + %s erabiliko da laguntzarako zure hasiera-zerbitzariak ez badu bat eskaintzen (Zure IP helbidea deian partekatuko da) + Gehitu identitate-zerbitzari bat zure ezarpenetan ekintza hau burutzeko. + Bigarren planoko sinkronizazio modua (Esperimentala) + Bateria erabilerarako optimizatua + Riot bigarren planoan sinkronizatuko da gailuaren baliabide mugatuen erabilera ahal beste murriztuz (bateria). +\nZure gailuaren baliabideen egoeraren arabera, sistema eragileak sinkronizazioa atzeratu dezake. + Denbora errealerako optimizatua + Riot bigarren planoan sinkronizatuko da maiztasun finkoarekin (konfiguragarria). +\nHonek irrati eta bateriaren erabileran eragina izango du, eta Riot gertaerei adi dagoela dion jakinarazpen bat bistaratuko da etengabe. + Ez sinkronizatu bigarren planoan + Ez zaizu jasotako mezuei buruz jakinaraziko aplikazioa bigarren planoan dagoenean. + Huts egin du ezarpenak eguneratzean. + + + Hobetsitako sinkronizazio tartea + %s +\nSinkronizazioa atzeratu daiteke zure baliabideen arabera (bateria) edo gailuaren egoeraren arabera (lo). + Aurkitzea + Kudeatu aurkitzeko ezarpenak. + Izen publikoa (Zurekin komunikatzen den jendeak ikusi dezake) + Gailu baten izen publikoa zurekin komunikatzen den jendeak ikusi dezake + Jarraitzeko erabilera baldintzak onartu behar dituzu. + + Ez duzu identitate zerbitzaririk erabiltzen + Ez da identitate zerbitzaririk konfiguratu, zure pasahitza berrezartzeko beharrezkoa da. + + Riot bertsio zaharrek segurtasun akats bat zuten eta zure identitate zerbitzariak (%1$s) zure kontua atzitu zezakeen. %2$s fidagarritzat jotzen baduzu hau ezikusi dezakezu, bestela maiatu saioa eta hasi berriro. +\n +\nXehetasun gehiago hemen: +\nhttps://medium.com/@RiotChat/36b4792ea0d6 + + Badirudi beste hasiera-zerbitzari batera konektatzen saiatzen ari zarela. Saioa amaitu nahi duzu\? + + Erabilera baldintzak + Irakurri baldintzak + Izan besteentzat aurkigarria + Erabili botak, zubiak, trepetak eta eranskailu multzoak + + Irakurri hemen + + + Identitate-zerbitzaria + Deskonektatu identitate-zerbitzaria + Konfiguratu identitate-zerbitzaria + Aldatu identitate-zerbitzaria + Orain %1$s erabiltzen ari zara ezagunak aurkitzeko eta ezagunek zu aurkitzeko. + Orain ez duzu identitate-zerbitzaririk erabiltzen. Kontaktuak aurkitzeko eta aurkigarria izateko, gehitu bat azpian. + E-mail helbide aurkigarria + Aurkitze aukerak behin e-mail bat gehitu duzunean agertuko dira. + Aurkitze aukerak behin telefono zenbaki bat gehitu duzunean agertuko dira. + Identitate-zerbitzaritik deskonektatzean beste erabiltzaileek ezin izango zaituzte e-mail edo telefonoa erabilita aurkitu, eta zuk ezin izango dituzu e-mail edo telefonoa erabilita aurkitu. + Telefono zenbaki aurkigarriak + Berrespen e-mail bat bidali dizugu %s helbidera, begiratu zure e-maila eta sakatu baieztapen esteka + Egiteke + + Sartu identitate-zerbitzari berria + Ezin izan da identitate-zerbitzarira konektatu + Sartu identitate-zerbitzariaren URL-a + Identitate-zerbitzariak ez du erabilera baldintzarik + Hautatu duzun identitate-zerbitzariak ez du erabilera baldintzarik. Jarraitu soilik zerbitzuaren jabea fidagarritzat jotzen baduzu + SMS mezu bat bidali zaizu %s zenbakira. Sartu hemen mezu horrek daukan egiaztatze-kodea. + + Orain e-mail helbideak edo telefono zenbakiak partekatzen dituzu %s zerbitzarian. %s zerbitzarira konektatu beharko zara partekatzeari uzteko. + Onartu %s identitate-zerbitzariaren erabilera baldintzak besteek zu e-mail helbidea edo telefonoa erabiliz aurkitzea ahalbidetzeko. From c290c87dc5d769853c03b030e491ca2dfcf4655a Mon Sep 17 00:00:00 2001 From: Walter Date: Mon, 14 Oct 2019 12:35:44 +0000 Subject: [PATCH 07/77] Translated using Weblate (Russian) Currently translated at 96.1% (1161 of 1208 strings) Translation: Riot Android/Riot Android Translate-URL: https://translate.riot.im/projects/riot-android/riot-android/ru/ --- vector/src/main/res/values-ru/strings.xml | 66 ++++++++++++++++------- 1 file changed, 46 insertions(+), 20 deletions(-) diff --git a/vector/src/main/res/values-ru/strings.xml b/vector/src/main/res/values-ru/strings.xml index 00ef36dc34..385e51bf6f 100644 --- a/vector/src/main/res/values-ru/strings.xml +++ b/vector/src/main/res/values-ru/strings.xml @@ -96,7 +96,7 @@ %d пользователь %d пользователя %d пользователей - + Отправить логи @@ -611,7 +611,7 @@ Ошибка дешифровки Информация об устройстве отправителя - Имя устройства + Публичное имя Имя ID устройства Ключ устройства @@ -843,13 +843,13 @@ %d комната %d комнаты %d комнат - + %d комната %d комнаты %d комнат - + %1$s в %2$s @@ -857,7 +857,7 @@ %d активный виджет %d активных виджета %d активных виджетов - + @@ -867,45 +867,45 @@ %d активный участник %d активных участника %d активных участников - + %d участник %d участника %d участников - + %d новое сообщение %d новых сообщения %d новых сообщений - + %1$s комната найдена для %2$s %1$s комнаты найдено для %2$s %1$s комнат найдено для %2$s - + %d изменение членства %d изменения членства %d изменений членства - + %d непрочитанное уведомление %d непрочитанных уведомления %d непрочитанных уведомлений - + %d непрочитанное уведомление %d непрочитанных уведомления %d непрочитанных уведомлений - + Получить аватар Заметка аватара @@ -1020,13 +1020,13 @@ %dm %dm %dm - + %dh %dh %dh - + %d день @@ -1045,20 +1045,20 @@ %d выбран %d выбрано %d выбраны - + %d участник %d участника %d участников - + %d комната %d комнаты %d комнат - + Системные оповещения @@ -1346,7 +1346,7 @@ %d новый ключ был добавлен к этому устройству. %d новых ключа были добавлены к этому устройству. %d новых ключей были добавлены к этому устройству. - + @@ -1398,7 +1398,7 @@ Резервное копирование %d ключа… Резервное копирование %d ключей… Резервное копирование %d ключей… - + Все ключи сохранены @@ -1725,4 +1725,30 @@ Читать в - +Никто + Отмена + Отключить + Сервер идентификации не настроен. + + Звонок не состоялся из-за неправильно настроенного сервера + Попросите администратора вашего домашнего сервера (%1$s) настроить TURN сервер, чтобы звонки работали надежно. +\n +\nКроме того, вы можете попробовать использовать публичный сервер по %2$s, но это будет не так надежно, и он предоставит ваш IP-адрес этому серверу. Вы также можете управлять этим в настройках. + Попробуйте использовать %s + Не спрашивай меня больше + + Установите адрес электронной почты для восстановления учетной записи, и позже она может будет найдена участниками, которые вас знают. + Установите телефон, и позже его могут опционально обнаруживать люди, которые вас знают. + Установите адрес электронной почты для восстановления аккаунта. Позже используйте электронную почту или телефон, чтобы их могли найти люди, которые вас знают. + Установите адрес электронной почты для восстановления аккаунта. Позже используйте электронную почту или телефон, чтобы их могли найти люди, которые вас знают. + Не удается связаться с домашним сервером по этому URL, пожалуйста, проверьте его + Разрешить резервный сервер помощи при вызове + Оптимизирован для батареи + Оптимизирован для работы в реальном времени + Без фоновой синхронизации + Не удалось обновить настройки. + + + Предпочтительный интервал синхронизации + Обнаружение + From d61b869e98f292563c1036504e7c00378849ba64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sava=20Rado=C5=A1?= Date: Sun, 13 Oct 2019 18:55:00 +0000 Subject: [PATCH 08/77] Translated using Weblate (Serbian (latin)) Currently translated at 28.7% (347 of 1208 strings) Translation: Riot Android/Riot Android Translate-URL: https://translate.riot.im/projects/riot-android/riot-android/sr_Latn/ --- .../src/main/res/values-b+sr+Latn/strings.xml | 269 ++++++++++++++++++ 1 file changed, 269 insertions(+) diff --git a/vector/src/main/res/values-b+sr+Latn/strings.xml b/vector/src/main/res/values-b+sr+Latn/strings.xml index fddc801282..ea3532296b 100644 --- a/vector/src/main/res/values-b+sr+Latn/strings.xml +++ b/vector/src/main/res/values-b+sr+Latn/strings.xml @@ -131,4 +131,273 @@ Ponovi lozinku Potvrdite vašu novu lozinku Pogrešno korisničko ime i/ili lozinka + Obriši + Vidi izvor + Prijavi sadržaj + Napredak (%s%%) + + Pošalji u + Priključi se sobi + Pretraži + + Pošalji datoteke + Adresa elektronske pošte + Adresa elektronske pošte (opciono) + Lozinka je prekratka (minimum 6) + Lozinka nedostaje + Ovo ne izgleda kao validna adresa elektronske pošte + Ovo ne izgleda kao validan broj telefona + Ova adresa elektronske pošte je već definisana. + Adresa elektronske pošte nedostaje + Broj telefona nedostaje + Nedostaje adresa elektronske pošte ili broj telefona + Lozinke nisu iste + Zaboravili ste lozinku\? + Koristi prilagođene opcije servera (napredno) + Molim proverite vašu elektronsku poštu kako bi nastavili registraciju + Korisničko ime je već u upotrebi + Verifikovao sam adresu elektronske pošte + Kako bi resetovali vašu lozinku, unesite adresu elektronske pošte povezanu sa vašim nalogom: + Morate uneti adresu elektronske pošte povezane sa vašim nalogom. + Morate uneti novu lozinku. + Mobilni + + Poslato je previše zahteva + Ovo korisničko ime je već korišćeno + Link u elektronskoj pošti još uvek nije kliknut + + Zahtev za ključ poslat. + + Zahtev poslat + Pošalji kao + Original + Veliko + Srednje + Malo + + Juče + Danas + + Ime sobe + Tema sobe + + Pozivi + Koristi podrazumevani Riot zvuk zvona za dolazeće pozive + Zvuk zvona dolazećeg poziva + Izaberite zvuk zvona za pozive: + + Poziv + Poziv uspostavljen + Poziv se uspostavlja… + Poziv završen + Pozivam… + Dolazeći poziv + Dolazeći video poziv + Dolazeći glasovni poziv + Poziv u toku… + Video poziv u toku.. + + Izbaci iz ove sobe + Izbaci + Pomeni + Servis Obaveštenja + Servis obaveštenja radi. + Servis obaveštenja ne radi. +\nPokušajte da ponovo pokrenete aplikaciju. + Pokreni servis + + Servis obaveštenja, automatsko ponovno pokretanje + Servis je eliminisan i pokrenut ponovo automatski. + Servis nije uspeo da se ponovo pokrene + + Servis će se početi sa radom prilikom ponovnog pokretanja uređaja. + Optimizacija potrošnje baterije + Optimizacija potrošnje baterije ne utiče na Riot. + Ignoriši optimizacije + + Normalno + Smanjena privatnost + Aplikaciji treba dozvola za rad u pozadini + • Obaveštenja sadrže samo meta podatke + • Obaveštenja sadrže meta podatke i poruku + "• Obaveštenja "neće prikazivati sadržaj poruke + + Zvuk obaveštenja + Omogući obaveštenja za ovaj nalog + Omogući obaveštenja za ovaj uređaj + Upali ekran na 3 sekunde + Podesi bučna obaveštenja + Podesi obaveštenja o pozivima + Podesi tiha obaveštenja + Izabeti LED boju, vibraciju, zvuk… + + + Kada sam pozvan u sobu + Poruke koje je poslao bot + + Sinhronizacija u pozadini + Optimizovano za potrošnju baterije + Bez sinhronizacije u pozadini + sekundu + sekundi + + Verzija + olm verzija + Drugo + Napredno + Kriptografija + Rukovanje kriptografskim ključevima + Učitaj kontakte + Dozvola za kontakte + Zemlja telefonskog imenika + Glavni prikaz + Uređaji + Šalji obaveštenja o pisanju + Dozvoli da drugi korisnici znaju da pisete. + Prikaži obaveštenja o pročitanim porukama + Klikni na obaveštenja o pročitanim porukama za detaljan prikaz. + Pokaži obaveštenja o priključivanjima i napuštanjima + Ne odnosi se na pozivnice, izbacivanja i zabrane. + Prikaži obaveštenja o nalogu + Uključuje obaveštenja o promeni avatara i imena. + Vibriraj kad neko pomene korisnika + Pošalji poruku pritiskom na enter + Dugme enter na softverskoj tastaturi će poslati poruku umesto da napravi novu liniju + + Deaktiviraj nalog + Deaktiviraj moj nalog + Pronalaženje + Upravljajte vašim podešavanjima za pronalaženje. + Privatnost obaveštenja + Riot može da radi u pozadini kako bi upravljao vašim obaveštenjima sigurno i privatno. Ovo može da utiče na potrošnju baterije. + Dozvoli + Izaberi drugu opciju + + Pozadinska veza + Da, želim da pomognem! + + Režim uštede podataka + Režim uštede podataka primenjuje poseban filter tako da se obaveštenja o prisutnosti i pisanju filtriraju. + + Podaci o uređaju + ID + Javno ime + Promeni javno ime + Poslednji put viđen + Ova operacija zahteva dodatnu autentifikaciju. +\nMolim unesite vašu lozinku, kako bi nastavili. + Autentifikacija + Lozinka: + Pošalji + + Prijavljen kao + Jezik + Izaberi jezik + + Čeka se verifikacija + Molim proverite vašu elektronsku poštu i kliknite na link u njoj. Kad ovo uradite, kliknite na nastavi. + Lozinka + Promeni lozinku + Trenutna lozinka + Nova lozinka + Potvrdite novu lozinku + Promeni lozinku + Promena lozinke nije uspela + Lozinka nije tačna + Vaša lozinka je promenjena + Izaberi zemlju + + Zemlja + Molim izaberite zemlju + Broj telefona + Pogrešan broj telefona za izabranu zemlju + Verifikacija putem telefona + Poslali smo vam SMS sa aktivacionim kodom. Molimo unesite ovaj kod ispod. + Unesi aktivacioni kod + Desila se greška prilikom validacije vašeg broja telefona + Kod + Desila se greška prilikom verifikacije vašeg broja telefona. + Dodatne informacije: %s + + Izaberi + Izaberi + 3 dana + 1 nedelja + 1 mesec + Zauvek + + Omiljeno + Nizak prioritet + Ništa + + Pristup sobi + Ko može čitati istoriju\? + Ko može pristupiti ovoj sobi\? + + BIlo ko + Samo članovi (od trenutka kad je ova opcija izabrana) + Samo članovi (od trenutka kad su pozvani) + Samo članovi (od trenutka kad su se pridružili) + + Samo ljudi koji su pozvani + Bilo ko, ko zna link sobe, sem gostiju + Bilo ko, ko zna link sobe, uključujući goste + + Izbačeni korisnici + + Napredno + Interni ID ove sobe + Adrese + Laboratorije + Ovo su eksperimentalne karakteristike koje se mogu pokvariti na neočekivane načine. Koristiti sa pažnjom. + Nova adresa (npr. #foo:matrix.org) + + Algoritam + ID sesije + Greška prilikom dešifrovanja + + Informacije o uređaju pošiljaoca + Javno ime + Verifikacija + Uvezi ključeve za sobu + Uvezi ključeve iz datoteke + Uvezi + Šifruj samo ka verifikovanim uređajima + Nikad ne šalji šifrovane poruke ka neverifikovanim uređajima sa ovog uređaja. + Verifikovan + Na crnoj listi + + nepoznat uređaj + nepoznata IP adresa + ništa + + Verifikuj + Ukloni verifikaciju + Stavi na crnu listu + Ukloni sa crne liste + + Verifikuj uređaj + Soba sadrži nepoznate uređaje + Soba + Nove poruke + Nova pozivnica + Ja + Veličina fonta + Najmanji + Mali + Normalni + Veliki + Veći + Najveći + Ogroman + + Slanje zahteva nije uspelo. + Niste u ovoj sobi. + Nemate dozvolu da uradite to u ovoj sobi. + Nedostajući room_id u zahtevu. + Nedostajući user_id u zahtevu. + Soba %s nije vidljiva. + Nedostaje parametar koji je obavezan. + Parametar nije ispravan. + Šalji glasovne poruke From df191b78f0dd852388e41e566025f81858666660 Mon Sep 17 00:00:00 2001 From: Besnik Bleta Date: Sat, 19 Oct 2019 08:44:41 +0000 Subject: [PATCH 09/77] Translated using Weblate (Albanian) Currently translated at 99.4% (1201 of 1208 strings) Translation: Riot Android/Riot Android Translate-URL: https://translate.riot.im/projects/riot-android/riot-android/sq/ --- vector/src/main/res/values-sq/strings.xml | 81 +++++++++++++++++++++-- 1 file changed, 74 insertions(+), 7 deletions(-) diff --git a/vector/src/main/res/values-sq/strings.xml b/vector/src/main/res/values-sq/strings.xml index 8e439a41fe..7d7faa061e 100644 --- a/vector/src/main/res/values-sq/strings.xml +++ b/vector/src/main/res/values-sq/strings.xml @@ -408,7 +408,7 @@ Njëkohësim në prapaskenë Aktivizo njëkohësim në prapaskenë Mbarim kohe për kërkesë njëkohësimi - Vonesë mes çdo kërkese + Vonesë mes çdo Njëkohësimi sekondë sekonda @@ -459,10 +459,10 @@ Mënyrë ruajtjeje të dhënash - Hollësi pajisjeje + Të dhëna pajisjeje ID - Emër - Emër Pajisjeje + Emër Publik + Përditësoni Emër Publik Parë së fundi më %1$s @ %2$s Mirëfilltësim @@ -572,9 +572,9 @@ Gabim shfshehtëzimi Të dhëna pajisjeje dërguesi - Emër pajisjeje - Emër - ID Pajisjeje + Emër publik + Emër publik + ID Kyç pajisjeje Verifikim Shenja gishtash Ed25519 @@ -1587,4 +1587,71 @@ Që të garantoni se s’ju shpëton gjë, thjesht mbajeni të aktivizuar mekani Lexoni te +Asnjë + Shfuqizoje + Shkëputu + S’ka shërbyes identitetesh të formësuar. + + Thirrja dështoi për shkak shërbyesi të keqformësuar + Që thirrjet të funksionojnë në mënyrë të qëndrueshme, ju lutemi, kërkojini përgjegjësit të shërbyesit tuaj Home (%1$s) të formësojë një shërbyes TURN. +\n +\nNdryshe, mund të provoni të përdorni shërbyesin publik te %2$s, por kjo s’do të jetë edhe aq e qëndrueshme, dhe adresa juaj IP do të jetë e ditur për atë shërbyes. Këtë mund ta administroni edhe që nga Rregullimet. + Provoni të përdorni %s + Mos më pyet sërish + + Caktoni një email për rimarrje llogarie, dhe më vonë të jetë i zbulueshëm (opsionale) nga persona që ju njohin. + Caktoni një telefon, dhe më vonë të jetë i zbulueshëm (opsionale) nga persona që ju njohin. + Caktoni një email për rimarrje llogarie. Përdoni email ose telefon që të jeni i zbulueshëm (opsionale) nga persona që ju njohin. + Caktoni një email për rimarrje llogarie. Përdorni email ose telefon që të jeni i zbulueshëm (opsionale) nga persona që ju njohin. + S’kapet dot shërbyes Home te kjo URL, ju lutemi, kontrollojeni + Do të përdoret %s si ndihmë kur shërbyesi juaj Home nuk ofron të tillë (gjatë thirrjes, adresa juaj IP do të ndahet me të tjerë) + Që të kryhet ky veprim, shtoni një shërbyes identitetesh, që nga rregullimet tuaja. + Mënyrë Njëkohësimi Në Prapaskenë (Eksperimentale) + E optimizuar për baterinë + Riot-i do të bëjë njëkohësim në prapaskenë, në një mënyrë që kursen burimet e kufizuara të pajisjes (baterinë). +\nNë varësi të gjendjes së burimeve tuaja, njëkohësimi mund të shtyhet për më vonë nga sistemi operativ. + I optimizuar për kohë të njëmendtë + Riot0-i do të bëjë njëkohësim në prapaskenë periodikisht në një kohë të caktuar (e formësueshme). +\nKjo do të ketë ndikim mbi përdorimin e baterisë dhe të transmetimit, do të shfaqet një njoftim i pandërprerë që pohon se Riot-i po përgjon për akte. + Pa njëkohësim në prapraskenë + S’do të njoftoheni për mesazhe ardhës, kur aplikacioni gjendet në prapaskenë. + S’u arrit të përditësohen rregullime. + + + Interval i Parapëlqyer Njëkohësimesh + %s +\nNjëkohësimi mund të shtyhet për më vonë, në varësi të burimeve (baterisë) ose gjendjes së pajisjes (dremitje). + Administroni rregullimet tuaja për zbulime. + Emër publik (i dukshëm për persona me të cilët komunikoni) + Emri publik i një pajisjeje është i dukshëm për persona me të cilët komunikoni + S’po përdorni ndonjë Shërbyes Identitetesh + S’ka shërbyes identitetesh të formësuar, kjo është e domosdoshme për ricaktimin e fjalëkalimit tuaj. + + Duket se po rrekeni të lidheni me një tjetër shërbyes Home. Doni të bëhet dalja\? + + Që të përgjigjeni te rrjedha kohore, aktivizoni fërkimin + + Shërbyes identitetesh + Shkëpute shërbyesin e identiteteve + Formësoni shërbyes identitetesh + Ndryshoni shërbyes identitetesh + Po përdorni %1$s për të zbuluar dhe për të qenë i zbulueshëm nga kontakte ekzistues që njihni. + S’po përdorni ndonjë shërbyes identitetesh. Që të zbuloni dhe të jini i zbulueshëm nga kontakte ekzistuese që njihni, formësoni një të tillë më poshtë. + Adresa email të zbulueshme + Mundësitë rreth zbulimesh do të shfaqen sapo të keni shtuar një email. + Mundësi zbulimesh do të shfaqen sapo të keni shtuar një numër telefoni. + Shkëputja prej shërbyesit tuaj të identiteteve do të thotë se s’do të jeni i zbulueshëm prej përdoruesish të tjerë dhe s’do të jeni në gjendje të ftoni të tjerë me email ose telefon. + Numra telefoni të zbulueshëm + Ju dërguam një email ripohimi te %s, hapeni dhe klikoni mbi lidhjen e ripohimit + Pezull + + Jepni një shërbyes të ri identitetesh + S’u lidh dot te shërbyes identitetesh + Ju lutemi, jepni URL-në e shërbyesit të identiteteve + Shërbyesi i identiteteve s’ka kushte shërbimi + Shërbyesi i identiteteve që keni zgjedhur nuk ka ndonjë kusht shërbimi. Vazhdoni vetëm nëse i zini besë të zotit të shërbimit + Te %s u dërgua një mesazh tekst. Ju lutemi, jepni kodin e verifikimit që përmban ai. + + Hëpërhë, ndani me të tjerë adresa email ose numra telefoni te shërbyesi i identiteteve %s. Do të duhet të rilidheni me %s që të ndalni ndarjen e tyre. + Që të lejoni veten të jetë e zbulueshme nga adresë email apo numër telefoni, pajtohuni me Kushtet e Shërbimit të shërbyesit të identiteteve (%s). From 3b7bc9565d06a5bd7903dd59d3cd27b1a67fe7bb Mon Sep 17 00:00:00 2001 From: Walter Date: Fri, 18 Oct 2019 11:10:17 +0000 Subject: [PATCH 10/77] Translated using Weblate (Russian) Currently translated at 98.3% (1187 of 1208 strings) Translation: Riot Android/Riot Android Translate-URL: https://translate.riot.im/projects/riot-android/riot-android/ru/ --- vector/src/main/res/values-ru/strings.xml | 32 +++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/vector/src/main/res/values-ru/strings.xml b/vector/src/main/res/values-ru/strings.xml index 385e51bf6f..f516f4b4cd 100644 --- a/vector/src/main/res/values-ru/strings.xml +++ b/vector/src/main/res/values-ru/strings.xml @@ -1751,4 +1751,36 @@ Предпочтительный интервал синхронизации Обнаружение + Будет использовать%s в качестве помощника, если ваш домашний сервер не предлагает его (ваш IP-адрес будет доступен во время разговора) + Добавьте идентификационный сервер в свои настройки, чтобы выполнить это действие. + Режим фоновой синхронизации (Экспериментальный) + Riot будет синхронизироваться в фоновом режиме таким образом, чтобы сохранить ограниченные ресурсы устройства (батарея). +\nВ зависимости от состояния ресурса вашего устройства, синхронизация может быть отложена операционной системой. + Riot будет синхронизироваться в фоновом режиме периодически в точное время (настраивается). +\nЭто повлияет на использование радио и батареи, появится постоянное уведомление о том, что Riot прислушивается к событиям. + Вы не будете уведомлены о входящих сообщениях, когда приложение находится в фоновом режиме. + %s +\nСинхронизация может быть отложена в зависимости от ресурсов (батареи) или состояния устройства (спящий режим). + Управляйте настройками обнаружения. + Публичное имя (видимое для людей, с которыми вы общаетесь) + Публичное имя устройства видны людям, с которыми вы общаетесь + Вы не используете какой-либо сервер идентификации + Идентификационный сервер не настроен, требуется сброс пароля. + + Похоже, вы пытаетесь подключиться к другому домашнему серверу. Вы хотите выйти\? + + Сервер идентификации + Отключить идентификационный сервер + Настроить идентификационный сервер + Изменить идентификационный сервер + В настоящее время вы используете %1$s для обнаружения и быть найденным вашими контактами. + "Вы в настоящее время не используете идентификационный сервер. Чтобы обнаружить и быть найденным вашими существующими контактами, настройте один из них ниже." + Видимые адреса электронной почты + Доступные номера телефонов + В ожидании + + Введите новый сервер идентификации + Не удалось подключиться к серверу идентификации + Пожалуйста, введите URL сервера идентификации + Сервер идентификации не имеет условий предоставления услуг From 36d53fdfe4e4fe98a760c0cff3ed6c8d68562071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=86=A1=ED=83=9C=EC=84=AD?= Date: Mon, 21 Oct 2019 03:31:29 +0000 Subject: [PATCH 11/77] Translated using Weblate (Korean) Currently translated at 100.0% (1208 of 1208 strings) Translation: Riot Android/Riot Android Translate-URL: https://translate.riot.im/projects/riot-android/riot-android/ko/ --- vector/src/main/res/values-ko/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vector/src/main/res/values-ko/strings.xml b/vector/src/main/res/values-ko/strings.xml index 2e574e4015..763d51978e 100644 --- a/vector/src/main/res/values-ko/strings.xml +++ b/vector/src/main/res/values-ko/strings.xml @@ -31,8 +31,8 @@ 다운로드 공유 고유 주소 - 출처 보기 - 해독된 출처 보기 + 소스 보기 + 해독된 소스 보기 삭제 다시 이름 짓기 내용 신고하기 From dbb9b1cb4de4a73c161b53a71e149b25b7dd5adc Mon Sep 17 00:00:00 2001 From: Walter Date: Mon, 21 Oct 2019 10:12:30 +0000 Subject: [PATCH 12/77] Translated using Weblate (Russian) Currently translated at 99.8% (1206 of 1208 strings) Translation: Riot Android/Riot Android Translate-URL: https://translate.riot.im/projects/riot-android/riot-android/ru/ --- vector/src/main/res/values-ru/strings.xml | 43 ++++++++++++++--------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/vector/src/main/res/values-ru/strings.xml b/vector/src/main/res/values-ru/strings.xml index f516f4b4cd..95da308c7d 100644 --- a/vector/src/main/res/values-ru/strings.xml +++ b/vector/src/main/res/values-ru/strings.xml @@ -446,7 +446,7 @@ Синхронизация Включить фоновую синхронизацию Таймаут синхронизации - Задержка между запросами + Задержка между каждой синхронизацией секунда секунд @@ -474,10 +474,10 @@ Прикрепить комнаты с отключенными уведомлениями Прикрепить комнаты с непрочитанными сообщениями Устройства - Подробности о устройстве + Информация об устройстве ID - Имя - Имя устройства + Общеизвестное имя + Обновить публичное имя Последнее подключение %1$s @ %2$s Для этой операции требуется дополнительная проверка подлинности. @@ -612,8 +612,8 @@ Информация об устройстве отправителя Публичное имя - Имя - ID устройства + Публичное имя + ID Ключ устройства Проверка Ed25519 отпечаток @@ -1653,15 +1653,15 @@ RiotX - Matrix клиент следующего поколения Быстрый и легкий клиент для Matrix с новейшими фреймворками Android - RiotX - это новый клиент для матричного протокола (Matrix.org): открытой сети для безопасной децентрализованной связи. RiotX - это полная перезапись Riot Android клиента, основанная на полной перезаписи Matrix Android SDK. -\n -\nОговорка: Это бета-версия. В настоящее время RiotX находится в активной разработке и содержит ограничения и (надеемся, не слишком много) ошибки. Мы будем рады любым отзывам! -\n -\nПоддержка RiotX: - Войти в существующую учетную запись - Создать комнату и присоединиться к общей комнате - Принять и отклонить приглашения - Список комнат пользователей - Просмотр сведений о комнате - Отправить текстовые сообщения - Отправить вложение - Читать и писать сообщения в зашифрованных комнатах - Криптографически: Резервное копирование клавиш E2E, предварительная проверка устройства, запрос и ответ на общий доступ к ключам - Нажмите уведомление - Светлые, темные и черные темы -\n -\nНе все функции RiotX пока реализованы в RiotX. Основные отсутствующие (и скоро появятся!) особенности: - Создание учетной записи - Настройки комнат (список членов комнат и т.д.) - Создание прямых чатов - Вызовы - Виджеты - .… + RiotX - это новый клиент для матричного протокола (Matrix.org): открытой сети для безопасной децентрализованной связи. RiotX - это полная перезапись Riot Android клиента, основанная на полной перезаписи Matrix Android SDK. +\n +\nОговорка: Это бета-версия. В настоящее время RiotX находится в активной разработке и содержит ограничения и (надеемся, не слишком много) ошибки. Мы будем рады любым отзывам! +\n +\nПоддержка RiotX: - Войти в существующую учетную запись - Создать комнату и присоединиться к общедоступным комнатам - Принять и отклонить приглашения - Список комнат пользователей - Просмотр сведений о комнате - Отправить текстовые сообщения - Отправить вложение - Читать и писать сообщения в зашифрованных комнатах - Криптография: Резервное копирование клавиш E2E, предварительная проверка устройства, запрос и ответ на общий доступ к ключам - Нажмите уведомление - Светлые и черные темы +\n +\nНе все функции Riot пока реализованы в RiotX. Основные отсутствующие (и скоро появятся!) свойства: - Создание учетной записи - Настройки комнат (список членов комнат и т.д.) - Создание прямых чатов - Вызовы - Виджеты - .… - Предварительный просмотр открытой комнаты в RiotX пока не поддерживается. + Предварительный просмотр открытой комнаты в RiotX пока не поддерживается Прямые сообщения @@ -1695,7 +1695,7 @@ Ссылка скопирована в буфер обмена - Добавить по matrix ID + Добавить по Matrix ID Создание комнаты… "Результат не найден, используйте добавить matrix ID для поиска на сервере." Начните печатать, чтобы получить результат @@ -1715,7 +1715,7 @@ \nПодробнее об этом читайте здесь: \nhttps://medium.com/@RiotChat/36b4792ea0d6 - Правила пуш не определены + Пуш-правила не определены Нет зарегистрированных пуш-шлюзов Условия предоставления услуг @@ -1783,4 +1783,13 @@ Не удалось подключиться к серверу идентификации Пожалуйста, введите URL сервера идентификации Сервер идентификации не имеет условий предоставления услуг - + Параметры обнаружения появятся после добавления электронной почты. + Параметры поиска появятся после добавления номера телефона. + Отключение от сервера идентификации будет означать, что другие пользователи не смогут обнаружить вас, и вы не сможете приглашать других по электронной почте или по телефону. + Мы отправили вам электронное письмо с подтверждением на %s, проверьте вашу электронную почту и нажмите на ссылку для подтверждения + Выбранный сервер идентификации не имеет условий обслуживания. Продолжить, только если вы доверяете владельцу службы + Текстовое сообщение отправлено %s. Введите код проверки, который он содержит. + + В настоящее время вы делитесь адресами электронной почты или телефонными номерами на сервере идентификации %s. Вам нужно повторно подключиться к %s, чтобы прекратить делиться ими. + Примите Условия обслуживания сервера идентификации (%s), чтобы разрешить обнаружение по адресу электронной почты или номеру телефона. + From a559129afe2d36fdc3ad9d367e7c363da4f2de5f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 23 Oct 2019 10:53:08 +0200 Subject: [PATCH 13/77] Format resources --- .../layout/dialog_background_sync_mode.xml | 5 +-- .../src/main/res/values-b+sr+Latn/strings.xml | 5 ++- vector/src/main/res/values-eu/strings.xml | 2 +- vector/src/main/res/values-fi/strings.xml | 2 +- vector/src/main/res/values-fr/strings.xml | 2 +- vector/src/main/res/values-hu/strings.xml | 10 ++--- vector/src/main/res/values-it/strings.xml | 2 +- vector/src/main/res/values-ko/strings.xml | 2 +- vector/src/main/res/values-nl/strings.xml | 4 +- vector/src/main/res/values-ru/strings.xml | 38 +++++++++---------- vector/src/main/res/values-sq/strings.xml | 2 +- vector/src/main/res/values-sr/strings.xml | 5 ++- vector/src/main/res/values-zh-rTW/strings.xml | 2 +- .../res/xml/vector_settings_preferences.xml | 4 +- 14 files changed, 43 insertions(+), 42 deletions(-) diff --git a/vector/src/main/res/layout/dialog_background_sync_mode.xml b/vector/src/main/res/layout/dialog_background_sync_mode.xml index 03603ba30f..89b2aaefde 100644 --- a/vector/src/main/res/layout/dialog_background_sync_mode.xml +++ b/vector/src/main/res/layout/dialog_background_sync_mode.xml @@ -1,14 +1,13 @@ + tools:listitem="@layout/item_custom_dialog_radio_line" /> diff --git a/vector/src/main/res/values-b+sr+Latn/strings.xml b/vector/src/main/res/values-b+sr+Latn/strings.xml index ea3532296b..605af19db6 100644 --- a/vector/src/main/res/values-b+sr+Latn/strings.xml +++ b/vector/src/main/res/values-b+sr+Latn/strings.xml @@ -1,5 +1,6 @@ -en + + en US Svetla Tema @@ -400,4 +401,4 @@ Nedostaje parametar koji je obavezan. Parametar nije ispravan. Šalji glasovne poruke - + diff --git a/vector/src/main/res/values-eu/strings.xml b/vector/src/main/res/values-eu/strings.xml index e76f3b826c..632522c518 100644 --- a/vector/src/main/res/values-eu/strings.xml +++ b/vector/src/main/res/values-eu/strings.xml @@ -1612,7 +1612,7 @@ Abisua: Fitxategi hau ezabatu daiteke aplikazioa desinstalatzen bada. Ikusi edizioen historiala -Bat ere ez + Bat ere ez Indargabetu Deskonektatu Berrikusi diff --git a/vector/src/main/res/values-fi/strings.xml b/vector/src/main/res/values-fi/strings.xml index 3eb5e6ff9d..74680e0fb2 100644 --- a/vector/src/main/res/values-fi/strings.xml +++ b/vector/src/main/res/values-fi/strings.xml @@ -1604,7 +1604,7 @@ Jotta et menetä mitään, automaattiset päivitykset kannattaa pitää käytös Play Storen kuvaus Push-säännöt %1$s luodaksesi tilin. -Katkaise yhteys + Katkaise yhteys Kieltäydy Identiteettipalvelinta ei ole määritetty. diff --git a/vector/src/main/res/values-fr/strings.xml b/vector/src/main/res/values-fr/strings.xml index 6e3841867e..79234af764 100644 --- a/vector/src/main/res/values-fr/strings.xml +++ b/vector/src/main/res/values-fr/strings.xml @@ -1634,7 +1634,7 @@ Si vous n’avez pas configuré de nouvelle méthode de récupération, un attaq Lu à -Aucun + Aucun Révoquer Déconnecter Aucun serveur d’identité configuré. diff --git a/vector/src/main/res/values-hu/strings.xml b/vector/src/main/res/values-hu/strings.xml index a3d72189ba..870e02fbad 100644 --- a/vector/src/main/res/values-hu/strings.xml +++ b/vector/src/main/res/values-hu/strings.xml @@ -1021,7 +1021,7 @@ Vedd figyelembe, hogy az alkalmazás újraindul ami sok időt vehet igénybe.Elküld Ezeket az embereket biztosan kirúgod? - + Ok @@ -1249,11 +1249,11 @@ Figyelmeztetés: ez a fájl törlésre kerülhet, ha az alkalmazást törlik.Visszaállítva: %1$d kapcsolati kulcs, és %2$d kulcs, ami(k) ismeretlenek voltak az eszköz számára, hozzáadva Visszaállított mentés %d kulccsal. - + %d új kulcs lett hozzáadva ehhez az eszközhöz. - + "Nem sikerült beszerezni a legfrissebb verziójú visszaállítási kulcsot (%s)." @@ -1332,7 +1332,7 @@ A Visszaállítási Kulcsot tartsd biztonságos helyen, mint pl. egy jelszókeze Minden kulcs elmentve %d kulcs mentése… - + Verzió @@ -1633,7 +1633,7 @@ Ha nem te állítottad be a visszaállítási metódust, akkor egy támadó pró Olvasd itt -Nincs + Nincs Visszavon Lecsatlakozik Azonosítási szerver nincs beállítva. diff --git a/vector/src/main/res/values-it/strings.xml b/vector/src/main/res/values-it/strings.xml index 0e497c8eb0..9697c084d5 100644 --- a/vector/src/main/res/values-it/strings.xml +++ b/vector/src/main/res/values-it/strings.xml @@ -1678,7 +1678,7 @@ Per essere certo di non perdere nulla, mantieni gli aggiornamenti attivi."Leggi su -Nessuno + Nessuno Revoca Disconnetti Nessun server di identità configurato. diff --git a/vector/src/main/res/values-ko/strings.xml b/vector/src/main/res/values-ko/strings.xml index 763d51978e..2b97d0ff8a 100644 --- a/vector/src/main/res/values-ko/strings.xml +++ b/vector/src/main/res/values-ko/strings.xml @@ -1556,7 +1556,7 @@ 읽은 시간 -없음 + 없음 취소 연결 해제 설정된 ID 서버가 없습니다. diff --git a/vector/src/main/res/values-nl/strings.xml b/vector/src/main/res/values-nl/strings.xml index f099593898..bacc675f86 100644 --- a/vector/src/main/res/values-nl/strings.xml +++ b/vector/src/main/res/values-nl/strings.xml @@ -1510,7 +1510,7 @@ Gebruikers komen niet overeen Onbekende fout -Geen + Geen Intrekken Verbinding verbreken Nakijken @@ -1519,4 +1519,4 @@ Geen identiteitsserver geconfigureerd. Oproep mislukt door verkeerd geconfigureerde server - + diff --git a/vector/src/main/res/values-ru/strings.xml b/vector/src/main/res/values-ru/strings.xml index 95da308c7d..b26ec299fb 100644 --- a/vector/src/main/res/values-ru/strings.xml +++ b/vector/src/main/res/values-ru/strings.xml @@ -96,7 +96,7 @@ %d пользователь %d пользователя %d пользователей - + Отправить логи @@ -843,13 +843,13 @@ %d комната %d комнаты %d комнат - + %d комната %d комнаты %d комнат - + %1$s в %2$s @@ -857,7 +857,7 @@ %d активный виджет %d активных виджета %d активных виджетов - + @@ -867,45 +867,45 @@ %d активный участник %d активных участника %d активных участников - + %d участник %d участника %d участников - + %d новое сообщение %d новых сообщения %d новых сообщений - + %1$s комната найдена для %2$s %1$s комнаты найдено для %2$s %1$s комнат найдено для %2$s - + %d изменение членства %d изменения членства %d изменений членства - + %d непрочитанное уведомление %d непрочитанных уведомления %d непрочитанных уведомлений - + %d непрочитанное уведомление %d непрочитанных уведомления %d непрочитанных уведомлений - + Получить аватар Заметка аватара @@ -1020,13 +1020,13 @@ %dm %dm %dm - + %dh %dh %dh - + %d день @@ -1045,20 +1045,20 @@ %d выбран %d выбрано %d выбраны - + %d участник %d участника %d участников - + %d комната %d комнаты %d комнат - + Системные оповещения @@ -1346,7 +1346,7 @@ %d новый ключ был добавлен к этому устройству. %d новых ключа были добавлены к этому устройству. %d новых ключей были добавлены к этому устройству. - + @@ -1398,7 +1398,7 @@ Резервное копирование %d ключа… Резервное копирование %d ключей… Резервное копирование %d ключей… - + Все ключи сохранены @@ -1725,7 +1725,7 @@ Читать в -Никто + Никто Отмена Отключить Сервер идентификации не настроен. diff --git a/vector/src/main/res/values-sq/strings.xml b/vector/src/main/res/values-sq/strings.xml index 7d7faa061e..b9f3b5d6ff 100644 --- a/vector/src/main/res/values-sq/strings.xml +++ b/vector/src/main/res/values-sq/strings.xml @@ -1587,7 +1587,7 @@ Që të garantoni se s’ju shpëton gjë, thjesht mbajeni të aktivizuar mekani Lexoni te -Asnjë + Asnjë Shfuqizoje Shkëputu S’ka shërbyes identitetesh të formësuar. diff --git a/vector/src/main/res/values-sr/strings.xml b/vector/src/main/res/values-sr/strings.xml index 5d5fb3e9f2..b4d735f8c5 100644 --- a/vector/src/main/res/values-sr/strings.xml +++ b/vector/src/main/res/values-sr/strings.xml @@ -1,5 +1,6 @@ -Светла тема + + Светла тема Тамна тема Црна тема Status.im тема @@ -105,4 +106,4 @@ Лозинка Нова лозинка Корисничко име - + diff --git a/vector/src/main/res/values-zh-rTW/strings.xml b/vector/src/main/res/values-zh-rTW/strings.xml index 9af87fd740..f8e06673be 100644 --- a/vector/src/main/res/values-zh-rTW/strings.xml +++ b/vector/src/main/res/values-zh-rTW/strings.xml @@ -1586,7 +1586,7 @@ Matrix 中的消息可見度類似于電子郵件。我們忘記您的郵件意 閱讀於 - + 撤銷 斷線 未設定身份識別伺服器。 diff --git a/vector/src/main/res/xml/vector_settings_preferences.xml b/vector/src/main/res/xml/vector_settings_preferences.xml index 9465ab6254..ed239ad014 100755 --- a/vector/src/main/res/xml/vector_settings_preferences.xml +++ b/vector/src/main/res/xml/vector_settings_preferences.xml @@ -48,7 +48,7 @@ android:persistent="false" android:title="@string/settings_discovery_category" android:summary="@string/settings_discovery_manage" - app:fragment="im.vector.fragments.discovery.VectorSettingsDiscoveryFragment" /> + app:fragment="im.vector.fragments.discovery.VectorSettingsDiscoveryFragment" /> @@ -444,7 +444,7 @@ android:key="SETTINGS_IDENTITY_SERVER_PREFERENCE_KEY" android:title="@string/settings_identity_server" tools:summary="@string/default_identity_server_url" - app:fragment="im.vector.fragments.discovery.VectorSettingsDiscoveryFragment"/> + app:fragment="im.vector.fragments.discovery.VectorSettingsDiscoveryFragment" /> Date: Wed, 23 Oct 2019 11:44:57 +0200 Subject: [PATCH 14/77] Fix bad resources values --- vector/src/main/res/values-ar/strings.xml | 2 +- vector/src/main/res/values-b+sr+Latn/strings.xml | 4 ++-- vector/src/main/res/values-el/strings.xml | 2 +- vector/src/main/res/values-sr/strings.xml | 2 ++ 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/vector/src/main/res/values-ar/strings.xml b/vector/src/main/res/values-ar/strings.xml index 8730af8a90..3b5b373d0b 100644 --- a/vector/src/main/res/values-ar/strings.xml +++ b/vector/src/main/res/values-ar/strings.xml @@ -1,6 +1,7 @@ ar + SA السمة الفاتحة السمة الداكنة @@ -371,7 +372,6 @@ تحذير! - العربية لم تُرسل الرسائل بسبب وجود أجهزة مجهولة. ماذا أفعل؟ %1$s. ‏%2$s. ليس ’⁨%s⁩‘ تنسيقا صالحا لاختصار diff --git a/vector/src/main/res/values-b+sr+Latn/strings.xml b/vector/src/main/res/values-b+sr+Latn/strings.xml index 605af19db6..07f02a0e81 100644 --- a/vector/src/main/res/values-b+sr+Latn/strings.xml +++ b/vector/src/main/res/values-b+sr+Latn/strings.xml @@ -1,7 +1,7 @@ - en - US + sr + RS Svetla Tema Tamna Tema diff --git a/vector/src/main/res/values-el/strings.xml b/vector/src/main/res/values-el/strings.xml index 6e4706bc63..4b70066fe4 100644 --- a/vector/src/main/res/values-el/strings.xml +++ b/vector/src/main/res/values-el/strings.xml @@ -3,7 +3,7 @@ el - ΕL + GR Ακύρωση diff --git a/vector/src/main/res/values-sr/strings.xml b/vector/src/main/res/values-sr/strings.xml index b4d735f8c5..f8dc41af7b 100644 --- a/vector/src/main/res/values-sr/strings.xml +++ b/vector/src/main/res/values-sr/strings.xml @@ -1,5 +1,7 @@ + sr + RS Светла тема Тамна тема Црна тема From 5af31c405366b62f498efe88658a165055a0b6fb Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 23 Oct 2019 11:48:51 +0200 Subject: [PATCH 15/77] Support Cyrillic languages variant --- .../java/im/vector/settings/VectorLocale.kt | 46 ++++++++++++++++--- .../src/main/res/values-b+sr+Latn/strings.xml | 1 + vector/src/main/res/values-sr/strings.xml | 2 + vector/src/main/res/values/strings.xml | 2 + 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/vector/src/main/java/im/vector/settings/VectorLocale.kt b/vector/src/main/java/im/vector/settings/VectorLocale.kt index 139f6246eb..eb318a3464 100644 --- a/vector/src/main/java/im/vector/settings/VectorLocale.kt +++ b/vector/src/main/java/im/vector/settings/VectorLocale.kt @@ -21,7 +21,6 @@ import android.content.res.Configuration import android.os.Build import android.preference.PreferenceManager import android.text.TextUtils -import android.util.Pair import androidx.core.content.edit import im.vector.R import kotlinx.coroutines.GlobalScope @@ -38,6 +37,7 @@ object VectorLocale { private const val APPLICATION_LOCALE_COUNTRY_KEY = "APPLICATION_LOCALE_COUNTRY_KEY" private const val APPLICATION_LOCALE_VARIANT_KEY = "APPLICATION_LOCALE_VARIANT_KEY" private const val APPLICATION_LOCALE_LANGUAGE_KEY = "APPLICATION_LOCALE_LANGUAGE_KEY" + private const val APPLICATION_LOCALE_SCRIPT_KEY = "APPLICATION_LOCALE_SCRIPT_KEY" private val defaultLocale = Locale("en", "US") @@ -109,6 +109,15 @@ object VectorLocale { } else { putString(APPLICATION_LOCALE_VARIANT_KEY, variant) } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + val script = locale.script + if (TextUtils.isEmpty(script)) { + remove(APPLICATION_LOCALE_SCRIPT_KEY) + } else { + putString(APPLICATION_LOCALE_SCRIPT_KEY, script) + } + } } } @@ -157,24 +166,43 @@ object VectorLocale { * @param context the context */ private fun initApplicationLocales(context: Context) { - val knownLocalesSet = HashSet>() + val knownLocalesSet = HashSet>() try { val availableLocales = Locale.getAvailableLocales() for (locale in availableLocales) { - knownLocalesSet.add(Pair(getString(context, locale, R.string.resources_language), - getString(context, locale, R.string.resources_country_code))) + knownLocalesSet.add( + Triple( + getString(context, locale, R.string.resources_language), + getString(context, locale, R.string.resources_country_code), + getString(context, locale, R.string.resources_script) + )) } } catch (e: Exception) { Log.e(LOG_TAG, "## getApplicationLocales() : failed " + e.message, e) - knownLocalesSet.add(Pair(context.getString(R.string.resources_language), context.getString(R.string.resources_country_code))) + knownLocalesSet.add( + Triple( + context.getString(R.string.resources_language), + context.getString(R.string.resources_country_code), + context.getString(R.string.resources_script) + )) } supportedLocales.clear() for (knownLocale in knownLocalesSet) { - supportedLocales.add(Locale(knownLocale.first, knownLocale.second)) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + supportedLocales.add( + Locale.Builder() + .setLanguage(knownLocale.first) + .setRegion(knownLocale.second) + .setScript(knownLocale.third) + .build() + ) + } else { + supportedLocales.add(Locale(knownLocale.first, knownLocale.second)) + } } // sort by human display names @@ -190,6 +218,12 @@ object VectorLocale { fun localeToLocalisedString(locale: Locale): String { var res = locale.getDisplayLanguage(locale) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + if (locale.script != "Latn" && !TextUtils.isEmpty(locale.getDisplayScript(locale))) { + res += " - " + locale.getDisplayScript(locale) + } + } + if (!TextUtils.isEmpty(locale.getDisplayCountry(locale))) { res += " (" + locale.getDisplayCountry(locale) + ")" } diff --git a/vector/src/main/res/values-b+sr+Latn/strings.xml b/vector/src/main/res/values-b+sr+Latn/strings.xml index 07f02a0e81..8bce8a32ff 100644 --- a/vector/src/main/res/values-b+sr+Latn/strings.xml +++ b/vector/src/main/res/values-b+sr+Latn/strings.xml @@ -2,6 +2,7 @@ sr RS + Latn Svetla Tema Tamna Tema diff --git a/vector/src/main/res/values-sr/strings.xml b/vector/src/main/res/values-sr/strings.xml index f8dc41af7b..121589a6cd 100644 --- a/vector/src/main/res/values-sr/strings.xml +++ b/vector/src/main/res/values-sr/strings.xml @@ -2,6 +2,8 @@ sr RS + Cyrl + Светла тема Тамна тема Црна тема diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index de8d1d9e22..9134124b67 100755 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -5,6 +5,8 @@ en US + + Latn Light Theme From c060aa8dfce6192c6344e59de37d265bcd88d683 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 23 Oct 2019 11:58:40 +0200 Subject: [PATCH 16/77] Display locales in the current locale in debug mode --- .../java/im/vector/settings/VectorLocale.kt | 49 +++++++++++++------ vector/src/main/res/layout/item_locale.xml | 9 ++-- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/vector/src/main/java/im/vector/settings/VectorLocale.kt b/vector/src/main/java/im/vector/settings/VectorLocale.kt index eb318a3464..3ba74c1945 100644 --- a/vector/src/main/java/im/vector/settings/VectorLocale.kt +++ b/vector/src/main/java/im/vector/settings/VectorLocale.kt @@ -20,8 +20,8 @@ import android.content.Context import android.content.res.Configuration import android.os.Build import android.preference.PreferenceManager -import android.text.TextUtils import androidx.core.content.edit +import im.vector.BuildConfig import im.vector.R import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch @@ -69,7 +69,7 @@ object VectorLocale { // detect if the default language is used val defaultStringValue = getString(context, defaultLocale, R.string.resources_country_code) - if (TextUtils.equals(defaultStringValue, getString(context, applicationLocale, R.string.resources_country_code))) { + if (defaultStringValue == getString(context, applicationLocale, R.string.resources_country_code)) { applicationLocale = defaultLocale } @@ -90,21 +90,21 @@ object VectorLocale { PreferenceManager.getDefaultSharedPreferences(context).edit { val language = locale.language - if (TextUtils.isEmpty(language)) { + if (language.isEmpty()) { remove(APPLICATION_LOCALE_LANGUAGE_KEY) } else { putString(APPLICATION_LOCALE_LANGUAGE_KEY, language) } val country = locale.country - if (TextUtils.isEmpty(country)) { + if (country.isEmpty()) { remove(APPLICATION_LOCALE_COUNTRY_KEY) } else { putString(APPLICATION_LOCALE_COUNTRY_KEY, country) } val variant = locale.variant - if (TextUtils.isEmpty(variant)) { + if (variant.isEmpty()) { remove(APPLICATION_LOCALE_VARIANT_KEY) } else { putString(APPLICATION_LOCALE_VARIANT_KEY, variant) @@ -112,7 +112,7 @@ object VectorLocale { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { val script = locale.script - if (TextUtils.isEmpty(script)) { + if (script.isEmpty()) { remove(APPLICATION_LOCALE_SCRIPT_KEY) } else { putString(APPLICATION_LOCALE_SCRIPT_KEY, script) @@ -216,19 +216,38 @@ object VectorLocale { * @return the string */ fun localeToLocalisedString(locale: Locale): String { - var res = locale.getDisplayLanguage(locale) + return buildString { + append(locale.getDisplayLanguage(locale)) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP + && locale.script != "Latn" + && locale.getDisplayScript(locale).isNotEmpty()) { + append(" - ") + append(locale.getDisplayScript(locale)) + } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - if (locale.script != "Latn" && !TextUtils.isEmpty(locale.getDisplayScript(locale))) { - res += " - " + locale.getDisplayScript(locale) + if (locale.getDisplayCountry(locale).isNotEmpty()) { + append(" (") + append(locale.getDisplayCountry(locale)) + append(")") } - } - if (!TextUtils.isEmpty(locale.getDisplayCountry(locale))) { - res += " (" + locale.getDisplayCountry(locale) + ")" + // In debug mode, also display information about the locale in the current locale. + if (BuildConfig.DEBUG) { + append("\n[") + append(locale.displayLanguage) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && locale.script != "Latn") { + append(" - ") + append(locale.displayScript) + } + if (locale.displayCountry.isNotEmpty()) { + append(" (") + append(locale.displayCountry) + append(")") + } + append("]") + } } - - return res } } diff --git a/vector/src/main/res/layout/item_locale.xml b/vector/src/main/res/layout/item_locale.xml index a418f9beba..fb58b84c01 100644 --- a/vector/src/main/res/layout/item_locale.xml +++ b/vector/src/main/res/layout/item_locale.xml @@ -1,5 +1,5 @@ - - \ No newline at end of file + tools:text="English (United States)" /> + + \ No newline at end of file From d22f5f70fbb14335215e70d8fb755bda980bc6f9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 23 Oct 2019 13:44:28 +0200 Subject: [PATCH 17/77] Remove country code for Arabic --- vector/src/main/res/values-ar/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/res/values-ar/strings.xml b/vector/src/main/res/values-ar/strings.xml index 3b5b373d0b..35e8f246aa 100644 --- a/vector/src/main/res/values-ar/strings.xml +++ b/vector/src/main/res/values-ar/strings.xml @@ -1,7 +1,7 @@ ar - SA + "" السمة الفاتحة السمة الداكنة From 1d95859b23ebf2542d6620904e0caff0456dcace Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 23 Oct 2019 14:11:23 +0200 Subject: [PATCH 18/77] Add strings for RiotX --- vector/src/main/res/values/strings.xml | 61 ++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 9134124b67..3d20bdf5c3 100755 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -1709,4 +1709,65 @@ Not all features in Riot are implemented in RiotX yet. Main missing (and coming You are currently sharing email addresses or phone numbers on the identity server %s. You will need to reconnect to %s to stop sharing them. Agree to the identity server (%s) Terms of Service to allow yourself to be discoverable by email address or phone number. + + Enable verbose logs. + Verbose logs will help developers by providing more logs when you send a RageShake. Even when enabled, the application does not log message contents or any other private data. + + + Please retry once you have accepted the terms and conditions of your homeserver. + + Looks like the server is taking to long to respond, this can be caused by either poor connectivity or an error with our servers. Please try again in a while. + + Send attachment + + Open the navigation drawer + Open the create room menu + Close the create room menu… + Create a new direct conversation + Create a new room + Close keys backup banner + Show password + Hide password + Jump to bottom + + + %1$s, %2$s and %3$d others read + %1$s, %2$s and %3$s read + %1$s and %2$s read + %s read + + 1 user read + %d users read + + + "The file '%1$s' (%2$s) is too large to upload. The limit is %3$s." + + "An error occurred while retrieving the attachment." + "File" + "Contact" + "Camera" + "Audio" + "Gallery" + "Sticker" + Couldn\'t handle share data + + "It's spam" + "It's inappropriate" + "Custom report" + "Report this content" + "Reason for reporting this content" + "REPORT" + "BLOCK USER" + + "Content reported" + "This content was reported.\n\nIf you don't want to see any more content from this user, you can block him to hide his messages" + "Reported as spam" + "This content was reported as spam.\n\nIf you don't want to see any more content from this user, you can block him to hide his messages" + "Reported as inappropriate" + "This content was reported as inappropriate.\n\nIf you don't want to see any more content from this user, you can block him to hide his messages" + + Riot needs permission to save your E2E keys on disk.\n\nPlease allow access on the next pop-up to be able to export your keys manually. + + There is no network connection right now + From b132d691a64eae4aa67630065aa5ad8a10b677b8 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 23 Oct 2019 14:14:01 +0200 Subject: [PATCH 19/77] Creation of direct chat room is supported now --- vector/src/main/res/values-bg/strings.xml | 2 +- vector/src/main/res/values-eu/strings.xml | 2 +- vector/src/main/res/values-fr/strings.xml | 2 +- vector/src/main/res/values-hu/strings.xml | 2 +- vector/src/main/res/values-it/strings.xml | 2 +- vector/src/main/res/values-ko/strings.xml | 2 +- vector/src/main/res/values-ru/strings.xml | 2 +- vector/src/main/res/values-sq/strings.xml | 2 +- vector/src/main/res/values-zh-rTW/strings.xml | 2 +- vector/src/main/res/values/strings.xml | 1 - 10 files changed, 9 insertions(+), 10 deletions(-) diff --git a/vector/src/main/res/values-bg/strings.xml b/vector/src/main/res/values-bg/strings.xml index 077da3b3d0..e03e174e54 100644 --- a/vector/src/main/res/values-bg/strings.xml +++ b/vector/src/main/res/values-bg/strings.xml @@ -1558,7 +1558,7 @@ \n \nRiotX поддържа: • Вход в съществуващ акаунт • Създаване на стая и влизане в публични стаи • Приемане и отхвърляне на покани • Показване на списък със стаите • Преглеждане на информация за стая • Изпращане на текстови съобщения • Изпращане на прикачени файлове • Четене и писане на съобщения в шифровани стаи • Шифроване: резервни копия на E2E ключове, потвърждение на устройства, заявяване и отговаряне на заявки за споделяне на ключове • Уведомления • Светла, Тъмна и Черна тема \n -\nЗасега не всички функции на Riot са налични в RiotX. Основни липсващи (и скоро пристигащи!) функции са: • Създаване на нов профил • Настройки на стаи (показване на членове и т.н.) • Създаване на директни чатове • Обаждания • Приспособления • … +\nЗасега не всички функции на Riot са налични в RiotX. Основни липсващи (и скоро пристигащи!) функции са: • Създаване на нов профил • Настройки на стаи (показване на членове и т.н.) • Обаждания • Приспособления • … Директни съобщения diff --git a/vector/src/main/res/values-eu/strings.xml b/vector/src/main/res/values-eu/strings.xml index 632522c518..71b5a6ab30 100644 --- a/vector/src/main/res/values-eu/strings.xml +++ b/vector/src/main/res/values-eu/strings.xml @@ -1564,7 +1564,7 @@ Abisua: Fitxategi hau ezabatu daiteke aplikazioa desinstalatzen bada. \n \nRiotX bezeroak honakoa ahalbidetzen du: • Badagoen kontu batean saioa hasi • Gelak sortu eta gela publikoetara elkartu • Gonbidapenak onartu edo ukatu • Erabiltzailearen gelak zerrendatu • Gelaren xehetasunak ikusi • Testuzko mezuak bidali • Eranskinak bidali • Zifratutako geletan mezuak irakurri eta idatzi • Zifratzea: E2Egakoen babeskopia, gailuaren egiaztaketa aurreratua, gakoa partekatzeko eskaria eta erantzuna • Push jakinarazpena • Gai argia, iluna eta beltza \n -\nEz dira oraindik Riot bezeroaren ezaugarri guztiak ezarri RiotX bezeroan. Falta diren (eta laster etorriko direnen) artean nabarmenak dira: • Kontua sortzea • Gelaren ezarpenak (gelako kideak zerrendatzea, eta abar.) • Txat zuzenerako gelak sortzea • Deiak • Trepetak • … +\nEz dira oraindik Riot bezeroaren ezaugarri guztiak ezarri RiotX bezeroan. Falta diren (eta laster etorriko direnen) artean nabarmenak dira: • Kontua sortzea • Gelaren ezarpenak (gelako kideak zerrendatzea, eta abar.) • Deiak • Trepetak • … app_display_name: Mezu zuzenak diff --git a/vector/src/main/res/values-fr/strings.xml b/vector/src/main/res/values-fr/strings.xml index 79234af764..3ca4f03934 100644 --- a/vector/src/main/res/values-fr/strings.xml +++ b/vector/src/main/res/values-fr/strings.xml @@ -1570,7 +1570,7 @@ Si vous n’avez pas configuré de nouvelle méthode de récupération, un attaq \n \nRiotX prend en charge : • Se connecter à un compte existant • Créer de salons et rejoindre des salons publics • Accepter et refuser des invitations • Lister les salons des utilisateurs • Voir les informations des salons • Envoyer des messages texte • Envoyer des pièces jointes • Lire et écrire des messages dans les salons chiffrés • Chiffrement : sauvegarde des clés de chiffrement, vérification avancée des appareils, demande et réponse de partage de clé • Notifications • Thèmes clair, sombre et noir \n -\nToutes les fonctionnalités de Riot ne sont pas encore implémentées dans RiotX. Principales fonctionnalités manquantes (et qui arrivent bientôt !) : • Création de compte • Réglages des salons (lister les membres du salon etc.) • Création de salons de discussion directe • Appels • Widgets • … +\nToutes les fonctionnalités de Riot ne sont pas encore implémentées dans RiotX. Principales fonctionnalités manquantes (et qui arrivent bientôt !) : • Création de compte • Réglages des salons (lister les membres du salon etc.) • Appels • Widgets • … Messages directs diff --git a/vector/src/main/res/values-hu/strings.xml b/vector/src/main/res/values-hu/strings.xml index 870e02fbad..255887c340 100644 --- a/vector/src/main/res/values-hu/strings.xml +++ b/vector/src/main/res/values-hu/strings.xml @@ -1569,7 +1569,7 @@ Ha nem te állítottad be a visszaállítási metódust, akkor egy támadó pró \n \nRiotX ezeket támogatja: • Bejelentkezés létező fiókba • Szoba készítés és nyilvános szobába való belépés • Meghívók fogadása és elutasítás • Felhasználók szobáinak listázása • Szoba adatainak megtekintése • Szöveges üzenet küldése • Csatolmány küldése • Titkosított szobákban üzenetek olvasása és írása • Titkosítás: Végponttól végpontig titkosító kulcsok mentése, fejlett eszköz ellenőrzés, kulcs megosztás kérése és válasz • „Push” értesítések • Világos, sötét és fekete téma \n -\nNem minden Riot funkció támogatott a RiotX-ben jelenleg. A fő hiányzó (és hamarosan elérhető!) funkciók: • Felhasználói fiók létrehozása • Szoba beállítások (szoba tagság mutatása, stb…) • Közvetlen beszélgetések indítása • Hívások • Kisalkalmazások • … +\nNem minden Riot funkció támogatott a RiotX-ben jelenleg. A fő hiányzó (és hamarosan elérhető!) funkciók: • Felhasználói fiók létrehozása • Szoba beállítások (szoba tagság mutatása, stb…) • Hívások • Kisalkalmazások • … Közvetlen beszélgetés diff --git a/vector/src/main/res/values-it/strings.xml b/vector/src/main/res/values-it/strings.xml index 9697c084d5..4e41ad0a6c 100644 --- a/vector/src/main/res/values-it/strings.xml +++ b/vector/src/main/res/values-it/strings.xml @@ -1613,7 +1613,7 @@ Per essere certo di non perdere nulla, mantieni gli aggiornamenti attivi." +\nNon tutte le funzioni di Riot sono già implementate in RiotX. Principali funzioni mancanti (prossimamente!): • Creazione account • Impostazioni stanza (elenca membri stanza, ecc.) • Chiamate • Widget • … Non hai nulla di nuovo da vedere! Messaggi diretti diff --git a/vector/src/main/res/values-ko/strings.xml b/vector/src/main/res/values-ko/strings.xml index 2b97d0ff8a..ad1716f70b 100644 --- a/vector/src/main/res/values-ko/strings.xml +++ b/vector/src/main/res/values-ko/strings.xml @@ -1495,7 +1495,7 @@ \n \nRiotX 지원: • 존재하는 계정으로 로그인 • 방을 만들고 공공 방에 참가 • 초대를 수락하거나 거절 • 사용자 방 목록 • 방 세부 정보 보기 • 문자 메시지 보내기 • 첨부 파일 보내기 • 암호화된 방에서 메시지 읽고 쓰기 • 암호화: 종단간 암호화 키 백업, 고급 기기 확인, 키 공유 요청과 답장 • 푸시 알림 • 밝은 테마, 어두운 테마 그리고 검정 테마 \n -\n아직 Riot의 모든 기능이 RiotX에 구현되지 않았습니다. 주요 없는 (그리고 곧 나올!) 기능: • 계정 만들기 • 방 설정 (방 구성원 목록 등) • 다이렉트 대화 방 만들기 • 전화 • 위젯 • … +\n아직 Riot의 모든 기능이 RiotX에 구현되지 않았습니다. 주요 없는 (그리고 곧 나올!) 기능: • 계정 만들기 • 방 설정 (방 구성원 목록 등) • 전화 • 위젯 • … 다이렉트 메시지 diff --git a/vector/src/main/res/values-ru/strings.xml b/vector/src/main/res/values-ru/strings.xml index b26ec299fb..145bb548c8 100644 --- a/vector/src/main/res/values-ru/strings.xml +++ b/vector/src/main/res/values-ru/strings.xml @@ -1659,7 +1659,7 @@ \n \nПоддержка RiotX: - Войти в существующую учетную запись - Создать комнату и присоединиться к общедоступным комнатам - Принять и отклонить приглашения - Список комнат пользователей - Просмотр сведений о комнате - Отправить текстовые сообщения - Отправить вложение - Читать и писать сообщения в зашифрованных комнатах - Криптография: Резервное копирование клавиш E2E, предварительная проверка устройства, запрос и ответ на общий доступ к ключам - Нажмите уведомление - Светлые и черные темы \n -\nНе все функции Riot пока реализованы в RiotX. Основные отсутствующие (и скоро появятся!) свойства: - Создание учетной записи - Настройки комнат (список членов комнат и т.д.) - Создание прямых чатов - Вызовы - Виджеты - .… +\nНе все функции Riot пока реализованы в RiotX. Основные отсутствующие (и скоро появятся!) свойства: - Создание учетной записи - Настройки комнат (список членов комнат и т.д.) - Вызовы - Виджеты - .… Предварительный просмотр открытой комнаты в RiotX пока не поддерживается diff --git a/vector/src/main/res/values-sq/strings.xml b/vector/src/main/res/values-sq/strings.xml index b9f3b5d6ff..ea8a599718 100644 --- a/vector/src/main/res/values-sq/strings.xml +++ b/vector/src/main/res/values-sq/strings.xml @@ -1521,7 +1521,7 @@ Që të garantoni se s’ju shpëton gjë, thjesht mbajeni të aktivizuar mekani \n \nRiotX-i mbulon: • Hyrje në një llogari ekzistuese • Krijim dhome dhe pjesëmarrje në dhoma publike • Pranim dhe hedhje poshtë ftesash • Njohje të dhomave të përdoruesve • Parje hollësish dhome • Dërgim mesazhesh tekst • Dërgim bashkëngjitjesh • Lexim dhe shkrim mesazhesh në dhoma të fshehtëzuara • Kriptografi: kopjeruajtje kyçesh E2E, verifikim i thelluar pajisjesh, kërkesa dhe përgjigje për ndarje kyçesh • Njoftime push • Tema të Çelëta, të Errëta dhe të Zeza \n -\nNë RiotX s’janë sendërtuar ende krejt veçoritë e Riot-it. Veçori kryesore që mungojnë (dhe që do të vijnë së shpejti!): • Krijim llogarish • Rregullime dhome (shfaqje anëtarësh dhome, etj.) • Krijim dhomash fjalosjeje të drejtpërdrejtë • Thirrje • Widget-es • … +\nNë RiotX s’janë sendërtuar ende krejt veçoritë e Riot-it. Veçori kryesore që mungojnë (dhe që do të vijnë së shpejti!): • Krijim llogarish • Rregullime dhome (shfaqje anëtarësh dhome, etj.) • Thirrje • Widget-es • … Përgjegjës Integrimesh diff --git a/vector/src/main/res/values-zh-rTW/strings.xml b/vector/src/main/res/values-zh-rTW/strings.xml index f8e06673be..cd81aea785 100644 --- a/vector/src/main/res/values-zh-rTW/strings.xml +++ b/vector/src/main/res/values-zh-rTW/strings.xml @@ -1522,7 +1522,7 @@ Matrix 中的消息可見度類似于電子郵件。我們忘記您的郵件意 \n \nRiotX 支援:• 登入到既有的帳號 • 建立聊天室與加入公開聊天室 • 接受與回絕邀請 • 列出使用者聊天室 • 檢視聊天室詳細資訊 • 傳送文字訊息 • 傳送附件 • 讀取與編寫已加密的聊天室 • 加密:E2E 金鑰備份、進階裝置驗證、金鑰分享請求與回應 • 推送通知 • 亮、暗與黑色主題 \n -\n不是所有 Riot 的功能都已在 RiotX 中實作。主要缺少(會在稍後到來!)的功能:• 建立帳號 • 聊天室設定(列出聊天室成員等) • 直接聊天室建立 • 通話 • 小工具 • … +\n不是所有 Riot 的功能都已在 RiotX 中實作。主要缺少(會在稍後到來!)的功能:• 建立帳號 • 聊天室設定(列出聊天室成員等) • 通話 • 小工具 • … 直接訊息 diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 3d20bdf5c3..8d5e211fbd 100755 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -1628,7 +1628,6 @@ RiotX supports: Not all features in Riot are implemented in RiotX yet. Main missing (and coming soon!) features: • Account creation • Room settings (list room members, etc.) -• Creation of direct chat rooms • Calls • Widgets • …" From 8e73b4e0a109947451bf46bbff95aacc81171005 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 23 Oct 2019 15:16:22 +0200 Subject: [PATCH 20/77] Fix warning --- vector/src/main/res/values-eu/strings.xml | 2 +- vector/src/main/res/values-fi/strings.xml | 2 +- vector/src/main/res/values-fr/strings.xml | 2 +- vector/src/main/res/values-hu/strings.xml | 2 +- vector/src/main/res/values-it/strings.xml | 2 +- vector/src/main/res/values-ko/strings.xml | 2 +- vector/src/main/res/values-ru/strings.xml | 2 +- vector/src/main/res/values-sq/strings.xml | 2 +- vector/src/main/res/values-zh-rTW/strings.xml | 2 +- vector/src/main/res/values/strings.xml | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/vector/src/main/res/values-eu/strings.xml b/vector/src/main/res/values-eu/strings.xml index 71b5a6ab30..9e02bf8103 100644 --- a/vector/src/main/res/values-eu/strings.xml +++ b/vector/src/main/res/values-eu/strings.xml @@ -1695,6 +1695,6 @@ Abisua: Fitxategi hau ezabatu daiteke aplikazioa desinstalatzen bada. Hautatu duzun identitate-zerbitzariak ez du erabilera baldintzarik. Jarraitu soilik zerbitzuaren jabea fidagarritzat jotzen baduzu SMS mezu bat bidali zaizu %s zenbakira. Sartu hemen mezu horrek daukan egiaztatze-kodea. - Orain e-mail helbideak edo telefono zenbakiak partekatzen dituzu %s zerbitzarian. %s zerbitzarira konektatu beharko zara partekatzeari uzteko. + Orain e-mail helbideak edo telefono zenbakiak partekatzen dituzu %1$s zerbitzarian. %2$s zerbitzarira konektatu beharko zara partekatzeari uzteko. Onartu %s identitate-zerbitzariaren erabilera baldintzak besteek zu e-mail helbidea edo telefonoa erabiliz aurkitzea ahalbidetzeko. diff --git a/vector/src/main/res/values-fi/strings.xml b/vector/src/main/res/values-fi/strings.xml index 74680e0fb2..3b037a9ead 100644 --- a/vector/src/main/res/values-fi/strings.xml +++ b/vector/src/main/res/values-fi/strings.xml @@ -1655,6 +1655,6 @@ Jotta et menetä mitään, automaattiset päivitykset kannattaa pitää käytös Syötä identiteettipalvelimen URL-osoite Identiteettipalvelimella ei ole käyttöehtoja Valitsemallasi identiteettipalvelimella ei ole käyttöehtoja. Jatka vain, jos luotat palvelun omistajaan - Jaat sähköpostiosoitteita tai puhelinnumeroita identiteettipalvelimella %s. Sinun täytyy yhdistää uudelleen palvelimeen %s, jotta voit lopettaa niiden jakamisen. + Jaat sähköpostiosoitteita tai puhelinnumeroita identiteettipalvelimella %1$s. Sinun täytyy yhdistää uudelleen palvelimeen %2$s, jotta voit lopettaa niiden jakamisen. Hyväksy identiteettipalvelimen (%s) käyttöehdot salliaksesi, että sinut voi löytää sähköpostiosoitteen tai puhelinnumeron perusteella. diff --git a/vector/src/main/res/values-fr/strings.xml b/vector/src/main/res/values-fr/strings.xml index 3ca4f03934..1fe493d9d4 100644 --- a/vector/src/main/res/values-fr/strings.xml +++ b/vector/src/main/res/values-fr/strings.xml @@ -1699,6 +1699,6 @@ Si vous n’avez pas configuré de nouvelle méthode de récupération, un attaq Le serveur d’identité qui vous avez choisi n’a pas de conditions de service. Continuez uniquement si vous faites confiance au propriétaire de ce service Un SMS a été envoyé à %s. Saisissez le code de vérification qu’il contient. - Vous partagez actuellement des adresse e-mails et des numéros de téléphone sur le serveur d’identité %s. Vous devrez vous reconnecter à %s pour arrêter de les partager. + Vous partagez actuellement des adresse e-mails et des numéros de téléphone sur le serveur d’identité %1$s. Vous devrez vous reconnecter à %2$s pour arrêter de les partager. Acceptez les conditions de service du serveur d’identité (%s) pour vous permettre d’être découvrable avec une adresse e-mail ou un numéro de téléphone. diff --git a/vector/src/main/res/values-hu/strings.xml b/vector/src/main/res/values-hu/strings.xml index 255887c340..2e13eb7531 100644 --- a/vector/src/main/res/values-hu/strings.xml +++ b/vector/src/main/res/values-hu/strings.xml @@ -1698,6 +1698,6 @@ Ha nem te állítottad be a visszaállítási metódust, akkor egy támadó pró Az általad választott azonosítási szervernek nincs felhasználási feltétele. Csak akkor lépj tovább ha megbízol a szolgáltatás tulajdonosában Szöveges üzenetet küldtünk ide: %s. Kérlek add meg az ellenőrző kódot amit az üzenet tartalmaz. - Az azonosítási szerverrel (%s) megosztod az e-mail címeket és telefonszámokat. Újra kell csatlakoznod ehhez: %s, hogy megállítsd a megosztást. + Az azonosítási szerverrel (%1$s) megosztod az e-mail címeket és telefonszámokat. Újra kell csatlakoznod ehhez: %2$s, hogy megállítsd a megosztást. Egyetértek az azonosítási szerver (%s) Felhasználási feltételeivel ahhoz, hogy megtalálható legyek e-mail címmel vagy telefonszámmal. diff --git a/vector/src/main/res/values-it/strings.xml b/vector/src/main/res/values-it/strings.xml index 4e41ad0a6c..1c879ad794 100644 --- a/vector/src/main/res/values-it/strings.xml +++ b/vector/src/main/res/values-it/strings.xml @@ -1743,6 +1743,6 @@ Per essere certo di non perdere nulla, mantieni gli aggiornamenti attivi."Il server di identità che hai scelto non ha alcuna condizione di servizio. Continua solo se ti fidi del proprietario del servizio È stato inviato un messaggio a %s. Inserisci il codice di verifica contenuto. - Attualmente stai condividendo indirizzi email o numeri di telefono sul server di identità %s. Dovrai riconnetterti a %s per fermarne la condivisione. + Attualmente stai condividendo indirizzi email o numeri di telefono sul server di identità %1$s. Dovrai riconnetterti a %2$s per fermarne la condivisione. Accetta le condizioni di servizio del server di identità (%s) per consentire di essere trovabile per email o numero di telefono. diff --git a/vector/src/main/res/values-ko/strings.xml b/vector/src/main/res/values-ko/strings.xml index ad1716f70b..7f76e47ea7 100644 --- a/vector/src/main/res/values-ko/strings.xml +++ b/vector/src/main/res/values-ko/strings.xml @@ -1621,6 +1621,6 @@ 선택한 ID 서버가 서비스 약관이 없습니다. 서비스의 소유자를 신뢰하는 경우에만 계속하세요 %s(으)로 문자 메시지를 보냈습니다. 문자에 있는 확인 코드를 입력해주세요. - 현재 이메일 주소나 전화번호를 ID 서버 %s와 공유하고 있습니다. 공유하기를 중지하려면 %s(으)로 다시 연결해야 합니다. + 현재 이메일 주소나 전화번호를 ID 서버 %1$s와 공유하고 있습니다. 공유하기를 중지하려면 %2$s(으)로 다시 연결해야 합니다. ID 서버 (%s)의 서비스 약관에 동의하면 다른 사용자가 당신을 이메일 주소나 전화번호로 찾을 수 있게 됩니다. diff --git a/vector/src/main/res/values-ru/strings.xml b/vector/src/main/res/values-ru/strings.xml index 145bb548c8..eaad9bf4aa 100644 --- a/vector/src/main/res/values-ru/strings.xml +++ b/vector/src/main/res/values-ru/strings.xml @@ -1790,6 +1790,6 @@ Выбранный сервер идентификации не имеет условий обслуживания. Продолжить, только если вы доверяете владельцу службы Текстовое сообщение отправлено %s. Введите код проверки, который он содержит. - В настоящее время вы делитесь адресами электронной почты или телефонными номерами на сервере идентификации %s. Вам нужно повторно подключиться к %s, чтобы прекратить делиться ими. + В настоящее время вы делитесь адресами электронной почты или телефонными номерами на сервере идентификации %1$s. Вам нужно повторно подключиться к %2$s, чтобы прекратить делиться ими. Примите Условия обслуживания сервера идентификации (%s), чтобы разрешить обнаружение по адресу электронной почты или номеру телефона. diff --git a/vector/src/main/res/values-sq/strings.xml b/vector/src/main/res/values-sq/strings.xml index ea8a599718..f299ad4385 100644 --- a/vector/src/main/res/values-sq/strings.xml +++ b/vector/src/main/res/values-sq/strings.xml @@ -1652,6 +1652,6 @@ Që të garantoni se s’ju shpëton gjë, thjesht mbajeni të aktivizuar mekani Shërbyesi i identiteteve që keni zgjedhur nuk ka ndonjë kusht shërbimi. Vazhdoni vetëm nëse i zini besë të zotit të shërbimit Te %s u dërgua një mesazh tekst. Ju lutemi, jepni kodin e verifikimit që përmban ai. - Hëpërhë, ndani me të tjerë adresa email ose numra telefoni te shërbyesi i identiteteve %s. Do të duhet të rilidheni me %s që të ndalni ndarjen e tyre. + Hëpërhë, ndani me të tjerë adresa email ose numra telefoni te shërbyesi i identiteteve %1$s. Do të duhet të rilidheni me %2$s që të ndalni ndarjen e tyre. Që të lejoni veten të jetë e zbulueshme nga adresë email apo numër telefoni, pajtohuni me Kushtet e Shërbimit të shërbyesit të identiteteve (%s). diff --git a/vector/src/main/res/values-zh-rTW/strings.xml b/vector/src/main/res/values-zh-rTW/strings.xml index cd81aea785..b54c05b784 100644 --- a/vector/src/main/res/values-zh-rTW/strings.xml +++ b/vector/src/main/res/values-zh-rTW/strings.xml @@ -1651,6 +1651,6 @@ Matrix 中的消息可見度類似于電子郵件。我們忘記您的郵件意 您選擇的身份識別伺服器沒有任何服務條款。僅在您信任服務擁有者時才繼續 文字訊息已傳送給 %s。請輸入其中包含的驗證碼。 - 您目前正在身份識別伺服器 %s 上分享電子郵件地址或電話號碼。您將必須重新連線到 %s 以停止分享它們。 + 您目前正在身份識別伺服器 %1$s 上分享電子郵件地址或電話號碼。您將必須重新連線到 %2$s 以停止分享它們。 同意身份識別伺服器 (%s) 的服務條款以允許您被透過電子郵件地址或電話號碼探索。 diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 8d5e211fbd..83ce65783f 100755 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -1706,7 +1706,7 @@ Not all features in Riot are implemented in RiotX yet. Main missing (and coming The identity server you have chosen does not have any terms of services. Only continue if you trust the owner of the service A text message has been sent to %s. Please enter the verification code it contains. - You are currently sharing email addresses or phone numbers on the identity server %s. You will need to reconnect to %s to stop sharing them. + You are currently sharing email addresses or phone numbers on the identity server %1$s. You will need to reconnect to %2$s to stop sharing them. Agree to the identity server (%s) Terms of Service to allow yourself to be discoverable by email address or phone number. Enable verbose logs. From e2da74a752b59ebe3029e640f8baa546964e8102 Mon Sep 17 00:00:00 2001 From: Valere Date: Fri, 25 Oct 2019 11:39:53 +0200 Subject: [PATCH 21/77] Fix potential NPE on logout --- CHANGES.rst | 2 +- .../java/im/vector/activity/CommonActivityUtils.java | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index cf7977cf35..e1c54b6854 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -14,7 +14,7 @@ Other changes: - Bugfix 🐛: - - + - Crash / potential NPE after logout (#3367) Translations 🗣: - diff --git a/vector/src/main/java/im/vector/activity/CommonActivityUtils.java b/vector/src/main/java/im/vector/activity/CommonActivityUtils.java index 600be07ba3..c35210e830 100755 --- a/vector/src/main/java/im/vector/activity/CommonActivityUtils.java +++ b/vector/src/main/java/im/vector/activity/CommonActivityUtils.java @@ -436,15 +436,12 @@ public void onSuccess(Void info) { if (goToLoginPage) { Activity activeActivity = VectorApp.getCurrentActivity(); + final Context activeContext = (null == activeActivity) ? VectorApp.getInstance().getApplicationContext() : activeActivity; + // go to login page - Intent intent = new Intent(activeActivity, LoginActivity.class); + Intent intent = new Intent(activeContext, LoginActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); - - if (null != activeActivity) { - activeActivity.startActivity(intent); - } else { - context.startActivity(intent); - } + activeContext.startActivity(intent); } } }); From 5b1d295e4f07c32bf1da203c544599a598cd31b4 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 24 Oct 2019 15:55:30 +0000 Subject: [PATCH 22/77] Translated using Weblate (Catalan) Currently translated at 86.6% (1084 of 1252 strings) Translation: Riot Android/Riot Android Translate-URL: https://translate.riot.im/projects/riot-android/riot-android/ca/ --- vector/src/main/res/values-ca/strings.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/vector/src/main/res/values-ca/strings.xml b/vector/src/main/res/values-ca/strings.xml index d9af5deb46..9be9a0c077 100644 --- a/vector/src/main/res/values-ca/strings.xml +++ b/vector/src/main/res/values-ca/strings.xml @@ -1430,13 +1430,13 @@ Per què triar Riot.im? Ho sentim, els dispositius amb SO Android inferior a 5.0 no suporten trucades multi-usuari amb Jitsi No heu configurat cap administrador d\'integracions. - Un nou dispositiu està sol·licitant claus d\'encriptació. -\nNom del dispositiu: %1$s -\nVist per última vegada: %s$s + Un nou dispositiu està sol·licitant claus d\'encriptació. +\nNom del dispositiu: %1$s +\nVist per última vegada: %2$s \nSi no heu iniciat sessió en un altre dispositiu, ignoreu la sol·licitud. - Un dispositiu no verificat està sol·licitant claus d\'encriptació. -\nNom del dispositiu: %1$s -\nVist per última vegada: %s$s + Un dispositiu no verificat està sol·licitant claus d\'encriptació. +\nNom del dispositiu: %1$s +\nVist per última vegada: %2$s \nSi no heu iniciat sessió en un altre dispositiu, ignoreu la sol·licitud. Verificar From 5151c9108279da9de9f74f75c07595cbb29832a0 Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Fri, 25 Oct 2019 03:01:17 +0000 Subject: [PATCH 23/77] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (1252 of 1252 strings) Translation: Riot Android/Riot Android Translate-URL: https://translate.riot.im/projects/riot-android/riot-android/zh_Hant/ --- vector/src/main/res/values-zh-rTW/strings.xml | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/vector/src/main/res/values-zh-rTW/strings.xml b/vector/src/main/res/values-zh-rTW/strings.xml index b54c05b784..1bee9de8f8 100644 --- a/vector/src/main/res/values-zh-rTW/strings.xml +++ b/vector/src/main/res/values-zh-rTW/strings.xml @@ -1653,4 +1653,72 @@ Matrix 中的消息可見度類似于電子郵件。我們忘記您的郵件意 您目前正在身份識別伺服器 %1$s 上分享電子郵件地址或電話號碼。您將必須重新連線到 %2$s 以停止分享它們。 同意身份識別伺服器 (%s) 的服務條款以允許您被透過電子郵件地址或電話號碼探索。 +緯度 + + 啟用詳細紀錄。 + 詳細紀錄可以協助開發者在您傳送憤怒搖晃時取得更多紀錄。即使啟用這個設定,應用程式依然不會紀錄訊息內容或任何個人資料。 + + + 請在您接受您家伺服器的條款與條件前繼續重試。 + + 看起來伺服器回應時間似乎太久了,這可能是不良的網路連線或我們的伺服器錯誤所造成。請稍後再試。 + + 傳送附件 + + 開啟導航選單 + 開啟建立聊天室選單 + 關閉建立聊天室選單…… + 建立新的直接對話 + 建立新的聊天室 + 關閉金鑰備份橫幅 + 顯示密碼 + 隱藏密碼 + 跳到底部 + + %1$s、%2$s 與 %3$d 個其他人已閱讀 + %1$s、%2$s 與 %3$d 已閱讀 + %1$s 與 %2$s 已閱讀 + %s 已閱讀 + + %d 個使用者已閱讀 + + + 檔案「%1$s」(%2$s) 太大無法上傳。限制為 %3$s。 + + 在擷取附件時遇到錯誤。 + 檔案 + 聯絡人 + 相機 + 音訊 + 相簿 + 貼圖 + 無法處理分享資料 + + 垃圾訊息 + 不合適 + 自訂回報 + 回報此內容 + 回報此內容的理由 + 回報 + 封鎖使用者 + + 內容已回報 + 此內容已回報。 +\n +\n如果您不想要看到從此使用者而來的更多內容,您可以封鎖他以隱藏他的訊息 + 回報為垃圾訊息 + 此內容已被回報為垃圾訊息。 +\n +\n如果您不想要看到從此使用者而來的更多內容,您可以封鎖他以隱藏他的訊息 + 回報為不合適 + 此內容已被回報為不合適。 +\n +\n如果您不想要看到從此使用者而來的更多內容,您可以封鎖他以隱藏他的訊息 + + Riot 需要權限以在磁碟上儲存您的 E2E 金鑰。 +\n +\n請在下個彈出視窗中允許存取以讓您可以手動匯出您的金鑰。 + + 目前沒有網路連線 + From 214fddf9e4ca1e11ee5cd401213700d8bd496051 Mon Sep 17 00:00:00 2001 From: Tuomas Hietala Date: Thu, 24 Oct 2019 17:55:56 +0000 Subject: [PATCH 24/77] Translated using Weblate (Finnish) Currently translated at 93.5% (1171 of 1252 strings) Translation: Riot Android/Riot Android Translate-URL: https://translate.riot.im/projects/riot-android/riot-android/fi/ --- vector/src/main/res/values-fi/strings.xml | 72 +++++++++++++++++------ 1 file changed, 53 insertions(+), 19 deletions(-) diff --git a/vector/src/main/res/values-fi/strings.xml b/vector/src/main/res/values-fi/strings.xml index 3b037a9ead..78856d0309 100644 --- a/vector/src/main/res/values-fi/strings.xml +++ b/vector/src/main/res/values-fi/strings.xml @@ -175,8 +175,8 @@ Kotipalvelin: Identiteettipalvelin: Olen varmistanut sähköpostiosoitteeni - Nollataksesi salasanasi, anna tilisi sähköpostiosoite: - Anna tilisi sähköpostiosoite. + Palauttaaksesi salasanasi, anna tiliisi liitetty sähköpostiosoite: + Anna tiliisi liitetty sähköpostiosoite. Anna uusi salasana. Osoitteeseen %s on lähetetty sähköposti. Kun olet avannut siinä olevan linkin, paina alla olevaa nappia. Sähköpostiosoitteesi vahvistaminen epäonnistui. Varmista, että klikkasit sähköpostissa olevaa linkkiä @@ -1190,12 +1190,12 @@ Haluatko lisätä paketteja? Jatkaaksesi kotipalvelimen %1$s käyttöä, sinun täytyy hyväksyä palvelun käyttöehdot. Näytä ehdot - Tämä tekee tunnuksestasi lopullisesti käyttökelvottoman. Et voi kirjautua sisään eikä kukaan pysty rekisteröimään tunnusta samalla käyttäjä-ID:llä. Tämä saa tunnuksesi lähtemään kaikista huoneista, joissa se on osallisena, ja se poistaa tunnuksen tiedot identiteettipalvelimelta. Tämä toiminto on peruuttamaton. + Tämä tekee tilistäsi lopullisesti käyttökelvottoman. Et voi kirjautua sisään eikä kukaan pysty rekisteröitymään samalla käyttäjätunnuksella. Tämä saa tilisi poistumaan kaikista huoneista, joissa se on osallisena, ja poistaa tilin tiedot identiteettipalvelimelta. Tämä toiminto on peruuttamaton. \n -\nTunnuksen otto pois käytöstä ei oletuksena saa meitä unohtamaan lähettämiäsi viestejä. Jos haluat meidän unohtavan viestisi, merkitse alapuolella oleva laatikko. +\nTilin deaktivointi ei oletuksena saa meitä unohtamaan lähettämiäsi viestejä. Jos haluat meidän unohtavan viestisi, merkitse alapuolella oleva valintaruutu. \n -\nViestin näkyvyys Matrixissa on samanlainen kuin sähköpostissa. Vaikka unohdamme viestisi, kaikki tahot, joilla viestisi jo on, tulevat pääsemään omaan kopioonsa viesteistäsi. - Unohda kaikki viestit, jotka olen lähittänyt, kun tunnuksesi on deaktivoitu (varoitus: tämä aiheuttaa tulevien käyttäjien näkevän vanhat keskustelusi epätäydellisinä) +\nViestien näkyvyys Matrixissa on samantapainen kuin sähköpostissa. Viestiesi unohtaminen tarkoittaa, että lähettämiäsi viestejä ei näytetä uusille tai rekisteröitymättömille käyttäjille. Ne rekisteröityneet käyttäjät, joilla viestisi jo on, pääsevät kuitenkin näkemään oman kopionsa niistä jatkossakin. + Unohda kaikki viestit, jotka olen lähettänyt, kun tilini on deaktivoitu (Varoitus: tästä seuraa, että tulevat käyttäjät näkevät vanhat keskustelut epätäydellisinä) Syötä käyttäjätunnus. Tämä huone on korvattu toisella huoneella Keskustelu jatkuu täällä @@ -1258,9 +1258,9 @@ Jotta et menetä mitään, automaattiset päivitykset kannattaa pitää käytös Tallenna avaimet käsin Turvaa varmuuskopiosi salalauseella. - Tallennamme salatun kopion avaimistasi kotipalvelimellesi. Suojaa varmuuskopiosi salalauseella pitääksesi sen turvattuna. -\n -\nTurvallisuuden takia tämän salalauseen tulisi olla eri tunnuksesi salasanasta. + Tallennamme salatun kopion avaimistasi kotipalvelimellesi. Suojaa varmuuskopiosi salalauseella pitääksesi sen turvattuna. +\n +\nParhaan turvallisuuden takaamiseksi salalauseen tulisi olla eri kuin tilisi salasana. Aseta salalause Luodaan varmuuskopiota Tai, turvaa varmuuskopio palautusavaimella, tallentamalla palautusavain johonkin turvalliseen paikkaan. @@ -1387,25 +1387,25 @@ Jotta et menetä mitään, automaattiset päivitykset kannattaa pitää käytös %1$s -> %2$s - Keskusteluohjelma, joka on täysin hallinnoitavissasi ja erittäin joustava. Riot sallii sinun kommunikoivan juuri sillä tavalla kuin haluat. [matrix]-sovellus — avoimen ja hajautetun kommunikaation standardi. + Keskustelusovellus, joka on sinun hallinnassasi ja erittäin joustava. Riot antaa sinun viestiä juuri sillä tavalla kuin haluat. Taustalla [matrix] – avoimen ja hajautetun viestinnän standardi. \n -\nKäytä ilmaista matrix.org-tunnusta, hanki oma palvelimesi osoitteesta https://modular.im tai käytä muuta Matrix-palvelinta. +\nHanki ilmainen matrix.org-tili, hanki oma palvelimesi osoitteesta https://modular.im tai käytä muuta Matrix-palvelinta. \n \nMiksi valita Riot.im\? \n -\n• Täydellinen kommunikaatio: rakenna huoneita tiimeillesi, ystävillesi ja yhteisöllesi — juuri niin kuin haluat! Keskustele, jaa tiedostoja, lisää sovelmia ja tee ääni‐ ja videopuheluita — kaikki tämä ilmaiseksi. -\n -\n• Tehokkaat integraatiot: Käytä Riotia juuri niillä työkaluilla, jotka tiedät ja joita rakastat. Riot.im jopa mahdollistaa keskustelun henkilöiden kanssa, jotka käyttävät eri keskusteluohjelmia. +\n• Kattavat mahdollisuudet viestintään: rakenna huoneita tiimeillesi, ystävillesi ja yhteisöllesi – juuri niin kuin haluat! Keskustele, jaa tiedostoja, lisää sovelmia ja soita ääni‐ ja videopuheluita – kaikki tämä ilmaiseksi. +\n +\n• Tehokkaat integraatiot: Käytä Riotia tuntemiesi työkalujen kanssa. Riot.im mahdollistaa keskustelut jopa eri keskusteluohjelmia käyttävien ihmisten ja ryhmien kanssa. \n -\n• Yksityinen ja turvallinen: Pidä keskustelusi salaisina. Nykyaikainen osapuolten välinen salaus pitää huolen, että yksityiset keskustelut pysyvät yksityisenä. +\n• Yksityinen ja turvallinen: Pidä keskustelusi salaisina. Nykyaikainen osapuolten välinen salaus pitää huolen, että yksityiset keskustelut pysyvät yksityisinä. \n -\n• Avoin, ei suljettu: Avointa koodia, ja rakennettu käyttämään Matrixia. Voit omistaa oman datasi ylläpitämällä omaa palvelintasi, tai käyttämällä palvelinta, johon luotat. +\n• Avoin, ei suljettu: Avointa lähdekoodia ja rakennettu käyttämään Matrixia. Voit omistaa oman datasi ylläpitämällä omaa palvelintasi, tai käyttämällä palvelinta, johon luotat. \n -\n• Kaikkialla, missä olet: pysy yhteydessä siellä, missä ikinä oletkin täysin synkronoidulla viestihistorialla kaikkien laitteidesi ja sivun https://riot.im välillä. +\n• Kaikkialla, missä olet: pysy yhteydessä missä ikinä oletkin, täysin synkronoidulla viestihistorialla kaikkien laitteidesi ja https://riot.im-verkkopalvelun välillä. - Uusi avainvarmuuskopio on löydetty. + Uusi avainvarmuuskopio löydetty. \n -\nJos et asettanut uutta palautustapaa, hyökkääjä saattaa yrittää päästä käsiksi tunnukseesi. Vaihda tunnuksesi salasana ja aseta uusi palautustapa asetuksissa välittömästi. +\nJos et asettanut uutta palautustapaa, hyökkääjä saattaa yrittää päästä käsiksi tiliisi. Vaihda tilisi salasana ja aseta uusi palautustapa asetuksissa välittömästi. Epäkelpo kotipalvelimen löytövastaus Automaattitäydennyksen palvelinasetukset Riot löysi mukautetun palvelinasetuksen userId:si domainille ”%1$s”: @@ -1657,4 +1657,38 @@ Jotta et menetä mitään, automaattiset päivitykset kannattaa pitää käytös Valitsemallasi identiteettipalvelimella ei ole käyttöehtoja. Jatka vain, jos luotat palvelun omistajaan Jaat sähköpostiosoitteita tai puhelinnumeroita identiteettipalvelimella %1$s. Sinun täytyy yhdistää uudelleen palvelimeen %2$s, jotta voit lopettaa niiden jakamisen. Hyväksy identiteettipalvelimen (%s) käyttöehdot salliaksesi, että sinut voi löytää sähköpostiosoitteen tai puhelinnumeron perusteella. +Aseta sähköposti tilin palauttamista varten. Myöhemmin voit halutessasi antaa ihmisten etsiä sinua sen perusteella. + Salli varalla oleva puhelun apupalvelin + Yhteyden katkaiseminen identiteettipalvelimeesi tarkoittaa, että muut käyttäjät eivät voi etsiä sinua etkä voi kutsua muita sähköpostin tai puhelinnumeron perusteella. + Lähetimme sinulle vahvistussähköpostin osoitteeseen %s, tarkista sähköpostisi ja klikkaa vahvistuslinkkiä + Ota yksityiskohtaiset lokit käyttöön. + Yritä uudelleen, kun olet hyväksynyt kotipalvelimesi käyttöehdot. + + Palvelimen vastaus näyttää viipyvän. Tämä voi johtua kehnosta yhteydestä tai palvelimillamme tapahtuneesta virheestä. Yritä hetken kuluttua uudelleen. + + Lähetä liite + + Luo uusi huone + Näytä salasana + Piilota salasana + Siirry loppuun + + %1$s, %2$s ja %3$d muuta lukivat + %1$s, %2$s ja %3$s lukivat + %1$s ja %2$s lukivat + %s luki + + 1 käyttäjä luki + %d käyttäjää luki + + + Liitettä noudettaessa tapahtui virhe. + Tiedosto + Kamera + Galleria + Tarra + Se on roskapostia + Se on sopimaton + Verkkoyhteyttä ei ole juuri nyt + From a90c2fe56dc78e2851b28853499b68b1fb72006e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20C?= Date: Fri, 25 Oct 2019 07:56:09 +0000 Subject: [PATCH 25/77] Translated using Weblate (French) Currently translated at 100.0% (1252 of 1252 strings) Translation: Riot Android/Riot Android Translate-URL: https://translate.riot.im/projects/riot-android/riot-android/fr/ --- vector/src/main/res/values-fr/strings.xml | 71 ++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/vector/src/main/res/values-fr/strings.xml b/vector/src/main/res/values-fr/strings.xml index 1fe493d9d4..d65e0f3756 100644 --- a/vector/src/main/res/values-fr/strings.xml +++ b/vector/src/main/res/values-fr/strings.xml @@ -783,7 +783,7 @@ Appareils inconnus : Abandonner le salon Badge - Secouer avec frustration pour signaler un bug + Secouer avec frustration pour signaler une anomalie Actions Synchronisation… @@ -1701,4 +1701,73 @@ Si vous n’avez pas configuré de nouvelle méthode de récupération, un attaq Vous partagez actuellement des adresse e-mails et des numéros de téléphone sur le serveur d’identité %1$s. Vous devrez vous reconnecter à %2$s pour arrêter de les partager. Acceptez les conditions de service du serveur d’identité (%s) pour vous permettre d’être découvrable avec une adresse e-mail ou un numéro de téléphone. +Latn + + Activer les journaux verbeux. + Les journaux verbeux aideront les développeurs en fournissant plus de journaux quand vous envoyez un rapport d’anomalie. Même si cette option est activée, l’application n’envoie pas le contenu des messages ou toute autre donnée personnelle. + + + Réessayez quand vous aurez accepté les termes et conditions de votre serveur d’accueil. + + On dirait que le serveur mette trop de temps à répondre. Ça peut être dû à une mauvaise connexion ou à une erreur avec nos serveurs. Réessayez plus tard. + + Envoyer une pièce jointe + + Ouvrir le menu de navigation + Ouvrir le menu de création de salon + Fermer le menu de création de salon… + Créer une nouvelle conversation directe + Créer un nouveau salon + Fermer la bannière de sauvegarde des clés + Afficher le mot de passe + Masquer le mot de passe + Sauter en bas de page + + %1$s, %2$s et %3$d autres ont lu + %1$s, %2$s et %3$s ont lu + %1$s et %2$s ont lu + %s a lu + + 1 utilisateur a lu + %d utilisateurs ont lu + + + Le fichier « %1$s » (%2$s) est trop gros pour être envoyé. La limite est %3$s. + + Une erreur est survenue pendant la récupération de la pièce jointe. + Fichier + Contact + Appareil photo + Audio + Galerie + Sticker + Impossible de traiter les données de partage + + C’est du pourriel + C’est inapproprié + Signalement personnalisé + Signaler ce contenu + Motif de signalement de ce contenu + SIGNALER + BLOQUER L’UTILISATEUR + + Contenu signalé + Ce contenu a été signalé. +\n +\nSi vous ne voulez plus voir de contenu de cet utilisateur, vous pouvez le bloquer pour masquer ses messages + Signalé comme pourriel + Ce contenu a été signalé comme pourriel. +\n +\nSi vous ne voulez plus voir de contenu de cet utilisateur, vous pouvez le bloquer pour masquer ses messages + Signalé comme inapproprié + Ce contenu a été signalé comme inapproprié. +\n +\nSi vous ne voulez plus voir de contenu de cet utilisateur, vous pouvez le bloquer pour masquer ses messages + + Riot a besoin de votre permission pour sauvegarder vos clés de chiffrement sur le disque. +\n +\nAutorisez l’accès dans le prochaine fenêtre pour pouvoir exporter vos clés manuellement. + + Il n’y a aucune connexion au réseau pour le moment + From d51d00691007003b8c26e29fda9f6cb4b5d44930 Mon Sep 17 00:00:00 2001 From: dccs Date: Fri, 25 Oct 2019 12:33:37 +0000 Subject: [PATCH 26/77] Translated using Weblate (German) Currently translated at 91.2% (1142 of 1252 strings) Translation: Riot Android/Riot Android Translate-URL: https://translate.riot.im/projects/riot-android/riot-android/de/ --- vector/src/main/res/values-de/strings.xml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/vector/src/main/res/values-de/strings.xml b/vector/src/main/res/values-de/strings.xml index b8b86b5081..c31eb7c2a2 100644 --- a/vector/src/main/res/values-de/strings.xml +++ b/vector/src/main/res/values-de/strings.xml @@ -1656,4 +1656,16 @@ Wenn du diese neue Wiederherstellungsmethode nicht eingerichtet hast, kann ein A app_id: Überprüfung - +Keine + Widerrufen + Trennen + Kein Integrationsserver konfiguriert. + + Anruf aufgrund eines falsch konfigurierten Servers fehlgeschlagen + Versuchen Sie es mit %@ + Nicht erneut fragen + + Richten Sie eine E-Mail für die Kontowiederherstellung ein, die später von Personen, die Sie kennen, optional gefunden werden kann. + Richten Sie ein Telefon ein und lassen Sie es später optional von Personen erkennen, die Sie kennen. + Legen Sie eine E-Mail für die Kontowiederherstellung fest. Verwenden Sie eine spätere E-Mail oder ein späteres Telefon, um von Personen, die Sie kennen, optional gefunden zu werden. + From ec8cd1971b6213ed5cb00b88da80dd26f25df2dc Mon Sep 17 00:00:00 2001 From: Szimszon Date: Fri, 25 Oct 2019 10:01:15 +0000 Subject: [PATCH 27/77] Translated using Weblate (Hungarian) Currently translated at 100.0% (1252 of 1252 strings) Translation: Riot Android/Riot Android Translate-URL: https://translate.riot.im/projects/riot-android/riot-android/hu/ --- vector/src/main/res/values-hu/strings.xml | 77 +++++++++++++++++++++-- 1 file changed, 73 insertions(+), 4 deletions(-) diff --git a/vector/src/main/res/values-hu/strings.xml b/vector/src/main/res/values-hu/strings.xml index 2e13eb7531..7a3a05eedf 100644 --- a/vector/src/main/res/values-hu/strings.xml +++ b/vector/src/main/res/values-hu/strings.xml @@ -1021,7 +1021,7 @@ Vedd figyelembe, hogy az alkalmazás újraindul ami sok időt vehet igénybe.Elküld Ezeket az embereket biztosan kirúgod? - + Ok @@ -1249,11 +1249,11 @@ Figyelmeztetés: ez a fájl törlésre kerülhet, ha az alkalmazást törlik.Visszaállítva: %1$d kapcsolati kulcs, és %2$d kulcs, ami(k) ismeretlenek voltak az eszköz számára, hozzáadva Visszaállított mentés %d kulccsal. - + %d új kulcs lett hozzáadva ehhez az eszközhöz. - + "Nem sikerült beszerezni a legfrissebb verziójú visszaállítási kulcsot (%s)." @@ -1332,7 +1332,7 @@ A Visszaállítási Kulcsot tartsd biztonságos helyen, mint pl. egy jelszókeze Minden kulcs elmentve %d kulcs mentése… - + Verzió @@ -1700,4 +1700,73 @@ Ha nem te állítottad be a visszaállítási metódust, akkor egy támadó pró Az azonosítási szerverrel (%1$s) megosztod az e-mail címeket és telefonszámokat. Újra kell csatlakoznod ehhez: %2$s, hogy megállítsd a megosztást. Egyetértek az azonosítási szerver (%s) Felhasználási feltételeivel ahhoz, hogy megtalálható legyek e-mail címmel vagy telefonszámmal. +Latn + + Kibővített naplózás engedélyezése. + A kiterjesztett naplózás a fejlesztőknek nyújt több információt amikor hibajegyet küldesz. Még bekapcsolva sem naplóz üzenet tartalmat vagy más személyes adatot. + + + Kérlek ismételd meg miután elfogadtad a matrix szervered felhasználási feltételeit. + + Úgy tűnik a szerver sokáig nem válaszol, ennek a bizonytalan kapcsolat vagy egy hiba a szerverünkben lehet az oka. Kicsit később próbáld újra. + + Csatolmány küldése + + Navigációs panel megnyitása + Szoba készítés menü megnyitása + Szoba készítés menü bezárása… + Új közvetlen beszélgetés indítása + Új szoba készítése + Kulcs mentés csík bezárása + Jelszó mutatása + Jelszó elrejtése + Végére ugrás + + %1$s, %2$s és %3$d olvasták + %1$s, %2$s és %3$s olvasták + %1$s és %2$s olvasták + %s olvasta + + 1 felhasználó olvasta + %d felhasználó olvasta + + + \'%1$s\' (%2$s) fájl túl nagy a feltöltéshez. A korlát: %3$s. + + A csatolmány letöltésénél hiba történt. + Fájl + Kapcsolat + Kamera + Hang + Galéria + Matrica + Az adatmegosztást nem sikerül kezelni + + Ez nemkívánt (spam) + Ez nem idevaló + Egyedi jelentés + Tartalom bejelentése + A tartalom bejelentésének oka + JELENTÉS + FELHASZNÁLÓ BLOKKOLÁSA + + Tartalom bejelentve + Ez a tartalom bejelentve. +\n +\nHa nem akarsz ettől a felhasználótól több üzenetet látni akkor blokkolhatod, hogy az üzenetei ne jelenjenek meg számodra + Bejelentve nem kívántként (spam) + Ez a tartalom nem kívántnak (spam) lett bejelentve. +\n +\n Ha nem akarsz ettől a felhasználótól több üzenetet látni akkor blokkolhatod, hogy az üzenetei ne jelenjenek meg számodra + Nem idevalónak bejelentve + Ez a tartalom nem idevalónak lett bejelentve. +\n +\n Ha nem akarsz ettől a felhasználótól több üzenetet látni akkor blokkolhatod, hogy az üzenetei ne jelenjenek meg számodra + + Riotnak engedélyre van szüksége ahhoz, hogy a végponttól végpontig titkosító kulcsokat a lemezre menthesse. +\n +\nKérlek a következő felugró ablakban engedélyezd a hozzáférést, hogy a kulcsokat kézzel kimenthesd. + + Jelenleg nincs hálózati kapcsolat + From 9fc1e588a88919527cf7d87e0e5bac3bc37c9da4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=86=A1=ED=83=9C=EC=84=AD?= Date: Fri, 25 Oct 2019 09:59:05 +0000 Subject: [PATCH 28/77] Translated using Weblate (Korean) Currently translated at 100.0% (1252 of 1252 strings) Translation: Riot Android/Riot Android Translate-URL: https://translate.riot.im/projects/riot-android/riot-android/ko/ --- vector/src/main/res/values-ko/strings.xml | 84 ++++++++++++++++++++--- 1 file changed, 76 insertions(+), 8 deletions(-) diff --git a/vector/src/main/res/values-ko/strings.xml b/vector/src/main/res/values-ko/strings.xml index 7f76e47ea7..24abda3fad 100644 --- a/vector/src/main/res/values-ko/strings.xml +++ b/vector/src/main/res/values-ko/strings.xml @@ -412,8 +412,8 @@ 초대 이 방 떠나기 이 방에서 삭제하기 - 차단 - 차단 해제 + 출입 금지 + 출입 금지 풀기 추방 일반 사용자로 재 설정 중재자로 하기 @@ -432,7 +432,7 @@ 이 사용자들을 이 대화에서 추방하겠습니까\? - 이 사용자를 이 대화에서 차단하겠습니까\? + 이 사용자를 이 대화에서 출입 금지하겠습니까\? 이유 %s님을 이 대화에 초대하겠습니까\? @@ -720,7 +720,7 @@ 읽은 기록 보이기 세부적인 목록으로 읽은 목록을 클릭하세요. 참가 및 떠남 이벤트 보이기 - 초대, 추방, 그리고 차단은 영향이 없습니다. + 초대, 추방, 그리고 출입 금지은 영향이 없습니다. 계정 이벤트 보이기 아바타와 표시 이름 변경도 포함합니다. 사용자가 언급할 때 진동 @@ -854,7 +854,7 @@ 방의 링크를 아는 누구나, 손님 제외 방의 링크를 아는 누구나, 손님 포함 - 차단한 사용자 + 출입 금지한 사용자 고급 이 방의 내부 ID @@ -1064,8 +1064,8 @@ 인식할 수 없는 명령어: %s \"%s\" 명령어는 더 많은 매개 변수가 필요하거나, 일부 매개 변수가 옳지 않습니다. 활동 표시하기 - 주어진 ID로 사용자 차단하기 - 주어진 ID로 사용자 차단 풀기 + 주어진 ID로 사용자 출입 금지하기 + 주어진 ID로 사용자 출입 금지 풀기 사용자의 권한 등급 정의하기 주어진 ID로 사용자 강등하기 주어진 ID 현재 방에 사용자 초대하기 @@ -1114,7 +1114,7 @@ 커뮤니티 관리자가 이 커뮤니티에 대한 자세한 설명을 제공하지 않았습니다. %2$s님에 의해 %1$s 방에서 추방당했습니다 - %2$s님에 의해 %1$s 방에서 차단당했습니다 + %2$s님에 의해 %1$s 방에서 출입 금지당했습니다 이유: %1$s 다시 참가하기 방 잊어버리기 @@ -1623,4 +1623,72 @@ 현재 이메일 주소나 전화번호를 ID 서버 %1$s와 공유하고 있습니다. 공유하기를 중지하려면 %2$s(으)로 다시 연결해야 합니다. ID 서버 (%s)의 서비스 약관에 동의하면 다른 사용자가 당신을 이메일 주소나 전화번호로 찾을 수 있게 됩니다. +Latn + + 상세 로그 켜기. + 상세 로그는 분노의 흔들기를 보낼 때 더 많은 로그를 제공해서 개발자에게 도움을 줍니다. 이 설정을 켜도 애플리케이션은 메시지 내용이나 다른 개인 정보를 기록하지 않습니다. + + + 홈서버의 이용 약관에 동의한 후 다시 시도해주세요. + + 서버의 응답 시간이 지연되고 있습니다. 연결 상태가 좋지 않거나 서버에서 오류가 발생했을지도 모릅니다. 나중에 다시 시도해주세요. + + 첨부 파일 보내기 + + 내비게이션 서랍 열기 + 방 만들기 메뉴 열기 + 방 만들기 메뉴 닫기… + 새 다이렉트 대화 만들기 + 새 방 만들기 + 키 백업 배너 닫기 + 비밀번호 보이기 + 비밀번호 감추기 + 맨 아래로 건너뛰기 + + %1$s님, %2$s님 외 %3$d명이 읽음 + %1$s님, %2$s님 그리고 %3$s님이 읽음 + %1$s님 그리고 %2$s님이 읽음 + %s님이 읽음 + + %d명이 읽음 + + + 파일 \'%1$s\' (%2$s)이(가) 업로드하기에 너무 큽니다. 제한은 %3$s입니다. + + 첨부 파일을 검색하는 중 오류가 발생했습니다. + 파일 + 연락처 + 카메라 + 소리 + 갤러리 + 스티커 + 공유 데이터를 처리할 수 없음 + + 스팸 문자입니다 + 부적절한 문자입니다 + 맞춤 신고 + 이 내용 신고하기 + 이 내용을 신고하는 이유 + 신고 + 사용자 출입 금지 + + 내용 신고됨 + 이 내용을 신고했습니다. +\n +\n이 사용자의 내용을 더 이상 보고 싶지 않다면, 사용자를 차단하거나 메시지를 감출 수 있습니다 + 스팸 문자로 신고됨 + 이 내용을 스팸 메일로 신고했습니다. +\n +\n이 사용자의 내용을 더 이상 보고 싶지 않다면, 사용자를 차단하거나 메시지를 감출 수 있습니다 + 부적절한 문자로 신고됨 + 이 내용을 부적절한 문자로 신고했습니다. +\n +\n이 사용자의 내용을 더 이상 보고 싶지 않다면, 사용자를 차단하거나 메시지를 감출 수 있습니다 + + Riot은 종단간 키를 디스크에 저장하려면 권한이 필요합니다. +\n +\n키를 수동으로 내보내려면 다음 팝업에서 접근을 허용해주세요. + + 현재 네트워크 연결이 없습니다 + From 0f504d9ae70777015e47e1ae46f40f9c2be4d2f5 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 24 Oct 2019 15:54:55 +0000 Subject: [PATCH 29/77] Translated using Weblate (Spanish) Currently translated at 85.8% (1074 of 1252 strings) Translation: Riot Android/Riot Android Translate-URL: https://translate.riot.im/projects/riot-android/riot-android/es/ --- vector/src/main/res/values-es/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vector/src/main/res/values-es/strings.xml b/vector/src/main/res/values-es/strings.xml index 894f7e3d47..252acefabc 100644 --- a/vector/src/main/res/values-es/strings.xml +++ b/vector/src/main/res/values-es/strings.xml @@ -1420,8 +1420,8 @@ Ten en cuenta que esta acción reiniciará la aplicación y puede tardar algo de Firma autocompletar opciones del servidor - Riot ha detectado una configuración personalizada del servidor para el dominio de su ID de usuario \"%s\": -\n%s + Riot ha detectado una configuración personalizada del servidor para el dominio de su ID de usuario \"%1$s\": +\n%2$s Configuración de uso Origen predeterminado de medios From ffe700b392092a548704f7d0f00991f9464483c2 Mon Sep 17 00:00:00 2001 From: Tiffany Thuy Kim Nguyen Date: Fri, 25 Oct 2019 23:38:45 +0000 Subject: [PATCH 30/77] Translated using Weblate (Spanish (Mexico)) Currently translated at 43.2% (541 of 1252 strings) Translation: Riot Android/Riot Android Translate-URL: https://translate.riot.im/projects/riot-android/riot-android/es_MX/ --- vector/src/main/res/values-es-rMX/strings.xml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/vector/src/main/res/values-es-rMX/strings.xml b/vector/src/main/res/values-es-rMX/strings.xml index 423ecb5438..9ae9d36794 100644 --- a/vector/src/main/res/values-es-rMX/strings.xml +++ b/vector/src/main/res/values-es-rMX/strings.xml @@ -779,4 +779,9 @@ Dispositivos desconocidos: Enviar una respuesta cifrada… Enviar una respuesta (sin cifrar)… - +Latn + + Iniciando servicio + Copia de seguridad de la clave + Usar copia de seguridad de la clave + From 5d03d10b05f2683c8448b54a36a127bdfdd82b2c Mon Sep 17 00:00:00 2001 From: Tuomas Hietala Date: Wed, 30 Oct 2019 14:24:00 +0000 Subject: [PATCH 31/77] Translated using Weblate (Finnish) Currently translated at 94.4% (1182 of 1252 strings) Translation: Riot Android/Riot Android Translate-URL: https://translate.riot.im/projects/riot-android/riot-android/fi/ --- vector/src/main/res/values-fi/strings.xml | 76 ++++++++++++++--------- 1 file changed, 46 insertions(+), 30 deletions(-) diff --git a/vector/src/main/res/values-fi/strings.xml b/vector/src/main/res/values-fi/strings.xml index 78856d0309..6f5973ea7f 100644 --- a/vector/src/main/res/values-fi/strings.xml +++ b/vector/src/main/res/values-fi/strings.xml @@ -6,7 +6,7 @@ FI - Keskustelut + Viestit Huone Asetukset Jäsenen tiedot @@ -155,7 +155,7 @@ Toista salasana Vahvista uusi salasanasi Väärä käyttäjätunnus ja/tai salasana - Käyttäjätunnus saa koostua vain kirjaimista a-z, numeroista, pisteistä, väliviivoista ja alaviivoista + Käyttäjätunnus saa koostua vain kirjaimista a-z, numeroista, pisteistä, yhdysviivoista ja alaviivoista Liian lyhyt salasana (vähintään 6 merkkiä) Salasana puuttuu Tämä ei näytä oikealta sähköpostiosoitteelta @@ -183,7 +183,7 @@ Salasanasi on vaihdettu.\n\nSinut on kirjauduttu ulos kaikista laitteistasi, etkä enää saa viesti-ilmoituksia. Ottaaksesi käyttöön ilmoitukset uudelleen, kirjaudu sisään uudelleen kaikilla laitteillasi. - URL:n on alettava seuraavasti: http[s]:// + URL-osoitteen on alettava seuraavasti: http[s]:// Kirjautuminen epäonnistui: Verkkovirhe Kirjautuminen epäonnistui Rekisteröityminen epäonnistui: Verkkovirhe @@ -232,7 +232,7 @@ Yhdistetty Yhdistetään… - Puhelu loppu + Puhelu loppui Soitetaan… Saapuva puhelu Saapuva videopuhelu @@ -285,7 +285,7 @@ Hylkää - Hyppää ensimmäiseen lukemattomaan viestiin. + Siirry ensimmäiseen lukemattomaan viestiin. %s on kutsunut sinut huoneeseen @@ -298,7 +298,7 @@ Uusi keskustelu Lisää jäsen - 1 jäsen + yksi jäsen Poistu huoneesta @@ -349,7 +349,7 @@ Lähetä salattu viesti… Lähetä viesti (salaamaton)… Yhteys palvelimeen katkesi. - Viesteja ei lähetetty. %1$s vai %2$s\? + Viestejä ei lähetetty. %1$s vai %2$s\? Viestejä ei lähetetty koska huoneessa on tuntemattomia laitteita. %1$s vai %2$s\? Lähetä kaikki uudelleen Peruuta kaikki @@ -423,7 +423,7 @@ Unohda - Keskustelut + Viestit Asetukset Versio Käyttöehdot @@ -785,9 +785,9 @@ Yhteisöt Ei ryhmiä - Oletko varma, että haluat aloittaa uuden keskustelun käyttäjän %s kanssa\? - Oletko varma että haluat aloittaa äänipuhelun? - Oletko varma, että haluat aloittaa videopuhelun? + Haluatko varmasti aloittaa uuden keskustelun käyttäjän %s kanssa\? + Haluatko varmasti aloittaa äänipuhelun\? + Haluatko varmasti aloittaa videopuhelun\? Ryhmälistaus @@ -933,13 +933,13 @@ Haluatko lisätä paketteja? Avaa otsikko Synkronoidaan… - yksi aktiivinen käyttäjä - %d aktiivista käyttäjää - + yksi aktiivinen jäsen + %d aktiivista jäsentä + - yksi käyttäjä - %d käyttäjää - + yksi jäsen + %d jäsentä + 1 s %d s @@ -1136,13 +1136,13 @@ Haluatko lisätä paketteja? Kirjoita tähän… - yksi lukematon viesti - %d lukematonta viestiä - + yksi lukematon ilmoitettu viesti + %d lukematonta ilmoitettua viestiä + - 1 lukematon viesti - %d lukematonta viestiä - + yksi lukematon ilmoitettu viesti + %d lukematonta ilmoitettua viestiä + yksi huone %d huonetta @@ -1156,7 +1156,7 @@ Haluatko lisätä paketteja? Parametri ei ole kelvollinen. Käynnistä järjestelmän kamera Riotin kameraruudun sijaan. Käytä näppäimistön rivinvaihtopainiketta viestin lähettämiseen - Tämä vaihtoehto vaatii kolmannen osapuolen sovelluksen viestien tallennukseen. + Tämä valinta vaatii kolmannen osapuolen sovelluksen viestien tallennukseen. Komento ”%s” vaatii enemmän parametreja, tai jotkin parametrit ovat virheellisiä. Näyttää toiminnon @@ -1200,7 +1200,7 @@ Haluatko lisätä paketteja? Tämä huone on korvattu toisella huoneella Keskustelu jatkuu täällä Tämä huone on jatkoa toiselle keskustelulle - Täppää tästä nähdäksesi vanhat viestit + Paina tästä nähdäksesi vanhemmat viestit Resurssiraja saavutettu Ota yhteys ylläpitäjään @@ -1227,7 +1227,7 @@ Haluatko lisätä paketteja? Näytä infoalue Aina - Tiedotuksille ja virheille + Viesteille ja virheille Vain virheille %1$s: @@ -1249,7 +1249,7 @@ Jotta et menetä mitään, automaattiset päivitykset kannattaa pitää käytös Poista salalause, jos haluat Riotin generoivan palautusavaimen. Matrix-istuntoa ei ole saatavilla - Älä ikinä menetä salattuja viestejä + Älä koskaan menetä salattuja viestejä Salatuissa huoneissa viestit ovat suojattuna osapuolten välisellä salauksella. Vain sinä ja vastaanottaja(t) omistavat avaimet näiden viestien lukemiseen. \n \nVarmuuskopioi avaimesi, jotta et menetä niitä. @@ -1377,7 +1377,7 @@ Jotta et menetä mitään, automaattiset päivitykset kannattaa pitää käytös Kirjaudu sisään kertakirjautumisella Tämä osoite ei ole saavutettavissa. Tarkistathan osoitteen - Laitteesi käyttää vanhentunutta, haavoittuvaista TLS-protokollan versiota. Turvallisuutesi vuoksi et pysty yhdistämään + Laitteesi käyttää vanhentunutta, haavoittuvaista TLS-protokollan versiota. Turvallisuutesi tähden et voi muodostaa yhteyttä Lähetä viesti enter-näppäimellä Näppäimistön enter-näppäin lähettää viestin sen sijaan, että se lisäisi rivinvaihdon @@ -1646,7 +1646,7 @@ Jotta et menetä mitään, automaattiset päivitykset kannattaa pitää käytös Katkaise yhteys identiteettipalvelimeen Määritä identiteettipalvelin Vaihda identiteettipalvelinta - Käytät palvelinta %1$s löytääksesi tuntemiasi ihmisiä ja jotta he löytäisivät sinut. + Käytät palvelinta %1$s löytääksesi tuntemiasi ihmisiä ja ollaksesi heidän löydettävissään. Et käytä tällä hetkellä identiteettipalvelinta. Jotta voit löytää tuntemiasi ihmisiä ja jotta he löytävät sinut, määritä identiteettipalvelin alla. Odottaa @@ -1691,4 +1691,20 @@ Jotta et menetä mitään, automaattiset päivitykset kannattaa pitää käytös Se on sopimaton Verkkoyhteyttä ei ole juuri nyt - +Ei mitään + Pyydä kotipalvelimesi (%1$s) ylläpitäjää määrittämään TURN-palvelin, jotta puhelut toimivat luotettavasti. +\n +\nVaihtoehtoisesti voit yrittää käyttää julkista palvelinta osoitteessa %2$s, mutta tämä ei ole yhtä luotettava vaihtoehto ja antaa IP-osoitteesi kyseisen palvelimen tietoon. Voit myös hallita tätä asetuksista. + Kokeile käyttää palvelinta %s + Käyttää palvelinta %s apupalvelimena, jos kotipalvelimesi ei tarjoa sellaista (IP-osoitteesi näkyy palvelimelle puhelun aikana) + Optimoitu akunkestoa varten + Riot synkronoi taustalla laitteen rajallisia resursseja (akkua) säästäen. +\nLaitteesi resurssien tilasta riippuen käyttöjärjestelmä saattaa lykätä synkronointia. + Optimoitu reaaliaikaa varten + Riot synkronoi taustalla täsmällisin aikavälein (säädettävä). +\nTämä vaikuttaa radion ja akun käyttöön. Näet pysyvän ilmoituksen, joka kertoo, että Riot kuuntelee tapahtumia. + Viestimuokkaukset + Ole löydettävissä + Tekstiviesti on lähetetty numeroon %s. Syötä sen sisältämä varmistuskoodi. + + From 6d64e820dbd995dcb80cad6db7a355b8edb525b3 Mon Sep 17 00:00:00 2001 From: dccs Date: Mon, 28 Oct 2019 09:29:46 +0000 Subject: [PATCH 32/77] Translated using Weblate (German) Currently translated at 93.9% (1176 of 1252 strings) Translation: Riot Android/Riot Android Translate-URL: https://translate.riot.im/projects/riot-android/riot-android/de/ --- vector/src/main/res/values-de/strings.xml | 60 +++++++++++++++++++---- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/vector/src/main/res/values-de/strings.xml b/vector/src/main/res/values-de/strings.xml index c31eb7c2a2..790cc432c7 100644 --- a/vector/src/main/res/values-de/strings.xml +++ b/vector/src/main/res/values-de/strings.xml @@ -343,7 +343,7 @@ Bist du sicher? Nachrichten konnten nicht gesendet werden. %1$s oder %2$s? Nachrichten wurden nicht gesendet, da unbekannte Geräte anwesend sind. %1$s oder %2$s? Alles erneut senden - Senden abbrechen + alles abbrechen Nicht gesendete Nachrichten erneut senden Nicht gesendete Nachrichten löschen Datei nicht gefunden @@ -445,7 +445,7 @@ Beachte: Diese Aktion wird die App neu starten und einige Zeit brauchen.Hintergrundsynchronisierung Hintergrundsynchronisierung aktivieren Timeout für Synchronisierungsanfragen - Verzögerung zwischen jeder Anfrage + Verzögerung zwischen jeder Synchronisierung Sekunde Sekunden @@ -473,10 +473,10 @@ Beachte: Diese Aktion wird die App neu starten und einige Zeit brauchen.Räume mit ungelesenen Benachrichtigungen anheften Räume mit ungelesenen Nachrichten anheften Geräte - Geräte-Details + Geräte Information ID - Name - Gerätename + Öffentlicher Name + Öffentlichen Namen aktualisieren Zuletzt gesehen %1$s @ %2$s Diese Operation benötigt weitere Authentifizierung. @@ -607,9 +607,9 @@ Beachte: Diese Aktion wird die App neu starten und einige Zeit brauchen.Entschlüsselungsfehler Absendergeräteinformationen - Gerätename - Name - Geräte-ID + Öffentlicher Name + Öffentlicher Name + ID Geräte-Schlüssel Verifizierungsstatus Ed25519-Fingerabdruck @@ -1552,8 +1552,8 @@ Wenn du diese neue Wiederherstellungsmethode nicht eingerichtet hast, kann ein A Überprüfen Sie dieses Gerät, um es als vertrauenswürdig zu markieren. Das Vertrauen auf Geräte von Partnern gibt Ihnen zusätzliche Sicherheit, wenn Sie verschlüsselte End-to-End-Nachrichten verwenden. Das Verifizieren dieses Benutzers wird seine Geräte als \"vertraut\" markieren und dein Gerät bei ihnen als \"vertraut\" markieren. - Verifizieren Sie diesen Benutzer, indem Sie bestätigen, dass folgendes Emoji auf dessen Bildschirm erscheint. - Verifizieren Sie diesen Benutzer, indem Sie bestätigen, dass die folgende Nummer auf dessen Bildschirm erscheint. + Überprüfen Sie dieses Gerät, indem Sie bestätigen, dass das folgende Emoji auf dem Bildschirm des Partners angezeigt wird + Überprüfen Sie dieses Gerät, indem Sie bestätigen, dass die folgenden Zahlen auf dem Bildschirm des Partners angezeigt werden Es ist nichts aufgetaucht\? Noch nicht alle Clients unterstützen die interaktive Verifikation. . Verwenden Sie die Alte-Überprüfung @@ -1668,4 +1668,44 @@ Wenn du diese neue Wiederherstellungsmethode nicht eingerichtet hast, kann ein A Richten Sie eine E-Mail für die Kontowiederherstellung ein, die später von Personen, die Sie kennen, optional gefunden werden kann. Richten Sie ein Telefon ein und lassen Sie es später optional von Personen erkennen, die Sie kennen. Legen Sie eine E-Mail für die Kontowiederherstellung fest. Verwenden Sie eine spätere E-Mail oder ein späteres Telefon, um von Personen, die Sie kennen, optional gefunden zu werden. + Legen Sie eine E-Mail für die Kontowiederherstellung fest. Verwenden Sie eine spätere E-Mail oder ein späteres Telefon, um von Personen, die Sie kennen, optional gefunden zu werden. + Fallback-Call-Assist-Server zulassen + Optimiert für die Batterie + Optimiert für die Echtzeit + Keine Hintergrundsynchronisation + Fehler beim Aktualisieren der Einstellungen. + + + Bevorzugtes Synchronisationsintervall + Discovery + Öffentlicher Name (sichtbar für Personen, mit denen Sie kommunizieren) + Der öffentliche Name eines Geräts ist für Personen sichtbar, mit denen Sie kommunizieren + Um fortzufahren, müssen Sie die Bedingungen dieses Dienstes akzeptieren. + + Sie verwenden keinen Identity Server + Es ist kein Identitätsserver konfiguriert. Sie müssen Ihr Kennwort zurücksetzen. + + Sie versuchen anscheinend, eine Verbindung zu einem anderen Homeserver herzustellen. Möchten Sie sich abmelden\? + + push_key: + app_display_name: + Url: + Nutzungsbedingungen + Nutzungsbedingungen überprüfen + Für andere auffindbar sein + Verwenden Sie Bots, Bridges, Widgets und Sticker-Packs + + Lesen Sie bei + + + Identitätsserver + Trennen Sie den Identitätsserver + Konfigurieren Sie den Identitätsserver + Identitätsserver ändern + Erkennbare E-Mail-Adressen + Erkennungsoptionen werden angezeigt, sobald Sie eine E-Mail hinzugefügt haben. + ausstehend + + Gib einen neuen Identitätsserver ein + Konnte keine Verbindung zum Heimserver herstellen. From f97547cf32712067fc1416c802bb4bb3cf9374f1 Mon Sep 17 00:00:00 2001 From: random Date: Tue, 29 Oct 2019 13:16:14 +0000 Subject: [PATCH 33/77] Translated using Weblate (Italian) Currently translated at 100.0% (1252 of 1252 strings) Translation: Riot Android/Riot Android Translate-URL: https://translate.riot.im/projects/riot-android/riot-android/it/ --- vector/src/main/res/values-it/strings.xml | 69 +++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/vector/src/main/res/values-it/strings.xml b/vector/src/main/res/values-it/strings.xml index 1c879ad794..74035998ab 100644 --- a/vector/src/main/res/values-it/strings.xml +++ b/vector/src/main/res/values-it/strings.xml @@ -1745,4 +1745,73 @@ Per essere certo di non perdere nulla, mantieni gli aggiornamenti attivi."Attualmente stai condividendo indirizzi email o numeri di telefono sul server di identità %1$s. Dovrai riconnetterti a %2$s per fermarne la condivisione. Accetta le condizioni di servizio del server di identità (%s) per consentire di essere trovabile per email o numero di telefono. +Latn + + Attiva log dettagliati. + I log dettagliati aiuteranno gli sviluppatori fornendo loro più informazioni quando invii una segnalazione. Anche quando attivi, l\'applicazione non registra i contenuti dei messaggi o altri dati personali. + + + Riprova dopo avere accettato i termini e condizioni del tuo homeserver. + + Sembra che il server stia impiegando troppo tempo a rispondere, ciò può essere causato da scarsa connettività o un errore con i nostri server. Riprova fra qualche minuto. + + Invia allegato + + Apri il pannello di navigazione + Apri il menu di creazione stanza + Chiudi il menu di creazione stanza… + Crea una nuova conversazione diretta + Crea una nuova stanza + Chiudi il banner di backup chiavi + Mostra password + Nascondi password + Salta in fondo + + %1$s, %2$s ed altri %3$d hanno letto + %1$s, %2$s e %3$s hanno letto + %1$s e %2$s hanno letto + %s ha letto + + 1 utente ha letto + %d utenti hanno letto + + + Il file \'%1$s\' (%2$s) è troppo grande da inviare. Il limite è %3$s. + + Si è verificato un errore ricevendo l\'allegato. + File + Contatto + Fotocamera + Audio + Galleria + Adesivo + Errore di gestione dati condivisi + + È spam + È inappropriato + Segnalazione personalizzata + Segnala questo contenuto + Motivo della segnalazione + SEGNALA + BLOCCA UTENTE + + Contenuto segnalato + Questo contenuto è stato segnalato. +\n +\nSe non vuoi più vedere contenuti da questo utente, puoi bloccarlo per nascondere i suoi messaggi + Segnalato come spam + Questo contenuto è stato segnalato come spam. +\n +\nSe non vuoi più vedere contenuti da questo utente, puoi bloccarlo per nascondere i suoi messaggi + Segnalato come inappropriato + Questo contenuto è stato segnalato come inappropriato. +\n +\nSe non vuoi più vedere contenuti da questo utente, puoi bloccarlo per nascondere i suoi messaggi + + Riot richiede l\'autorizzazione per salvare le tue chiavi E2E su disco. +\n +\nPermetti l\'accesso nel prossimo pop-up per poter esportare le chiavi manualmente. + + Non c\'è nessuna connessione di rete al momento + From 7f68718df1086bfeac408ac1079fc8c2c2199a41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=86=A1=ED=83=9C=EC=84=AD?= Date: Tue, 29 Oct 2019 06:59:47 +0000 Subject: [PATCH 34/77] Translated using Weblate (Korean) Currently translated at 100.0% (1252 of 1252 strings) Translation: Riot Android/Riot Android Translate-URL: https://translate.riot.im/projects/riot-android/riot-android/ko/ --- vector/src/main/res/values-ko/strings.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/vector/src/main/res/values-ko/strings.xml b/vector/src/main/res/values-ko/strings.xml index 24abda3fad..2a01a279e0 100644 --- a/vector/src/main/res/values-ko/strings.xml +++ b/vector/src/main/res/values-ko/strings.xml @@ -302,8 +302,8 @@ 방 주제 전화 - 오는 전화에 Riot 기본 벨소리를 사용합니다 - 오는 전화 벨소리 + 수신 전화에 Riot 기본 벨소리를 사용합니다 + 수신 전화 벨소리 전화에 사용할 벨소리를 선택하세요: 전화 @@ -311,9 +311,9 @@ 전화 연결 중… 전화 종료됨 전화 중… - 오는 전화 - 오는 영상 통화 - 오는 음성 통화 + 수신 전화 + 수신 영상 통화 + 수신 음성 통화 전화 진행 중… 영상 통화 진행 중… @@ -1584,7 +1584,7 @@ Riot은 (설정할 수 있는) 특정 시간에 주기적으로 백그라운드에거 동기화됩니다. \n이는 라디오와 배터리 사용에 영향을 주며 Riot이 이벤트를 수신하고 있는 상태라는 알림이 영구적으로 표시됩니다. 백그라운드 동기화 없음 - 앱이 백그라운드에 있을 때 오는 메시지의 알림을 받지 않습니다. + 앱이 백그라운드에 있을 때 수신 메시지의 알림을 받지 않습니다. 설정을 업데이트하는데 실패했습니다. From 7c0e671dedc9d0957bd62964ac48dccb62a8d209 Mon Sep 17 00:00:00 2001 From: Walter Date: Tue, 29 Oct 2019 14:39:15 +0000 Subject: [PATCH 35/77] Translated using Weblate (Russian) Currently translated at 96.6% (1209 of 1252 strings) Translation: Riot Android/Riot Android Translate-URL: https://translate.riot.im/projects/riot-android/riot-android/ru/ --- vector/src/main/res/values-ru/strings.xml | 43 +++++++++++++---------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/vector/src/main/res/values-ru/strings.xml b/vector/src/main/res/values-ru/strings.xml index eaad9bf4aa..c2c8e30378 100644 --- a/vector/src/main/res/values-ru/strings.xml +++ b/vector/src/main/res/values-ru/strings.xml @@ -96,7 +96,7 @@ %d пользователь %d пользователя %d пользователей - + Отправить логи @@ -843,13 +843,13 @@ %d комната %d комнаты %d комнат - + %d комната %d комнаты %d комнат - + %1$s в %2$s @@ -857,7 +857,7 @@ %d активный виджет %d активных виджета %d активных виджетов - + @@ -867,45 +867,45 @@ %d активный участник %d активных участника %d активных участников - + %d участник %d участника %d участников - + %d новое сообщение %d новых сообщения %d новых сообщений - + %1$s комната найдена для %2$s %1$s комнаты найдено для %2$s %1$s комнат найдено для %2$s - + %d изменение членства %d изменения членства %d изменений членства - + %d непрочитанное уведомление %d непрочитанных уведомления %d непрочитанных уведомлений - + %d непрочитанное уведомление %d непрочитанных уведомления %d непрочитанных уведомлений - + Получить аватар Заметка аватара @@ -1020,13 +1020,13 @@ %dm %dm %dm - + %dh %dh %dh - + %d день @@ -1045,20 +1045,20 @@ %d выбран %d выбрано %d выбраны - + %d участник %d участника %d участников - + %d комната %d комнаты %d комнат - + Системные оповещения @@ -1346,7 +1346,7 @@ %d новый ключ был добавлен к этому устройству. %d новых ключа были добавлены к этому устройству. %d новых ключей были добавлены к этому устройству. - + @@ -1398,7 +1398,7 @@ Резервное копирование %d ключа… Резервное копирование %d ключей… Резервное копирование %d ключей… - + Все ключи сохранены @@ -1792,4 +1792,9 @@ В настоящее время вы делитесь адресами электронной почты или телефонными номерами на сервере идентификации %1$s. Вам нужно повторно подключиться к %2$s, чтобы прекратить делиться ими. Примите Условия обслуживания сервера идентификации (%s), чтобы разрешить обнаружение по адресу электронной почты или номеру телефона. - +Включить подробное журнал. + Отправить вложенное + + Откройте навигационный ящик + Откройте меню «Создать комнату» + From 471f8442c2bf373dfcbf90ed2ac1a082a76dd9d8 Mon Sep 17 00:00:00 2001 From: Osoitz Date: Fri, 1 Nov 2019 09:08:06 +0000 Subject: [PATCH 36/77] Translated using Weblate (Basque) Currently translated at 100.0% (1252 of 1252 strings) Translation: Riot Android/Riot Android Translate-URL: https://translate.riot.im/projects/riot-android/riot-android/eu/ --- vector/src/main/res/values-eu/strings.xml | 69 +++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/vector/src/main/res/values-eu/strings.xml b/vector/src/main/res/values-eu/strings.xml index 9e02bf8103..675bc74932 100644 --- a/vector/src/main/res/values-eu/strings.xml +++ b/vector/src/main/res/values-eu/strings.xml @@ -1697,4 +1697,73 @@ Abisua: Fitxategi hau ezabatu daiteke aplikazioa desinstalatzen bada. Orain e-mail helbideak edo telefono zenbakiak partekatzen dituzu %1$s zerbitzarian. %2$s zerbitzarira konektatu beharko zara partekatzeari uzteko. Onartu %s identitate-zerbitzariaren erabilera baldintzak besteek zu e-mail helbidea edo telefonoa erabiliz aurkitzea ahalbidetzeko. +Latn + + Gaitu egunkari xehetsuak. + Amorruz astintzean egunkari xehetsuak bidaltzeak garatzaileei laguntzen diete. Gaituta badago ere, aplikazioak ez ditu mezuen edukiak edo beste datu probaturik gordetzen egunkarian. + + + Saiatu berriro zure hasiera-zerbitzariaren erabilera baldintzak onartu eta gero. + + Badirudi zerbitzariak luze hartu duela erantzuteko, hau konexio kaxkar baten ondorioz izan daiteke edo zerbitzarian errore bat dagoelako. Saiatu berriro geroago. + + Bidali eranskina + + Ireki nabigazio-tiradera + Ireki gela sortzeko menua + Itxi gela sortzeko menua… + Sortu elkarrizketa zuzen berria + Sortu gela berria + Itxi gakoen babes-kopiaren banda + Erakutsi pasahitza + Ezkutatu pasahitza + Jauzi behera + + %1$s, %2$s eta beste %3$d erabiltzailek irakurria + %1$s, %2$s eta%3$s erabiltzaileek irakurria + %1$s eta %2$s erabiltzaileek irakurria + %s erabiltzaileak irakurria + + Erabiltzaile batek irakurria + %d erabiltzailek irakurria + + + \'%1$s\' fitxategia (%2$s) handiegia da igotzeko. Muga %3$s da. + + Errore bat gertatu da eranskina eskuratzean. + Fitxategia + Kontaktua + Kamera + Audioa + Galeria + Eranskailua + Ezin izan dira partekatutako datuak kudeatu + + Spama da + Desegokia da + Salaketa pertsonalizatua + Salatu eduki hau + Eduki hau salatzeko arrazoia + SALATU + BLOKEATU ERABILTZAILEA + + Edukia salatuta + Eduki hau salatu da. +\n +\nEz baduzu erabiltzaile honen eduki gehiago ikusi nahi, bere mezuak ezkutatzeko blokeatu dezakezu + Spam gisa salatua + Eduki hau spam gisa salatu da. +\n +\nEz baduzu erabiltzaile honen eduki gehiago ikusi nahi, bere mezuak ezkutatzeko blokeatu dezakezu + Desegoki gisa salatua + Eduki hau desegoki gisa salatu da. +\n +\nEz baduzu erabiltzaile honen eduki gehiago ikusi nahi, bere mezuak ezkutatzeko blokeatu dezakezu + + Riot-ek zure E2E gakoak diskoan gordetzeko baimena behar du. +\n +\nBaimendu sarbidea hurrengo laster-leihoan zure gakoak eskuz esportatu ahal izateko. + + Ez dago sare konexiorik orain + From 3a9c845837cf4ba851e6fea3adfbeb828f7cda1b Mon Sep 17 00:00:00 2001 From: Elwyn Malethan Date: Sun, 3 Nov 2019 11:31:37 +0000 Subject: [PATCH 37/77] Added translation using Weblate (Welsh) --- vector/src/main/res/values-cy/strings.xml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 vector/src/main/res/values-cy/strings.xml diff --git a/vector/src/main/res/values-cy/strings.xml b/vector/src/main/res/values-cy/strings.xml new file mode 100644 index 0000000000..a6b3daec93 --- /dev/null +++ b/vector/src/main/res/values-cy/strings.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file From 38c57f9bae23554bfb8268242c2c866f316702b8 Mon Sep 17 00:00:00 2001 From: Valere Date: Wed, 23 Oct 2019 10:35:37 +0200 Subject: [PATCH 38/77] WidgetManagerProvider no more singleton, but attached to session --- vector/src/main/java/im/vector/Matrix.java | 33 ++++++-- .../vector/activity/AbstractWidgetActivity.kt | 8 +- .../im/vector/activity/JitsiCallActivity.java | 22 ++++-- .../vector/activity/VectorRoomActivity.java | 37 +++++---- .../java/im/vector/activity/WidgetActivity.kt | 16 ++-- .../im/vector/util/PreferencesManager.java | 6 ++ .../im/vector/util/SlashCommandsParser.java | 15 +++- .../im/vector/view/ActiveWidgetsBanner.java | 19 ++++- .../view/VectorOngoingConferenceCallView.java | 18 ++++- .../vector/widgets/WidgetManagerProvider.kt | 77 +++++++++++++++---- vector/src/main/res/values/strings.xml | 1 + .../res/xml/vector_settings_preferences.xml | 6 ++ 12 files changed, 198 insertions(+), 60 deletions(-) diff --git a/vector/src/main/java/im/vector/Matrix.java b/vector/src/main/java/im/vector/Matrix.java index 8ba21131d7..60701b1c26 100755 --- a/vector/src/main/java/im/vector/Matrix.java +++ b/vector/src/main/java/im/vector/Matrix.java @@ -117,6 +117,8 @@ public class Matrix { @Nullable private KeyRequestHandler mKeyRequestHandler; + private HashMap mWidgetManagerProviders = new HashMap<>(); + // i.e the event has been read from another client private static final MXEventListener mLiveEventListener = new MXEventListener() { boolean mClearCacheRequired = false; @@ -133,10 +135,12 @@ public void onIgnoredUsersListUpdate() { public void onLiveEvent(Event event, RoomState roomState) { mRefreshUnreadCounter |= Event.EVENT_TYPE_MESSAGE.equals(event.getType()) || Event.EVENT_TYPE_RECEIPT.equals(event.getType()); - // TODO update to manage multisessions - WidgetsManager wm = WidgetManagerProvider.INSTANCE.getWidgetManager(VectorApp.getInstance().getApplicationContext()); - if (wm != null) { - wm.onLiveEvent(instance.getDefaultSession(), event); + WidgetManagerProvider wp = instance.mWidgetManagerProviders.get(instance.getDefaultSession().getMyUserId()); + if (wp != null) { + WidgetsManager wm = wp.getWidgetManager(VectorApp.getInstance().getApplicationContext()); + if (wm != null) { + wm.onLiveEvent(instance.getDefaultSession(), event); + } } } @@ -306,6 +310,23 @@ public List getSessions() { return sessions; } + @Nullable + public WidgetManagerProvider getWidgetManagerProvider(MXSession session) { + if (session == null) { + return null; + } + return mWidgetManagerProviders.get(session.getMyUserId()); + } + + @Nullable + public static WidgetsManager getWidgetManager(Context activity) { + if (Matrix.getInstance(activity) == null) return null; + MXSession session = Matrix.getInstance(activity).getDefaultSession(); + if (session == null) return null; + WidgetManagerProvider widgetManagerProvider = Matrix.getInstance(activity).getWidgetManagerProvider(session); + if (widgetManagerProvider == null) return null; + return widgetManagerProvider.getWidgetManager(activity); + } /** * Retrieve the default session if one exists. *

@@ -648,7 +669,9 @@ public synchronized void addSession(MXSession session) { * @return The session. */ public MXSession createSession(HomeServerConnectionConfig hsConfig) { - return createSession(mAppContext, hsConfig); + MXSession session = createSession(mAppContext, hsConfig); + mWidgetManagerProviders.put(session.getMyUserId(), new WidgetManagerProvider(session)); + return session; } /** diff --git a/vector/src/main/java/im/vector/activity/AbstractWidgetActivity.kt b/vector/src/main/java/im/vector/activity/AbstractWidgetActivity.kt index a4905a2152..68ed3582e7 100755 --- a/vector/src/main/java/im/vector/activity/AbstractWidgetActivity.kt +++ b/vector/src/main/java/im/vector/activity/AbstractWidgetActivity.kt @@ -35,7 +35,6 @@ import im.vector.types.JsonDict import im.vector.types.WidgetEventData import im.vector.util.AssetReader import im.vector.util.toJsonMap -import im.vector.widgets.WidgetManagerProvider import im.vector.widgets.WidgetsManager import org.jetbrains.anko.toast import org.matrix.androidsdk.MXSession @@ -88,7 +87,8 @@ abstract class AbstractWidgetActivity : VectorAppCompatActivity() { @CallSuper override fun initUiAndData() { - mSession = Matrix.getInstance(this).getSession(intent.getStringExtra(EXTRA_MATRIX_ID)) + val matrix = Matrix.getInstance(this) + mSession = matrix.getSession(intent.getStringExtra(EXTRA_MATRIX_ID)) if (null == mSession || !mSession!!.isAlive) { Log.e(LOG_TAG, "## onCreate() : invalid session") @@ -100,7 +100,7 @@ abstract class AbstractWidgetActivity : VectorAppCompatActivity() { mRoom = mSession!!.dataHandler.getRoom(intent.getStringExtra(EXTRA_ROOM_ID)) - widgetManager = WidgetManagerProvider.getWidgetManager(this) ?: run { + widgetManager = matrix.getWidgetManagerProvider(mSession)?.getWidgetManager(this) ?: run { finish() return } @@ -149,7 +149,7 @@ abstract class AbstractWidgetActivity : VectorAppCompatActivity() { } private fun presentTermsForServices(token: String) { - val wm = WidgetManagerProvider.getWidgetManager(this) + val wm = Matrix.getInstance(this).getWidgetManagerProvider(mSession)?.getWidgetManager(this)//WidgetManagerProvider.getWidgetManagerProvider(this) if (wm == null) { // should not happen finish() return diff --git a/vector/src/main/java/im/vector/activity/JitsiCallActivity.java b/vector/src/main/java/im/vector/activity/JitsiCallActivity.java index 7a9ec345e2..6113f75c6f 100755 --- a/vector/src/main/java/im/vector/activity/JitsiCallActivity.java +++ b/vector/src/main/java/im/vector/activity/JitsiCallActivity.java @@ -27,6 +27,7 @@ import com.facebook.react.modules.core.PermissionListener; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jitsi.meet.sdk.JitsiMeetActivityDelegate; import org.jitsi.meet.sdk.JitsiMeetActivityInterface; import org.jitsi.meet.sdk.JitsiMeetConferenceOptions; @@ -109,10 +110,7 @@ public int getLayoutRes() { @Override @SuppressLint("NewApi") public void initUiAndData() { - if (WidgetManagerProvider.INSTANCE.getWidgetManager(this) == null) { - finish(); - return; - } + // Waiting View setWaitingView(findViewById(R.id.jitsi_progress_layout)); @@ -136,6 +134,10 @@ public void initUiAndData() { return; } + if (getWidgetManager() == null) { + finish(); + return; + } mRoom = mSession.getDataHandler().getRoom(mWidget.getRoomId()); if (null == mRoom) { @@ -237,7 +239,7 @@ public void onNewIntent(Intent intent) { protected void onStop() { super.onStop(); JitsiMeetActivityDelegate.onHostPause(this); - WidgetsManager wm = WidgetManagerProvider.INSTANCE.getWidgetManager(this); + WidgetsManager wm = getWidgetManager(); if (wm != null) { wm.removeListener(mWidgetListener); } @@ -253,12 +255,20 @@ protected void onResume() { super.onResume(); JitsiMeetActivityDelegate.onHostResume(this); - WidgetsManager wm = WidgetManagerProvider.INSTANCE.getWidgetManager(this); + WidgetsManager wm = getWidgetManager(); if (wm != null) { wm.addListener(mWidgetListener); } } + @Nullable + private WidgetsManager getWidgetManager() { + if (mSession == null) return null; + WidgetManagerProvider widgetManagerProvider = Matrix.getInstance(this).getWidgetManagerProvider(mSession); + if (widgetManagerProvider == null) return null; + return widgetManagerProvider.getWidgetManager(this); + } + @Override public void onBackPressed() { JitsiMeetActivityDelegate.onBackPressed(); diff --git a/vector/src/main/java/im/vector/activity/VectorRoomActivity.java b/vector/src/main/java/im/vector/activity/VectorRoomActivity.java index a76802317a..539db45a0c 100755 --- a/vector/src/main/java/im/vector/activity/VectorRoomActivity.java +++ b/vector/src/main/java/im/vector/activity/VectorRoomActivity.java @@ -864,7 +864,7 @@ public void onCloseWidgetClick(final Widget widget) { .setPositiveButton(R.string.remove, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - WidgetsManager wm = WidgetManagerProvider.INSTANCE.getWidgetManager(VectorRoomActivity.this); + WidgetsManager wm = Matrix.getWidgetManager(VectorRoomActivity.this); if (wm != null) { showWaitingView(); @@ -969,7 +969,7 @@ public void onVideoCallClick(Widget widget) { @Override public void onCloseWidgetClick(Widget widget) { - WidgetsManager wm = WidgetManagerProvider.INSTANCE.getWidgetManager(VectorRoomActivity.this); + WidgetsManager wm = Matrix.getWidgetManager(VectorRoomActivity.this); if (wm != null) { showWaitingView(); @@ -1493,7 +1493,7 @@ public boolean onPrepareOptionsMenu(Menu menu) { return true; } - boolean hasIntegrationManager = WidgetManagerProvider.INSTANCE.getWidgetManager(this) != null; + boolean hasIntegrationManager = Matrix.getWidgetManager(this) != null; // the menu is only displayed when the current activity does not display a timeline search if (TextUtils.isEmpty(mEventId) && (null == sRoomPreviewData)) { @@ -1637,7 +1637,7 @@ private void openIntegrationManagerActivity(@Nullable String screenId) { return; } - WidgetsManager wm = WidgetManagerProvider.INSTANCE.getWidgetManager(this); + WidgetsManager wm = Matrix.getWidgetManager(this); if (wm == null) { //Should not happen this action is not activated if no wm return; @@ -1779,7 +1779,7 @@ private void launchJitsiActivity(Widget widget, boolean aIsVideoCall) { * @param aIsVideoCall true if the call is a video one */ private void startJitsiCall(final boolean aIsVideoCall) { - WidgetsManager wm = WidgetManagerProvider.INSTANCE.getWidgetManager(this); + WidgetsManager wm = Matrix.getWidgetManager(this); if (wm != null) { enableActionBarHeader(HIDE_ACTION_BAR_HEADER); showWaitingView(); @@ -3871,7 +3871,7 @@ private void chooseMediaSource(boolean useNativeCamera, boolean isVoiceFeatureEn } // Send sticker - if (WidgetManagerProvider.INSTANCE.getWidgetManager(this) != null) { + if (Matrix.getWidgetManager(this) != null) { items.add(DialogListItem.SendSticker.INSTANCE); } @@ -4009,13 +4009,13 @@ void onStartCallClick() { .setIcon(android.R.drawable.ic_dialog_alert) .setPositiveButton(R.string.ok, null) .show(); - } else if (WidgetManagerProvider.INSTANCE.getWidgetManager(this) == null) { - // display the dialog with the info text - new AlertDialog.Builder(this) - .setMessage(R.string.integration_manager_not_configured) - .setIcon(android.R.drawable.ic_dialog_alert) - .setPositiveButton(R.string.ok, null) - .show(); +// } else if (Matrix.getWidgetManager(this) == null) { +// // display the dialog with the info text +// new AlertDialog.Builder(this) +// .setMessage(R.string.integration_manager_not_configured) +// .setIcon(android.R.drawable.ic_dialog_alert) +// .setPositiveButton(R.string.ok, null) +// .show(); } else if (isUserAllowedToStartConfCall()) { if (mRoom.getNumberOfMembers() > 2) { new AlertDialog.Builder(this) @@ -4026,7 +4026,16 @@ void onStartCallClick() { @Override public void onClick(DialogInterface dialog, int which) { if (PreferencesManager.useJitsiConfCall(VectorRoomActivity.this)) { - startJitsiCall(true); + if (Matrix.getWidgetManager(VectorRoomActivity.this) == null) { + // display the dialog with the info text + new AlertDialog.Builder(VectorRoomActivity.this) + .setMessage(R.string.integration_manager_not_configured) + .setIcon(android.R.drawable.ic_dialog_alert) + .setPositiveButton(R.string.ok, null) + .show(); + } else { + startJitsiCall(true); + } } else { displayVideoCallIpDialog(); } diff --git a/vector/src/main/java/im/vector/activity/WidgetActivity.kt b/vector/src/main/java/im/vector/activity/WidgetActivity.kt index a74d8e537f..ecb17db300 100755 --- a/vector/src/main/java/im/vector/activity/WidgetActivity.kt +++ b/vector/src/main/java/im/vector/activity/WidgetActivity.kt @@ -37,7 +37,6 @@ import butterknife.OnClick import im.vector.Matrix import im.vector.R import im.vector.widgets.Widget -import im.vector.widgets.WidgetManagerProvider import im.vector.widgets.WidgetsManager import org.jetbrains.anko.toast import org.matrix.androidsdk.MXSession @@ -104,14 +103,17 @@ class WidgetActivity : VectorAppCompatActivity() { return } - widgetsManager = WidgetManagerProvider.getWidgetManager(this) ?: run { - Log.e(LOG_TAG, "## onCreate() : No widget manager ") - finish() - return - } - mSession = Matrix.getMXSession(this, mWidget!!.sessionId) + + widgetsManager = Matrix.getInstance(this).getWidgetManagerProvider(mSession)?.getWidgetManager(this) + ?: run { + Log.e(LOG_TAG, "## onCreate() : No widget manager ") + finish() + return + } + + if (null == mSession) { Log.e(LOG_TAG, "## onCreate() : invalid session") finish() diff --git a/vector/src/main/java/im/vector/util/PreferencesManager.java b/vector/src/main/java/im/vector/util/PreferencesManager.java index e6ee643bec..b626a146ed 100755 --- a/vector/src/main/java/im/vector/util/PreferencesManager.java +++ b/vector/src/main/java/im/vector/util/PreferencesManager.java @@ -170,6 +170,7 @@ public class PreferencesManager { public static final String SETTINGS_USE_RAGE_SHAKE_KEY = "SETTINGS_USE_RAGE_SHAKE_KEY"; //Integrations + public static final String SETTINGS_INTEGRATION_ALLOW = "SETTINGS_INTEGRATION_ALLOW"; public static final String SETTINGS_INTEGRATION_MANAGER_UI_URL = "SETTINGS_INTEGRATION_MANAGER_UI_URL"; public static final String SETTINGS_INTEGRATION_MANAGER_API_URL = "SETTINGS_INTEGRATION_MANAGER_API_URL"; public static final String SETTINGS_INTEGRATION_MANAGER_JITSI_URL = "SETTINGS_INTEGRATION_MANAGER_JITSI_URL"; @@ -289,6 +290,11 @@ public static void setDidAskUserToIgnoreBatteryOptimizations(Context context) { .apply(); } + public static Boolean areIntegrationAllowed(Context context) { + return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SETTINGS_INTEGRATION_ALLOW, + true); + } + public static String getIntegrationManagerUiUrl(Context context) { return PreferenceManager.getDefaultSharedPreferences(context).getString(SETTINGS_INTEGRATION_MANAGER_UI_URL, context.getString(R.string.integrations_ui_url)); diff --git a/vector/src/main/java/im/vector/util/SlashCommandsParser.java b/vector/src/main/java/im/vector/util/SlashCommandsParser.java index c16ee5d827..710ca5342e 100755 --- a/vector/src/main/java/im/vector/util/SlashCommandsParser.java +++ b/vector/src/main/java/im/vector/util/SlashCommandsParser.java @@ -18,12 +18,14 @@ package im.vector.util; +import android.app.Activity; import android.text.TextUtils; import android.widget.Toast; import androidx.annotation.StringRes; import androidx.appcompat.app.AlertDialog; +import org.jetbrains.annotations.Nullable; import org.matrix.androidsdk.MXSession; import org.matrix.androidsdk.core.Log; import org.matrix.androidsdk.core.callback.ApiCallback; @@ -38,6 +40,7 @@ import java.util.HashMap; import java.util.Map; +import im.vector.Matrix; import im.vector.R; import im.vector.VectorApp; import im.vector.activity.CommonActivityUtils; @@ -353,7 +356,7 @@ public void onMatrixError(final MatrixError e) { isIRCCmd = true; isIRCCmdValid = true; - WidgetsManager wm = WidgetManagerProvider.INSTANCE.getWidgetManager(activity); + WidgetsManager wm = getWidgetManager(activity); if (wm != null) { wm.clearScalarToken(activity, session); Toast.makeText(activity, "Scalar token cleared", Toast.LENGTH_SHORT).show(); @@ -384,4 +387,14 @@ public void onMatrixError(final MatrixError e) { return isIRCCmd; } + + @Nullable + private static WidgetsManager getWidgetManager(Activity activity) { + if (Matrix.getInstance(activity) == null) return null; + MXSession session = Matrix.getInstance(activity).getDefaultSession(); + if (session == null) return null; + WidgetManagerProvider widgetManagerProvider = Matrix.getInstance(activity).getWidgetManagerProvider(session); + if (widgetManagerProvider == null) return null; + return widgetManagerProvider.getWidgetManager(activity); + } } diff --git a/vector/src/main/java/im/vector/view/ActiveWidgetsBanner.java b/vector/src/main/java/im/vector/view/ActiveWidgetsBanner.java index f833a2d3df..171fd7f528 100755 --- a/vector/src/main/java/im/vector/view/ActiveWidgetsBanner.java +++ b/vector/src/main/java/im/vector/view/ActiveWidgetsBanner.java @@ -18,12 +18,14 @@ package im.vector.view; +import android.app.Activity; import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.widget.FrameLayout; import android.widget.TextView; +import org.jetbrains.annotations.Nullable; import org.matrix.androidsdk.MXSession; import org.matrix.androidsdk.core.Log; import org.matrix.androidsdk.data.Room; @@ -31,6 +33,7 @@ import java.util.ArrayList; import java.util.List; +import im.vector.Matrix; import im.vector.R; import im.vector.widgets.Widget; import im.vector.widgets.WidgetManagerProvider; @@ -168,7 +171,7 @@ public void setOnUpdateListener(onUpdateListener listener) { * Refresh the view visibility */ private void refresh() { - WidgetsManager wm = WidgetManagerProvider.INSTANCE.getWidgetManager(getContext()); + WidgetsManager wm = getWidgetManager(getContext()); if (wm == null) { return; } @@ -209,7 +212,7 @@ private void refresh() { */ public void onActivityResume() { refresh(); - WidgetsManager wm = WidgetManagerProvider.INSTANCE.getWidgetManager(getContext()); + WidgetsManager wm = getWidgetManager(getContext()); if (wm != null) { wm.addListener(mWidgetListener); } @@ -219,9 +222,19 @@ public void onActivityResume() { * The parent activity is suspended */ public void onActivityPause() { - WidgetsManager wm = WidgetManagerProvider.INSTANCE.getWidgetManager(getContext()); + WidgetsManager wm = getWidgetManager(getContext()); if (wm != null) { wm.removeListener(mWidgetListener); } } + + @Nullable + private WidgetsManager getWidgetManager(Context activity) { + if (Matrix.getInstance(activity) == null) return null; + MXSession session = Matrix.getInstance(activity).getDefaultSession(); + if (session == null) return null; + WidgetManagerProvider widgetManagerProvider = Matrix.getInstance(activity).getWidgetManagerProvider(session); + if (widgetManagerProvider == null) return null; + return widgetManagerProvider.getWidgetManager(activity); + } } diff --git a/vector/src/main/java/im/vector/view/VectorOngoingConferenceCallView.java b/vector/src/main/java/im/vector/view/VectorOngoingConferenceCallView.java index 517b52e3c0..86e1caec02 100755 --- a/vector/src/main/java/im/vector/view/VectorOngoingConferenceCallView.java +++ b/vector/src/main/java/im/vector/view/VectorOngoingConferenceCallView.java @@ -31,6 +31,7 @@ import android.widget.RelativeLayout; import android.widget.TextView; +import org.jetbrains.annotations.Nullable; import org.matrix.androidsdk.MXSession; import org.matrix.androidsdk.call.IMXCall; import org.matrix.androidsdk.call.IMXCallsManagerListener; @@ -44,6 +45,7 @@ import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; +import im.vector.Matrix; import im.vector.R; import im.vector.widgets.Widget; import im.vector.widgets.WidgetManagerProvider; @@ -241,7 +243,7 @@ public void setCallClickListener(ICallClickListener callClickListener) { * Refresh the view visibility */ public void refresh() { - WidgetsManager wm = WidgetManagerProvider.INSTANCE.getWidgetManager(getContext()); + WidgetsManager wm = getWidgetManager(getContext()); if (wm == null) { return; } @@ -278,7 +280,7 @@ public void onActivityResume() { if (null != mSession) { mSession.mCallsManager.addListener(mCallsListener); } - WidgetsManager wm = WidgetManagerProvider.INSTANCE.getWidgetManager(getContext()); + WidgetsManager wm = getWidgetManager(getContext()); if (wm != null) { wm.addListener(mWidgetListener); } @@ -291,7 +293,7 @@ public void onActivityPause() { if (null != mSession) { mSession.mCallsManager.removeListener(mCallsListener); } - WidgetsManager wm = WidgetManagerProvider.INSTANCE.getWidgetManager(getContext()); + WidgetsManager wm = getWidgetManager(getContext()); if (wm != null) { wm.removeListener(mWidgetListener); } @@ -303,4 +305,14 @@ public void onActivityPause() { public Widget getActiveWidget() { return mActiveWidget; } + + @Nullable + private WidgetsManager getWidgetManager(Context activity) { + if (Matrix.getInstance(activity) == null) return null; + MXSession session = Matrix.getInstance(activity).getDefaultSession(); + if (session == null) return null; + WidgetManagerProvider widgetManagerProvider = Matrix.getInstance(activity).getWidgetManagerProvider(session); + if (widgetManagerProvider == null) return null; + return widgetManagerProvider.getWidgetManager(activity); + } } diff --git a/vector/src/main/java/im/vector/widgets/WidgetManagerProvider.kt b/vector/src/main/java/im/vector/widgets/WidgetManagerProvider.kt index 8839b1af4b..1376d8da90 100644 --- a/vector/src/main/java/im/vector/widgets/WidgetManagerProvider.kt +++ b/vector/src/main/java/im/vector/widgets/WidgetManagerProvider.kt @@ -16,36 +16,79 @@ package im.vector.widgets import android.content.Context +import im.vector.R import im.vector.util.PreferencesManager +import org.matrix.androidsdk.MXSession +import org.matrix.androidsdk.features.integrationmanager.IntegrationManager +import org.matrix.androidsdk.features.integrationmanager.isEmptyConfig import java.net.MalformedURLException import java.net.URL -object WidgetManagerProvider { +class WidgetManagerProvider(val session: MXSession) : IntegrationManager.IntegrationManagerManagerListener { + + + override fun onIntegrationManagerChange(managerConfig: IntegrationManager) { + //Clear caches + currentConfig = null + widgetsManager = null + } + + init { + session.integrationManager.addListener(this) + } private var widgetsManager: WidgetsManager? = null + private var currentConfig: IntegrationManagerConfig? = null fun getWidgetManager(context: Context): WidgetsManager? { - if (widgetsManager != null) { + val userDefinedConfig = session.integrationManager.integrationServerConfig + var sdkConfig: IntegrationManagerConfig? = null + + if (userDefinedConfig != null) { + if (userDefinedConfig.isEmptyConfig()) { + //The user forced a null config so we don't use the default one + currentConfig = null + widgetsManager = null + return null + } + val defaultWhitelist = ArrayList(PreferencesManager.getIntegrationWhiteListedUrl(context)) + defaultWhitelist.add(0, userDefinedConfig.apiUrl) + sdkConfig = IntegrationManagerConfig( + uiUrl = userDefinedConfig.uiUrl, + apiUrl = userDefinedConfig.apiUrl, + jitsiUrl = "${userDefinedConfig.apiUrl}/widgets/jitsi.html", + whiteListedUrls = defaultWhitelist) + } else { + //Use the default IM + // TODO we should try to get the one suggested by the HS well-known + sdkConfig = IntegrationManagerConfig( + uiUrl = context.getString(R.string.integrations_ui_url), + apiUrl = context.getString(R.string.integrations_rest_url), + jitsiUrl = context.getString(R.string.integrations_jitsi_widget_url), + whiteListedUrls = ArrayList(PreferencesManager.getIntegrationWhiteListedUrl(context))) + } + + + + if (currentConfig == sdkConfig && widgetsManager != null) { return widgetsManager } - val uiURl = PreferencesManager.getIntegrationManagerUiUrl(context) - val apiURL = PreferencesManager.getIntegrationManagerApiUrl(context) - val jitsiUrl = PreferencesManager.getIntegrationManagerJitsiUrl(context) - if (uiURl.isNullOrBlank() || apiURL.isNullOrBlank() || jitsiUrl.isNullOrBlank()) return null + + if (sdkConfig.uiUrl.isBlank() || sdkConfig.apiUrl.isBlank() || sdkConfig.jitsiUrl.isBlank()) { + currentConfig = null + widgetsManager = null + return null + } + return try { //Very basic validity check (well formed url) - URL(uiURl) - URL(apiURL) - URL(jitsiUrl) - val defaultWhitelist = ArrayList(PreferencesManager.getIntegrationWhiteListedUrl(context)) - defaultWhitelist.add(0, apiURL) + URL(sdkConfig.uiUrl) + URL(sdkConfig.apiUrl) + URL(sdkConfig.jitsiUrl) - val config = IntegrationManagerConfig( - uiUrl = uiURl, - apiUrl = apiURL, - jitsiUrl = jitsiUrl, - whiteListedUrls = defaultWhitelist) - WidgetsManager(config).also { + currentConfig = sdkConfig + + WidgetsManager(sdkConfig).also { this.widgetsManager = it } } catch (e: MalformedURLException) { diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index de8d1d9e22..caf620cb7e 100755 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -834,6 +834,7 @@ Logged in as Home Server Identity Server + Allow Integrations Integration Manager User interface diff --git a/vector/src/main/res/xml/vector_settings_preferences.xml b/vector/src/main/res/xml/vector_settings_preferences.xml index 9465ab6254..35e84e933a 100755 --- a/vector/src/main/res/xml/vector_settings_preferences.xml +++ b/vector/src/main/res/xml/vector_settings_preferences.xml @@ -447,7 +447,13 @@ app:fragment="im.vector.fragments.discovery.VectorSettingsDiscoveryFragment"/> + + From 54545004e7eb49d336922e68ffc8b73683af6a14 Mon Sep 17 00:00:00 2001 From: Valere Date: Wed, 6 Nov 2019 10:08:36 +0100 Subject: [PATCH 39/77] Use IM wellknown if needed + enable/disable integration setting --- vector/src/main/java/im/vector/VectorApp.java | 5 -- .../PhoneNumberVerificationActivity.java | 2 +- .../VectorSettingsPreferencesFragment.kt | 83 +++++++++++++++---- .../im/vector/util/PreferencesManager.java | 53 ------------ .../vector/widgets/WidgetManagerProvider.kt | 40 +++++---- .../res/xml/vector_settings_preferences.xml | 5 +- 6 files changed, 97 insertions(+), 91 deletions(-) diff --git a/vector/src/main/java/im/vector/VectorApp.java b/vector/src/main/java/im/vector/VectorApp.java index 187961c131..b8eabc13c9 100755 --- a/vector/src/main/java/im/vector/VectorApp.java +++ b/vector/src/main/java/im/vector/VectorApp.java @@ -197,11 +197,6 @@ public void onCreate() { Log.d(LOG_TAG, "onCreate"); super.onCreate(); - PreferencesManager.setIntegrationManagerUrls(this, - getString(R.string.integrations_ui_url), - getString(R.string.integrations_rest_url), - getString(R.string.integrations_jitsi_widget_url)); - mLifeCycleListener = new VectorLifeCycleObserver(); ProcessLifecycleOwner.get().getLifecycle().addObserver(mLifeCycleListener); diff --git a/vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.java b/vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.java index d4f0ef6aed..a4f05bc56e 100644 --- a/vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.java +++ b/vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.java @@ -184,7 +184,7 @@ public void onUnexpectedError(Exception e) { } private void registerAfterPhoneNumberValidation(final ThreePid pid) { - mSession.getIdentityServerManager().finalizeAddSessionForEmail(pid, new ApiCallback() { + mSession.getIdentityServerManager().finalize3pidAddSession(pid, null, new ApiCallback() { @Override public void onSuccess(Void info) { Intent intent = new Intent(); diff --git a/vector/src/main/java/im/vector/fragments/VectorSettingsPreferencesFragment.kt b/vector/src/main/java/im/vector/fragments/VectorSettingsPreferencesFragment.kt index aff7df47d1..9c9cc3ffbb 100755 --- a/vector/src/main/java/im/vector/fragments/VectorSettingsPreferencesFragment.kt +++ b/vector/src/main/java/im/vector/fragments/VectorSettingsPreferencesFragment.kt @@ -60,11 +60,7 @@ import im.vector.dialogs.ExportKeysDialog import im.vector.extensions.getFingerprintHumanReadable import im.vector.extensions.showPassword import im.vector.extensions.withArgs -import im.vector.fragments.troubleshoot.NotificationTroubleshootTestManager -import im.vector.preference.ProgressBarPreference -import im.vector.preference.UserAvatarPreference -import im.vector.preference.VectorGroupPreference -import im.vector.preference.VectorPreference +import im.vector.preference.* import im.vector.settings.FontScale import im.vector.settings.VectorLocale import im.vector.ui.themes.ThemeUtils @@ -88,6 +84,7 @@ import org.matrix.androidsdk.data.MyUser import org.matrix.androidsdk.data.Pusher import org.matrix.androidsdk.data.RoomMediaMessage import org.matrix.androidsdk.db.MXMediaCache +import org.matrix.androidsdk.features.integrationmanager.IntegrationManager import org.matrix.androidsdk.listeners.MXEventListener import org.matrix.androidsdk.listeners.MXMediaUploadListener import org.matrix.androidsdk.rest.model.bingrules.BingRule @@ -126,7 +123,7 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref override fun onAccountDataUpdated(accountDataElement: AccountDataElement) { if (accountDataElement.type == AccountDataElement.ACCOUNT_DATA_TYPE_IDENTITY_SERVER) { - (findPreference(PreferencesManager.SETTINGS_IDENTITY_SERVER_PREFERENCE_KEY) as EditTextPreference).let { + (findPreference(PreferencesManager.SETTINGS_IDENTITY_SERVER_PREFERENCE_KEY) as VectorPreference).let { updateIdentityServerPref() } } @@ -152,6 +149,12 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref // current publicised group list private var mPublicisedGroups: MutableSet? = null + private var integrationManagerManagerListener = object : IntegrationManager.IntegrationManagerManagerListener { + override fun onIntegrationManagerChange(managerConfig: IntegrationManager) { + refreshIntegrationManagerSettings() + } + } + /* ========================================================================================== * Preferences * ========================================================================================== */ @@ -621,8 +624,33 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref // identity server updateIdentityServerPref() - findPreference(PreferencesManager.SETTINGS_INTEGRATION_MANAGER_UI_URL) - .summary = PreferencesManager.getIntegrationManagerUiUrl(context) + + (findPreference(PreferencesManager.SETTINGS_INTEGRATION_ALLOW) as? VectorSwitchPreference)?.let { + it.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> + + //Disable it while updating the state, will be re-enabled by the account data listener. + it.isEnabled = false + mSession.enableIntegrationManagerUsage(newValue as Boolean, object : ApiCallback { + override fun onSuccess(info: Void?) { + //nop + } + + override fun onUnexpectedError(e: java.lang.Exception?) { + refreshIntegrationManagerSettings() + } + + override fun onNetworkError(e: java.lang.Exception?) { + refreshIntegrationManagerSettings() + } + + override fun onMatrixError(e: MatrixError?) { + refreshIntegrationManagerSettings() + } + + }) + true + } + } // Analytics @@ -789,7 +817,7 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref } else { MXCallsManager.defaultStunServerUri = null } - PreferencesManager.setUseDefaultTurnServer(activity,mUseDefaultStunPreference.isChecked) + PreferencesManager.setUseDefaultTurnServer(activity, mUseDefaultStunPreference.isChecked) false } } @@ -831,6 +859,29 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref } } + + private fun refreshIntegrationManagerSettings() { + val integrationAllowed = mSession.integrationManager.integrationAllowed + (findPreference(PreferencesManager.SETTINGS_INTEGRATION_ALLOW) as SwitchPreference).let { + val savedListener = it.onPreferenceChangeListener + it.onPreferenceChangeListener = null + it.isChecked = integrationAllowed + it.isEnabled = true + it.onPreferenceChangeListener = savedListener + } + + findPreference(PreferencesManager.SETTINGS_INTEGRATION_MANAGER_UI_URL).let { + if (integrationAllowed) { + it.summary = Matrix.getWidgetManager(context)?.uiUrl ?: getString(R.string.none) + it.isVisible = true + } else { + it.isVisible = false + } + } + + + } + private fun refreshBackgroundSyncSection(appContext: Context?) { // background sync tuning settings // these settings are useless and hidden if the app is registered to the FCM push service @@ -896,7 +947,7 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref // Even if using foreground service with foreground notif, it stops to work // in doze mode for certain devices :/ - if ( !isIgnoringBatteryOptimizations(requireContext())) { + if (!isIgnoringBatteryOptimizations(requireContext())) { requestDisablingBatteryOptimization(requireActivity(), this@VectorSettingsPreferencesFragment, REQUEST_BATTERY_OPTIMIZATION) @@ -905,11 +956,11 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref pushManager.setFdroidSyncModeOptimizedForRealTime(); } - PreferencesManager.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY -> { + PreferencesManager.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY -> { pushManager.setFdroidSyncModeOptimizedForBattery(); } - PreferencesManager.FDROID_BACKGROUND_SYNC_MODE_DISABLED -> { + PreferencesManager.FDROID_BACKGROUND_SYNC_MODE_DISABLED -> { pushManager.setFdroidSyncModeDisabled() } } @@ -1031,6 +1082,9 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref PreferenceManager.getDefaultSharedPreferences(context).registerOnSharedPreferenceChangeListener(this) + mSession.integrationManager.addListener(integrationManagerManagerListener) + refreshIntegrationManagerSettings() + // refresh anything else refreshPreferences() refreshNotificationPrivacy() @@ -1055,6 +1109,7 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref if (mSession.isAlive) { mSession.dataHandler.removeListener(mEventsListener) Matrix.getInstance(context)?.removeNetworkEventListener(mNetworkListener) + mSession.integrationManager.removeListener(integrationManagerManagerListener) } PreferenceManager.getDefaultSharedPreferences(context).unregisterOnSharedPreferenceChangeListener(this) @@ -2049,11 +2104,11 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref .setTitle(R.string.account_email_validation_title) .setMessage(R.string.account_email_validation_message) .setPositiveButton(R.string._continue) { _, _ -> - mSession.identityServerManager.finalizeAddSessionForEmail(pid, object : ApiCallback { + mSession.identityServerManager.finalize3pidAddSession(pid, null, object : ApiCallback { override fun onSuccess(info: Void?) { it.runOnUiThread { hideLoadingView() - mSession.myUser.refreshThirdPartyIdentifiers(object : SimpleApiCallback(){ + mSession.myUser.refreshThirdPartyIdentifiers(object : SimpleApiCallback() { override fun onSuccess(info: Void?) { refreshEmailsList() } diff --git a/vector/src/main/java/im/vector/util/PreferencesManager.java b/vector/src/main/java/im/vector/util/PreferencesManager.java index b626a146ed..fb4c7aea07 100755 --- a/vector/src/main/java/im/vector/util/PreferencesManager.java +++ b/vector/src/main/java/im/vector/util/PreferencesManager.java @@ -172,9 +172,6 @@ public class PreferencesManager { //Integrations public static final String SETTINGS_INTEGRATION_ALLOW = "SETTINGS_INTEGRATION_ALLOW"; public static final String SETTINGS_INTEGRATION_MANAGER_UI_URL = "SETTINGS_INTEGRATION_MANAGER_UI_URL"; - public static final String SETTINGS_INTEGRATION_MANAGER_API_URL = "SETTINGS_INTEGRATION_MANAGER_API_URL"; - public static final String SETTINGS_INTEGRATION_MANAGER_JITSI_URL = "SETTINGS_INTEGRATION_MANAGER_JITSI_URL"; - public static final String SETTINGS_INTEGRATION_WHITELIST_URL = "SETTINGS_INTEGRATION_WHITELIST_URL"; // other public static final String SETTINGS_MEDIA_SAVING_PERIOD_KEY = "SETTINGS_MEDIA_SAVING_PERIOD_KEY"; @@ -290,56 +287,6 @@ public static void setDidAskUserToIgnoreBatteryOptimizations(Context context) { .apply(); } - public static Boolean areIntegrationAllowed(Context context) { - return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SETTINGS_INTEGRATION_ALLOW, - true); - } - - public static String getIntegrationManagerUiUrl(Context context) { - return PreferenceManager.getDefaultSharedPreferences(context).getString(SETTINGS_INTEGRATION_MANAGER_UI_URL, - context.getString(R.string.integrations_ui_url)); - } - - public static String getIntegrationManagerApiUrl(Context context) { - return PreferenceManager.getDefaultSharedPreferences(context).getString(SETTINGS_INTEGRATION_MANAGER_API_URL, - context.getString(R.string.integrations_rest_url)); - } - - public static String getIntegrationManagerJitsiUrl(Context context) { - return PreferenceManager.getDefaultSharedPreferences(context).getString(SETTINGS_INTEGRATION_MANAGER_JITSI_URL, - context.getString(R.string.integrations_jitsi_widget_url)); - } - - - public static void setIntegrationManagerUrls(Context context, String uiURl, String apiURl, String jitsiUrl) { - if (uiURl != null) { - PreferenceManager.getDefaultSharedPreferences(context) - .edit() - .putString(SETTINGS_INTEGRATION_MANAGER_UI_URL, uiURl) - .apply(); - } - if (apiURl != null) { - PreferenceManager.getDefaultSharedPreferences(context) - .edit() - .putString(SETTINGS_INTEGRATION_MANAGER_API_URL, apiURl) - .apply(); - } - - if (jitsiUrl != null) { - PreferenceManager.getDefaultSharedPreferences(context) - .edit() - .putString(SETTINGS_INTEGRATION_MANAGER_JITSI_URL, jitsiUrl) - .apply(); - } - } - - public static List getIntegrationWhiteListedUrl(Context context) { - Set defaultSet = new HashSet<>(Arrays.asList(context.getResources().getStringArray(R.array.integrations_widgets_urls))); - Set set = PreferenceManager.getDefaultSharedPreferences(context).getStringSet(SETTINGS_INTEGRATION_WHITELIST_URL, defaultSet); - return new ArrayList<>(set); - } - - public static boolean didMigrateToNotificationRework(Context context) { return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(DID_MIGRATE_TO_NOTIFICATION_REWORK, false); } diff --git a/vector/src/main/java/im/vector/widgets/WidgetManagerProvider.kt b/vector/src/main/java/im/vector/widgets/WidgetManagerProvider.kt index 1376d8da90..30725bec03 100644 --- a/vector/src/main/java/im/vector/widgets/WidgetManagerProvider.kt +++ b/vector/src/main/java/im/vector/widgets/WidgetManagerProvider.kt @@ -20,9 +20,10 @@ import im.vector.R import im.vector.util.PreferencesManager import org.matrix.androidsdk.MXSession import org.matrix.androidsdk.features.integrationmanager.IntegrationManager -import org.matrix.androidsdk.features.integrationmanager.isEmptyConfig import java.net.MalformedURLException import java.net.URL +import java.util.* +import kotlin.collections.ArrayList class WidgetManagerProvider(val session: MXSession) : IntegrationManager.IntegrationManagerManagerListener { @@ -41,31 +42,38 @@ class WidgetManagerProvider(val session: MXSession) : IntegrationManager.Integra private var currentConfig: IntegrationManagerConfig? = null fun getWidgetManager(context: Context): WidgetsManager? { + if (!session.integrationManager.integrationAllowed) return null + val userDefinedConfig = session.integrationManager.integrationServerConfig var sdkConfig: IntegrationManagerConfig? = null + val defaultWhitelist = context.resources.getStringArray(R.array.integrations_widgets_urls).asList() if (userDefinedConfig != null) { - if (userDefinedConfig.isEmptyConfig()) { - //The user forced a null config so we don't use the default one - currentConfig = null - widgetsManager = null - return null - } - val defaultWhitelist = ArrayList(PreferencesManager.getIntegrationWhiteListedUrl(context)) - defaultWhitelist.add(0, userDefinedConfig.apiUrl) + + val whiteList = defaultWhitelist + userDefinedConfig.apiUrl sdkConfig = IntegrationManagerConfig( uiUrl = userDefinedConfig.uiUrl, apiUrl = userDefinedConfig.apiUrl, jitsiUrl = "${userDefinedConfig.apiUrl}/widgets/jitsi.html", - whiteListedUrls = defaultWhitelist) + whiteListedUrls = whiteList) } else { //Use the default IM - // TODO we should try to get the one suggested by the HS well-known - sdkConfig = IntegrationManagerConfig( - uiUrl = context.getString(R.string.integrations_ui_url), - apiUrl = context.getString(R.string.integrations_rest_url), - jitsiUrl = context.getString(R.string.integrations_jitsi_widget_url), - whiteListedUrls = ArrayList(PreferencesManager.getIntegrationWhiteListedUrl(context))) + // Check if a config is defined in wellknown + val wellKnownIM = session.integrationManager.getWellKnownIntegrationManagerConfigs().firstOrNull() + sdkConfig = if (wellKnownIM != null) { + IntegrationManagerConfig( + uiUrl = wellKnownIM.uiUrl, + apiUrl = wellKnownIM.apiUrl, + jitsiUrl = "${wellKnownIM.apiUrl}/widgets/jitsi.html", + whiteListedUrls = listOf(wellKnownIM.apiUrl) + ) + } else { + IntegrationManagerConfig( + uiUrl = context.getString(R.string.integrations_ui_url), + apiUrl = context.getString(R.string.integrations_rest_url), + jitsiUrl = context.getString(R.string.integrations_jitsi_widget_url), + whiteListedUrls = defaultWhitelist) + } } diff --git a/vector/src/main/res/xml/vector_settings_preferences.xml b/vector/src/main/res/xml/vector_settings_preferences.xml index 35e84e933a..b01cc64444 100755 --- a/vector/src/main/res/xml/vector_settings_preferences.xml +++ b/vector/src/main/res/xml/vector_settings_preferences.xml @@ -449,12 +449,13 @@ From d8a7e954888033bd9eeb31bc07c18f978e80665d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 6 Nov 2019 17:38:10 +0100 Subject: [PATCH 40/77] Format strings --- vector/src/main/res/values-de/strings.xml | 4 +- vector/src/main/res/values-es-rMX/strings.xml | 4 +- vector/src/main/res/values-eu/strings.xml | 8 ++-- vector/src/main/res/values-fi/strings.xml | 36 ++++++++--------- vector/src/main/res/values-fr/strings.xml | 8 ++-- vector/src/main/res/values-hu/strings.xml | 16 ++++---- vector/src/main/res/values-it/strings.xml | 8 ++-- vector/src/main/res/values-ko/strings.xml | 6 +-- vector/src/main/res/values-ru/strings.xml | 40 +++++++++---------- vector/src/main/res/values-zh-rTW/strings.xml | 6 +-- 10 files changed, 68 insertions(+), 68 deletions(-) diff --git a/vector/src/main/res/values-de/strings.xml b/vector/src/main/res/values-de/strings.xml index 790cc432c7..356e3fdaaa 100644 --- a/vector/src/main/res/values-de/strings.xml +++ b/vector/src/main/res/values-de/strings.xml @@ -1656,7 +1656,7 @@ Wenn du diese neue Wiederherstellungsmethode nicht eingerichtet hast, kann ein A app_id: Überprüfung -Keine + Keine Widerrufen Trennen Kein Integrationsserver konfiguriert. @@ -1708,4 +1708,4 @@ Wenn du diese neue Wiederherstellungsmethode nicht eingerichtet hast, kann ein A Gib einen neuen Identitätsserver ein Konnte keine Verbindung zum Heimserver herstellen. - + diff --git a/vector/src/main/res/values-es-rMX/strings.xml b/vector/src/main/res/values-es-rMX/strings.xml index 9ae9d36794..313e7737d1 100644 --- a/vector/src/main/res/values-es-rMX/strings.xml +++ b/vector/src/main/res/values-es-rMX/strings.xml @@ -779,9 +779,9 @@ Dispositivos desconocidos: Enviar una respuesta cifrada… Enviar una respuesta (sin cifrar)… -Latn + Latn Iniciando servicio Copia de seguridad de la clave Usar copia de seguridad de la clave - + diff --git a/vector/src/main/res/values-eu/strings.xml b/vector/src/main/res/values-eu/strings.xml index 675bc74932..57eed05cca 100644 --- a/vector/src/main/res/values-eu/strings.xml +++ b/vector/src/main/res/values-eu/strings.xml @@ -1697,7 +1697,7 @@ Abisua: Fitxategi hau ezabatu daiteke aplikazioa desinstalatzen bada. Orain e-mail helbideak edo telefono zenbakiak partekatzen dituzu %1$s zerbitzarian. %2$s zerbitzarira konektatu beharko zara partekatzeari uzteko. Onartu %s identitate-zerbitzariaren erabilera baldintzak besteek zu e-mail helbidea edo telefonoa erabiliz aurkitzea ahalbidetzeko. -Latn + Latn Gaitu egunkari xehetsuak. Amorruz astintzean egunkari xehetsuak bidaltzeak garatzaileei laguntzen diete. Gaituta badago ere, aplikazioak ez ditu mezuen edukiak edo beste datu probaturik gordetzen egunkarian. @@ -1724,9 +1724,9 @@ Abisua: Fitxategi hau ezabatu daiteke aplikazioa desinstalatzen bada. %1$s eta %2$s erabiltzaileek irakurria %s erabiltzaileak irakurria - Erabiltzaile batek irakurria - %d erabiltzailek irakurria - + Erabiltzaile batek irakurria + %d erabiltzailek irakurria + \'%1$s\' fitxategia (%2$s) handiegia da igotzeko. Muga %3$s da. diff --git a/vector/src/main/res/values-fi/strings.xml b/vector/src/main/res/values-fi/strings.xml index 6f5973ea7f..651978f92f 100644 --- a/vector/src/main/res/values-fi/strings.xml +++ b/vector/src/main/res/values-fi/strings.xml @@ -933,13 +933,13 @@ Haluatko lisätä paketteja? Avaa otsikko Synkronoidaan… - yksi aktiivinen jäsen - %d aktiivista jäsentä - + yksi aktiivinen jäsen + %d aktiivista jäsentä + - yksi jäsen - %d jäsentä - + yksi jäsen + %d jäsentä + 1 s %d s @@ -1136,13 +1136,13 @@ Haluatko lisätä paketteja? Kirjoita tähän… - yksi lukematon ilmoitettu viesti - %d lukematonta ilmoitettua viestiä - + yksi lukematon ilmoitettu viesti + %d lukematonta ilmoitettua viestiä + - yksi lukematon ilmoitettu viesti - %d lukematonta ilmoitettua viestiä - + yksi lukematon ilmoitettu viesti + %d lukematonta ilmoitettua viestiä + yksi huone %d huonetta @@ -1657,7 +1657,7 @@ Jotta et menetä mitään, automaattiset päivitykset kannattaa pitää käytös Valitsemallasi identiteettipalvelimella ei ole käyttöehtoja. Jatka vain, jos luotat palvelun omistajaan Jaat sähköpostiosoitteita tai puhelinnumeroita identiteettipalvelimella %1$s. Sinun täytyy yhdistää uudelleen palvelimeen %2$s, jotta voit lopettaa niiden jakamisen. Hyväksy identiteettipalvelimen (%s) käyttöehdot salliaksesi, että sinut voi löytää sähköpostiosoitteen tai puhelinnumeron perusteella. -Aseta sähköposti tilin palauttamista varten. Myöhemmin voit halutessasi antaa ihmisten etsiä sinua sen perusteella. + Aseta sähköposti tilin palauttamista varten. Myöhemmin voit halutessasi antaa ihmisten etsiä sinua sen perusteella. Salli varalla oleva puhelun apupalvelin Yhteyden katkaiseminen identiteettipalvelimeesi tarkoittaa, että muut käyttäjät eivät voi etsiä sinua etkä voi kutsua muita sähköpostin tai puhelinnumeron perusteella. Lähetimme sinulle vahvistussähköpostin osoitteeseen %s, tarkista sähköpostisi ja klikkaa vahvistuslinkkiä @@ -1678,9 +1678,9 @@ Jotta et menetä mitään, automaattiset päivitykset kannattaa pitää käytös %1$s ja %2$s lukivat %s luki - 1 käyttäjä luki - %d käyttäjää luki - + 1 käyttäjä luki + %d käyttäjää luki + Liitettä noudettaessa tapahtui virhe. Tiedosto @@ -1691,7 +1691,7 @@ Jotta et menetä mitään, automaattiset päivitykset kannattaa pitää käytös Se on sopimaton Verkkoyhteyttä ei ole juuri nyt -Ei mitään + Ei mitään Pyydä kotipalvelimesi (%1$s) ylläpitäjää määrittämään TURN-palvelin, jotta puhelut toimivat luotettavasti. \n \nVaihtoehtoisesti voit yrittää käyttää julkista palvelinta osoitteessa %2$s, mutta tämä ei ole yhtä luotettava vaihtoehto ja antaa IP-osoitteesi kyseisen palvelimen tietoon. Voit myös hallita tätä asetuksista. @@ -1707,4 +1707,4 @@ Jotta et menetä mitään, automaattiset päivitykset kannattaa pitää käytös Ole löydettävissä Tekstiviesti on lähetetty numeroon %s. Syötä sen sisältämä varmistuskoodi. - + diff --git a/vector/src/main/res/values-fr/strings.xml b/vector/src/main/res/values-fr/strings.xml index d65e0f3756..6057627163 100644 --- a/vector/src/main/res/values-fr/strings.xml +++ b/vector/src/main/res/values-fr/strings.xml @@ -1701,7 +1701,7 @@ Si vous n’avez pas configuré de nouvelle méthode de récupération, un attaq Vous partagez actuellement des adresse e-mails et des numéros de téléphone sur le serveur d’identité %1$s. Vous devrez vous reconnecter à %2$s pour arrêter de les partager. Acceptez les conditions de service du serveur d’identité (%s) pour vous permettre d’être découvrable avec une adresse e-mail ou un numéro de téléphone. -Latn + Latn Activer les journaux verbeux. Les journaux verbeux aideront les développeurs en fournissant plus de journaux quand vous envoyez un rapport d’anomalie. Même si cette option est activée, l’application n’envoie pas le contenu des messages ou toute autre donnée personnelle. @@ -1728,9 +1728,9 @@ Si vous n’avez pas configuré de nouvelle méthode de récupération, un attaq %1$s et %2$s ont lu %s a lu - 1 utilisateur a lu - %d utilisateurs ont lu - + 1 utilisateur a lu + %d utilisateurs ont lu + Le fichier « %1$s » (%2$s) est trop gros pour être envoyé. La limite est %3$s. diff --git a/vector/src/main/res/values-hu/strings.xml b/vector/src/main/res/values-hu/strings.xml index 7a3a05eedf..caca6bd7c8 100644 --- a/vector/src/main/res/values-hu/strings.xml +++ b/vector/src/main/res/values-hu/strings.xml @@ -1021,7 +1021,7 @@ Vedd figyelembe, hogy az alkalmazás újraindul ami sok időt vehet igénybe.Elküld Ezeket az embereket biztosan kirúgod? - + Ok @@ -1249,11 +1249,11 @@ Figyelmeztetés: ez a fájl törlésre kerülhet, ha az alkalmazást törlik.Visszaállítva: %1$d kapcsolati kulcs, és %2$d kulcs, ami(k) ismeretlenek voltak az eszköz számára, hozzáadva Visszaállított mentés %d kulccsal. - + %d új kulcs lett hozzáadva ehhez az eszközhöz. - + "Nem sikerült beszerezni a legfrissebb verziójú visszaállítási kulcsot (%s)." @@ -1332,7 +1332,7 @@ A Visszaállítási Kulcsot tartsd biztonságos helyen, mint pl. egy jelszókeze Minden kulcs elmentve %d kulcs mentése… - + Verzió @@ -1700,7 +1700,7 @@ Ha nem te állítottad be a visszaállítási metódust, akkor egy támadó pró Az azonosítási szerverrel (%1$s) megosztod az e-mail címeket és telefonszámokat. Újra kell csatlakoznod ehhez: %2$s, hogy megállítsd a megosztást. Egyetértek az azonosítási szerver (%s) Felhasználási feltételeivel ahhoz, hogy megtalálható legyek e-mail címmel vagy telefonszámmal. -Latn + Latn Kibővített naplózás engedélyezése. A kiterjesztett naplózás a fejlesztőknek nyújt több információt amikor hibajegyet küldesz. Még bekapcsolva sem naplóz üzenet tartalmat vagy más személyes adatot. @@ -1727,9 +1727,9 @@ Ha nem te állítottad be a visszaállítási metódust, akkor egy támadó pró %1$s és %2$s olvasták %s olvasta - 1 felhasználó olvasta - %d felhasználó olvasta - + 1 felhasználó olvasta + %d felhasználó olvasta + \'%1$s\' (%2$s) fájl túl nagy a feltöltéshez. A korlát: %3$s. diff --git a/vector/src/main/res/values-it/strings.xml b/vector/src/main/res/values-it/strings.xml index 74035998ab..d46eaa987b 100644 --- a/vector/src/main/res/values-it/strings.xml +++ b/vector/src/main/res/values-it/strings.xml @@ -1745,7 +1745,7 @@ Per essere certo di non perdere nulla, mantieni gli aggiornamenti attivi."Attualmente stai condividendo indirizzi email o numeri di telefono sul server di identità %1$s. Dovrai riconnetterti a %2$s per fermarne la condivisione. Accetta le condizioni di servizio del server di identità (%s) per consentire di essere trovabile per email o numero di telefono. -Latn + Latn Attiva log dettagliati. I log dettagliati aiuteranno gli sviluppatori fornendo loro più informazioni quando invii una segnalazione. Anche quando attivi, l\'applicazione non registra i contenuti dei messaggi o altri dati personali. @@ -1772,9 +1772,9 @@ Per essere certo di non perdere nulla, mantieni gli aggiornamenti attivi."%1$s e %2$s hanno letto %s ha letto - 1 utente ha letto - %d utenti hanno letto - + 1 utente ha letto + %d utenti hanno letto + Il file \'%1$s\' (%2$s) è troppo grande da inviare. Il limite è %3$s. diff --git a/vector/src/main/res/values-ko/strings.xml b/vector/src/main/res/values-ko/strings.xml index 2a01a279e0..3f2469d766 100644 --- a/vector/src/main/res/values-ko/strings.xml +++ b/vector/src/main/res/values-ko/strings.xml @@ -1623,7 +1623,7 @@ 현재 이메일 주소나 전화번호를 ID 서버 %1$s와 공유하고 있습니다. 공유하기를 중지하려면 %2$s(으)로 다시 연결해야 합니다. ID 서버 (%s)의 서비스 약관에 동의하면 다른 사용자가 당신을 이메일 주소나 전화번호로 찾을 수 있게 됩니다. -Latn + Latn 상세 로그 켜기. 상세 로그는 분노의 흔들기를 보낼 때 더 많은 로그를 제공해서 개발자에게 도움을 줍니다. 이 설정을 켜도 애플리케이션은 메시지 내용이나 다른 개인 정보를 기록하지 않습니다. @@ -1650,8 +1650,8 @@ %1$s님 그리고 %2$s님이 읽음 %s님이 읽음 - %d명이 읽음 - + %d명이 읽음 + 파일 \'%1$s\' (%2$s)이(가) 업로드하기에 너무 큽니다. 제한은 %3$s입니다. diff --git a/vector/src/main/res/values-ru/strings.xml b/vector/src/main/res/values-ru/strings.xml index c2c8e30378..e815f01b9f 100644 --- a/vector/src/main/res/values-ru/strings.xml +++ b/vector/src/main/res/values-ru/strings.xml @@ -96,7 +96,7 @@ %d пользователь %d пользователя %d пользователей - + Отправить логи @@ -843,13 +843,13 @@ %d комната %d комнаты %d комнат - + %d комната %d комнаты %d комнат - + %1$s в %2$s @@ -857,7 +857,7 @@ %d активный виджет %d активных виджета %d активных виджетов - + @@ -867,45 +867,45 @@ %d активный участник %d активных участника %d активных участников - + %d участник %d участника %d участников - + %d новое сообщение %d новых сообщения %d новых сообщений - + %1$s комната найдена для %2$s %1$s комнаты найдено для %2$s %1$s комнат найдено для %2$s - + %d изменение членства %d изменения членства %d изменений членства - + %d непрочитанное уведомление %d непрочитанных уведомления %d непрочитанных уведомлений - + %d непрочитанное уведомление %d непрочитанных уведомления %d непрочитанных уведомлений - + Получить аватар Заметка аватара @@ -1020,13 +1020,13 @@ %dm %dm %dm - + %dh %dh %dh - + %d день @@ -1045,20 +1045,20 @@ %d выбран %d выбрано %d выбраны - + %d участник %d участника %d участников - + %d комната %d комнаты %d комнат - + Системные оповещения @@ -1346,7 +1346,7 @@ %d новый ключ был добавлен к этому устройству. %d новых ключа были добавлены к этому устройству. %d новых ключей были добавлены к этому устройству. - + @@ -1398,7 +1398,7 @@ Резервное копирование %d ключа… Резервное копирование %d ключей… Резервное копирование %d ключей… - + Все ключи сохранены @@ -1792,9 +1792,9 @@ В настоящее время вы делитесь адресами электронной почты или телефонными номерами на сервере идентификации %1$s. Вам нужно повторно подключиться к %2$s, чтобы прекратить делиться ими. Примите Условия обслуживания сервера идентификации (%s), чтобы разрешить обнаружение по адресу электронной почты или номеру телефона. -Включить подробное журнал. + Включить подробное журнал. Отправить вложенное Откройте навигационный ящик Откройте меню «Создать комнату» - + diff --git a/vector/src/main/res/values-zh-rTW/strings.xml b/vector/src/main/res/values-zh-rTW/strings.xml index 1bee9de8f8..f7ed5500ea 100644 --- a/vector/src/main/res/values-zh-rTW/strings.xml +++ b/vector/src/main/res/values-zh-rTW/strings.xml @@ -1653,7 +1653,7 @@ Matrix 中的消息可見度類似于電子郵件。我們忘記您的郵件意 您目前正在身份識別伺服器 %1$s 上分享電子郵件地址或電話號碼。您將必須重新連線到 %2$s 以停止分享它們。 同意身份識別伺服器 (%s) 的服務條款以允許您被透過電子郵件地址或電話號碼探索。 -緯度 + 緯度 啟用詳細紀錄。 詳細紀錄可以協助開發者在您傳送憤怒搖晃時取得更多紀錄。即使啟用這個設定,應用程式依然不會紀錄訊息內容或任何個人資料。 @@ -1680,8 +1680,8 @@ Matrix 中的消息可見度類似于電子郵件。我們忘記您的郵件意 %1$s 與 %2$s 已閱讀 %s 已閱讀 - %d 個使用者已閱讀 - + %d 個使用者已閱讀 + 檔案「%1$s」(%2$s) 太大無法上傳。限制為 %3$s。 From 8870c91d10095e3a39e2e0daec37a2eebc6f0329 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 6 Nov 2019 18:24:12 +0100 Subject: [PATCH 41/77] Fix bad script --- vector/src/main/res/values-zh-rTW/strings.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/vector/src/main/res/values-zh-rTW/strings.xml b/vector/src/main/res/values-zh-rTW/strings.xml index f7ed5500ea..837e75583a 100644 --- a/vector/src/main/res/values-zh-rTW/strings.xml +++ b/vector/src/main/res/values-zh-rTW/strings.xml @@ -1653,7 +1653,6 @@ Matrix 中的消息可見度類似于電子郵件。我們忘記您的郵件意 您目前正在身份識別伺服器 %1$s 上分享電子郵件地址或電話號碼。您將必須重新連線到 %2$s 以停止分享它們。 同意身份識別伺服器 (%s) 的服務條款以允許您被透過電子郵件地址或電話號碼探索。 - 緯度 啟用詳細紀錄。 詳細紀錄可以協助開發者在您傳送憤怒搖晃時取得更多紀錄。即使啟用這個設定,應用程式依然不會紀錄訊息內容或任何個人資料。 From aaa29cf19363133f99b5683f54aab6e70c5c0346 Mon Sep 17 00:00:00 2001 From: Valere Date: Fri, 8 Nov 2019 11:58:29 +0100 Subject: [PATCH 42/77] Code review --- vector/src/main/java/im/vector/Matrix.java | 2 +- .../view/VectorOngoingConferenceCallView.java | 15 +++------------ .../im/vector/widgets/WidgetManagerProvider.kt | 7 ++----- 3 files changed, 6 insertions(+), 18 deletions(-) diff --git a/vector/src/main/java/im/vector/Matrix.java b/vector/src/main/java/im/vector/Matrix.java index 60701b1c26..6a7d75caaf 100755 --- a/vector/src/main/java/im/vector/Matrix.java +++ b/vector/src/main/java/im/vector/Matrix.java @@ -117,7 +117,7 @@ public class Matrix { @Nullable private KeyRequestHandler mKeyRequestHandler; - private HashMap mWidgetManagerProviders = new HashMap<>(); + private Map mWidgetManagerProviders = new HashMap<>(); // i.e the event has been read from another client private static final MXEventListener mLiveEventListener = new MXEventListener() { diff --git a/vector/src/main/java/im/vector/view/VectorOngoingConferenceCallView.java b/vector/src/main/java/im/vector/view/VectorOngoingConferenceCallView.java index 86e1caec02..fbb135fc26 100755 --- a/vector/src/main/java/im/vector/view/VectorOngoingConferenceCallView.java +++ b/vector/src/main/java/im/vector/view/VectorOngoingConferenceCallView.java @@ -243,7 +243,7 @@ public void setCallClickListener(ICallClickListener callClickListener) { * Refresh the view visibility */ public void refresh() { - WidgetsManager wm = getWidgetManager(getContext()); + WidgetsManager wm = Matrix.getWidgetManager(getContext()); if (wm == null) { return; } @@ -280,7 +280,7 @@ public void onActivityResume() { if (null != mSession) { mSession.mCallsManager.addListener(mCallsListener); } - WidgetsManager wm = getWidgetManager(getContext()); + WidgetsManager wm = Matrix.getWidgetManager(getContext()); if (wm != null) { wm.addListener(mWidgetListener); } @@ -293,7 +293,7 @@ public void onActivityPause() { if (null != mSession) { mSession.mCallsManager.removeListener(mCallsListener); } - WidgetsManager wm = getWidgetManager(getContext()); + WidgetsManager wm = Matrix.getWidgetManager(getContext()); if (wm != null) { wm.removeListener(mWidgetListener); } @@ -306,13 +306,4 @@ public Widget getActiveWidget() { return mActiveWidget; } - @Nullable - private WidgetsManager getWidgetManager(Context activity) { - if (Matrix.getInstance(activity) == null) return null; - MXSession session = Matrix.getInstance(activity).getDefaultSession(); - if (session == null) return null; - WidgetManagerProvider widgetManagerProvider = Matrix.getInstance(activity).getWidgetManagerProvider(session); - if (widgetManagerProvider == null) return null; - return widgetManagerProvider.getWidgetManager(activity); - } } diff --git a/vector/src/main/java/im/vector/widgets/WidgetManagerProvider.kt b/vector/src/main/java/im/vector/widgets/WidgetManagerProvider.kt index 30725bec03..ea24f173b8 100644 --- a/vector/src/main/java/im/vector/widgets/WidgetManagerProvider.kt +++ b/vector/src/main/java/im/vector/widgets/WidgetManagerProvider.kt @@ -17,15 +17,12 @@ package im.vector.widgets import android.content.Context import im.vector.R -import im.vector.util.PreferencesManager import org.matrix.androidsdk.MXSession import org.matrix.androidsdk.features.integrationmanager.IntegrationManager import java.net.MalformedURLException import java.net.URL -import java.util.* -import kotlin.collections.ArrayList -class WidgetManagerProvider(val session: MXSession) : IntegrationManager.IntegrationManagerManagerListener { +class WidgetManagerProvider(private val session: MXSession) : IntegrationManager.IntegrationManagerManagerListener { override fun onIntegrationManagerChange(managerConfig: IntegrationManager) { @@ -45,7 +42,7 @@ class WidgetManagerProvider(val session: MXSession) : IntegrationManager.Integra if (!session.integrationManager.integrationAllowed) return null val userDefinedConfig = session.integrationManager.integrationServerConfig - var sdkConfig: IntegrationManagerConfig? = null + val sdkConfig: IntegrationManagerConfig? val defaultWhitelist = context.resources.getStringArray(R.array.integrations_widgets_urls).asList() if (userDefinedConfig != null) { From 54db4f07d97bb126b6129c12d85f6c2a4998fa46 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 12 Nov 2019 10:16:40 +0100 Subject: [PATCH 43/77] Fix error in translation (already changed on Weblate) --- vector/src/main/res/values-zh-rTW/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/res/values-zh-rTW/strings.xml b/vector/src/main/res/values-zh-rTW/strings.xml index 837e75583a..a1d6ceb32b 100644 --- a/vector/src/main/res/values-zh-rTW/strings.xml +++ b/vector/src/main/res/values-zh-rTW/strings.xml @@ -1675,7 +1675,7 @@ Matrix 中的消息可見度類似于電子郵件。我們忘記您的郵件意 跳到底部 %1$s、%2$s 與 %3$d 個其他人已閱讀 - %1$s、%2$s 與 %3$d 已閱讀 + %1$s、%2$s 與 %3$s 已閱讀 %1$s 與 %2$s 已閱讀 %s 已閱讀 From c88142fb55f6fcee043d778ad52c6d6f1ddff50d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 12 Nov 2019 10:38:28 +0100 Subject: [PATCH 44/77] Once again... --- vector/src/main/res/values-de/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/res/values-de/strings.xml b/vector/src/main/res/values-de/strings.xml index 356e3fdaaa..251c42c00c 100644 --- a/vector/src/main/res/values-de/strings.xml +++ b/vector/src/main/res/values-de/strings.xml @@ -1662,7 +1662,7 @@ Wenn du diese neue Wiederherstellungsmethode nicht eingerichtet hast, kann ein A Kein Integrationsserver konfiguriert. Anruf aufgrund eines falsch konfigurierten Servers fehlgeschlagen - Versuchen Sie es mit %@ + Versuchen Sie es mit %s Nicht erneut fragen Richten Sie eine E-Mail für die Kontowiederherstellung ein, die später von Personen, die Sie kennen, optional gefunden werden kann. From 8c9dfa18d5ab7eb50ee60fd4ce2d35391531fc5e Mon Sep 17 00:00:00 2001 From: Valere Date: Thu, 24 Oct 2019 19:08:59 +0200 Subject: [PATCH 45/77] Prompt for password to add 3pid --- .../java/im/vector/activity/DialogUtils.kt | 60 ++++ .../activity/PhoneNumberAdditionActivity.java | 2 +- .../PhoneNumberVerificationActivity.java | 250 ---------------- .../PhoneNumberVerificationActivity.kt | 277 ++++++++++++++++++ .../VectorSettingsPreferencesFragment.kt | 179 ++++++++--- .../res/layout/dialog_confirm_password.xml | 52 ++++ vector/src/main/res/values/strings.xml | 2 + 7 files changed, 536 insertions(+), 286 deletions(-) create mode 100644 vector/src/main/java/im/vector/activity/DialogUtils.kt delete mode 100644 vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.java create mode 100644 vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.kt create mode 100644 vector/src/main/res/layout/dialog_confirm_password.xml diff --git a/vector/src/main/java/im/vector/activity/DialogUtils.kt b/vector/src/main/java/im/vector/activity/DialogUtils.kt new file mode 100644 index 0000000000..c15e5bdf8f --- /dev/null +++ b/vector/src/main/java/im/vector/activity/DialogUtils.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2019 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. + */ + +package im.vector.activity + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.appcompat.app.AlertDialog +import com.google.android.material.textfield.TextInputEditText +import com.google.android.material.textfield.TextInputLayout +import im.vector.R +import im.vector.extensions.showPassword + +object DialogUtils { + + fun promptPassword(context: Context, errorText: String? = null, defaultPwd: String? = null, done: (String) -> Unit) { + val view: ViewGroup = LayoutInflater.from(context).inflate(R.layout.dialog_confirm_password, null) as ViewGroup + + val showPassword: ImageView = view.findViewById(R.id.confirm_password_show_passwords) + val passwordTil: TextInputLayout = view.findViewById(R.id.confirm_password_til) + val passwordText: TextInputEditText = view.findViewById(R.id.password_label) + passwordText.setText(defaultPwd) + + var passwordShown = false + + showPassword.setOnClickListener(object : View.OnClickListener { + override fun onClick(v: View?) { + passwordShown = !passwordShown + passwordText.showPassword(passwordShown) + showPassword.setImageResource(if (passwordShown) R.drawable.ic_eye_closed_black else R.drawable.ic_eye_black) + } + }) + + passwordTil.error = errorText + + AlertDialog.Builder(context) + .setView(view) + .setPositiveButton(R.string._continue) { tv, _ -> + done(passwordText.text.toString()) + } + .show() + + } +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/activity/PhoneNumberAdditionActivity.java b/vector/src/main/java/im/vector/activity/PhoneNumberAdditionActivity.java index bd49371e9c..1d04b1969d 100644 --- a/vector/src/main/java/im/vector/activity/PhoneNumberAdditionActivity.java +++ b/vector/src/main/java/im/vector/activity/PhoneNumberAdditionActivity.java @@ -267,7 +267,7 @@ private void addPhoneNumber(final Phonenumber.PhoneNumber phoneNumber) { @Override public void onSuccess(ThreePid pid) { hideWaitingView(); - Intent intent = PhoneNumberVerificationActivity.getIntent(PhoneNumberAdditionActivity.this, + Intent intent = PhoneNumberVerificationActivity.Companion.getIntent(PhoneNumberAdditionActivity.this, mSession.getCredentials().userId, pid); startActivityForResult(intent, REQUEST_VERIFICATION); } diff --git a/vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.java b/vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.java deleted file mode 100644 index a4f05bc56e..0000000000 --- a/vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright 2017 Vector Creations Ltd - * Copyright 2018 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. - */ - -package im.vector.activity; - -import android.content.Context; -import android.content.Intent; -import android.text.Editable; -import android.text.TextUtils; -import android.text.TextWatcher; -import android.view.KeyEvent; -import android.view.MenuItem; -import android.view.inputmethod.EditorInfo; -import android.widget.TextView; -import android.widget.Toast; - -import com.google.android.material.textfield.TextInputEditText; -import com.google.android.material.textfield.TextInputLayout; - -import org.matrix.androidsdk.MXSession; -import org.matrix.androidsdk.core.Log; -import org.matrix.androidsdk.core.callback.ApiCallback; -import org.matrix.androidsdk.core.model.MatrixError; -import org.matrix.androidsdk.rest.model.SuccessResult; -import org.matrix.androidsdk.rest.model.pid.ThreePid; - -import im.vector.Matrix; -import im.vector.R; - -public class PhoneNumberVerificationActivity extends VectorAppCompatActivity implements TextView.OnEditorActionListener, TextWatcher { - - private static final String LOG_TAG = PhoneNumberVerificationActivity.class.getSimpleName(); - - private static final String EXTRA_MATRIX_ID = "EXTRA_MATRIX_ID"; - private static final String EXTRA_PID = "EXTRA_PID"; - - private TextInputEditText mPhoneNumberCode; - private TextInputLayout mPhoneNumberCodeLayout; - - private MXSession mSession; - private ThreePid mThreePid; - - // True when a phone number token is submitted - // Used to prevent user to submit several times in a row - private boolean mIsSubmittingToken; - - /* - * ********************************************************************************************* - * Static methods - * ********************************************************************************************* - */ - - public static Intent getIntent(final Context context, final String sessionId, final ThreePid pid) { - final Intent intent = new Intent(context, PhoneNumberVerificationActivity.class); - intent.putExtra(EXTRA_MATRIX_ID, sessionId); - intent.putExtra(EXTRA_PID, pid); - return intent; - } - - /* - * ********************************************************************************************* - * Activity lifecycle - * ********************************************************************************************* - */ - - @Override - public int getLayoutRes() { - return R.layout.activity_phone_number_verification; - } - - @Override - public int getTitleRes() { - return R.string.settings_phone_number_verification; - } - - @Override - public void initUiAndData() { - configureToolbar(); - - mPhoneNumberCode = findViewById(R.id.phone_number_code_value); - mPhoneNumberCodeLayout = findViewById(R.id.phone_number_code); - setWaitingView(findViewById(R.id.loading_view)); - - final Intent intent = getIntent(); - mSession = Matrix.getInstance(this).getSession(intent.getStringExtra(EXTRA_MATRIX_ID)); - - if ((null == mSession) || !mSession.isAlive()) { - finish(); - return; - } - - mThreePid = intent.getParcelableExtra(EXTRA_PID); - - mPhoneNumberCode.addTextChangedListener(this); - mPhoneNumberCode.setOnEditorActionListener(this); - } - - @Override - protected void onResume() { - super.onResume(); - mIsSubmittingToken = false; - } - - @Override - public int getMenuRes() { - return R.menu.menu_phone_number_verification; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.action_verify_phone_number: - submitCode(); - return true; - default: - return super.onOptionsItemSelected(item); - } - } - - /* - * ********************************************************************************************* - * Utils - * ********************************************************************************************* - */ - - /** - * Submit code (token) to attach phone number to account - */ - private void submitCode() { - if (!mIsSubmittingToken) { - mIsSubmittingToken = true; - if (TextUtils.isEmpty(mPhoneNumberCode.getText())) { - mPhoneNumberCodeLayout.setErrorEnabled(true); - mPhoneNumberCodeLayout.setError(getString(R.string.settings_phone_number_verification_error_empty_code)); - } else { - showWaitingView(); - mSession.getIdentityServerManager().submitValidationToken(mThreePid, mPhoneNumberCode.getText().toString(), - new ApiCallback() { - @Override - public void onSuccess(SuccessResult result) { - if (result.success) { - // the validation of mail ownership succeed, just resume the registration flow - // next step: just register - Log.e(LOG_TAG, "## submitPhoneNumberValidationToken(): onSuccess() - registerAfterEmailValidations() started"); - registerAfterPhoneNumberValidation(mThreePid); - } else { - Log.e(LOG_TAG, "## submitPhoneNumberValidationToken(): onSuccess() - failed (success=false)"); - onSubmitCodeError(getString(R.string.settings_phone_number_verification_error)); - } - } - - @Override - public void onNetworkError(Exception e) { - onSubmitCodeError(e.getLocalizedMessage()); - } - - @Override - public void onMatrixError(MatrixError e) { - onSubmitCodeError(e.getLocalizedMessage()); - } - - @Override - public void onUnexpectedError(Exception e) { - onSubmitCodeError(e.getLocalizedMessage()); - } - }); - } - - } - } - - private void registerAfterPhoneNumberValidation(final ThreePid pid) { - mSession.getIdentityServerManager().finalize3pidAddSession(pid, null, new ApiCallback() { - @Override - public void onSuccess(Void info) { - Intent intent = new Intent(); - setResult(RESULT_OK, intent); - finish(); - } - - @Override - public void onNetworkError(Exception e) { - onSubmitCodeError(e.getLocalizedMessage()); - } - - @Override - public void onMatrixError(MatrixError e) { - onSubmitCodeError(e.getLocalizedMessage()); - } - - @Override - public void onUnexpectedError(Exception e) { - onSubmitCodeError(e.getLocalizedMessage()); - } - }); - } - - private void onSubmitCodeError(final String errorMessage) { - mIsSubmittingToken = false; - hideWaitingView(); - Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT).show(); - } - - /* - * ********************************************************************************************* - * Listeners - * ********************************************************************************************* - */ - - @Override - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if (actionId == EditorInfo.IME_ACTION_DONE && !isFinishing()) { - submitCode(); - return true; - } - return false; - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - - } - - @Override - public void afterTextChanged(Editable s) { - if (mPhoneNumberCodeLayout.getError() != null) { - mPhoneNumberCodeLayout.setError(null); - mPhoneNumberCodeLayout.setErrorEnabled(false); - } - } -} diff --git a/vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.kt b/vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.kt new file mode 100644 index 0000000000..b5da7fbde1 --- /dev/null +++ b/vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.kt @@ -0,0 +1,277 @@ +/* + * Copyright 2017 Vector Creations Ltd + * Copyright 2018 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. + */ + +package im.vector.activity + +import android.app.Activity +import android.app.AlertDialog +import android.content.Context +import android.content.Intent +import android.text.Editable +import android.text.TextUtils +import android.text.TextWatcher +import android.view.KeyEvent +import android.view.MenuItem +import android.view.inputmethod.EditorInfo +import android.widget.EditText +import android.widget.TextView +import android.widget.Toast +import com.google.android.material.textfield.TextInputEditText +import com.google.android.material.textfield.TextInputLayout +import im.vector.Matrix +import im.vector.R +import org.matrix.androidsdk.MXSession +import org.matrix.androidsdk.core.JsonUtils +import org.matrix.androidsdk.core.Log +import org.matrix.androidsdk.core.callback.ApiCallback +import org.matrix.androidsdk.core.model.MatrixError +import org.matrix.androidsdk.rest.model.SuccessResult +import org.matrix.androidsdk.rest.model.login.AuthParams +import org.matrix.androidsdk.rest.model.login.AuthParamsLoginPassword +import org.matrix.androidsdk.rest.model.login.LoginParams +import org.matrix.androidsdk.rest.model.pid.ThreePid + +class PhoneNumberVerificationActivity : VectorAppCompatActivity(), TextView.OnEditorActionListener, TextWatcher { + + private var mPhoneNumberCode: TextInputEditText? = null + private var mPhoneNumberCodeLayout: TextInputLayout? = null + + private var mSession: MXSession? = null + private var mThreePid: ThreePid? = null + + // True when a phone number token is submitted + // Used to prevent user to submit several times in a row + private var mIsSubmittingToken: Boolean = false + + /* + * ********************************************************************************************* + * Activity lifecycle + * ********************************************************************************************* + */ + + override fun getLayoutRes(): Int { + return R.layout.activity_phone_number_verification + } + + override fun getTitleRes(): Int { + return R.string.settings_phone_number_verification + } + + override fun initUiAndData() { + configureToolbar() + + mPhoneNumberCode = findViewById(R.id.phone_number_code_value) + mPhoneNumberCodeLayout = findViewById(R.id.phone_number_code) + waitingView = findViewById(R.id.loading_view) + + val intent = intent + mSession = Matrix.getInstance(this)!!.getSession(intent.getStringExtra(EXTRA_MATRIX_ID)) + + if (null == mSession || !mSession!!.isAlive) { + finish() + return + } + + mThreePid = intent.getParcelableExtra(EXTRA_PID) + + mPhoneNumberCode!!.addTextChangedListener(this) + mPhoneNumberCode!!.setOnEditorActionListener(this) + } + + override fun onResume() { + super.onResume() + mIsSubmittingToken = false + } + + override fun getMenuRes(): Int { + return R.menu.menu_phone_number_verification + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.action_verify_phone_number -> { + submitCode() + return true + } + else -> return super.onOptionsItemSelected(item) + } + } + + /* + * ********************************************************************************************* + * Utils + * ********************************************************************************************* + */ + + /** + * Submit code (token) to attach phone number to account + */ + private fun submitCode() { + if (!mIsSubmittingToken) { + mIsSubmittingToken = true + if (TextUtils.isEmpty(mPhoneNumberCode!!.text)) { + mPhoneNumberCodeLayout!!.isErrorEnabled = true + mPhoneNumberCodeLayout!!.error = getString(R.string.settings_phone_number_verification_error_empty_code) + } else { + showWaitingView() + mSession!!.identityServerManager.submitValidationToken(mThreePid!!, mPhoneNumberCode!!.text!!.toString(), + object : ApiCallback { + override fun onSuccess(result: SuccessResult) { + if (result.success) { + // the validation of mail ownership succeed, just resume the registration flow + // next step: just register + Log.e(LOG_TAG, "## submitPhoneNumberValidationToken(): onSuccess() - registerAfterEmailValidations() started") + registerAfterPhoneNumberValidation(mThreePid, null) + } else { + Log.e(LOG_TAG, "## submitPhoneNumberValidationToken(): onSuccess() - failed (success=false)") + onSubmitCodeError(getString(R.string.settings_phone_number_verification_error)) + } + } + + override fun onNetworkError(e: Exception) { + onSubmitCodeError(e.localizedMessage) + } + + override fun onMatrixError(e: MatrixError) { + onSubmitCodeError(e.localizedMessage) + } + + override fun onUnexpectedError(e: Exception) { + onSubmitCodeError(e.localizedMessage) + } + }) + } + + } + } + + private fun registerAfterPhoneNumberValidation(pid: ThreePid?, auth: AuthParams?) { + mSession!!.identityServerManager.finalize3pidAddSession(pid!!, auth, object : ApiCallback { + override fun onSuccess(info: Void?) { + val intent = Intent() + setResult(Activity.RESULT_OK, intent) + finish() + } + + override fun onNetworkError(e: Exception) { + onSubmitCodeError(e.localizedMessage) + } + + override fun onMatrixError(e: MatrixError) { + if (e.mStatus == 401 && e.mErrorBodyAsString.isNullOrBlank().not()) { + val flow = JsonUtils.toRegistrationFlowResponse(e.mErrorBodyAsString) + if (flow != null) { + val supportsLoginPassword = flow.flows.any { it.stages == listOf("m.login.password") } + if (supportsLoginPassword) { + //we prompt for it + + val invalidPassError = getString(R.string.login_error_forbidden) + .takeIf { e.errcode == MatrixError.FORBIDDEN } + + DialogUtils.promptPassword(this@PhoneNumberVerificationActivity, + invalidPassError, + (auth as? AuthParamsLoginPassword)?.let { auth.password } + ) { password -> + val authParams = AuthParamsLoginPassword().apply { + this.user = mSession?.myUserId + this.password = password + } + registerAfterPhoneNumberValidation(pid, authParams) + } + } else { + //you can only do that on mobile + AlertDialog.Builder(this@PhoneNumberVerificationActivity) + .setTitle(R.string.dialog_title_error) + .setMessage(R.string.settings_add_3pid_flow_not_supported) + .setPositiveButton(R.string._continue) { _, _ -> + registerAfterPhoneNumberValidation(pid, auth) + } + .show() + + } + + } else { + onSubmitCodeError(e.localizedMessage) + } + } else { + onSubmitCodeError(e.localizedMessage) + } + + } + + override fun onUnexpectedError(e: Exception) { + onSubmitCodeError(e.localizedMessage) + } + }) + } + + private fun onSubmitCodeError(errorMessage: String) { + mIsSubmittingToken = false + hideWaitingView() + Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT).show() + } + + /* + * ********************************************************************************************* + * Listeners + * ********************************************************************************************* + */ + + override fun onEditorAction(v: TextView, actionId: Int, event: KeyEvent): Boolean { + if (actionId == EditorInfo.IME_ACTION_DONE && !isFinishing) { + submitCode() + return true + } + return false + } + + override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { + + } + + override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { + + } + + override fun afterTextChanged(s: Editable) { + if (mPhoneNumberCodeLayout!!.error != null) { + mPhoneNumberCodeLayout!!.error = null + mPhoneNumberCodeLayout!!.isErrorEnabled = false + } + } + + companion object { + + private val LOG_TAG = PhoneNumberVerificationActivity::class.java.simpleName + + private val EXTRA_MATRIX_ID = "EXTRA_MATRIX_ID" + private val EXTRA_PID = "EXTRA_PID" + + /* + * ********************************************************************************************* + * Static methods + * ********************************************************************************************* + */ + + fun getIntent(context: Context, sessionId: String, pid: ThreePid): Intent { + val intent = Intent(context, PhoneNumberVerificationActivity::class.java) + intent.putExtra(EXTRA_MATRIX_ID, sessionId) + intent.putExtra(EXTRA_PID, pid) + return intent + } + } +} diff --git a/vector/src/main/java/im/vector/fragments/VectorSettingsPreferencesFragment.kt b/vector/src/main/java/im/vector/fragments/VectorSettingsPreferencesFragment.kt index 9c9cc3ffbb..d4c26b35ca 100755 --- a/vector/src/main/java/im/vector/fragments/VectorSettingsPreferencesFragment.kt +++ b/vector/src/main/java/im/vector/fragments/VectorSettingsPreferencesFragment.kt @@ -44,6 +44,7 @@ import androidx.appcompat.app.AlertDialog import androidx.core.content.ContextCompat import androidx.core.content.edit import androidx.core.view.isVisible +import androidx.fragment.app.FragmentActivity import androidx.preference.* import com.bumptech.glide.Glide import com.google.android.material.textfield.TextInputEditText @@ -60,7 +61,10 @@ import im.vector.dialogs.ExportKeysDialog import im.vector.extensions.getFingerprintHumanReadable import im.vector.extensions.showPassword import im.vector.extensions.withArgs -import im.vector.preference.* +import im.vector.preference.ProgressBarPreference +import im.vector.preference.UserAvatarPreference +import im.vector.preference.VectorGroupPreference +import im.vector.preference.VectorPreference import im.vector.settings.FontScale import im.vector.settings.VectorLocale import im.vector.ui.themes.ThemeUtils @@ -70,6 +74,7 @@ import org.jetbrains.anko.toast import org.matrix.androidsdk.MXSession import org.matrix.androidsdk.call.MXCallsManager import org.matrix.androidsdk.core.BingRulesManager +import org.matrix.androidsdk.core.JsonUtils import org.matrix.androidsdk.core.Log import org.matrix.androidsdk.core.ResourceUtils import org.matrix.androidsdk.core.callback.ApiCallback @@ -87,8 +92,10 @@ import org.matrix.androidsdk.db.MXMediaCache import org.matrix.androidsdk.features.integrationmanager.IntegrationManager import org.matrix.androidsdk.listeners.MXEventListener import org.matrix.androidsdk.listeners.MXMediaUploadListener +import org.matrix.androidsdk.rest.client.LoginRestClient import org.matrix.androidsdk.rest.model.bingrules.BingRule import org.matrix.androidsdk.rest.model.group.Group +import org.matrix.androidsdk.rest.model.login.AuthParamsLoginPassword import org.matrix.androidsdk.rest.model.pid.ThirdPartyIdentifier import org.matrix.androidsdk.rest.model.pid.ThreePid import org.matrix.androidsdk.rest.model.sync.AccountDataElement @@ -2028,6 +2035,30 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref addEmailBtn.order = order addEmailBtn.isVisible = true + addEmailBtn.isEnabled = false + //We need to check if the password flow is available + mSession.identityServerManager.checkAdd3pidInteractiveFlow(listOf(LoginRestClient.LOGIN_FLOW_TYPE_PASSWORD), + object : ApiCallback { + override fun onSuccess(info: Boolean?) { + addEmailBtn.isEnabled = info == null || info == true + } + + override fun onUnexpectedError(e: java.lang.Exception?) { + //In doubt enable + addEmailBtn.isEnabled = true + } + + override fun onNetworkError(e: java.lang.Exception?) { + //In doubt enable + addEmailBtn.isEnabled = true + } + + override fun onMatrixError(e: MatrixError?) { + //In doubt enable + addEmailBtn.isEnabled = true + } + + }) } } @@ -2072,7 +2103,7 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref mSession.identityServerManager.startAddSessionForEmail(pid, null, object : ApiCallback { override fun onSuccess(info: ThreePid) { - activity?.runOnUiThread { showEmailValidationDialog(pid) } + activity?.runOnUiThread { showEmailValidationDialog(pid, null) } } override fun onNetworkError(e: Exception) { @@ -2098,50 +2129,104 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref * * @param pid the used pid. */ - private fun showEmailValidationDialog(pid: ThreePid) { - activity?.let { - AlertDialog.Builder(it) + private fun showEmailValidationDialog(pid: ThreePid, password: String?) { + activity?.let { fragmentActivity -> + val auth = password?.let { + AuthParamsLoginPassword().apply { + this.user = mSession.myUserId + this.password = password + } + } + AlertDialog.Builder(fragmentActivity) .setTitle(R.string.account_email_validation_title) .setMessage(R.string.account_email_validation_message) .setPositiveButton(R.string._continue) { _, _ -> - mSession.identityServerManager.finalize3pidAddSession(pid, null, object : ApiCallback { - override fun onSuccess(info: Void?) { - it.runOnUiThread { - hideLoadingView() - mSession.myUser.refreshThirdPartyIdentifiers(object : SimpleApiCallback() { - override fun onSuccess(info: Void?) { - refreshEmailsList() - } - }) - } - } + finalizeAdd(pid, auth, fragmentActivity) + } + .setNegativeButton(R.string.cancel) { _, _ -> + hideLoadingView() + } + .show() + } + } - override fun onNetworkError(e: Exception) { - onCommonDone(e.localizedMessage) - } + private fun finalizeAdd(pid: ThreePid, auth: AuthParamsLoginPassword?, fragmentActivity: FragmentActivity) { + mSession.identityServerManager.finalize3pidAddSession(pid, auth, object : ApiCallback { + override fun onSuccess(info: Void?) { + fragmentActivity.runOnUiThread { + hideLoadingView() + mSession.myUser.refreshThirdPartyIdentifiers(object : SimpleApiCallback() { + override fun onSuccess(info: Void?) { + refreshEmailsList() + } + }) + } + } - override fun onMatrixError(e: MatrixError) { - if (TextUtils.equals(e.errcode, MatrixError.THREEPID_AUTH_FAILED)) { - it.runOnUiThread { - hideLoadingView() - it.toast(R.string.account_email_validation_error) - } - } else { - onCommonDone(e.localizedMessage) + override fun onNetworkError(e: Exception) { + onCommonDone(e.localizedMessage) + } + + override fun onMatrixError(e: MatrixError) { + if (e.mStatus == 401 && e.mErrorBodyAsString.isNullOrBlank().not()) { + val flow = JsonUtils.toRegistrationFlowResponse(e.mErrorBodyAsString) + if (flow != null) { + val supportsLoginPassword = flow.flows.any { it.stages == listOf("m.login.password") } + if (supportsLoginPassword) { + //we prompt for it + val invalidPassError = requireContext().getString(R.string.login_error_forbidden) + .takeIf { e.errcode == MatrixError.FORBIDDEN } + DialogUtils.promptPassword(requireContext(), + invalidPassError, + auth?.let { auth.password }) { password -> + val authParams = AuthParamsLoginPassword().apply { + this.user = mSession.myUserId + this.password = password } + finalizeAdd(pid, authParams, fragmentActivity) } + } else { + //you can only do that on mobile + AlertDialog.Builder(fragmentActivity) + .setMessage(R.string.settings_add_3pid_flow_not_supported) + .setPositiveButton(R.string._continue) { _, _ -> + finalizeAdd(pid, auth, fragmentActivity) + } + .setNegativeButton(R.string.cancel) { _, _ -> + onCommonDone(null) + } + .show() - override fun onUnexpectedError(e: Exception) { - onCommonDone(e.localizedMessage) - } - }) + } + } else { + onCommonDone(e.localizedMessage) } - .setNegativeButton(R.string.cancel) { _, _ -> - hideLoadingView() + } else if (TextUtils.equals(e.errcode, MatrixError.THREEPID_AUTH_FAILED)) { + fragmentActivity.runOnUiThread { + fragmentActivity.toast(R.string.account_email_validation_error) + //Re-display the popup so that not everything is lost + AlertDialog.Builder(fragmentActivity) + .setTitle(R.string.account_email_validation_title) + .setMessage(R.string.account_email_validation_message) + .setPositiveButton(R.string._continue) { _, _ -> + finalizeAdd(pid, auth, fragmentActivity) + } + .setNegativeButton(R.string.cancel) { _, _ -> + hideLoadingView() + } + .show() + } - .show() - } + } else { + onCommonDone(e.localizedMessage) + } + } + + override fun onUnexpectedError(e: Exception) { + onCommonDone(e.localizedMessage) + } + }) } //============================================================================================================== @@ -2274,6 +2359,30 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref addPhoneBtn.order = order addPhoneBtn.isVisible = true + addPhoneBtn.isEnabled = false + //We need to check if the password flow is available + mSession.identityServerManager.checkAdd3pidInteractiveFlow(listOf(LoginRestClient.LOGIN_FLOW_TYPE_PASSWORD), + object : ApiCallback { + override fun onSuccess(info: Boolean?) { + addPhoneBtn.isEnabled = info == null || info == true + } + + override fun onUnexpectedError(e: java.lang.Exception?) { + //In doubt enable + addPhoneBtn.isEnabled = true + } + + override fun onNetworkError(e: java.lang.Exception?) { + //In doubt enable + addPhoneBtn.isEnabled = true + } + + override fun onMatrixError(e: MatrixError?) { + //In doubt enable + addPhoneBtn.isEnabled = true + } + + }) } } diff --git a/vector/src/main/res/layout/dialog_confirm_password.xml b/vector/src/main/res/layout/dialog_confirm_password.xml new file mode 100644 index 0000000000..b457bd7089 --- /dev/null +++ b/vector/src/main/res/layout/dialog_confirm_password.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index c9adaa19fb..705f949690 100755 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -630,6 +630,8 @@ Add phone number Application info Show the application info in the system settings. + Confirm your password + You can\'t do this from Riot mobile Advanced Notification Settings From 6f83299e9674fb5b71cb1c06feea7c2b4300b4a7 Mon Sep 17 00:00:00 2001 From: Valere Date: Fri, 25 Oct 2019 10:07:32 +0200 Subject: [PATCH 46/77] Update changes --- CHANGES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index e1c54b6854..2d448a16ab 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -11,7 +11,7 @@ Improvementss 🙌: - Other changes: - - + - Add User-Interactive Auth to /account/3pid/add (#3333) Bugfix 🐛: - Crash / potential NPE after logout (#3367) From 07cda8237fe86cdf43bc3bddeec74a3d7e1136f1 Mon Sep 17 00:00:00 2001 From: Valere Date: Fri, 25 Oct 2019 12:20:20 +0200 Subject: [PATCH 47/77] Fix / code quality --- .../im/vector/activity/PhoneNumberVerificationActivity.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.kt b/vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.kt index b5da7fbde1..86c6ffaacd 100644 --- a/vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.kt +++ b/vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.kt @@ -18,7 +18,6 @@ package im.vector.activity import android.app.Activity -import android.app.AlertDialog import android.content.Context import android.content.Intent import android.text.Editable @@ -27,9 +26,9 @@ import android.text.TextWatcher import android.view.KeyEvent import android.view.MenuItem import android.view.inputmethod.EditorInfo -import android.widget.EditText import android.widget.TextView import android.widget.Toast +import androidx.appcompat.app.AlertDialog import com.google.android.material.textfield.TextInputEditText import com.google.android.material.textfield.TextInputLayout import im.vector.Matrix @@ -42,7 +41,6 @@ import org.matrix.androidsdk.core.model.MatrixError import org.matrix.androidsdk.rest.model.SuccessResult import org.matrix.androidsdk.rest.model.login.AuthParams import org.matrix.androidsdk.rest.model.login.AuthParamsLoginPassword -import org.matrix.androidsdk.rest.model.login.LoginParams import org.matrix.androidsdk.rest.model.pid.ThreePid class PhoneNumberVerificationActivity : VectorAppCompatActivity(), TextView.OnEditorActionListener, TextWatcher { From a3ec358c6c0bc6c85d08ff1869ad5ac7fe7d6533 Mon Sep 17 00:00:00 2001 From: Valere Date: Wed, 30 Oct 2019 11:25:21 +0100 Subject: [PATCH 48/77] Code review --- .../java/im/vector/activity/DialogUtils.kt | 13 ++--- .../PhoneNumberVerificationActivity.kt | 5 +- .../VectorSettingsPreferencesFragment.kt | 57 +++++++++---------- 3 files changed, 34 insertions(+), 41 deletions(-) diff --git a/vector/src/main/java/im/vector/activity/DialogUtils.kt b/vector/src/main/java/im/vector/activity/DialogUtils.kt index c15e5bdf8f..3d7f331696 100644 --- a/vector/src/main/java/im/vector/activity/DialogUtils.kt +++ b/vector/src/main/java/im/vector/activity/DialogUtils.kt @@ -18,7 +18,6 @@ package im.vector.activity import android.content.Context import android.view.LayoutInflater -import android.view.View import android.view.ViewGroup import android.widget.ImageView import androidx.appcompat.app.AlertDialog @@ -39,13 +38,11 @@ object DialogUtils { var passwordShown = false - showPassword.setOnClickListener(object : View.OnClickListener { - override fun onClick(v: View?) { - passwordShown = !passwordShown - passwordText.showPassword(passwordShown) - showPassword.setImageResource(if (passwordShown) R.drawable.ic_eye_closed_black else R.drawable.ic_eye_black) - } - }) + showPassword.setOnClickListener { + passwordShown = !passwordShown + passwordText.showPassword(passwordShown) + showPassword.setImageResource(if (passwordShown) R.drawable.ic_eye_closed_black else R.drawable.ic_eye_black) + } passwordTil.error = errorText diff --git a/vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.kt b/vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.kt index 86c6ffaacd..8dbd381ccb 100644 --- a/vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.kt +++ b/vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.kt @@ -38,6 +38,7 @@ import org.matrix.androidsdk.core.JsonUtils import org.matrix.androidsdk.core.Log import org.matrix.androidsdk.core.callback.ApiCallback import org.matrix.androidsdk.core.model.MatrixError +import org.matrix.androidsdk.rest.client.LoginRestClient import org.matrix.androidsdk.rest.model.SuccessResult import org.matrix.androidsdk.rest.model.login.AuthParams import org.matrix.androidsdk.rest.model.login.AuthParamsLoginPassword @@ -173,7 +174,7 @@ class PhoneNumberVerificationActivity : VectorAppCompatActivity(), TextView.OnEd if (e.mStatus == 401 && e.mErrorBodyAsString.isNullOrBlank().not()) { val flow = JsonUtils.toRegistrationFlowResponse(e.mErrorBodyAsString) if (flow != null) { - val supportsLoginPassword = flow.flows.any { it.stages == listOf("m.login.password") } + val supportsLoginPassword = flow.flows.any { it.stages == listOf(LoginRestClient.LOGIN_FLOW_TYPE_PASSWORD) } if (supportsLoginPassword) { //we prompt for it @@ -196,7 +197,7 @@ class PhoneNumberVerificationActivity : VectorAppCompatActivity(), TextView.OnEd .setTitle(R.string.dialog_title_error) .setMessage(R.string.settings_add_3pid_flow_not_supported) .setPositiveButton(R.string._continue) { _, _ -> - registerAfterPhoneNumberValidation(pid, auth) + hideWaitingView() } .show() diff --git a/vector/src/main/java/im/vector/fragments/VectorSettingsPreferencesFragment.kt b/vector/src/main/java/im/vector/fragments/VectorSettingsPreferencesFragment.kt index d4c26b35ca..3efe6a9fef 100755 --- a/vector/src/main/java/im/vector/fragments/VectorSettingsPreferencesFragment.kt +++ b/vector/src/main/java/im/vector/fragments/VectorSettingsPreferencesFragment.kt @@ -89,6 +89,7 @@ import org.matrix.androidsdk.data.MyUser import org.matrix.androidsdk.data.Pusher import org.matrix.androidsdk.data.RoomMediaMessage import org.matrix.androidsdk.db.MXMediaCache +import org.matrix.androidsdk.features.identityserver.IdentityServerManager import org.matrix.androidsdk.features.integrationmanager.IntegrationManager import org.matrix.androidsdk.listeners.MXEventListener import org.matrix.androidsdk.listeners.MXMediaUploadListener @@ -2038,9 +2039,9 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref addEmailBtn.isEnabled = false //We need to check if the password flow is available mSession.identityServerManager.checkAdd3pidInteractiveFlow(listOf(LoginRestClient.LOGIN_FLOW_TYPE_PASSWORD), - object : ApiCallback { - override fun onSuccess(info: Boolean?) { - addEmailBtn.isEnabled = info == null || info == true + object : ApiCallback { + override fun onSuccess(info: IdentityServerManager.SupportedFlowResult) { + addEmailBtn.isEnabled = info == IdentityServerManager.SupportedFlowResult.SUPPORTED } override fun onUnexpectedError(e: java.lang.Exception?) { @@ -2069,6 +2070,7 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref * @param errorMessage the error message */ private fun onCommonDone(errorMessage: String?) { + if (!isAdded) return activity?.runOnUiThread { if (!TextUtils.isEmpty(errorMessage) && errorMessage != null) { VectorApp.getInstance().toast(errorMessage) @@ -2137,22 +2139,27 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref this.password = password } } - AlertDialog.Builder(fragmentActivity) - .setTitle(R.string.account_email_validation_title) - .setMessage(R.string.account_email_validation_message) - .setPositiveButton(R.string._continue) { _, _ -> - finalizeAdd(pid, auth, fragmentActivity) - } - .setNegativeButton(R.string.cancel) { _, _ -> - hideLoadingView() - } - .show() + showEmailValidationDialog(fragmentActivity, pid, auth) } } + private fun showEmailValidationDialog(fragmentActivity: FragmentActivity, pid: ThreePid, auth: AuthParamsLoginPassword?) { + AlertDialog.Builder(fragmentActivity) + .setTitle(R.string.account_email_validation_title) + .setMessage(R.string.account_email_validation_message) + .setPositiveButton(R.string._continue) { _, _ -> + finalizeAdd(pid, auth, fragmentActivity) + } + .setNegativeButton(R.string.cancel) { _, _ -> + hideLoadingView() + } + .show() + } + private fun finalizeAdd(pid: ThreePid, auth: AuthParamsLoginPassword?, fragmentActivity: FragmentActivity) { mSession.identityServerManager.finalize3pidAddSession(pid, auth, object : ApiCallback { override fun onSuccess(info: Void?) { + if (!isAdded) return fragmentActivity.runOnUiThread { hideLoadingView() mSession.myUser.refreshThirdPartyIdentifiers(object : SimpleApiCallback() { @@ -2168,10 +2175,11 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref } override fun onMatrixError(e: MatrixError) { + if (!isAdded) return if (e.mStatus == 401 && e.mErrorBodyAsString.isNullOrBlank().not()) { val flow = JsonUtils.toRegistrationFlowResponse(e.mErrorBodyAsString) if (flow != null) { - val supportsLoginPassword = flow.flows.any { it.stages == listOf("m.login.password") } + val supportsLoginPassword = flow.flows.any { it.stages == listOf(LoginRestClient.LOGIN_FLOW_TYPE_PASSWORD) } if (supportsLoginPassword) { //we prompt for it val invalidPassError = requireContext().getString(R.string.login_error_forbidden) @@ -2190,9 +2198,6 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref AlertDialog.Builder(fragmentActivity) .setMessage(R.string.settings_add_3pid_flow_not_supported) .setPositiveButton(R.string._continue) { _, _ -> - finalizeAdd(pid, auth, fragmentActivity) - } - .setNegativeButton(R.string.cancel) { _, _ -> onCommonDone(null) } .show() @@ -2206,17 +2211,7 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref fragmentActivity.runOnUiThread { fragmentActivity.toast(R.string.account_email_validation_error) //Re-display the popup so that not everything is lost - AlertDialog.Builder(fragmentActivity) - .setTitle(R.string.account_email_validation_title) - .setMessage(R.string.account_email_validation_message) - .setPositiveButton(R.string._continue) { _, _ -> - finalizeAdd(pid, auth, fragmentActivity) - } - .setNegativeButton(R.string.cancel) { _, _ -> - hideLoadingView() - } - .show() - + showEmailValidationDialog(requireActivity(), pid, auth) } } else { onCommonDone(e.localizedMessage) @@ -2362,9 +2357,9 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref addPhoneBtn.isEnabled = false //We need to check if the password flow is available mSession.identityServerManager.checkAdd3pidInteractiveFlow(listOf(LoginRestClient.LOGIN_FLOW_TYPE_PASSWORD), - object : ApiCallback { - override fun onSuccess(info: Boolean?) { - addPhoneBtn.isEnabled = info == null || info == true + object : ApiCallback { + override fun onSuccess(info: IdentityServerManager.SupportedFlowResult) { + addPhoneBtn.isEnabled = info == IdentityServerManager.SupportedFlowResult.SUPPORTED } override fun onUnexpectedError(e: java.lang.Exception?) { From aa4d03d459451da88944b4dbd8041f09a02dc302 Mon Sep 17 00:00:00 2001 From: Valere Date: Mon, 4 Nov 2019 14:38:32 +0100 Subject: [PATCH 49/77] Add cancel option to prompt password --- .../java/im/vector/activity/DialogUtils.kt | 12 +++++++- .../PhoneNumberVerificationActivity.kt | 19 +++++++------ .../VectorSettingsPreferencesFragment.kt | 28 +++++++++++-------- vector/src/main/res/values/strings.xml | 1 + 4 files changed, 39 insertions(+), 21 deletions(-) diff --git a/vector/src/main/java/im/vector/activity/DialogUtils.kt b/vector/src/main/java/im/vector/activity/DialogUtils.kt index 3d7f331696..5c87db890d 100644 --- a/vector/src/main/java/im/vector/activity/DialogUtils.kt +++ b/vector/src/main/java/im/vector/activity/DialogUtils.kt @@ -28,7 +28,9 @@ import im.vector.extensions.showPassword object DialogUtils { - fun promptPassword(context: Context, errorText: String? = null, defaultPwd: String? = null, done: (String) -> Unit) { + fun promptPassword(context: Context, errorText: String? = null, defaultPwd: String? = null, + done: (String) -> Unit, + cancel: (() -> Unit)? = null) { val view: ViewGroup = LayoutInflater.from(context).inflate(R.layout.dialog_confirm_password, null) as ViewGroup val showPassword: ImageView = view.findViewById(R.id.confirm_password_show_passwords) @@ -51,6 +53,14 @@ object DialogUtils { .setPositiveButton(R.string._continue) { tv, _ -> done(passwordText.text.toString()) } + .apply { + if (cancel != null) { + setNegativeButton(R.string.cancel) { _, _ -> + cancel() + } + } + } + .show() } diff --git a/vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.kt b/vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.kt index 8dbd381ccb..c08eb3e81b 100644 --- a/vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.kt +++ b/vector/src/main/java/im/vector/activity/PhoneNumberVerificationActivity.kt @@ -183,14 +183,17 @@ class PhoneNumberVerificationActivity : VectorAppCompatActivity(), TextView.OnEd DialogUtils.promptPassword(this@PhoneNumberVerificationActivity, invalidPassError, - (auth as? AuthParamsLoginPassword)?.let { auth.password } - ) { password -> - val authParams = AuthParamsLoginPassword().apply { - this.user = mSession?.myUserId - this.password = password - } - registerAfterPhoneNumberValidation(pid, authParams) - } + (auth as? AuthParamsLoginPassword)?.let { auth.password }, + { password -> + val authParams = AuthParamsLoginPassword().apply { + this.user = mSession?.myUserId + this.password = password + } + registerAfterPhoneNumberValidation(pid, authParams) + }, + { + onSubmitCodeError(getString(R.string.settings_add_3pid_authentication_needed)) + }) } else { //you can only do that on mobile AlertDialog.Builder(this@PhoneNumberVerificationActivity) diff --git a/vector/src/main/java/im/vector/fragments/VectorSettingsPreferencesFragment.kt b/vector/src/main/java/im/vector/fragments/VectorSettingsPreferencesFragment.kt index 3efe6a9fef..c53d8169f5 100755 --- a/vector/src/main/java/im/vector/fragments/VectorSettingsPreferencesFragment.kt +++ b/vector/src/main/java/im/vector/fragments/VectorSettingsPreferencesFragment.kt @@ -61,10 +61,7 @@ import im.vector.dialogs.ExportKeysDialog import im.vector.extensions.getFingerprintHumanReadable import im.vector.extensions.showPassword import im.vector.extensions.withArgs -import im.vector.preference.ProgressBarPreference -import im.vector.preference.UserAvatarPreference -import im.vector.preference.VectorGroupPreference -import im.vector.preference.VectorPreference +import im.vector.preference.* import im.vector.settings.FontScale import im.vector.settings.VectorLocale import im.vector.ui.themes.ThemeUtils @@ -2041,7 +2038,8 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref mSession.identityServerManager.checkAdd3pidInteractiveFlow(listOf(LoginRestClient.LOGIN_FLOW_TYPE_PASSWORD), object : ApiCallback { override fun onSuccess(info: IdentityServerManager.SupportedFlowResult) { - addEmailBtn.isEnabled = info == IdentityServerManager.SupportedFlowResult.SUPPORTED + addEmailBtn.isEnabled = info == IdentityServerManager.SupportedFlowResult.SUPPORTED + || info == IdentityServerManager.SupportedFlowResult.INTERACTIVE_AUTH_NOT_SUPPORTED } override fun onUnexpectedError(e: java.lang.Exception?) { @@ -2186,13 +2184,18 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref .takeIf { e.errcode == MatrixError.FORBIDDEN } DialogUtils.promptPassword(requireContext(), invalidPassError, - auth?.let { auth.password }) { password -> - val authParams = AuthParamsLoginPassword().apply { - this.user = mSession.myUserId - this.password = password - } - finalizeAdd(pid, authParams, fragmentActivity) - } + auth?.let { auth.password }, + { password -> + val authParams = AuthParamsLoginPassword().apply { + this.user = mSession.myUserId + this.password = password + } + finalizeAdd(pid, authParams, fragmentActivity) + }, + { + onCommonDone(getString(R.string.settings_add_3pid_authentication_needed)) + } + ) } else { //you can only do that on mobile AlertDialog.Builder(fragmentActivity) @@ -2360,6 +2363,7 @@ class VectorSettingsPreferencesFragment : PreferenceFragmentCompat(), SharedPref object : ApiCallback { override fun onSuccess(info: IdentityServerManager.SupportedFlowResult) { addPhoneBtn.isEnabled = info == IdentityServerManager.SupportedFlowResult.SUPPORTED + || info == IdentityServerManager.SupportedFlowResult.INTERACTIVE_AUTH_NOT_SUPPORTED } override fun onUnexpectedError(e: java.lang.Exception?) { diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 705f949690..856b637b40 100755 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -632,6 +632,7 @@ Show the application info in the system settings. Confirm your password You can\'t do this from Riot mobile + Authentication is required Advanced Notification Settings From 92c0e71780e3edaf57dcd9195c693fec2136bf66 Mon Sep 17 00:00:00 2001 From: Valere Date: Wed, 13 Nov 2019 14:16:10 +0100 Subject: [PATCH 50/77] Allow room widget flow --- vector/src/main/java/im/vector/VectorApp.java | 1 - .../vector/activity/StickerPickerActivity.kt | 2 +- .../activity/VectorAppCompatActivity.kt | 3 +- .../vector/activity/VectorRoomActivity.java | 1 - .../java/im/vector/activity/WidgetActivity.kt | 364 +++--------------- .../roomwidgets/RoomWidgetFragment.kt | 328 ++++++++++++++++ .../RoomWidgetPermissionBottomSheet.kt | 115 ++++++ .../RoomWidgetPermissionViewModel.kt | 126 ++++++ .../roomwidgets/RoomWidgetViewModel.kt | 286 ++++++++++++++ .../widgets/IntegrationManagerConfig.kt | 1 - .../im/vector/widgets/WidgetsManager.java | 9 +- .../main/res/drawable-hdpi/ic_widget_bin.png | Bin 0 -> 756 bytes .../drawable-hdpi/ic_widget_external_link.png | Bin 0 -> 583 bytes .../res/drawable-hdpi/ic_widget_refresh.png | Bin 0 -> 1036 bytes .../main/res/drawable-mdpi/ic_widget_bin.png | Bin 0 -> 503 bytes .../drawable-mdpi/ic_widget_external_link.png | Bin 0 -> 423 bytes .../res/drawable-mdpi/ic_widget_refresh.png | Bin 0 -> 670 bytes .../main/res/drawable-xhdpi/ic_widget_bin.png | Bin 0 -> 946 bytes .../ic_widget_external_link.png | Bin 0 -> 717 bytes .../res/drawable-xhdpi/ic_widget_refresh.png | Bin 0 -> 1338 bytes .../res/drawable-xxhdpi/ic_widget_bin.png | Bin 0 -> 1342 bytes .../ic_widget_external_link.png | Bin 0 -> 1014 bytes .../res/drawable-xxhdpi/ic_widget_refresh.png | Bin 0 -> 2155 bytes .../res/drawable-xxxhdpi/ic_widget_bin.png | Bin 0 -> 1646 bytes .../ic_widget_external_link.png | Bin 0 -> 1400 bytes .../drawable-xxxhdpi/ic_widget_refresh.png | Bin 0 -> 2802 bytes .../src/main/res/layout/activity_widget.xml | 71 +--- .../bottom_sheet_room_widget_permission.xml | 114 ++++++ .../main/res/layout/fragment_room_widget.xml | 54 +++ vector/src/main/res/menu/menu_room_widget.xml | 26 ++ vector/src/main/res/values/strings.xml | 18 +- 31 files changed, 1144 insertions(+), 375 deletions(-) create mode 100644 vector/src/main/java/im/vector/fragments/roomwidgets/RoomWidgetFragment.kt create mode 100644 vector/src/main/java/im/vector/fragments/roomwidgets/RoomWidgetPermissionBottomSheet.kt create mode 100644 vector/src/main/java/im/vector/fragments/roomwidgets/RoomWidgetPermissionViewModel.kt create mode 100644 vector/src/main/java/im/vector/fragments/roomwidgets/RoomWidgetViewModel.kt create mode 100644 vector/src/main/res/drawable-hdpi/ic_widget_bin.png create mode 100644 vector/src/main/res/drawable-hdpi/ic_widget_external_link.png create mode 100644 vector/src/main/res/drawable-hdpi/ic_widget_refresh.png create mode 100644 vector/src/main/res/drawable-mdpi/ic_widget_bin.png create mode 100644 vector/src/main/res/drawable-mdpi/ic_widget_external_link.png create mode 100644 vector/src/main/res/drawable-mdpi/ic_widget_refresh.png create mode 100644 vector/src/main/res/drawable-xhdpi/ic_widget_bin.png create mode 100644 vector/src/main/res/drawable-xhdpi/ic_widget_external_link.png create mode 100644 vector/src/main/res/drawable-xhdpi/ic_widget_refresh.png create mode 100644 vector/src/main/res/drawable-xxhdpi/ic_widget_bin.png create mode 100644 vector/src/main/res/drawable-xxhdpi/ic_widget_external_link.png create mode 100644 vector/src/main/res/drawable-xxhdpi/ic_widget_refresh.png create mode 100644 vector/src/main/res/drawable-xxxhdpi/ic_widget_bin.png create mode 100644 vector/src/main/res/drawable-xxxhdpi/ic_widget_external_link.png create mode 100644 vector/src/main/res/drawable-xxxhdpi/ic_widget_refresh.png create mode 100644 vector/src/main/res/layout/bottom_sheet_room_widget_permission.xml create mode 100644 vector/src/main/res/layout/fragment_room_widget.xml create mode 100644 vector/src/main/res/menu/menu_room_widget.xml diff --git a/vector/src/main/java/im/vector/VectorApp.java b/vector/src/main/java/im/vector/VectorApp.java index b8eabc13c9..5e798fb0df 100755 --- a/vector/src/main/java/im/vector/VectorApp.java +++ b/vector/src/main/java/im/vector/VectorApp.java @@ -28,7 +28,6 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; -import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; diff --git a/vector/src/main/java/im/vector/activity/StickerPickerActivity.kt b/vector/src/main/java/im/vector/activity/StickerPickerActivity.kt index a1ed6c3237..f83c623198 100755 --- a/vector/src/main/java/im/vector/activity/StickerPickerActivity.kt +++ b/vector/src/main/java/im/vector/activity/StickerPickerActivity.kt @@ -55,7 +55,7 @@ class StickerPickerActivity : AbstractWidgetActivity() { } override fun canScalarTokenBeProvided(): Boolean { - return widgetManager.isScalarUrl(this, mWidgetUrl) + return widgetManager.isScalarUrl( mWidgetUrl) } /** diff --git a/vector/src/main/java/im/vector/activity/VectorAppCompatActivity.kt b/vector/src/main/java/im/vector/activity/VectorAppCompatActivity.kt index 5c867ae13b..373829942b 100755 --- a/vector/src/main/java/im/vector/activity/VectorAppCompatActivity.kt +++ b/vector/src/main/java/im/vector/activity/VectorAppCompatActivity.kt @@ -30,6 +30,7 @@ import androidx.core.view.isVisible import butterknife.BindView import butterknife.ButterKnife import butterknife.Unbinder +import com.airbnb.mvrx.BaseMvRxActivity import im.vector.BuildConfig import im.vector.R import im.vector.VectorApp @@ -45,7 +46,7 @@ import org.matrix.androidsdk.core.Log /** * Parent class for all Activities in Vector application */ -abstract class VectorAppCompatActivity : AppCompatActivity() { +abstract class VectorAppCompatActivity : BaseMvRxActivity() { private var LOG_TAG = VectorAppCompatActivity::class.java.simpleName diff --git a/vector/src/main/java/im/vector/activity/VectorRoomActivity.java b/vector/src/main/java/im/vector/activity/VectorRoomActivity.java index 539db45a0c..e774279cfc 100755 --- a/vector/src/main/java/im/vector/activity/VectorRoomActivity.java +++ b/vector/src/main/java/im/vector/activity/VectorRoomActivity.java @@ -137,7 +137,6 @@ import im.vector.view.VectorOngoingConferenceCallView; import im.vector.view.VectorPendingCallView; import im.vector.widgets.Widget; -import im.vector.widgets.WidgetManagerProvider; import im.vector.widgets.WidgetsManager; /** diff --git a/vector/src/main/java/im/vector/activity/WidgetActivity.kt b/vector/src/main/java/im/vector/activity/WidgetActivity.kt index ecb17db300..6f0f1a3bad 100755 --- a/vector/src/main/java/im/vector/activity/WidgetActivity.kt +++ b/vector/src/main/java/im/vector/activity/WidgetActivity.kt @@ -20,70 +20,22 @@ package im.vector.activity import android.annotation.SuppressLint import android.content.Context import android.content.Intent -import android.graphics.Bitmap -import android.os.Build -import android.os.Handler -import android.os.Looper -import android.text.TextUtils -import android.view.View -import android.view.ViewGroup -import android.webkit.* -import android.widget.TextView -import androidx.appcompat.app.AlertDialog -import androidx.core.view.isInvisible -import androidx.core.view.isVisible -import butterknife.BindView -import butterknife.OnClick -import im.vector.Matrix +import android.graphics.Color +import android.widget.Toast +import androidx.core.content.ContextCompat +import androidx.lifecycle.Observer +import com.airbnb.mvrx.viewModel import im.vector.R +import im.vector.fragments.roomwidgets.* +import im.vector.ui.themes.ThemeUtils import im.vector.widgets.Widget -import im.vector.widgets.WidgetsManager -import org.jetbrains.anko.toast -import org.matrix.androidsdk.MXSession -import org.matrix.androidsdk.core.Log -import org.matrix.androidsdk.core.callback.ApiCallback -import org.matrix.androidsdk.core.model.MatrixError -import org.matrix.androidsdk.data.Room -import javax.net.ssl.HttpsURLConnection /* * This class displays a widget */ class WidgetActivity : VectorAppCompatActivity() { - // the linked widget - private var mWidget: Widget? = null - - // the session - private var mSession: MXSession? = null - - // the room - private var mRoom: Room? = null - - @BindView(R.id.widget_close_icon) - lateinit var mCloseWidgetIcon: View - - @BindView(R.id.widget_web_view) - lateinit var mWidgetWebView: WebView - - @BindView(R.id.widget_title) - lateinit var mWidgetTypeTextView: TextView - - private var mIsRefreshingToken = false - private var mTokenAlreadyRefreshed = false - private var mHistoryAlreadyCleared = false - - private lateinit var widgetsManager: WidgetsManager - /** - * Widget events listener - */ - private val mWidgetListener = WidgetsManager.onWidgetUpdateListener { widget -> - if (TextUtils.equals(widget.widgetId, mWidget!!.widgetId)) { - if (!widget.isActive) { - finish() - } - } - } + val viewModel: RoomWidgetViewModel by viewModel() /* ========================================================================================== * LIFE CYCLE @@ -91,284 +43,92 @@ class WidgetActivity : VectorAppCompatActivity() { override fun getLayoutRes() = R.layout.activity_widget - @SuppressLint("NewApi") - override fun initUiAndData() { - waitingView = findViewById(R.id.widget_progress_layout) - - mWidget = intent.getSerializableExtra(EXTRA_WIDGET_ID) as Widget - - if (null == mWidget || null == mWidget!!.url) { - Log.e(LOG_TAG, "## onCreate() : invalid widget") - finish() - return - } - - mSession = Matrix.getMXSession(this, mWidget!!.sessionId) - - - widgetsManager = Matrix.getInstance(this).getWidgetManagerProvider(mSession)?.getWidgetManager(this) - ?: run { - Log.e(LOG_TAG, "## onCreate() : No widget manager ") - finish() - return - } - - - if (null == mSession) { - Log.e(LOG_TAG, "## onCreate() : invalid session") - finish() - return - } - - mRoom = mSession!!.dataHandler.getRoom(mWidget!!.roomId) - - if (null == mRoom) { - Log.e(LOG_TAG, "## onCreate() : invalid room") - finish() - return - } - - mWidgetTypeTextView.text = mWidget!!.humanName + override fun getMenuRes() = R.menu.menu_room_widget - configureWebView() + override fun getTitleRes() = R.string.room_widget_activity_title - loadUrl() - } - - override fun onDestroy() { - mWidgetWebView.let { - (it.parent as ViewGroup).removeView(it) - it.removeAllViews() - it.destroy() - } - - super.onDestroy() - } - - override fun onResume() { - super.onResume() - - widgetsManager.addListener(mWidgetListener) - - mWidgetWebView.let { - it.resumeTimers() - it.onResume() - } - - refreshStatusBar() - } - - override fun onPause() { - super.onPause() - - mWidgetWebView.let { - it.pauseTimers() - it.onPause() - } - - widgetsManager.removeListener(mWidgetListener) - } - - /* ========================================================================================== - * UI EVENTS - * ========================================================================================== */ - - @OnClick(R.id.widget_close_icon) - internal fun onCloseClick() { - AlertDialog.Builder(this) - .setMessage(R.string.widget_delete_message_confirmation) - .setPositiveButton(R.string.remove) { _, _ -> - showWaitingView() - widgetsManager.closeWidget(mSession, mRoom, mWidget!!.widgetId, object : ApiCallback { - override fun onSuccess(info: Void?) { - hideWaitingView() - finish() - } - - private fun onError(errorMessage: String) { - hideWaitingView() - toast(errorMessage) - } - - override fun onNetworkError(e: Exception) { - onError(e.localizedMessage) - } - - override fun onMatrixError(e: MatrixError) { - onError(e.localizedMessage) - } - - override fun onUnexpectedError(e: Exception) { - onError(e.localizedMessage) - } - }) - } - .setNegativeButton(R.string.cancel, null) - .show() - } - - @OnClick(R.id.widget_back_icon) - internal fun onBackClicked() { - if (mWidgetWebView.canGoBack()) { - mWidgetWebView.goBack() - } else { - finish() - } - } - - /* ========================================================================================== - * PRIVATE - * ========================================================================================== */ - - /** - * Refresh the status bar - */ - private fun refreshStatusBar() { - val canCloseWidget = null == widgetsManager.checkWidgetPermission(mSession, mRoom) - - // close widget button - mCloseWidgetIcon.isInvisible = !canCloseWidget - } - - /** - * Load the widget call - */ @SuppressLint("NewApi") - private fun configureWebView() { - mWidgetWebView.let { - // xml value seems ignored - it.setBackgroundColor(0) - - // clear caches - it.clearHistory() - it.clearFormData() - it.clearCache(true) - - it.settings.let { - // does not cache the data - it.cacheMode = WebSettings.LOAD_NO_CACHE - - // Enable Javascript - it.javaScriptEnabled = true - - // Use WideViewport and Zoom out if there is no viewport defined - it.useWideViewPort = true - it.loadWithOverviewMode = true - - // Enable pinch to zoom without the zoom buttons - it.builtInZoomControls = true - - // Allow use of Local Storage - it.domStorageEnabled = true - - it.allowFileAccessFromFileURLs = true - it.allowUniversalAccessFromFileURLs = true - - it.displayZoomControls = false - } + override fun initUiAndData() { + configureToolbar() - // Permission requests - it.webChromeClient = object : WebChromeClient() { - override fun onPermissionRequest(request: PermissionRequest) { - Handler(Looper.getMainLooper()).post { request.grant(request.resources) } - } - } + supportActionBar?.setHomeAsUpIndicator(ContextCompat.getDrawable(this, R.drawable.ic_material_leave)?.let { + ThemeUtils.tintDrawableWithColor(it, Color.WHITE) + }) - it.webViewClient = object : WebViewClient() { - override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) { - showWaitingView() + viewModel.selectSubscribe(this, RoomWidgetViewModelState::status) { ws -> + when (ws) { + WidgetState.UNKWNOWN -> { } - - override fun onReceivedHttpError(view: WebView?, request: WebResourceRequest?, errorResponse: WebResourceResponse?) { - // In case of 403, try to refresh the scalar token - if (errorResponse?.statusCode == HttpsURLConnection.HTTP_FORBIDDEN - && !mTokenAlreadyRefreshed - && widgetsManager.isScalarUrl(this@WidgetActivity, mWidget!!.url)) { - mTokenAlreadyRefreshed = true - mIsRefreshingToken = true - - // Hide the webview because it's displaying an error message we try to fix by refreshing the token - mWidgetWebView.isVisible = false - - widgetsManager.clearScalarToken(this@WidgetActivity, mSession) - loadUrl() + WidgetState.WIDGET_NOT_ALLOWED -> { + val dFrag = supportFragmentManager.findFragmentByTag(FRAGMENT_TAG_PERMISSION) as? RoomWidgetPermissionBottomSheet + if (dFrag != null && dFrag.dialog?.isShowing == true && !dFrag.isRemoving) { + //already there + } else { + RoomWidgetPermissionBottomSheet.newInstance(viewModel.session!!.myUserId, viewModel.widget).show(supportFragmentManager, FRAGMENT_TAG_PERMISSION) } } - - override fun onPageFinished(view: WebView?, url: String?) { - // Check that the Activity is still alive - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && isDestroyed) { - return + WidgetState.WIDGET_ALLOWED -> { + //mount the webview fragment if needed + if (supportFragmentManager.findFragmentByTag(FRAGMENT_TAG_WEBVIEW) == null) { + supportFragmentManager.beginTransaction() + .replace(R.id.fragment_container, RoomWidgetFragment(), FRAGMENT_TAG_WEBVIEW) + .commit() } - - if (mIsRefreshingToken) { - // We are waiting for a scalar token refresh - return - } - - hideWaitingView() - - // Ensure the webview is visible, it may have been hidden during token refresh - mWidgetWebView.isVisible = true - - if (mTokenAlreadyRefreshed && !mHistoryAlreadyCleared) { - // Also clear WebView history, for the scenario when the scalar token was invalid, to avoid loading again the url with the invalid token - // It has to be done when page has finished to be loaded - mHistoryAlreadyCleared = true - mWidgetWebView.clearHistory() - } - } - } + WidgetState.CLOSING_WIDGET -> { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - val cookieManager = android.webkit.CookieManager.getInstance() - cookieManager.setAcceptThirdPartyCookies(mWidgetWebView, true) + } } } - } - private fun loadUrl() { - showWaitingView() - widgetsManager.getFormattedWidgetUrl(this, mWidget!!, object : ApiCallback { - override fun onSuccess(url: String) { - mIsRefreshingToken = false + viewModel.selectSubscribe(this, RoomWidgetViewModelState::widgetName) { name -> + supportActionBar?.title = name + } - hideWaitingView() - mWidgetWebView.loadUrl(url) - } + viewModel.selectSubscribe(this, RoomWidgetViewModelState::canManageWidgets) { + invalidateOptionsMenu() + } - private fun onError(errorMessage: String) { - hideWaitingView() - toast(errorMessage) - finish() + viewModel.navigateEvent.observe(this, Observer { uxStateEvent -> + when (uxStateEvent?.getContentIfNotHandled()) { + RoomWidgetViewModel.NAVIGATE_FINISH -> { + finish() + } } + }) - override fun onNetworkError(e: Exception) { - onError(e.localizedMessage) + viewModel.toastMessageEvent.observe(this, Observer { + it?.getContentIfNotHandled()?.let { + Toast.makeText(this, it, Toast.LENGTH_LONG).show() } + }) + } - override fun onMatrixError(e: MatrixError) { - onError(e.localizedMessage) - } + /* ========================================================================================== + * UI EVENTS + * ========================================================================================== */ - override fun onUnexpectedError(e: Exception) { - onError(e.localizedMessage) - } - }) + override fun onBackPressed() { + //Hugly i know + (supportFragmentManager.findFragmentByTag(FRAGMENT_TAG_WEBVIEW) as? RoomWidgetFragment)?.let { widgetFragment -> + if (widgetFragment.onBackPressed()) return + } + super.onBackPressed() } + /* ========================================================================================== * companion * ========================================================================================== */ companion object { - private val LOG_TAG = WidgetActivity::class.java.simpleName + private const val FRAGMENT_TAG_PERMISSION = "FRAGMENT_TAG_PERMISSION" + private const val FRAGMENT_TAG_WEBVIEW = "WebView" /** * The linked widget */ - private const val EXTRA_WIDGET_ID = "EXTRA_WIDGET_ID" + const val EXTRA_WIDGET_ID = "EXTRA_WIDGET_ID" fun getIntent(context: Context, widget: Widget): Intent { return Intent(context, WidgetActivity::class.java) diff --git a/vector/src/main/java/im/vector/fragments/roomwidgets/RoomWidgetFragment.kt b/vector/src/main/java/im/vector/fragments/roomwidgets/RoomWidgetFragment.kt new file mode 100644 index 0000000000..baf27397da --- /dev/null +++ b/vector/src/main/java/im/vector/fragments/roomwidgets/RoomWidgetFragment.kt @@ -0,0 +1,328 @@ +/* + * Copyright 2019 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. + */ +package im.vector.fragments.roomwidgets + +import android.annotation.SuppressLint +import android.graphics.Bitmap +import android.os.Build +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.view.Menu +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup +import android.webkit.* +import android.widget.ProgressBar +import android.widget.TextView +import androidx.annotation.RequiresApi +import androidx.core.view.isInvisible +import androidx.core.view.isVisible +import androidx.lifecycle.Observer +import butterknife.BindView +import com.airbnb.mvrx.* +import im.vector.R +import im.vector.fragments.VectorBaseMvRxFragment +import im.vector.ui.themes.ThemeUtils +import im.vector.util.openUrlInExternalBrowser + +class RoomWidgetFragment : VectorBaseMvRxFragment() { + + var mWidgetWebView: WebView? = null + + @BindView(R.id.webview_error_layout) + lateinit var errorContainer: ViewGroup + + @BindView(R.id.webview_error_text) + lateinit var errorText: TextView + + + @BindView(R.id.widget_progress_bar) + lateinit var webProgressBar: ProgressBar + + val viewModel: RoomWidgetViewModel by activityViewModel() + + override fun getLayoutResId(): Int = R.layout.fragment_room_widget + + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + configureWebView() + setHasOptionsMenu(true) + viewModel.loadWebURLEvent.observe(this, Observer { + it?.getContentIfNotHandled()?.let { + mWidgetWebView?.clearHistory() + mWidgetWebView?.loadUrl(it) + mWidgetWebView?.isVisible = true + } + }) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + mWidgetWebView = view.findViewById(R.id.widget_web_view) + } + + override fun onDestroy() { + //Looks like WebView creates memory leaks (?) according to legacy code + //We have to take additional steps to clear memory + destroyWebView() + super.onDestroy() + } + + private fun destroyWebView() { + + val webview = mWidgetWebView ?: return + // Make sure you remove the WebView from its parent view before doing anything. + (webview.parent as? ViewGroup)?.removeAllViews() + + webview.webViewClient = null + webview.clearHistory() + + // NOTE: clears RAM cache, if you pass true, it will also clear the disk cache. + webview.clearCache(true) + + // Loading a blank page is optional, but will ensure that the WebView isn't doing anything when you destroy it. + webview.loadUrl("about:blank") + + webview.onPause() + webview.removeAllViews() + + // NOTE: This pauses JavaScript execution for ALL WebViews, + // do not use if you have other WebViews still alive. + // If you create another WebView after calling this, + // make sure to call mWebView.resumeTimers(). + webview.pauseTimers() + + // NOTE: This can occasionally cause a segfault below API 17 (4.2) + webview.destroy() + + // Null out the reference so that you don't end up re-using it. + mWidgetWebView = null + } + + private var webViewClient = object : WebViewClient() { + + var isInError = false + var currentPage: String? = null + + override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) { +// Log.d("WEBVIEW", "onPageStarted $url") + isInError = false + currentPage = url + viewModel.webviewStartedToLoad(url) + } + + @RequiresApi(Build.VERSION_CODES.LOLLIPOP) + override fun onReceivedHttpError(view: WebView?, request: WebResourceRequest?, errorResponse: WebResourceResponse?) { +// Log.d("WEBVIEW", "onReceivedHttpError ${request?.url}") + if (request?.url.toString() != currentPage) { + // Ignore this error + return + } + isInError = true + viewModel.webviewLoadingError(request?.url?.toString(), + errorResponse?.reasonPhrase?.takeIf { it.isNotBlank() } + ?: errorResponse?.statusCode.toString()) + } + + override fun onReceivedError(view: WebView, errorCode: Int, description: String, failingUrl: String) { + isInError = true + viewModel.webviewLoadingError(failingUrl, description) + } + + override fun onPageFinished(view: WebView?, url: String?) { +// Log.d("WEBVIEW", "onPageFinished ${url}") + if (!isInError) { + viewModel.webviewLoadSuccess(url) + } + } + } + + + override fun invalidate() = withState(viewModel) { state -> + // mWidgetTypeTextView.text = it.widgetName + when (state.status) { + WidgetState.UNKWNOWN -> { + //Hide all? + mWidgetWebView?.isVisible = false + } + WidgetState.WIDGET_NOT_ALLOWED -> { + mWidgetWebView?.isVisible = false + } + WidgetState.WIDGET_ALLOWED -> { + mWidgetWebView?.isVisible = true + when (state.formattedURL) { + Uninitialized -> { + } + is Loading -> { + setError(null) + webProgressBar.isIndeterminate = true + webProgressBar.isVisible = true + } + is Success -> { + setError(null) + when (state.webviewLoadedUrl) { + Uninitialized -> { + mWidgetWebView?.isInvisible = true + } + is Loading -> { + setError(null) + mWidgetWebView?.isInvisible = false + webProgressBar.isIndeterminate = true + webProgressBar.isVisible = true + } + is Success -> { + mWidgetWebView?.isInvisible = false + webProgressBar.isVisible = false + setError(null) + } + is Fail -> { + webProgressBar.isInvisible = true + setError(state.webviewLoadedUrl.error.message) + } + } + } + is Fail -> { + //we need to show Error + mWidgetWebView?.isInvisible = true + webProgressBar.isVisible = false + setError(state.formattedURL.error.message) + } + } + } + WidgetState.CLOSING_WIDGET -> { +// showWaitingView() + } + } + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean = withState(viewModel) { state -> + when (item.itemId) { + R.id.action_close -> { + viewModel.doCloseWidget(requireContext()) + return@withState true + } + R.id.action_refresh -> if (state.formattedURL.complete) { + mWidgetWebView?.reload() + return@withState true + } + R.id.action_widget_open_ext -> if (state.formattedURL.complete) { + openUrlInExternalBrowser(requireContext(), state.formattedURL.invoke()) + return@withState true + } + } + return@withState super.onOptionsItemSelected(item) + } + + override fun onPrepareOptionsMenu(menu: Menu?) = withState(viewModel) { state -> + menu?.findItem(R.id.action_close)?.let { + it.isVisible = state.canManageWidgets + } + super.onPrepareOptionsMenu(menu) + } + + fun onBackPressed(): Boolean = withState(viewModel) { state -> + if (state.formattedURL.complete) { + if (mWidgetWebView?.canGoBack() == true) { + mWidgetWebView?.goBack() + return@withState true + } + } + return@withState false + } + + private fun setError(message: String?) { + if (message == null) { + errorContainer.isVisible = false + errorText.text = null + } else { + webProgressBar.isVisible = false + errorContainer.isVisible = true + mWidgetWebView?.isInvisible = true + errorText.text = getString(R.string.room_widget_failed_to_load, message) + } + } + + /** + * Load the widget call + */ + @SuppressLint("NewApi") + private fun configureWebView() { + mWidgetWebView?.let { + // xml value seems ignored + it.setBackgroundColor(ThemeUtils.getColor(requireContext(), R.attr.vctr_bottom_nav_background_color)) + + // clear caches + it.clearHistory() + it.clearFormData() + it.clearCache(true) + + it.settings.let { settings -> + // does not cache the data + settings.cacheMode = WebSettings.LOAD_NO_CACHE + + // Enable Javascript + settings.javaScriptEnabled = true + + // Use WideViewport and Zoom out if there is no viewport defined + settings.useWideViewPort = true + settings.loadWithOverviewMode = true + + // Enable pinch to zoom without the zoom buttons + settings.builtInZoomControls = true + + // Allow use of Local Storage + settings.domStorageEnabled = true + + settings.allowFileAccessFromFileURLs = true + settings.allowUniversalAccessFromFileURLs = true + + settings.displayZoomControls = false + } + + // Permission requests + it.webChromeClient = object : WebChromeClient() { + override fun onPermissionRequest(request: PermissionRequest) { + Handler(Looper.getMainLooper()).post { request.grant(request.resources) } + } + } + + it.webViewClient = webViewClient + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + val cookieManager = CookieManager.getInstance() + cookieManager.setAcceptThirdPartyCookies(mWidgetWebView, true) + } + } + } + + override fun onResume() { + super.onResume() + mWidgetWebView?.let { + it.resumeTimers() + it.onResume() + } + } + + override fun onPause() { + super.onPause() + mWidgetWebView?.let { + it.pauseTimers() + it.onPause() + } + } + +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/fragments/roomwidgets/RoomWidgetPermissionBottomSheet.kt b/vector/src/main/java/im/vector/fragments/roomwidgets/RoomWidgetPermissionBottomSheet.kt new file mode 100644 index 0000000000..3f083b6f1f --- /dev/null +++ b/vector/src/main/java/im/vector/fragments/roomwidgets/RoomWidgetPermissionBottomSheet.kt @@ -0,0 +1,115 @@ +/* + * Copyright 2019 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. + */ +package im.vector.fragments.roomwidgets + +import android.os.Build +import android.os.Parcelable +import android.text.Spannable +import android.text.SpannableStringBuilder +import android.text.style.BulletSpan +import android.widget.ImageView +import android.widget.TextView +import butterknife.BindView +import butterknife.OnClick +import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.activityViewModel +import com.airbnb.mvrx.fragmentViewModel +import com.airbnb.mvrx.withState +import im.vector.R +import im.vector.extensions.withArgs +import im.vector.fragments.VectorBaseBottomSheetDialogFragment +import im.vector.util.VectorUtils +import im.vector.widgets.Widget +import kotlinx.android.parcel.Parcelize + +class RoomWidgetPermissionBottomSheet : VectorBaseBottomSheetDialogFragment() { + + override fun getLayoutResId(): Int = R.layout.bottom_sheet_room_widget_permission + + private val viewModel: RoomWidgetPermissionViewModel by fragmentViewModel() + + @BindView(R.id.bottom_sheet_widget_permission_shared_info) + lateinit var sharedInfoTextView: TextView + + @BindView(R.id.bottom_sheet_widget_permission_owner_id) + lateinit var authorIdText: TextView + + @BindView(R.id.bottom_sheet_widget_permission_owner_display_name) + lateinit var authorNameText: TextView + + @BindView(R.id.bottom_sheet_widget_permission_owner_avatar) + lateinit var authorAvatarView: ImageView + + private val sharedActivityViewModel: RoomWidgetViewModel by activityViewModel() + + override fun invalidate() = withState(viewModel) { state -> + + authorIdText.text = state.authorId + authorNameText.text = state.authorName ?: "" + VectorUtils.loadUserAvatar(requireContext(), viewModel.session, authorAvatarView, + state.authorAvatarUrl, state.authorId, state.authorName) + + val infoBuilder = SpannableStringBuilder() + .append(getString(R.string.room_widget_permission_shared_info_title, "'${state.widgetDomain + ?: ""}'")) + infoBuilder.append("\n") + + state.permissionsList?.forEach { + infoBuilder.append("\n") + val bulletPoint = getString(it) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + infoBuilder.append(bulletPoint, BulletSpan(resources.getDimension(R.dimen.quote_gap).toInt()), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) + } else { + val start = infoBuilder.length + infoBuilder.append(bulletPoint) + infoBuilder.setSpan(BulletSpan(resources.getDimension(R.dimen.quote_gap).toInt()), start, bulletPoint.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) + } + } + infoBuilder.append("\n") + + sharedInfoTextView.text = infoBuilder + } + + @OnClick(R.id.bottom_sheet_widget_permission_decline_button) + fun doDecline() { + viewModel.blockWidget { + dismiss() + sharedActivityViewModel.doFinish() + } + } + + @OnClick(R.id.bottom_sheet_widget_permission_continue_button) + fun doAccept() { + viewModel.allowWidget { + dismiss() + } + } + + @Parcelize + data class FragArgs( + val widget: Widget, + val mxId: String + ) : Parcelable + + + companion object { + + fun newInstance(matrixId: String, widget: Widget) = RoomWidgetPermissionBottomSheet().withArgs { + putParcelable(MvRx.KEY_ARG, FragArgs(widget, matrixId)) + } + + } +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/fragments/roomwidgets/RoomWidgetPermissionViewModel.kt b/vector/src/main/java/im/vector/fragments/roomwidgets/RoomWidgetPermissionViewModel.kt new file mode 100644 index 0000000000..929317ed41 --- /dev/null +++ b/vector/src/main/java/im/vector/fragments/roomwidgets/RoomWidgetPermissionViewModel.kt @@ -0,0 +1,126 @@ +/* + * Copyright 2019 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. + */ +package im.vector.fragments.roomwidgets + +import com.airbnb.mvrx.BaseMvRxViewModel +import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.ViewModelContext +import im.vector.Matrix +import im.vector.R +import im.vector.widgets.Widget +import org.matrix.androidsdk.MXSession +import org.matrix.androidsdk.core.callback.ApiCallback +import org.matrix.androidsdk.core.model.MatrixError +import java.net.URL + +data class RoomWidgetPermissionViewState( + val authorId: String = "", + val authorAvatarUrl: String? = null, + val authorName: String? = null, + val widgetDomain: String? = null, + //List of @StringRes + val permissionsList: List? = null +) : MvRxState + +class RoomWidgetPermissionViewModel(val session: MXSession, val widget: Widget, initialState: RoomWidgetPermissionViewState) + : BaseMvRxViewModel(initialState, false) { + + init { + val room = session.dataHandler.getRoom(widget.roomId) + val creator = room.getMember(widget.widgetEvent.sender) + + var domain: String? + try { + domain = URL(widget.url).host + } catch (e: Throwable) { + domain = null + } + + //TODO check from widget urls the perms that should be shown? + //For now put all + val infoShared = listOf( + R.string.room_widget_permission_ip_address, + R.string.room_widget_permission_useragent, + R.string.room_widget_permission_widget_id, + R.string.room_widget_permission_room_id, + R.string.room_widget_permission_matrix_profile + ) + setState { + copy( + authorName = creator?.displayname, + authorId = widget.widgetEvent.sender, + authorAvatarUrl = creator?.getAvatarUrl(), + widgetDomain = domain, + permissionsList = infoShared + ) + } + } + + fun allowWidget(onFinished: (() -> Unit)) { + session.integrationManager.setWidgetAllowed(widget.widgetEvent?.eventId + ?: "", true, object : ApiCallback { + override fun onSuccess(info: Void?) { + onFinished() + } + + override fun onUnexpectedError(e: Exception?) { + //TODO.. make the button with a loading state? + } + + override fun onNetworkError(e: Exception?) { + //TODO.. make the button with a loading state? + } + + override fun onMatrixError(e: MatrixError?) { + //TODO.. make the button with a loading state? + } + + }) + } + + fun blockWidget(onFinished: (() -> Unit)) { + session.integrationManager.setWidgetAllowed(widget.widgetEvent?.eventId + ?: "", false, object : ApiCallback { + override fun onSuccess(info: Void?) { + onFinished() + } + + override fun onUnexpectedError(e: Exception?) { + //TODO.. make the button with a loading state? + } + + override fun onNetworkError(e: Exception?) { + //TODO.. make the button with a loading state? + } + + override fun onMatrixError(e: MatrixError?) { + //TODO.. make the button with a loading state? + } + + }) + } + + companion object : MvRxViewModelFactory { + + override fun create(viewModelContext: ViewModelContext, state: RoomWidgetPermissionViewState): RoomWidgetPermissionViewModel? { + val args = viewModelContext.args() + val session = Matrix.getMXSession(viewModelContext.activity, args.mxId) + return RoomWidgetPermissionViewModel(session, args.widget, state) + } + + } +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/fragments/roomwidgets/RoomWidgetViewModel.kt b/vector/src/main/java/im/vector/fragments/roomwidgets/RoomWidgetViewModel.kt new file mode 100644 index 0000000000..a11aa38029 --- /dev/null +++ b/vector/src/main/java/im/vector/fragments/roomwidgets/RoomWidgetViewModel.kt @@ -0,0 +1,286 @@ +/* + * Copyright 2019 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. + */ +package im.vector.fragments.roomwidgets + +import android.content.Context +import android.text.TextUtils +import androidx.appcompat.app.AlertDialog +import androidx.lifecycle.MutableLiveData +import com.airbnb.mvrx.* +import im.vector.Matrix +import im.vector.R +import im.vector.VectorApp +import im.vector.activity.WidgetActivity +import im.vector.ui.arch.LiveEvent +import im.vector.widgets.Widget +import im.vector.widgets.WidgetsManager +import org.matrix.androidsdk.MXSession +import org.matrix.androidsdk.core.callback.ApiCallback +import org.matrix.androidsdk.core.model.MatrixError +import org.matrix.androidsdk.data.Room +import org.matrix.androidsdk.features.integrationmanager.IntegrationManager + +enum class WidgetState { + UNKWNOWN, + WIDGET_NOT_ALLOWED, + WIDGET_ALLOWED, + CLOSING_WIDGET +} + +data class RoomWidgetViewModelState( + val status: WidgetState = WidgetState.UNKWNOWN, + val formattedURL: Async = Uninitialized, + val webviewLoadedUrl: Async = Uninitialized, + val widgetName: String = "", + val authorName: String? = null, + val authorId: String? = null, + val canManageWidgets: Boolean = false +) : MvRxState + +class RoomWidgetViewModel(initialState: RoomWidgetViewModelState, val widget: Widget) + : BaseMvRxViewModel(initialState, false) { + + companion object : MvRxViewModelFactory { + const val NAVIGATE_FINISH = "NAVIGATE_FINISH" + //private val LOG_TAG = KeysBackupSetupSharedViewModel::class.java.name + + + override fun create(viewModelContext: ViewModelContext, state: RoomWidgetViewModelState): RoomWidgetViewModel? { + return (viewModelContext.activity.intent?.extras?.getSerializable(WidgetActivity.EXTRA_WIDGET_ID) as? Widget)?.let { + RoomWidgetViewModel(state, it) + } ?: super.create(viewModelContext, state) + } + + } + + var navigateEvent: MutableLiveData> = MutableLiveData() + var loadWebURLEvent: MutableLiveData> = MutableLiveData() + var toastMessageEvent: MutableLiveData> = MutableLiveData() + + private var room: Room? = null + + var session: MXSession? = null + + var widgetsManager: WidgetsManager? = null + + /** + * Widget events listener + */ + private val mWidgetListener = WidgetsManager.onWidgetUpdateListener { widget -> + if (TextUtils.equals(widget.widgetId, widget.widgetId)) { + if (!widget.isActive) { + doFinish() + } + } + } + + init { + setState { + copy(widgetName = widget.humanName) + } + configure() + + session?.integrationManager?.addListener(object : IntegrationManager.IntegrationManagerManagerListener { + override fun onIntegrationManagerChange(managerConfig: IntegrationManager) { + refreshPermissionStatus() + } + + }) + } + + fun webviewStartedToLoad(url: String?) = withState { + //Only do it for first load + setState { + copy(webviewLoadedUrl = Loading()) + } + } + + fun webviewLoadingError(url: String?, reason: String?) = withState { + setState { + copy(webviewLoadedUrl = Fail(Throwable(reason))) + } + } + + fun webviewLoadSuccess(url: String?) = withState { + setState { + copy(webviewLoadedUrl = Success(url ?: "")) + } + } + + private fun configure() { + + val applicationContext = VectorApp.getInstance().applicationContext + val matrix = Matrix.getInstance(applicationContext) + + session = matrix.getSession(widget.sessionId) + + if (session == null) { + //defensive code + doFinish() + return + } + + room = session?.dataHandler?.getRoom(widget.roomId) + + if (room == null) { + //defensive code + doFinish() + return + } + + widgetsManager = matrix + .getWidgetManagerProvider(session)?.getWidgetManager(applicationContext) + + setState { + copy(canManageWidgets = WidgetsManager.checkWidgetPermission(session, room) == null) + } + + + widgetsManager?.addListener(mWidgetListener) + + refreshPermissionStatus(applicationContext) + } + + private fun refreshPermissionStatus(applicationContext: Context = VectorApp.getInstance().applicationContext) { + + //If it was added by me, consider it as allowed + if (widget.widgetEvent.getSender() == session?.myUserId) { + onWidgetAllowed(applicationContext) + return + } + + val isAllowed = session + ?.integrationManager + ?.getKnownWidgetPermissions() + ?.findLast { it.stateEventId == widget.widgetEvent.eventId } + ?.allowed + ?: false + + if (!isAllowed) { + setState { + copy(status = WidgetState.WIDGET_NOT_ALLOWED) + } + } else { + //we can start loading the widget then + onWidgetAllowed(applicationContext) + } + } + + + fun doCloseWidget(context: Context) { + AlertDialog.Builder(context) + .setMessage(R.string.widget_delete_message_confirmation) + .setPositiveButton(R.string.remove) { _, _ -> + // showWaitingView() + + setState { + copy(status = WidgetState.CLOSING_WIDGET) + } + + widgetsManager?.closeWidget(session, room, widget.widgetId, object : ApiCallback { + override fun onSuccess(info: Void?) { + doFinish() + } + + private fun onError(errorMessage: String) { + toastMessageEvent.postValue(LiveEvent(errorMessage)) + //TODO should not be handled with this state + setState { + copy(status = WidgetState.WIDGET_ALLOWED) + } + } + + override fun onNetworkError(e: Exception) { + onError(e.localizedMessage) + } + + override fun onMatrixError(e: MatrixError) { + onError(e.localizedMessage) + } + + override fun onUnexpectedError(e: Exception) { + onError(e.localizedMessage) + } + }) + } + .setNegativeButton(R.string.cancel, null) + .show() + } + + fun doFinish() { + navigateEvent.postValue(LiveEvent(NAVIGATE_FINISH)) + } + + private fun onWidgetAllowed(applicationContext: Context = VectorApp.getInstance().applicationContext) { + + setState { + copy( + status = WidgetState.WIDGET_ALLOWED, + formattedURL = Loading() + ) + } + if (widgetsManager != null) { + widgetsManager!!.getFormattedWidgetUrl(applicationContext, widget, object : ApiCallback { + override fun onSuccess(url: String) { + loadWebURLEvent.postValue(LiveEvent(url)) + setState { + //We use a live event to trigger the webview load + copy( + status = WidgetState.WIDGET_ALLOWED, + formattedURL = Success(url) + ) + } + } + + private fun onError(errorMessage: String) { + setState { + copy( + status = WidgetState.WIDGET_ALLOWED, + formattedURL = Fail(Throwable(errorMessage)) + ) + } + } + + override fun onNetworkError(e: Exception) { + onError(e.localizedMessage) + } + + override fun onMatrixError(e: MatrixError) { + onError(e.localizedMessage) + } + + override fun onUnexpectedError(e: Exception) { + onError(e.localizedMessage) + } + }) + } else { + setState { + copy( + status = WidgetState.WIDGET_ALLOWED, + formattedURL = Success(widget.url) + ) + } + loadWebURLEvent.postValue(LiveEvent(widget.url)) + } + } + + override fun onCleared() { + super.onCleared() + widgetsManager?.removeListener(mWidgetListener) + } + + +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/widgets/IntegrationManagerConfig.kt b/vector/src/main/java/im/vector/widgets/IntegrationManagerConfig.kt index d38aeba552..0eda53b71b 100644 --- a/vector/src/main/java/im/vector/widgets/IntegrationManagerConfig.kt +++ b/vector/src/main/java/im/vector/widgets/IntegrationManagerConfig.kt @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package im.vector.widgets /** diff --git a/vector/src/main/java/im/vector/widgets/WidgetsManager.java b/vector/src/main/java/im/vector/widgets/WidgetsManager.java index 174e892fac..f6822832c1 100755 --- a/vector/src/main/java/im/vector/widgets/WidgetsManager.java +++ b/vector/src/main/java/im/vector/widgets/WidgetsManager.java @@ -85,7 +85,7 @@ public String getUIUrl() { /** * Widget error code */ - public class WidgetError extends MatrixError { + public static class WidgetError extends MatrixError { public static final String WIDGET_NOT_ENOUGH_POWER_ERROR_CODE = "WIDGET_NOT_ENOUGH_POWER_ERROR_CODE"; public static final String WIDGET_CREATION_FAILED_ERROR_CODE = "WIDGET_CREATION_FAILED_ERROR_CODE"; @@ -236,7 +236,7 @@ public List getActiveWebviewWidgets(final MXSession session, final Room * @return an error if the user cannot act on widgets in this room. Else, null. */ - public WidgetError checkWidgetPermission(MXSession session, Room room) { + public static WidgetError checkWidgetPermission(MXSession session, Room room) { WidgetError error = null; if ((null != room) && (null != room.getState()) && (null != room.getState().getPowerLevels())) { @@ -489,7 +489,7 @@ public void onLiveEvent(MXSession session, Event event) { * @param callback the callback */ public void getFormattedWidgetUrl(final Context context, final Widget widget, final ApiCallback callback) { - if (isScalarUrl(context, widget.getUrl())) { + if (isScalarUrl(widget.getUrl())) { getScalarToken(context, Matrix.getInstance(context).getSession(widget.getSessionId()), new SimpleApiCallback(callback) { @Override public void onSuccess(String token) { @@ -509,11 +509,10 @@ public void onSuccess(String token) { /** * Return true if the url is allowed to receive the scalar token in parameter * - * @param context * @param url * @return true if the url is allowed to receive the scalar token in parameter */ - public boolean isScalarUrl(Context context, String url) { + public boolean isScalarUrl(String url) { List allowed = config.getWhiteListedUrls(); for (String allowedUrl : allowed) { if (url.startsWith(allowedUrl)) { diff --git a/vector/src/main/res/drawable-hdpi/ic_widget_bin.png b/vector/src/main/res/drawable-hdpi/ic_widget_bin.png new file mode 100644 index 0000000000000000000000000000000000000000..69d9ef5efacfcfd0ad2009bb0c46006580ad1cd4 GIT binary patch literal 756 zcmV)IbX=o|v69l9n5~Rfnf(HN1?J#TDi@kUc`y3QS@-?^f-kUc!dwcfn zAq;qs>n3Vn+LHn?(=SC5RZ=ISo9McYe!PjH379d>KaSU1<@-Q%n*gFF-yO4A8xR+h zvFrja-D-Ao<~U*kX546&9|2Gf0iOtfS0qH$)TkJxO!I|ZC89f=bC{tU{d5`&?6{FD zoc6%`1SpE>rwyh=tc{X1YgWizL*LTbQ9Du3z;&pz5_$d&6m`y57aljgrv&92)Z^n)c+_Bvv9JBw01yM^~d%Z1U;d-!VX-{24DgBNKoDZE; zf{S*Gkjx)X68K&__=S@voppY#-yo2S^<4fk|G)b0+*&;BS$TB4*poL3>&a|%Lwod? zH)abH(vxev4LQq1l>lp680L&XDc&=udHeHGIASVMDsE|?p27-LpB(Dt))YuQ56D}Z mQ4Yci2zr~$#@5VF6u$sLjOzg+^1z<}0000UjV{oVVn4B{a5#+Iu;K%qo?y+G&6q!Ico|BFg!u(Gs zjtEZhEBq3F#jEV66ICD)04D1|As$d0mk!Jd0Sy*K04|nwKITVT>h0lD(>Eyy$F73J6Key-|(@`CH&Vx6EZ3aC3mn4JR_4)Ais zhkIj5jA6V20v?jH8zcxgCXED0ou(oh3ur0=0i|Cg}^SG1|hmN4qm+jAi|C*aZ^bhRKgX1F{|7oJOP4xdkg^8PRp zFr)R6Uu%?&(%pT0fS*XMD461PUw%lfH0gl6SVjK<2m$~-uYu8v$_3LjyS_@<{Nb!+jZe^?&F;Q z`QLLN-~9}m)>*7pYmm`sjEjnjN;jEI;kmiFQ+<7Xi|c{Y`Qx;WGB-DOa&d977)i$0 z?XT16oU{j#Hl$``WJKy~DsGUKtW#1_QWq8$9%5r9*c`eA{fWMD^aO-Vdc8h_b{6e} zw2kOD*p))Yu7#bRp1yT*L>Nyz*L={^hy}oeh~F zO1{@ULGUgOC%?Nm|DgnlVOh0E2;LVYh6`)hZ}9&P|1twh8#6I6@i-e~%2y!P))^lk z-`U>YE+4NAFFGN>=4o65a*-UdHQ4!WB1dG3qqO7*nYTzKvY;ZlG64y-+wVHZzZ9n} zoWK&*Sv{f;2zCZ>a9yA9ye;`Ms(yag<^8~es0_!)p3d$YlfW;@fZUe(obhJ9c;TML zfwUoTRs6XzZ+YUlNyq?cs)dM+>i(ITnKp~XA~##Wg)in_Ku#l%$nbYhz`sbyAVi+S zwh%Hqrl+Sn$VjZGlRxd{r(qMzJQ5Zbc3sQYi-Z`#wh0o4sU|rbj;`gIX!)<$$3EE3 z(zaqW9}*IB$Zoe!YB^|<5JNVid~Ww44uCq?*(Hz(k+Ic^Jmq*8U1J|~G8uXF9_jDz z|LV(6FUL;?U0O9{Y3wY`F8W?GUIm$NfR{^(%gV~UCcw-y7^~>+?v|refxL={h_EoB z9u?QKu9Kgbv9Ym&goK2~m2O19b0BgFISPn8S{=v$A}Nk#wsDL_qL+RN=&NNC&FEE& z*Lz|$53|{v;B-2LPzGYgK7zpGXn6<^khuo-l+RxRE&M;6G^PTx&#e&v00002j85@c1RSWE+a5ONBn)V~dT02aq4M41@Ou3bXvL76a1c!fZXm^Ly^yxwAK^HKi0qu}A6pr1F$fe|AzJ=qt$k zcDWtwEf(!07ns@<8O0ai47~gj6IjNv2)=-q5wCaaot14!d-%GbUABV20md=719QO3 zJ&tYflx;~_{2IGk=ArBY$wKMK_@Sl)p7gBB(EDJ}#<2-bSnatAMxJ9b^|Ys*`Wm%D zebxzwrGfMYqLe*u4Wuo0f36*>6=7*2wM1d!98xV1BF-fZ5l2YLxdLmp6}5*)@;u3J zV3k98wS`V!!T$4M)e?`%hK?j;hI$-ga!LP_SiAmoZ<1?{D44NDB7Fcm)|sO-Il2`$ zz@x281T-e^-~*h3+DRd9MHkp1IAVeZKA_85JKqOO!2gfge6QX-V69qIo7qKBi>T$$ z2Mo5Du|+K=CTLd_G1Q_!h=LXqv=E|^mIV(#@S|L`DUwQ16Mg;eqx*Oc=)75W;BvnI z@7#0Gd5UWS8HS-~nzmO})#HTiLEnk2yWQ?jrBdnhgjAO@&KVAeQvfaF7ko`ol<&xG z&H?l!`~zpD(P+GbTa-v7b_m67S!@DTE|7c;(|jNhI8`VVIySc}9*=M9cDomdc}DDF zyff)nC~ySUwqh#d}xDplV>JOuay3)l(J#u)m05u3QBoivnLyW#(k z%~o)wRr>P9UNZU{`n_(qZADgjfF%;nbHbdVJOCTWj)}RSmRl#1J_Fcms(kJk z?O!0pMVX5Cyy~`vQhJF)(?AvlvAnHb~f!Nl?sgA z`Fy@BeS#}A{V-0&J^|@;daBuM-o<~GHa*3^POCnmPje%&X>-_4V_QuolMA_AZh&os zCT<>UK121F$(ZE>ak%&&i~sUluh;vcSS*f=D0Ykf0w2BE@%qa~t^fc407*qoM6N<$ Ef)J}RivR!s literal 0 HcmV?d00001 diff --git a/vector/src/main/res/drawable-xhdpi/ic_widget_bin.png b/vector/src/main/res/drawable-xhdpi/ic_widget_bin.png new file mode 100644 index 0000000000000000000000000000000000000000..f3c9cb9188bf1ba8c5413156c6af5da7040a96e6 GIT binary patch literal 946 zcmV;j15NyiP)6X5vOqe2wI;ssV}^kCBEo$DwI`tMc!?wD zlI4m~B;t=p(+vQrL3aBDJNh9|yDf~@E-aSIlQC5e%=*N__f7&3;-&+q8k(`SHEot7 z;uwh}xSOVliRSpdS5xf%5y8cCS47;bDP{l}C&VT(CQvS06(@5=FLFrnWJO7?f8$1D z%K};10YRd8@vRY=*}UR`H(5-M%M35#)&&B2MFOF^Bzik7pS#Rug`)z2R_Lma!B}Tx zmlaw{>d)A}5U6S+dOT4pImH-Cr$dlRF%L%3r!^MGOI@p!OwN`H7|wA4N~H|L)&dl= zT36+T@bd~O;#OV;Hu3c@p8vfvzXk(d!Zvf6Exefj0ivI>WWhomYwH=}g}4h9><*3& z4olEl^s$bfF3QjlFXY3)@xg9cbKQSQT!HeVvfH~3+I3FmxeiJv?Dp&4LCYJ~Vh3Vv zeTR9MJV~f@@D~1Vaa>&UUxYJAnNi+-w*<%gpO(Uy&DnQQNjLG&Q#}%$G%6xu0t1XS z!kEq57ih*@rMN55sgbUOu7ge;aGLKvgRX;49dMezai2lVz}Kuh3VktjDHmJ88Ul?2 zwzpgUdhJg9+tSBCo!9WRG_ccmoiUI6b>1h&63Rzx3*>{z3{yWYN6#4D3{x&V3T zXm;n-in|Uvb+XVw#JMaXQN2^*it}YnsUb&DAdt`IvP%ZP&p6HRH*9~yD-|bdiJBr$ zYLFZS0{z~)X@+Hlzq)5Nu2beMl7n|5;aBbWes`8f&)x39qZ_AgbYpb zL8iusiJ$mf`XMLI=ToXVqV3FmjBD-TS~@6rG&nlIXW03+N}veo?S0`TNZsalBjG&s zKaLP)yr7=d#`S=NdNjE&gUUg^L%!4MH+F4aq09>{tVg z^Sqh*(|RcylRd8Apm*q1aW0_$7oW>sulFOscff_buNk;N%6pC0S?7*+xDm9CZc!6E z8lItihGeCcHE)B_bzWfxKXJX|oxajup+EjQw7JLeAkF^3K!%QkJStZn?5Pm&oHw*BlE`fE=Hcv+t5WBK3#r^?>|E#Bsf-c<(kU9G^WRats_%v|1tK z3fC%Eg!8z<5k;#N@?tCO&d}Hw)IF`NRh=iCEqCR4o>f@;0GW>ecylwc#|6zWbn4+GS*KQFU;GS#m6(U8GY}*>>=9IKM{*t>EW0 z9rf-7!Nklc{R931@7Eby9|nz2GDgn{v~){!s~(OE+{Ct?e%(tM6@s%4BFwZgr1|X9@2a|Y&P4Q zZnxW|v!iU5l$7*IhsWbtrYS20jZDD446qiQ7t(hNYT^5H47rW6s&5=WhWrlnUxV_H z2{5RAMEgUPyvD>k$toQr<-)IX=`c)+^VA9|j41Fw$L|{9) z+NCm*3Xg5>9Qw7`|ChRcbaeDP{5}-RW=z1fwY3idwiU|8*dd~EGM154`OMmH*jNKy z#oubk5!v6TnT`o~czAdh(#6nFet!OuX_{$fFnj%^$5WV)XlSgt& z?G$06dzcMd@;Bp!^!N+V66q_@GBBJcJ(lVnD*=y;jL0Ux2(W`iMMWKYg-o~Q=*F+) z^aTJH;qPa?&usmN)@GC*PN*wv>iZoIha9JAFI81l`97a-g~~8MWoDb{J4ic9#`M9V zGMoyJz4cf0pG?3;h{b7DMmPZ@NsAIe*@3*&W`ZU+z(109Hmf)rf!PQoAA#@+Ws8xE zhy0tFDlF{JI7+vg5>B&_cG8&!n`Zw?bFnTyBCJI?{0kChSS){Y($)3%_dAu=GR)-e zu#Y{rnOUr37QZ*T(;}?#9SASxSeBbojmErRb!BB`0lp51KduFLRDPoX+wJxSMs^y| zh0qV=w%nZVTL}aLd+?hFh8`|Kzo;BX0p_9;;O@H~g|ASYkHT3ZE$U3YG+UuujC@U`H%MQm3V%1*6B83(;ALPbf#q|ZCkdRRb z-qA>3kot9Ff4aVz#ZM!Cu2)o4*yGuq7Gb?G*SUB2mPH_PZLHu!O-)U4b@cjX+JJqJ z-=S^D-eIAwb2^<@sc12fk1!~P1JJXRlaoEN7|A*10B3T_Og#_S-;vvZT`&9oCNp5guBixX z0LseBmNR`F0DU6DbK&qfFE$;#*!VO#RUL`wE66vZzfxpqcR^ctLikgqqvC}DGvapX zWRzP~LV6yX`vc?Si(O=5m87Orj1lemM0*R(R{;|BqZrE>{L275$unzvUtgaLGU1XmV7({6FCmhv w0J9waBB&6Ow+ugn@xXTi@*E(q!Aq&!19NK)MN7j@qyPW_07*qoM6N<$f{2ZS?*IS* literal 0 HcmV?d00001 diff --git a/vector/src/main/res/drawable-xxhdpi/ic_widget_bin.png b/vector/src/main/res/drawable-xxhdpi/ic_widget_bin.png new file mode 100644 index 0000000000000000000000000000000000000000..a8d8947488d97b721ebfab35f4ef89fe287c2542 GIT binary patch literal 1342 zcmV-E1;P4>P)kC$ zU$)?FpTT^w9>jl;ZES+^=*jW5m4A*22M-hIb%TI?o?j9MoGxs={v@0_w(8TTuURaD zuRd$;wC(D7LfYFGE&Ry^DRT$6ykTApA7b4zvS56^e1p|k{t8j-RAd0)PwIb3$9@(x zuGMj0EsbXYaVOc{i-@->A3An1pV@W*UMpQu$HKIkFiu_{tG@CoigmF>swxns^EYQ_ z!8C&j^#-Lrnxah;fK)aDDTz#f=m+j#9B-o8(2zWd{Up^a% z!2n}xvUJE1_zs&92ucI?<=!m+IKZvv=|I1rolzPHk0`N3=R(|K8E-u%T;M)qF(&uJ zZjl5F;T&iI1MrVlGFw}04`v9oXo3-LQkZo8ey93zw{5XKm|<|D2?mi>pc0)G)sMSv zi|xS-gA+|~7{np_q=JWBfW+aUT6}3wSQH!KJPN$S^_TMDjAQ>AHda5sh9P$e+x~!U zK)`Pj@L)gte&;d`6bt*dy z-sK^Le2@G;*nsc3o0k~h*CTQ7q}}yidbLZ){`$<o=Ao9u(=%?_NVCJoK;_b z%P&E;Wgpj`3K zH(nwY&gOHMXl}?FivdL6Q<;=4`*MsVl97mDIBoum8TlX>a3nvr?J2*+*_M4=Uy9+^ zFNj@Y@1>jXl>@z7Zoa>MC5V8awuw|YC<&eRsbHPi9tKug;bCN5CuUk`HH9F$Ju(hdNp`4x(cQ##k_XV-O#r8tNy6BZCpJXyu7;#M!=7i5zRS% z8YfNnTdz7ciY;?wu8JG=KT>^f+f{HOpL>stme`OdT(3d>44ykDy^f>QXKpUX=HzhV zwp1vLz2A*v*9qcmxK=!VgcfVhDkoYZ`-PA&mA`T98(KM9Q^$wd(hAh9b-BJ@*f>i| zZ|_rFXi@r9p>kqQ?R(pvf++x4#p7qG!jHB)K#kS~{7%a|HdbDE4K($MxTN8CJMn9+ zj$>$gw0t*TIdO;zBC{N|)XMPyO$CqFggon9! zp)^smmQ5uijvUoKU4z~0HS})P z9hw9P_F*`GSQS8%eQu1|N83sWw6XGCLqT}1p#4(iytvXJY9JgS@^}9Yhy@UK0fAl3 zla++VbaeS50i9*=t&frIPV_a3UJ8n!bn zF4$rwaCT^%2_6WXScGtneJ9W_&urHqhu z1gA)m6HGNfrDAQ1Aei?20i~x%4vf2>^5K=d}RS@+0rgwMH!I}p#1Ox(+F+#&JQ;s+$@aeTkUN#FNA_M}EXP|x= z7cI@Jf@_Q|AwWAVmb&_DZj5l5z;!~jfw2mfDG*~pAQ&?s#)M!7#Mlr_fUp2zbP!e` z5X5Nf2nQj`4=4uKRz?{ttwA8P!9m1^0Q(zM(-|=U1U_K;PQ|tK!=|NN2Fr-p5L~2B zvAyM#<;F4yh#CkV;AQV8ONB_UtGX_$-POfGK;Y7EpgYP1LU_^V8Kbflq!=9pvVjBF zE9I>@2=pyF2;6o4oAnvWf4AO3O=SZ7$z_lQ6<|DJW;iHvZByIm86nYHhCm+&10g`H zZW9Q1XA+16!tbOhBT`1BjPMDhjPQA+F(PF|$_Sr8$_SrF8Y2oB@mKM=t;$m?YTtEC zOXHA?_@P=pROP7^weLEnW^v%5$)sL5t%?dUY(meWBK*Xnz2NLgy@Fhf5dQPsagnp) z@y2yn;5Qmt%)gY*;Nb8*sD{88wi^fT8hUTB!vO!3)vxTt`b?p%pH=NSFmg7fLJFC=v0Ni^W&Q^0%Jpb$`led$G6tqLDTZOhCaYDjK})8t$3*}b*>XQ kMV_K7eC=W&ol`;J5*yP`xj6}(djJ3c07*qoM6N<$f-_CQmH+?% literal 0 HcmV?d00001 diff --git a/vector/src/main/res/drawable-xxhdpi/ic_widget_refresh.png b/vector/src/main/res/drawable-xxhdpi/ic_widget_refresh.png new file mode 100644 index 0000000000000000000000000000000000000000..561810122ae8e41d08d5a14402e1fc095d8084d0 GIT binary patch literal 2155 zcmV-x2$c7UP)qVh_tk{$ol&FNu8aY8T`omySln!%=|j)mQweOpP%2cfPjE~B_$>GX4=_X$7Mte z9XfOjKV%ue9wiL07oeqGGsGOgzgJ#fe%wJ>y3L(VL|k0lL;!E#$KR!^(Z{ES^7E9R zBfLVL7JMr{5R z;}Cv;y!n-tm4B*bHiUDjn`Np06X6!8SOg@@1l;@ha19tS=UgVfw@OP(i#7Q+N10%g zA!IQPpFu~EM!*#aUW|3@(c~FMv50KstdWXfd<~1p_A_kNONI3G^Z5%V-xxv>QuXl5c937s@e|#nGjW1f(48L z^jv!BlA7tP5V=+OXCZk!GB0T4F2^c&VL7_R)YNn|B_$~e{Ff@9v;4yH_eyWoM0_}13e(}{_R!_D9`O#~~%3Iq-o zp(wi?92`6|KR;hlDtVsZu#DZ{cnsencpxLDy}kVumON6@y*X1vuvdshsC66?f4R80 zxVksN?kaR=M(&fdwauViUxK+~h2oOrXso%W!Bo zOQAF6Fy`m5%UuK^vZC4SXy=C|BoJN-3k!SRW&z#?UIx4jcp30A;AOzefH0u!ELl%| z*{yA2ZM~JeGJC0^eIso@LFybBq#@XDthgesRM z!*E6dJ)si^nMLo5g2Hgb3pK&$kFoCwfuRIJqo2#Ex|Oze)H1 zrDIk>g8F8oi_V+Rr~IpCk(nYwgkfTZ43q0FOHjOrVe+(;yVJ38T0+Oj=1FmM+9pUi zsHV+?rilo0LV%+%3M)LNIy zAJHE*%GLvDI{*STc`l90J1&OiJ1EhTa5^+Jbn4!{dpm4ZZZi?005UE^Mmp?kccJrY zYHH3xNUE(MY^@IgiM*9M#n4=!wgt;KkTAKZs7QGZpyrzm?IJ>i%S03v6*Yxuu147i z0G(ytSTB#!HTh17%FR3^yn(Pn{Ag7uI(LC(qP--D9Dn(PkaPm^vI#j^TU(niaU)k< zUENt%SGPYpI=YtLNvFOH4S(Wec|yDpxxtZ{u*A8hP)@-QqSB4Rl*cOrWdf)w0f zZDRso#zg)iSY-2Lw^L4^2y8@wB1Gc0N@Eh;Mo)cCyBy@)Bkc+0DM2=VHN)ko9O-!* zna@j`-^ep`?B;Ld)R@6!oWaAe$;gu{eX9d!0eMRx;TLPB0}3KbIvaF)HF z+PEqA%gf7~fvh!Pk{fhASIv+3fr3BqvM;G49mJ0c!ABEMA}@(}456O8K;~+8y*u>^ z?agz^ZMYDUo0}^S)#m|BUadH+2ZBx`XDchyetT90BZ3?TXrzE0UkrpiiIq&?$BZVf zzP>SPDu=yOSm+Vj9bs}VH)`NWxyy;rf`bI#goFe!`(gNjl!@<;mw#MoCa-~IxfIfh h>G=v*^gMcW-9H5je{22Zd0hYi002ovPDHLkV1ih~`{V!s literal 0 HcmV?d00001 diff --git a/vector/src/main/res/drawable-xxxhdpi/ic_widget_bin.png b/vector/src/main/res/drawable-xxxhdpi/ic_widget_bin.png new file mode 100644 index 0000000000000000000000000000000000000000..8cf7db66c5a1f7de6c5400dc25febf26c9b7b535 GIT binary patch literal 1646 zcmV-!29f!RP)2f&L0;Ny&&T!48eYbbWjFtGzf$FZ_YYbOYtL(ulutj5?*SR#;)y}$iDIF4&9 z>=uDy1&A-bz9+kU{X>DGcZ=Nd4}n;)JNG^bZ@hdXu4J(RlrPyVXqIj3y zZ|_qhC#=M=^z8V8I%dMQOauwXD4{#0j)8#R?6&05xZ%m1GKb71bE-9jYf|^=*v0`C z`d_`DK5_5yilQlwkichQ#`)J9i+d|`m2*;VKNr&@Do_@obMYjV5M)Q^6!p;fd97;{1VoD z#u=a{z%~H*cB>eOB1tDR4tx9P^iY9LhF{zMuo++kXsUz(sx%_l z3@`#TRl)#O8WC&;7y+6pVSp-)2sQ(Z08N!JK$S)Wn*m0Erb-x~N+W{J03$$CB@9rd z5y57F5um9O2B^}AU^Bo7&{PQnRB1%8WBZMCty;1JV-E?}eV=}AcB=*A#mwB~d$o?Q zwlCK|`m~GUP5K$z-@>w%9UCmV;YlBp>_Z-Z&)A1dKgrHp7+dVc&0DTkt|&8V6(1I?7aGomm+&F6su zGC)lNnsT0j3{aDRrkrOW1Jop-Dd!o;05u6{%B#-6Og#E#4G4TAYwpDMy=pCHxA3cMJ!=Asf{Q}yo6ZXu6e}l%*{$1r}2gkax=$@yd zd(^_|r0ujlH~G9e7PfB+5MOZi=Cb+k)-O*D$mv7II!D*)63pbHn-Hsky*u2oN+ONL zLN{Hr+=IfEXS4ke4p};Zxty_6N8q$`y;dtX1t`Um?ixhJ(&6xl;a7djEKg0^CWrewQo7RIVNm3wEZzO3Ozs s(R=$9xpYt_k@~!m3uo<2Bu%L5Kb^RQGm|)`g8%>k07*qoM6N<$g1?jpvH$=8 literal 0 HcmV?d00001 diff --git a/vector/src/main/res/drawable-xxxhdpi/ic_widget_external_link.png b/vector/src/main/res/drawable-xxxhdpi/ic_widget_external_link.png new file mode 100644 index 0000000000000000000000000000000000000000..03b8c25b477f1e3fdb9e21284ee464f707d60555 GIT binary patch literal 1400 zcmV-;1&8{HP)M#o4Gp!f9}lO znRDj+-eKN*ckjEqX;UtlKqe3=f%WzES+s`Upit!rjy{hRiQ8on=#@}Zm7gajk`GL! zr^odv#kI%y-E1m-Jd#zri0fx`7zItH&6GYe4HgqG-bwVo+8TzJ^qb9gQxsP!N zi3xV6kj`A)&Va{xH2^zmTM)R?Unt|)-_UcQR|!|Z6zI~}(6G7&-vl=U?n=}e-v(|5 zYys<1Z3{O8?m~4iwhP=kz+2k*#@P^P>u%i?BsDiuH#)al%=8W2duX1wK1>?K) z-$0MiYZRi$9{el&-akH_30&+~?YTcW^Nphu`jw#l44ro7Br-$9R{IUD?Q%7@(mV!i zMUT|LKWWdE2KS_c*s8XL+BdXO;VW+CugVNKrUuCy+`=ehedr@LCz)$lD0U+OUsHot z%;dfuiPKr;8a9gENWk~ipk8J#F*?oME`a6D%r4u^t&X{9qKq4KiKWOF} zEco4pnx-yb3?$DACSupho+o$62Gx#j!uk@ zVFdqEgDcC$|Ds_qIQ}q37{e(+f4@8QT2T?WoRWa_o#kI~ho!r_94q_}y0@y+x~)#v zH=_X@3EX;GW1NiwFmR8s_GxGC82Fl}L;;v(UO>~_7Me+oIU*LoFRb;;pS(lvxt449 z)mQ+3O=!QMd+5u6Z)om`DvP6jqoIcQZvyl;ynN>0Q+N-tWN`S%19{AVJ%i4GGhojI zJe$uMoB?|#;Msi6;0)L^0ng@h24}#Y33xW2GdKhGOu)1GoWU8eX9Awh=M2t(JrnS3 zK4)+S?3sXP^Erb90xmoYje8YBJ)hEZh@H*rxC>mmTC+3wZ#DT7)!ryg9rs_81a1SC zzwFvYp0>IXi;nwuClJ^Y&Lg`#rBVLXxD#)28X?}(HUR4K3F5AU7=u@QM zWu2}elriGih8EBY5}3MNcCnVyKQzM2UJTzx+g&(F)P`&gN4ce|{Op~M0ok7--cQBo zA5;#ZhaGM8W%#!QvgiV?04V{M&H?0uR4<{4K4^=*M2aNV60x5{|GHXpX^YT?*)n$0 zcN`r>`;k0PxDWgAbK;OM5qFS$T3Q9HJaIdhOdt~&5_ku|m#n_r<+C0D0000kAMatW2iNbj|>GxX*+<8#m5vJ z2U{JW?FD@bLPj<=f-Cc6;7t# zCFSz|{{G9+Zz}0R(goBnket*_Iz^u^$t9g2eVmn*RasY8cZzb%9K#N9QBl#Twzjr8 zy}iBj0c<`Xj`xU86MQOCQ&YfT4JvQ-JZ#6o6eo{u|QuLn-HHJ0QPLdI+HZ?k8WB7q*p1{piu7A<5-9 zX8=!}IB^#8HUsR{1Cnii0HK{ehseJm)%ErD)n{a6{3|UjtusA6y=(O7(Os>rt)qz3 zxwPfd_flBRq;E0hBFaPE4I#qEgMNGTq)C%DqR(6I(A&^=j~qF&JleQfP*9NB)zvi%Ll?vEXUM$7LY9#FX@8cBwWhkd`oA`P zT#@tg@`TT*@JSuVj~~yLa-aa?wLe70>lk`*Sg@Y`m8<RQgcmKs{LgjREd%l+eMgf>so3;0jpbvFfz|Di6BI z0pPP3^^{MYI`umdqKASnA%bz~3+Qm8rpHHwh1q~B^8_(@pj!hv76bCfs)B%g1t3>2 zFEUZ3M^p9;Fb|IVQRpsJxF}4z8811l(qplVj{jynJR5!YYx?DNcXwA1N(wZ(tEwk} z!^5AaREa2BL;WVaqfMp9a#{Xt;K@Hm_nn%amoi^+Fl?vRf5o7M^Ks+{@MJv%YTc}>Q3Kr4(y|tom#J(4cPYcLqbe<) z%4KC`y*S4`c=IMzZ=C2`c=A3xdA>?_QjQ8><`*tQ=xS8};64qw`Yon*iHkCJ^kaui z)ad{0WD;p7lRAst7!no0JYk@T+3pHpnBS%`+MMX#tJ;e*9i%>+q)!C>T;FA&C1DN6PsRE>gPofPyPf? zmOmXT7Phvh+qPIV0OlHYE9?~U&3sK&doOb{d-sJOu zppSnT0?xY-A%-)aznM5Xoo9-l_NQ`pTnYQH__kwpwBL3Z7bck}5lAACL?DSk5`iQF zNd%GzBoRm=kVGJfz;GcD`K!n*(>ng@ttYvf!gQ)Qa{x7@J9+)`xzlqJpfTw6xS}#gHRG@!APMuQ$LI z8*nn)H^^2to()=spB1A7rmawI1MGUWK2+Hj;P9(y)7AhmU&tz=U9#Y1 zD8`A<&YO?#;<2XXXyEd!8{2FFCg#@i#iXn&JFYSWN)XRCN!?V z-pF$bu&cu#pEx$j7GU9U;kq`uLu z8D|ApnDJR^Ga%mp$W&x5f<#urQQGc?{KN zQ!G~n0B}C3g7IO#N{{z4BL`VTzCg7D2U}fPS=p)5oRl2_ER2Xfr@4aib>SYBF^Wu} zUe21bnJPVA%h+)dHf~Y%r~U!oq`CH9;o%ry=`2@p%$PB9Wp_y3H~=|^TPnm;x7eV? zV=mvVvC+qC*rSF$S&eTRs=2Yv6~Mxnv2gd2B}?u==u4WQ3;CF1KjC7IMvt57)~#C~ z0^GT(!g%lF+`XTwG&g0}01I=jbRW}>%K-TaO_+?2ck$pe#V@T-OjgnPKEPe4DHmex z+=Cj;RW&Mr4GDm}3XsVp%)q#Rg9R zi(o+h10es3qB;?jhQcqSxb6{NbPeQObo>RnJ`Zyh+%7`H?M&*lcopgyU{L^&p8@21 zD4MP|ia$b3eo3bLyejJV`7)=1Zku(_1=w%+JG_8VLxmqQeF0b$0pwQz`KJ_3V?{#7 zy-iI`W7|XvGHHMBbK7o&hd)Qm| z0_G%(^DFUm*%*mpG-UN*)X^i~48EMS*i0&4tLz*i48lta-5cImqY#jO^H z7ZdjmV6gl#xzRW$sGN&EhqMd+AKHNX4sEl709R}Z#Dj&gabVnC7$&n&V+@*_a}i{w z?p1b5eT}VYo7A>w%MxSxNA?rWmrdzpHPN60x$O{TzqF?)o9^C0ojnjD00Tsgp$r0R zxS}&W@HL$(8w?TmHo@OCd2Qlw`0!mUn!&Q@)bDcJnJoSl$}&$qc|Be%U))(@kf>u#`JBYZyk9p{SRbkXYZ@2scCg`ZqR*V24LM# z`Fq{m+?+!wkxiHf5&+6416`6ROKRm|bvV{G##e3mAJu;}mzl3NUjP6A07*qoM6N<$ Ef_^4JbN~PV literal 0 HcmV?d00001 diff --git a/vector/src/main/res/layout/activity_widget.xml b/vector/src/main/res/layout/activity_widget.xml index b6fbce4536..0a4324712c 100755 --- a/vector/src/main/res/layout/activity_widget.xml +++ b/vector/src/main/res/layout/activity_widget.xml @@ -1,73 +1,20 @@ - + android:orientation="vertical"> - + android:layout_height="wrap_content" /> - - - - - - - - - - - - - + android:layout_height="match_parent" /> - \ No newline at end of file + \ No newline at end of file diff --git a/vector/src/main/res/layout/bottom_sheet_room_widget_permission.xml b/vector/src/main/res/layout/bottom_sheet_room_widget_permission.xml new file mode 100644 index 0000000000..6aeb4c9d71 --- /dev/null +++ b/vector/src/main/res/layout/bottom_sheet_room_widget_permission.xml @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + +