From 4c2e62031afc3fcb3dec7d17313c796900363b91 Mon Sep 17 00:00:00 2001 From: "Auri B. P" Date: Thu, 5 Nov 2020 22:42:31 +0000 Subject: [PATCH 01/66] Translated using Weblate (Catalan) Currently translated at 58.9% (1140 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/ca/ --- vector/src/main/res/values-ca/strings.xml | 639 ++++++++-------------- 1 file changed, 230 insertions(+), 409 deletions(-) diff --git a/vector/src/main/res/values-ca/strings.xml b/vector/src/main/res/values-ca/strings.xml index d711d778ca..375133efc0 100644 --- a/vector/src/main/res/values-ca/strings.xml +++ b/vector/src/main/res/values-ca/strings.xml @@ -1,36 +1,31 @@ - + - ca ES - Tema clar Tema fosc Tema negre - - S\'està sincronitzant… - Escolta esdeveniments - Notificacions sorolloses + Sincronitzant… + Escoltant esdeveniments + Notificacions amb so Notificacions silencioses - Missatges Sala Configuració Detalls dels participants Historial - Informe d\'errors + Informe d\'error Detalls de la comunitat - D\'acord Cancel·la Desa - Abandona la sala + Surt Envia Reenvia Suprimeix @@ -45,25 +40,24 @@ Reanomena Informa del contingut Trucada activa - Conferència en curs. -\nUniu-vos hi per %1$s o %2$s. + Videoconferència en curs. +\nUneix-te amb %1$s o %2$s Veu Vídeo - La trucada no es pot iniciar, prova-ho més tard - Pot ser que algunes funcions no apareguin per manca de permisos… - Es necessiten permisos per convidar a iniciar una conferència en aquesta sala + No es pot iniciar la trucada, prova-ho més tard + Pot ser que algunes funcions no apareguin per falta de permisos… + Necessites permís per convidar a l\'inici d\'una videoconferència en aquesta sala No es pot iniciar la trucada - Informació del dispositiu - No es poden fer conferències en sales encriptades + Informació de la sessió + No s\'admeten videoconferències en sales xifrades Envia igualment o Convida Fora de línia - - Desconnecta + Tanca la sessió Trucada de veu - Vídeotrucada + Videotrucada Cerca global Marca-ho tot com a llegit Historial @@ -72,52 +66,44 @@ Tanca S\'ha copiat al porta-retalls Desactiva - Confirmació Avís - Inici Preferits Persones Sales - - Filtrar noms de sales - Filtrar preferits - Filtrar persones - Filtrar per noms de sala - Filtrar per nom de comunitats - + Filtra noms de sala + Filtra preferits + Filtra persones + Filtra noms de sala + Filtra noms de comunitat - Convida + Invitacions Prioritat baixa - Converses Llibreta d\'adreces local - Directori de l\'usuari + Directori d\'usuari Només contactes de Matrix - Cap conversa - No vau donar permís al Element per accedir als contactes locals - Cap resultat - + Sense converses + No has donat permís a Element perquè pugui accedir als teus contactes locals + Sense resultats Sales - Directori de sales - No hi ha cap sala - No hi ha cap sala pública disponible + Directori de sala + No hi ha sales + No hi ha sales públiques disponibles - 1 usuari + %d usuari %d usuaris - Convida Comunitats No hi ha cap grup - Envia els registres Envia els registres de fallada Envia una captura de pantalla @@ -127,14 +113,11 @@ Els registres d\'aquest client s\'enviaran amb aquest informe d\'error per tal de diagnosticar problemes. Aquest informe d\'errors, així com també els registres i la captura de pantalla, no seran visibles de forma pública. Desmarqueu si preferiu enviar només el text: Sembla que esteu prou frustrat per a estar sacsejant el telèfon. Voleu enviar un informe d\'error? En l\'última execució l\'aplicació va fallar. Voleu enviar un informe d\'error? - L\'informe d\'error s\'ha enviat correctament No s\'ha pogut enviar l\'informe d\'error (%s) En curs (%s%%) - Envia a Llegit - Uneix-te a la sala Nom d\'usuari Crear un compte @@ -143,20 +126,16 @@ URL del servidor URL del servidor d\'identitat Cerca - Inicia un xat nou Inicia una trucada de veu Inicia una vídeotrucada - Esteu segur que voleu començar una conversa amb %s? Esteu segur que voleu començar una trucada de veu? Esteu segur que voleu començar una trucada de vídeo? - Envia fitxers Fes una foto o un vídeo Fes una foto Fes un vídeo - Entra Crea un compte @@ -189,7 +168,9 @@ Heu oblidat la contrasenya? Usa les opcions personalitzades del servidor (avançat) Comproveu el correu electrònic per continuar el procés de registre - Registrar-se amb el correu elecrònic i el número de telefon alhora no es podrà fer fins que existeixi l\'api. Es farà el registre amb el número de telefon.\n\nPodreu afegir el correu electrònic en els paràmetres del perfil. + Registrar-se amb correu electrònic i número de telèfon alhora no es podrà fer fins que existeixi l\'api. Només es tindrà en compte el número de telèfon. +\n +\nPots afegir el correu electrònic en la configuració de perfil. Aquest servidor es vol assegurar que no sou un robot Aquest nom d\'usuari ja existeix Servidor: @@ -201,7 +182,6 @@ S\'ha enviat un correu electrònic a %s. Seguiu l\'enllaç que conté i feu clic a sota. No s\'ha pogut verificar l\'adreça del correu electrònic: assegureu-vos que heu fet clic a l\'enllaç del correu electrònic La contrasenya s\'ha reiniciat.\n\nLes sessions de tots els dispositius han estat tancades i no rebreu més notificacions automàtiques. Per tal de reactivar les notificacions, torneu a entrar en cada dispositiu. - La URL ha de començar per http[s]:// No s\'ha pogut iniciar la sessió: error de xarxa @@ -210,7 +190,6 @@ No s\'ha pogut fer el registre No s\'ha pogut fer el registre: s\'ha produït una errada en la propietat del correu electrònic Introduïu una URL vàlida - El nom d\'usuari/contrasenya és invàlid No s\'ha reconegut el testimoni d\'accés JSON mal format @@ -218,35 +197,27 @@ S\'han enviat massa peticions Aquest nom d\'usuari ja està en ús L\'enllaç del correu electrònic que encara no heu fet clic - - Llegit per - - Envia com Original Gran Mitjana Petita - "Voleu cancel·lar la baixada? Voleu cancel·lar la pujada? %d s %1$dm %2$ds - Ahir Avui - Nom de la sala Tema de la sala - Truca Trucada establerta @@ -257,16 +228,13 @@ Vídeotrucada d\'entrada Trucada de veu d\'entrada Trucada en curs… - No s\'està responent a la trucada. Ha fallat la connexió de mitjans No es pot iniciar la càmera s\'ha contestat la trucada des d\'un altre lloc - Fes una foto o un vídeo" No es poden gravar vídeos" - Informació Per poder enviar i desar adjunts, el Element necessita permís d\'accés a la galeria de fotos i vídeos.\n\nA la següent finestra emergent, doneu-li el permís d\'accés i així podreu enviar fitxers des del telefon. @@ -279,97 +247,84 @@ \n \nSi accepteu compartir la vostra agenda de contactes amb aquesta finalitat, si us plau permeteu l\'accés de la següent finestra emergent. Per tal de trobar altres usuaris de Matrix a partir dels seus correus electrònics o dels seus números de telefon, el Element necessita permís d\'accés a l\'agenda de contactes.\n\nPermeteu que Element accedeixi als vostres contactes? - No s\'ha realitzat l\'acció per falta de permisos - Desat Desar a baixades? NO Continua - Elimina Uneix-te Previsualitza Rebutja - - Salta al primer missatge no llegit. - + Salta fins al primer missatge no llegit. - L\'usuari de nom %s t\'ha convidat a unir-te a aquesta sala - La invitació s\'ha enviat a però aquest correu electrònic no està associat a aquest compte %s.\nPotser voleu iniciar una sessió amb un compte diferent o afegir aquest correu electrònic a aquest compte. - Esteu intentant accedir a %s. Voldríeu unir-vos per tal de participar en la discussió? + L\'usuari %s t\'ha convidat a unir-te a aquesta sala + Aquesta invitació s\'ha enviat a %s, que no està associat amb aquest compte. +\nPotser hauries d\'iniciar sessió amb un compte diferent o afegir aquest correu electrònic al teu compte. + Estàs intentant accedir a %s. Vols unir-te per poder participar en la discussió\? una sala Aquesta és una previsualització de la sala. Les interacions de la sala estan deshabilitades. - - Xat nou + Nou xat Afegeix un participant 1 participant - Abandona la sala Esteu segurs que voleu sortir de la sala\? Esteu segur que voleu eliminar %s d\'aques xat? Crea - En línia Fora de línia Inactiu - EINES D\'ADMINISTRACIÓ TRUCADA XATS DIRECTES DISPOSITIUS - Convida Deixa aquesta sala Elimina d\'aquesta sala Veta Treu el vet - Fes-lo usuari normal + Retorna\'l a usuari normal Fes-lo moderador Fes-lo administrador - Amaga tots els missatges d\'aquest usuari - Mostra tots els missatges d\'aquest usuari - ID de l\'usuari, nom o correu electrònic + Ignora + Deixa d\'ignorar + ID d\'usuari, nom o correu electrònic Menciona Mostra la llista de dispositius - No podreu desfer aquest canvi ja que esteu donant a aquest usuari els mateixos permisos que teniu.\nN\'esteu segur? - + No podràs desfer aquest canvi ja que estàs donant a l\'usuari el mateix nivell d\'autoritat que el teu. +\nN\'estàs segur\? "Esteu segur que voleu convidar a %s a aquest xat?" Esteu segur que voleu vetar aquest usuari en aquesta conversa? - Convida per ID CONTACTES LOCALS (%d) DIRECTORI D\'USUARI (%s) Només usuaris de Matrix - Convida un usuari per ID Entreu un o més correus electrònics o IDs de Matrix Correu electrònic o ID de Matrix - Cerca %s està escrivint… %1$s & %2$s estan escrivint… %1$s & %2$s & altres estan escrivint… Envia un missatge xifrat… - Envia un missatge (desxifrat)… - La connexió amb el servidor s\'ha perdut. - Els missatges no s\'han enviat. %1$s o %2$s ara? - Els missatges no s\'han enviat perquè hi ha disposistius desconeguts. %1$s o %2$s ara? + Envia un missatge (no encriptat)… + La connectivitat amb el servidor s\'ha perdut. + Missatges no enviats. %1$s o %2$s ara\? + Missatges no enviats ja que hi ha sessions desconegudes. %1$s o %2$s ara\? Reenvia-ho tot Cancel·la-ho tot Reenvia els missatges no enviats Elimina els missatges no enviats No s\'ha trobat el fitxer - No teniu permís per escriure en aquesta sala - + No tens permís per publicar res en aquesta sala Confia No hi confiïs @@ -382,7 +337,6 @@ El certificat ha canviat respecte aquell en el qual el telefon confia. Això NO ÉS GENS HABITUAL. Es recomana que NO ACCEPTEU el certificat nou. El certificat en el que confiàveu ha canviat per un en el que no confieu. El servidor pot haver renovat el certificat. Contacteu amb l\'administrador del servidor per saber l\'empremta digital esperada. Només accepteu el certificat si l\'administrador del servidor ha publicat una empremta digital que coincideixi amb l\'anterior. - Detalls de la sala Participants @@ -391,15 +345,13 @@ L\'ID és incorrecte. Ha de ser una adreça de correu electrònic o un identificador de Matrix com \'@partlocal:domini\' CONVIDATS S\'HAN UNIT - Motiu per informar d\'aquest contingut - Voleu amagar tots els missatges d\'aquest usuari? - -Tingueu en compte que aquesta acció reiniciarà l\'aplicació i que pot trigar una estona. + Vols amagar tots els missatges d\'aquest usuari\? +\n +\nTingues en compte que aquesta acció reiniciarà l\'aplicació i pot trigar una estona. Cancel·la la pujada Cancel·la la baixada - Cerca Filtra els participants de la sala @@ -408,7 +360,6 @@ Tingueu en compte que aquesta acció reiniciarà l\'aplicació i que pot trigar MISSATGES PARTICIPANTS FITXERS - UNEIX-TE DIRECTORI @@ -421,30 +372,25 @@ Tingueu en compte que aquesta acció reiniciarà l\'aplicació i que pot trigar Uneix-te a la sala Uneix-te a una sala Escriviu un id de sala o un àlies de sala - Navega pel directori S\'està cercant al directori… - Preferit Treu prioritat Xat directe Deixa la conversa Oblida - Afegeix una drecera de la pantalla d\'inici - + Afegeix a la pantalla d\'inici Missatges Configuració Versió Termes i condicions - Avisos de terceres parts + Avisos de tercers Copyright Política de privacitat - - Foto del perfil Nom a mostrar Correu electrònic @@ -453,12 +399,10 @@ Tingueu en compte que aquesta acció reiniciarà l\'aplicació i que pot trigar Afegeix un número de telèfon Mostra la informació de l\'aplicació als paràmetres del sistema. Informació de l\'aplicació - So de les notificacions Habilita les notificacions d\'aquest compte Habilita les notificacions d\'aquest dispositiu Encén la pantalla durant 3 segons - Missatges que contenen el meu nom Missatges que contenen el meu nom d\'usuari Missatges en xats entre dos @@ -466,13 +410,11 @@ Tingueu en compte que aquesta acció reiniciarà l\'aplicació i que pot trigar Quan em convidin a una sala Invitacions de trucada Missatges enviats per un bot - Inicia en arrencar Sincronització en segon pla Habilita la sincronització en segon pla Temps màxim d\'espera de la petició de sincronització Retard entre cada petició - Versió Versió d\'OLM Termes i condicions @@ -482,7 +424,6 @@ Tingueu en compte que aquesta acció reiniciarà l\'aplicació i que pot trigar Esborra la memòria cau Esborra la memòria cau multimèdia Manté els elements multimèdia - Configuració de l\'usuari Notificacions Usuaris ignorats @@ -494,19 +435,16 @@ Tingueu en compte que aquesta acció reiniciarà l\'aplicació i que pot trigar Permís dels contactes País de l\'agenda de telèfons Pantalla d\'inici - Destaca les sales amb notificacions sense llegir + Fixa les sales amb notificacions no llegides Destaca les sales amb missatges sense llegir Dispositius Previsualitzacions dels URL en línia Mostra sempre l\'hora a tots els missatges Mostra l\'hora en el format de 12 hores Vibra quan mencionin un usuari - Analítiques - Mode d\'estalvi de dades - Detalls del dispositiu ID Nom @@ -517,22 +455,18 @@ Tingueu en compte que aquesta acció reiniciarà l\'aplicació i que pot trigar Autenticació Contrasenya: Tramet - Registrat com a Servidor Servidor d\'identitat - Interfície d\'usuari Llengua Seleccioneu una llengua - Verificació pendent Mireu el correu electrònic feu clic en l\'enllaç que s\'ha enviat. Un cop fet això, feu clic per continuar. No s\'ha pogut verificar l\'adreça de correu electrònic. Comproveu el correu electrònic i feu clic en l\'enllaç que s\'ha enviat. Una vegada fet això, feu clic per continuar. Aquest correu electrònic ja està en ús. No s\'ha trobat aquesta adreça de correu electrònic. Aquest número de telèfon ja està en ús. - Canvia la contrasenya Contrasenya actual Contrasenya nova @@ -542,13 +476,9 @@ Tingueu en compte que aquesta acció reiniciarà l\'aplicació i que pot trigar Mostra tots els missatges des de %s? Tingueu en compte que aquesta acció reiniciarà l\'aplicació i que pot trigar una estona. - Esteu segur que voleu esborrar aquesta notificació? - Esteu segur que voleu esborrar el %1$s %2$s? - Escull un país - País Escolliu un país Número de telèfon @@ -558,30 +488,23 @@ Tingueu en compte que aquesta acció reiniciarà l\'aplicació i que pot trigar Introduïu un codi d\'activació S\'ha produït un error mentre es validava el número de telèfon Codi - - - Estil - + Insígnia Tres dies Una setmana Un mes Per sempre - - Foto de la sala Nom de la sala Tema Etiqueta de la sala Etiquetat com a: - Preferit Prioritat baixa Cap - Accés i visibilitat Mostra aquesta sala al directori de sales @@ -589,22 +512,18 @@ Tingueu en compte que aquesta acció reiniciarà l\'aplicació i que pot trigar Permisos de lectura de l\'historial de la sala Qui pot llegir l\'historial\? Qui pot accedir a la sala? - Ningú - Només els participants (a partir del moment en què es selecciona aquesta opció) - Només els participants (des de que són convidats) - Només els participants (des de que s\'uneixen a la sala) - + Només participants (a partir del moment en què es seleccioni aquesta opció) + Només participants (des de que són convidats) + Només participants (des de que s\'uneixen a la sala) La sala ha de tenir una adreça per tal d\'unir-s\'hi. - Només les persones convidades - Qualsevol que conegui l\'enllaç de la sala, excepte els convidats - Qualsevol que conegui l\'enllaç de la sala, inclosos els convidats - + Només persones que hagin estat convidades + Qualsevol que tingui l\'enllaç de la sala, a part dels convidats + Qualsevol que tingui l\'enllaç de la sala, inclosos els convidats Usuaris vetats - Avançat ID intern d\'aquesta sala @@ -614,43 +533,33 @@ Tingueu en compte que aquesta acció reiniciarà l\'aplicació i que pot trigar Encriptació d\'extrem a extrem L\'encriptació d\'extrem a extrem està acitva Necessiteu desconnectar-vos per poder habilitar l\'encriptació. - Encripta només per a dispositius verificats - No enviïs missatges encriptats en aquesta sala des d\'aquest dispositiu a dispositius no verificats. - + Encripta només a sessions verificades + No enviïs mai, des d\'aquesta sessió, missatges encriptats a sessions no verificades d\'aquesta sala. Aquesta sala no té adreces locals - Adreça nova (per exemple #foo:matrix.org") - - Aquesta sala no pertany a cap comunitat - Nova ID de comunitat (per exemple +foo:matrix.org") + Adreça nova (p.e. #foo:matrix.org) + Aquesta sala no mostra insígnies per a cap comunitat + Nou ID de comunitat (p.e. +foo:matrix.org) l\'ID de comunitat és invalid - \'%s\' no és una ID de comunitat vàlida - - + \'%s\' no és un ID de comunitat vàlid Format d\'àlies invàlid \'%s\' no és un format d\'àlies vàlid - No tindreu especificada una adreça principal per aquesta sala. + No tindràs cap adreça principal especificada per a aquesta sala. Avisos de l\'adreça principal - Estableix com a adreça principal Treu com a adreça principal Copia l\'ID de la sala Copia l\'adreça de la sala - L\'encriptació està activada en aquesta sala. L\'encriptació està desactivada en aquesta sala. Activa l\'encriptació \n(avís: no es podrà tornar a desactivar!) - Directori Tema - %s ha intentat carregar un moment concret de la línia de temps d\'aquesta sala però no l\'ha trobat. - Informació de l\'encriptació d\'extrem a extrem - Informació d\'esdeveniment Id de l\'usuari Clau de la identitat Curve25519 @@ -658,15 +567,13 @@ Tingueu en compte que aquesta acció reiniciarà l\'aplicació i que pot trigar Algoritme ID de la sessió Error de desencriptació - Informació del dispositiu que envia Nom del dispositiu Nom - ID del dispositiu + ID de sessió Clau del dispositiu Verificació Empremta digital Ed25519 - Exporta les claus de la sala E2E Exporta les claus de la sala Exporta les claus a un fitxer local @@ -676,35 +583,32 @@ Tingueu en compte que aquesta acció reiniciarà l\'aplicació i que pot trigar Les claus E2E de la sala s\'han desat a \'%s\' Atenció: es podria eliminar aquest fitxer si es desinstal·la l\'aplicació. - Importa les claus E2E de la sala Importa les claus de la sala Importa les claus de la sala des d\'un fitxer local Importa Encripta només per a dispositius verificats No enviïs mai missatges encriptats a dispositius no verificats des d\'aquest dispositiu. - NO verificat Verificat Bloquejat - dispositiu desconegut cap - Verifica No verifiquis Bloqueja Deixa de bloquejar - Verifica el dispositiu Per tal de verificar que es pot confiar amb aquest dispositiu, contacteu amb el seu propietari per algun altre mitjà (per exemple en persona o trucant-lo) i pregunteu-li si la clau que veu a les seves preferències d\'usuari coincideix amb la clau següent: Si coincideix, premeu el botó per verificar. Si no coincideix, algú està interceptant aquest dispositiu i probablement voldreu prémer el botó per bloquejar-lo. En un futur aquest procés de verificació serà més sofisticat. Verifica que les claus coincideixen - - La sala conté dispositius desconeguts - Aquesta sala conté dispositius desconeguts que no han estat verificats.\nAixò vol dir que no hi ha cap garantia que aquests dispositius siguin dels usuaris corresponents.\nEs recomana que feu el procés de verificació per a cada dispositiu abans de continuar, tot i que, si ho preferiu, podeu reenviar el missatge sense verificar.\n\nDispositius desconeguts: - + La sala conté sessions desconegudes + Aquesta sala conté sessions desconegudes que no han estat verificades. +\nAixò vol dir que no hi ha garanties de que aquestes sessions pertanyin als usuaris que diuen ser. +\nRecomanem que, abans de continuar, duguis a terme el procés de verificació de cadascuna de les sessions. Però, si ho prefereixes, pots reenviar el missatge sense la verificació. +\n +\nDispositius desconeguts: Escolliu un directori de sale És possible que el servidor no estigui disponible o que estigui sobrecarregat @@ -712,10 +616,8 @@ Atenció: es podria eliminar aquest fitxer si es desinstal·la l\'aplicació.URL del servidor base Totes les sales del servidor %s Totes les sales natives de %s - Busca a l\'historial - Mida de la font Molt petita @@ -725,46 +627,38 @@ Atenció: es podria eliminar aquest fitxer si es desinstal·la l\'aplicació.Molt gran Més gran Enorme - - No teniu permisos per a gestionar ginys en aquesta sala + Necessites permisos per gestionar ginys en aquesta sala Ha fallat la creació del giny Fes conferències amb jitsi Confirmeu que voleu esborrar el giny d\'aquesta sala? - No s\'ha pogut crear el giny. No s\'ha pogut enviar la sol·licitud. El nivell de potència ha de ser un enter positiu. - No us trobeu en aquesta sala. - No teniu el permis per fer això en aquesta sala. + No et trobes en aquesta sala. + No tens permís per fer això en aquesta sala. Falta l\'ID de la sala en la sol·licitud. Falta l\'ID d\'usuari en la sol·licitud. La sala %s no és visible. Afegeix aplicacions de Matrix Utilitza la càmera nativa - El nou dispositiu \'%s\' que heu afegit, sol·licita les claus d\'encriptació. El vostre dispositiu \'%s\' sense verificar, sol·licita les claus d\'encriptació. Inicia la verificació Comparteix sense verificar Ignora la sol·licitut - Avís! Les trucades per a conferències estan en desenvolupament i poden no ser fiables. - Error de comandament Ordre no reconegut: %s - Apagat - Sorollós - - Missatge encriptat - + Amb so + Missatge xifrat Crea Crea una comunitat @@ -772,58 +666,49 @@ Atenció: es podria eliminar aquest fitxer si es desinstal·la l\'aplicació.Exemple ID de la comunitat exemple - Inici Usuaris Sales Sense usuaris - Sales S\'hi ha unit Ha sigut convidat Filtre de participants de grups Filtra els grups de sales - L\'administrador de la comunitat no ha fet una descripció llarga per aquesta comunitat. - - %2$s l\'ha fet fora de la sala %1$s + %2$s t\'ha expulsat de %1$s %2$s l\'ha expulsat de la sala %1$s Raó: %1$s Tornar-hi a entrar Oblida la sala Carregant… - Surt Comunitats - Llista de grups - - Tots els missatges (sorollós) + Tots els missatges (amb so) Tots els missatges Només mencions Silencia Notificacions Sacseja el dispositiu amb ràbia per a informar d\'un error - Accions Llista de membres Sincronitzant… - 1 membre actiu + %d membre actiu %d membres actius - 1 membre + %d membre %d membres - 1 nou missatge - %d nous missatges + %d missatge nou + %d missatges nous - - 1 sala + %d sala %d sales @@ -831,93 +716,76 @@ Atenció: es podria eliminar aquest fitxer si es desinstal·la l\'aplicació.%1$s sales trobades per %2$s - 1 sala + %d sala %d sales Obre la capçalera - 1 missatge de notificació sense llegir - %d missatges de notificació sense llegir + %d missatge notificat no llegit + %d missatges notificats no llegits 1 canvi de membres %d canvis de membres - - 1 missatge de notificació sense llegir - %d missatges de notificació sense llegir + %d missatge notificat no llegit + %d missatges notificats no llegits %1$s a %2$s - - 1 complement actiu - %d complements actius + %d giny actiu + %d ginys actius - Envia un adhesiu - Envia un adhesiu Llicències de tercers - - Descarregar - Parlar - Netejar + Descarrega + Parla + Neteja Enviar veu - seguir amb… Ho sento, no s\'ha trobat cap aplicació externa per completar l\'acció. - Tornar a demanar les claus d\'encriptació als teus altres dispositius. - Petició de clau enviada. - Sol·licitud enviada Si us plau, engega Element a un altre dispositiu que pugui desencriptar el missatge de manera que pugui enviar la clau a aquest dispositiu. - Normal Tema Status.im - - Manquen permisos per a dur a terme aquesta acció. + No es pot dur a terme aquesta acció per falta de permisos. Error - Alertes de sistema - Si és possible, escriviu si us plau la descripció en anglès. Actualment no teniu cap conjunt d\'adhesius activat. En voleu afegir algun? - - 1s + %ds %ds - 1m + %dm %dm - 1h + %dh %dh - 1d + %dd %dd - - Ara %1$s + %1$s, ara %1$s fa %2$s - "%1$s,· " %1$s i %2$s %1$s %2$s - Envieu una resposta encriptada… - Envieu una resposta (sense encriptar)… + Envia una resposta (no encriptada)… - 1 escollit - %d escollits + %d seleccionat + %d seleccionats Versió %s Notificació de privacitat @@ -928,34 +796,26 @@ En voleu afegir algun? • El contingut dels missatges de les notificacions s\'obté de forma segura des del servidor de Matrix • Les notificacions contenen meta dades i dades de missatges • Les notificacions no mostraran el contingut dels missatges - Mostra el contingut multimèdia abans d\'enviar-lo - Desactivar el compte Desactivar el meu compte - Notificació de privacitat El Element pot funcionar en segon pla per gestionar les vostres notificacions de forma segura i privada. Això podria afectar el consum de bateria. Concedir permís Escolliu una altra opció - Envia dades d\'anàlisi Element recopila dades d\'anàlisi anònimes per tal de permetre\'ns millorar l\'aplicació. Si us plau, activeu les dades d\'anàlisi per ajudar-nos a millorar Element. Sí, vull ajudar! - - No sou ara mateix membre de cap comunitat. - + Ara mateix no ets membre de cap comunitat. Creeu una frase de pas per xifrar les claus exportades. Haureu d\'introduir la mateixa frase de pas per poder importar les claus. Crea frase de pas Les frases de pas han de coincidir Escriviu aquí… - Falta un paràmetre necessari. Un paràmetre no és vàlid. Premeu \"Enter\" per enviar el missatge Envia missatges de veu - Mostra l\'acció Veta l\'usuari amb l\'ID proporcionat Permeteu de nou l\'usuari amb l\'ID proporcionat @@ -965,74 +825,57 @@ En voleu afegir algun? Entreu a la sala amb l\'àlies donat Sortir de la sala Definir el motiu de la sala - Fer fora l\'usuari amb l\'ID proporcionat + Expulsa l\'usuari amb l\'ID proporcionat Canvia l\'àlies que es mostra Activa/Desactiva el markdown Arreglar la gestió de les Apps de Matrix - - 1 membre + %d membre %d membres - - 1 sala + %d sala %d sales Imatge de perfil - Per poder continuar usant el servidor %1$s heu de revisar i acceptar les clàusules i condicions. Revisa ara - Desactiva el compte - Això farà que no pugueu usar més el vostre compte. No podreu iniciar la sessió i ningú podrà donar-se d\'alta amb el mateix identificador d\'usuari. Això provocarà que el vostre compte abandoni totes les sales a les que estigui participant i eliminarà les vostres dades del compte que hi hagi al vostre servidor d\'identitats. Aquesta acció és irreversible. + Això farà que no puguis utilitzar més el teu compte. No podràs iniciar sessió i ningú podrà tornar-se a registrar amb el mateix ID d\'usuari. Això farà que el teu compte surti de totes les sales a les que estigui participant i eliminarà les dades del compte del teu servidor d\'identitat. Aquesta acció és irreversible. \n -\nDesactivar el compte no implica que s\'eliminin els missatges que heu enviat. Si voleu eliminar-los, marqueu la casella a continuació. +\nDesactivar el compte no implica que s\'oblidin els missatges que has enviat. Si vols que ens n\'oblidem, marca la casella a continuació. \n -\nLa visibilitat dels missatges a Matrix és similar a la del correu electrònic. Que eliminem els vostres missatges significa que els missatges que hagueu enviat no seran accessibles per a nous usuaris o usuaris no registrats, però els usuaris registrats que ja hi tinguin accés, en conservaran una còpia. +\nLa visibilitat dels missatges a Matrix és similar a la del correu electrònic. Que oblidem els teus missatges vol dir que els missatges que hagis enviat no seran accessibles per a nous usuaris o usuaris no registrats, però els usuaris registrats que ja hi tinguin accés, en conservaran una còpia. Si us plau elimina tots els missatges que he enviat mentre es desactiva el meu compte (Avís: això provocarà que els usuaris futurs tinguin una vista incompleta de les converses) Per a continuar, si us plau escriviu la vostra contrasenya: Desactivar el compte - Si us plau escriviu la vostra contrasenya. - Aquesta sala s\'ha substituït i ja no es troba activa + Aquesta sala s\'ha substituït i ja no està activa La conversa segueix aquí - Aquesta sala és la continuació d\'una altra conversa + Aquesta sala és un continuació d\'una altra conversa Feu clic aquí per veure els missatges antics - S\'ha sobrepassat el límit de recursos Contacta amb l\'administrador - Contacteu amb l\'administrador del servei - Aquest servidor base ha sobrepassat un dels seus límits de recursos, així que alguns usuaris no podran identificar-s\'hi. Aquest servidor base ha sobrepassat un dels seus límits de recursos. - Aquest servidor base ha assolit el seu límit màxim mensual d\'activitat d\'usuaris i alguns usuaris no podran identificar-s\'hi. Aquest servidor base ha assolit el seu límit mensual d\'activitat d\'usuaris. - Si us plau %s per tal d\'incrementar aquest límit. "Si us plau %s per continuar usant aquest servei." - - Torna a carregar els membres de la sala - Milloreu el rendiment carregant només els membres de la sala a primera vista. - El vostre servidor base encara no suporta la càrrega en diferit de membres d\'una sala. Proveu-ho més tard. - + Carrega en diferit els participants de la sala + Millora el rendiment carregant només els participants de la sala a primera vista. + El teu servidor encara no és compatible amb la càrrega en diferit dels participants d\'una sala. Prova-ho més tard. Ho sentim, s\'ha produït un error - desplega plega - - Acceptar - + Accepta Trucada Useu el to de Element per defecte per les trucades entrants To de trucada entrant Escolliu el to per les trucades: - - Expulsar + Expulsa Motiu - Mostra la vista prèvia dels enllaços dins del xat en cas que el vostre servidor base suporti aquesta funcionalitat. Envia notificacions d\'escriptura Feu saber a altres usuaris que esteu escrivint. @@ -1040,11 +883,9 @@ En voleu afegir algun? Doneu format a missatges usant la sintaxi Markdown abans d\'enviar-los. Això us permetrà l\'ús de format avançat com ara usar asteriscs per mostrar text en cursiva. No afecta invitacions, expulsions i bloquejos. Mostra els esdeveniments del compte - Truca de totes maneres + Truca igualment Reviseu i accepteu les polítiques d\'aquest servidor base: - Trucada de vídeo en procés… - Executa les proves S\'està executant… (%1$d de %2$d) El diagnòstic bàsic és correcte. Si encara no rebeu notificacions, envieu un informe d\'error per ajudar-nos a investigar. @@ -1054,28 +895,22 @@ En voleu afegir algun? Les notificacions són inhabilitades als paràmetres del sistema. Comproveu els paràmetres del sistema. Obre els paràmetres - Paràmetres del compte. Les notificacions són habilitades per al vostre compte. Les notificacions són inhabilitades per al vostre compte. Comproveu els paràmetres del compte. Habilita - Paràmetres del dispositiu. Les notificacions són habilitades per a aquest dispositiu. Habilita - Repara els serveis de Google Play - Servei de notificacions El servei de notificacions s\'està executant. El servei de notificacions s\'està executant. Proveu de reiniciar l\'aplicació. Inicia el servei - Inicia\'l a l\'arrencada Inhabilita les restriccions - Optimització de bateria El Element no està afectat per l\'optimització de bateria. Mostra els esdeveniments d\'entrada i sortida @@ -1085,36 +920,28 @@ Proveu de reiniciar l\'aplicació. A la pantalla següent se us demanarà que permeteu al Element executar-se sempre al rerefons, si us plau, accepteu-ho. Contrasenya Informació addicional: %s - S\'ha habilitat el Markdown. S\'ha inhabilitat el Markdown. - Avatar de recepció Avatar de notificació Mostra l\'àrea d\'informació Sempre Per als missatges i errors Només per als errors - %1$s: %1$s: %2$s +%d %d+ No s\'ha trobat cap APK de Google Play Services vàlid. Les notificacions poden no funcionar correctament. - - Còpia de seguretat de la clau - Empra una còpia de seguretat de la clau - + Còpia de seguretat de les claus + Utilitza la còpia de seguretat de les claus Omet Fet - Paràmetres avançats de notificacions Importància de les notificacions per esdeveniment - Diagnostica les notificacions Diagnòstic de la resolució de problemes Ha fallat una o més proves, envieu un informe d\'error per ajudar-nos a investigar-ho. - Les notificacions no són permeses per a aquest dispositiu. Comproveu els paràmetres del Element. Paràmetres personalitzats. @@ -1122,7 +949,6 @@ Comproveu els paràmetres del Element. Algunes notificacions estan inhabilitades als vostres paràmetres personalitzats. No s\'ha pogut carregar les regles personalitzades, torneu-ho a provar. Comproveu els paràmetres - Comprovació dels serveis de Play L\'APK dels serveis de Google Play és disponible i al dia. El Element empra els serveis de Google Play per a lliurar les notificacions, però no sembla que estiguen configurats correctament. @@ -1135,54 +961,41 @@ Comproveu els paràmetres del Element. [%1$s] Aquest error és fora del control del Element i segons Google aquest error indica que aquest dispositiu té massa aplicacions registrades amb FCM. L\'error només ocorre en casos en què hi ha un nombre extrem d\'aplicacions, i no hauria d\'afectar un usuari normal. Afegeix un compte - Registre del testimoni S\'ha registrat correctament el testimoni FCM al servidor base. No s\'ha pogut registrar el testimoni FCM al servidor base. \n%1$s - Reinici automàtic del servei de notificacions El servei s\'ha parat i tornat a iniciar automàticament. No s\'ha pogut iniciar el servei - El servei s\'iniciarà quan s\'iniciï el dispositiu. El servei no s\'iniciarà quan el dispositiu s\'iniciï, per la qual cosa no rebreu notificacions fins que el Element s\'haja obert una vegada. Habilita l\'inici durant l\'arrencada - Comprova les restriccions del rerefons Ignora l\'optimització - - Configura les notificacions sorolloses + Configura les notificacions amb so Configura les notificacions de les trucades Configura les notificacions silencioses Seleccioneu el color de LED, la vibració, so… - - Gestió de claus criptogràfiques Mostra les confirmacions de lectura Feu clic en les confirmacions de lectura per obtenir una llista detallada. Concedeix el permís - S\'ha produït un error en verificar la vostra adreça de correu electrònic. - S\'ha produït un error en verificar el vostre número de telèfon. Gestiona les còpies de seguretat de la clau - Inicia la càmera del sistema en lloc de la pantalla personalitzada de la càmera. Aquesta opció requereix una aplicació de tercers per enregistrar els missatges. - L\'ordre «%s» necessita més paràmetres, o alguns paràmetres no són correctes. Silenciós Introduïu una frase de pas La frase de pas és massa feble - Suprimiu la frase de pas si voleu que el Element generi una clau de recuperació. No hi ha cap sessió de Matrix disponible - No perdeu mai els missatges xifrats - Els missatges en sales xifrades estan assegurats amb xifratge punt a punt. Només tu i els destinaris tenen les claus per a llegir aquests missatges. - -Feu una còpia de seguretat de manera segura per evitar perdre-les. + Els missatges en sales encriptades estan assegurats amb encriptació d\'extrem a extrem. Només tu i el/s destinatari/s tenen les claus per a llegir aquests missatges. +\n +\nFes una còpia de seguretat de les teves claus per evitar perdre\'ls. Estableix la frase de pas Fet Desa la clau de recuperació @@ -1190,7 +1003,6 @@ Feu una còpia de seguretat de manera segura per evitar perdre-les. S\'ha desat la clau de recuperació a «%s». Avís: és possible que calgui suprimir el fitxer si es desinstal·la l\'aplicació. - Feu una còpia Comparteix la clau de recuperació amb… Clau de recuperació @@ -1198,17 +1010,13 @@ Avís: és possible que calgui suprimir el fitxer si es desinstal·la l\'aplicac S\'ha iniciat la còpia de seguretat N\'esteu segur? És possible que perdeu l\'accés als vostres missatges si sortiu de la sessió o perdeu el dispositiu. - S\'està recuperant la versió de la còpia de seguretat… Empreu la vostra frase de pas de recuperació per desblocar el vostre historial de missatges xifrat empreu la clau de recuperació Si no coneixeu la vostra contrasenya de recuperació, podeu %s. - Empreu la vostra clau de recuperació per desblocar el vostre historial de missatges xifrat Introduïu la clau de recuperació - Recuperació de missatges - Heu perdut la vostra clau de recuperació? Podeu establir una nova a les preferències. "[%1$s] Aquest error és fora del control del Element. Pot ocórrer per diferents raons. És possible que funcioni si ho torneu a provar més endavant. També podeu comprovar que el servei de Google Play no està restringit a l\'ús de dades a les preferències del sistema, o que el rellotge del dispositiu marca l\'hora correcta. També pot passar amb ROM personalitzades." @@ -1220,20 +1028,14 @@ Aquest error és fora del control del Element. No hi ha cap compte de Google al Les tasques que l\'aplicació intenta fer estaran restringides agressivament mentre estigui al rerefons, i això pot afectar les notificacions. %1$s Si un usuari deixa un dispositiu sense endollar i immòbil durant un període de temps, amb la pantalla apagada, el dispositiu entra en el mode d\'estalvi d\'energia. Això impedeix les aplicacions d\'accedir a la xarxa i ajorna les seves tasques, sincronitzacions i alarmes estàndard. - - S\'està generant la clau de recuperació emprant una frase de pas. Aquest procés pot trigar uns segons. Les vostres claus de xifratge s\'estan emmagatzemant al rerefons al vostre servidor base. La còpia inicial pot trigar alguns minuts. - - No s\'ha pogut desxifrar la còpia de seguretat amb aquesta frase de pas: verifiqueu que la frase de pas que heu introduït és la correcta. Error de xarxa: comproveu la vostra connectivitat i torneu-ho a provar. - S\'està restaurant la còpia de seguretat: Desbloca l\'historial Introduïu una clau de recuperació No s\'ha pogut desxifrar la còpia de seguretat amb aquesta clau de recuperació: verifiqueu que heu introduït la clau correcta. - S\'ha restaurat la còpia de seguretat %s! S\'ha restaurat una còpia amb %d clau. @@ -1243,24 +1045,16 @@ Les tasques que l\'aplicació intenta fer estaran restringides agressivament men S\'ha afegit %d clau nova a aquest dispositiu. S\'ha afegit %d claus noves a aquest dispositiu. - No s\'ha pogut obtenir la versió de les claus de recuperació més recents (%s). La criptografia de la sessió no és activa - - Restaura des de la còpia de seguretat Suprimeix la còpia de seguretat - S\'ha configurat la còpia de seguretat de la clau correctament per a aquest dispositiu. La còpia de seguretat de la clau no és activa en aquest dispositiu. No s\'està fent còpia de seguretat de les vostres claus en aquest dispositiu. - - S\'està suprimint la còpia de seguretat… No s\'ha pogut suprimir la còpia de seguretat (%s) - Suprimeix la còpia de seguretat - La còpia de seguretat té una signatura d\'un dispositiu desconegut amb ID %s. La còpia de seguretat té una signatura vàlida d\'aquest dispositiu. La còpia de seguretat té una signatura vàlida del dispositiu verificat %s. @@ -1268,28 +1062,23 @@ Les tasques que l\'aplicació intenta fer estaran restringides agressivament men La còpia de seguretat té una signatura no vàlida del dispositiu verificat %s La còpia de seguretat té una signatura no vàlida del dispositiu no verificat %s No s\'ha pogut obtenir la informació de confiança per a la còpia de seguretat (%s). - Voleu suprimir la còpia de les vostres claus de xifratge del servidor? Ja no podreu emprar la vostra clau de recuperació per llegir el vostre historial de missatges xifrats. - - La còpia de seguretat de les claus no ha finalitzat, espereu… - Perdreu els vostres missatges xifrats si sortiu ara - S\'està fent la còpia de seguretat de les claus. Si sortiu ara, perdreu accés als vostres missatges xifrats. - No vull els meus missatges xifrats - S\'està fent una còpia de les claus… - Empra la còpia de la clau - N\'esteu segur? - Fes una còpia - Roman + La còpia de seguretat de les claus no ha finalitzat, espera… + Si tanques sessió ara, perdràs els teus missatges xifrats + S\'està fent la còpia de seguretat de les claus. Si tanques sessió ara, perdràs els teus missatges xifrats. + No vull els meus missatges encriptats + Fent còpia de seguretat de les claus… + Utilitza la còpia de seguretat de les claus + N\'estàs segur\? + Còpia de seguretat + Queda\'t Avorta - - Esteu segurs que voleu sortir de la sessió\? - + Estàs segur que vols tancar la sessió\? Recuperació de missatges xifrats Introduïu un nom d\'usuari. Comenceu a emprar la còpia de la clau (Avançat) Exporta les claus manualment - Assegureu la vostra còpia amb una frase de pas. S\'està creant una còpia de seguretat O, assegureu la vostra còpia amb una clau de recuperació, desant-la en un lloc segur. @@ -1300,35 +1089,27 @@ Les tasques que l\'aplicació intenta fer estaran restringides agressivament men Comparteix No perdeu mai els missatges xifrats Comenceu a emprar la còpia de seguretat de les claus - No perdeu mai els missatges xifrats Empra la còpia de seguretat de la clau - Claus de missatges xifrats noves Gestiona en la còpia de la clau - S\'està fent una còpia de seguretat de les claus… - S\'ha fet una còpia de seguretat de totes les claus S\'està fent una còpia de seguretat d\'%d clau… S\'està fent una còpia de seguretat de %d claus… - Versió Algoritme Signatura - He sigut jo Còpia de seguretat nova de la clau - Per evitar la pèrdua d\'accés als vostres missatges encriptats, hauríeu d\'activar la còpia de seguretat encriptada a tots els vostres dispositius. - Perdreu accés als vostres missatges encriptats si no feu una còpia de seguretat de les vostres claus abans de sortir de la sessió. - + Per evitar la pèrdua d\'accés als teus missatges encriptats, hauries d\'activar la còpia de seguretat segura a totes les teves sessions. + Perdràs l\'accés als teus missatges encriptats si no fas una còpia de seguretat de les teves claus abans de tancar la sessió. Es desarà una còpia encriptada de les vostres claus al vostre servidor base. Protegiu la vostra còpia de seguretat amb una contrasenya per tal de mantenir-la segura. \n \nPer màxima seguretat, aquesta contrasenya hauria de ser diferent de la contrasenya del vostre compte. El mode d\'estalvi de dades aplica un filtre específic que evita l\'enviament de notificacions de presència i d\'escriptura. - En cas que oblideu la vostra contrasenya, la vostra clau de recuperació és un últim recurs per recuperar l\'accés als vostres missatges xifrats. \nDeseu aquesta clau de recuperació en un lloc molt segur, com ara un gestor de contrasenyes o una caixa forta Deseu la vostra clau de recuperació en un lloc molt segur, com ara un gestor de contrasenyes o una caixa forta @@ -1339,19 +1120,16 @@ Les tasques que l\'aplicació intenta fer estaran restringides agressivament men S\'ha trobat una còpia de seguretat nova de la clau. \n \nSi no heu configurat el mètode de recuperació nou, un atacant podria estar intentant accedir al vostre compte. Canvieu la contrasenya del vostre compte i configureu-hi un mètode de recuperació nou immediatament a la configuració. - Inicialitzar servei - Ignorar - - Iniciar sessió amb Single Sign-on + Inicialitzant servei + Ignora + Inicia sessió amb la inscripció única (SSO) Aquesta URL no està disponible , si us plau verifiqueu-la El vostre dispositiu està usant una versió obsoleta del protocol de seguretat TLS, vulnerable a atacs. Per a la vostra seguretat no us podreu connectar Envieu un missatge amb Enter La tecla Enter del teclat virtual enviarà un missatge en comptes d\'afegir un salt de línia - Actualitzar la contrasenya La contrasenya no és vàlida Les contrasenyes no coincideixen - Medis Compressió estàndard Escollir @@ -1359,34 +1137,27 @@ Les tasques que l\'aplicació intenta fer estaran restringides agressivament men Escollir Resposta no vàlida en descobrir homeservers Usar Config - - Verificar dispositiu - - Marcar com a llegit + Verifica sessió + Marca-ho com a llegit Les app no necessita connectar-se al HomeServer en segon pla, hauria de reduir el consum de bateria Administrador d\'integracions - Reproduir el so de disparador - IP desconeguda - %1$s: 1 missatge + %1$s: %2$d missatge %1$s: %2$d missatges %d notificacion %d notificacions - Nou esdeveniment Sala Missatges nous Nova invitació Jo - ** Error en enviar - Si us plau obriu la sala - - Ho sentim, els dispositius amb SO Android inferior a 5.0 no suporten trucades multi-usuari amb Jitsi - + ** No s\'ha pogut enviar - si us plau, obre la sala + Ho sentim, les videoconferències amb Jitsi no són compatibles amb dispositius antics (dispositius amb Android inferior a 5.0) No heu configurat cap administrador d\'integracions. Un nou dispositiu està sol·licitant claus d\'encriptació. \nNom del dispositiu: %1$s @@ -1396,56 +1167,45 @@ Les tasques que l\'aplicació intenta fer estaran restringides agressivament men \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 Compartir Sol·licitud de compartició de clau Ignorar - Ja existeix una còpia de seguretat al vostre HomeServer Sembla que ja heu configurat una còpia de seguretat de claus des d\'un altre dispositiu. Voleu reemplaçar-la amb la que esteu creant\? Reemplaçar Aturar - Comprovant l\'estat de la còpia de seguretat Opcions d\'autocompleció del servidor Element ha detectat una configuració de servidor personalitzat pel domini del seu identificador d\'usuari \"%1$s\": \n%2$s Us heu desconnectat a causa de credencials incorrectes o caducades. - Verificar comparant una cadena de text curta. Per la màxima seguretat us recomanem fer això en persona o usar un altre medi de comunicació confiable. Començar la verificació Sol·licitud de verificació entrant Verificar aquest dispositiu per marcar-lo com a confiable. Confiar en dispositius d\'amistats us dona un alleujament addicional quan useu missatges encriptats end-to-end. Verificant aquest dispositiu el marcareu com a confiable, i també marcareu el vostre dispositiu com a confiable pel vostre company. - Verificar aquest dispositiu confirmant els següents emojis que apareguin a la pantalla del vostre company Verificar aquest dispositiu confirmant els següents números que sortiran a la pantalla del vostre company - Heu rebut una sol·licitud de verificació entrant. Veure sol·licitud Esperant que el vostre company confirmi… - Verificat! Heu verificat aquest dispositiu amb èxit. Els missatges segurs amb aquest usuari estan encriptats end-to-end i no serà possible llegir-los per tercers. Entesos - No surt res\? Encara no tots els clients suporten la verificació interactiva. Useu el mètode de verificació antic. Useu el mètode antic de verificació. - Verificació de clau Sol·licitud cancel·lada L\'altre part ha cancel·lat la verificació. \n%s S\'ha cancel·lat la verificació. \nMotiu: %s - Verificació de dispositiu interactiva Sol·licitud de verificació %s vol verificar el vostre dispositiu - L\'usuari ha cancel·lat la verificació El marge de temps pel procés de verificació ha expirat El dispositiu no coneix la transacció @@ -1457,71 +1217,132 @@ Les tasques que l\'aplicació intenta fer estaran restringides agressivament men La clau no coincideix L\'usuari no coincideix Error desconegut - - Editar Respondre - Tornar-ho a provar Unir-se a una sala per començar usant l\'app. Se t\'ha enviat una invitació Convidat per %s - Esteu al dia! - No teniu més missatges sense llegir + No tens més missatges sense llegir Benvingut a casa! Posar-se al dia dels missatges sense llegir Converses Els vostres missatges directes es mostraran aquí Sales Les vostres sales es mostraran aquí - Reaccions Confirmar M\'agrada Afegir reacció Veure reaccions Reaccions - Esdeveniment eliminat per l\'usuari Esdeveniment moderat per l\'administrador de la sala Última edició per %1$s el %2$s - - Esdeveniment mal format, no es pot mostrar - Crear sala nova + Crea sala nova No hi ha xarxa. Si us plau comproveu la vostra connexió a internet. Canviar Canviar de xarxa Espereu, si us plau… Totes les comunitats - Aquesta sala no es pot pre-visualitzar - Element encara no suporta la pre-visualització de sales llegibles per tothom - + Element encara no admet la pre-visualització de les sales llegibles per tothom Sales Missatges directes - Sala nova CREAR - Nom de la sala + Nom Públic Qualsevol podrà unir-se a aquesta sala Directori de sales Publicar aquesta sala al directori de sales - Hi ha hagut un error rebent informació de confança Hi ha hagut un error rebent dades de la còpia de seguretat de les claus - Importar claus e2e des del fitxer \"%1$s\". - Versió de l\'SDK de Matrix Ja esteu veient aquesta sala! - Reaccions ràpides - General Preferències Seguretat i privadesa Expert - + Motiu de l\'expulsió + Expulsa usuari + Aquesta operació encara no està disponible en comptes que utilitzen la inscripció única (SSO). + Continua amb SSO + Per a la teva pròpia privadesa, Element només admet l\'enviament del \"hash\" de correus electrònics i números de telèfon. + Només admès en sales xifrades + El xifrat que utilitza aquesta sala no és compatible + No pots fer això des del mòbil + L\'aplicació no ha pogut crear un compte en aquest servidor. +\n +\nVols registrar-te utilitzant un client web\? + L\'aplicació no ha pogut iniciar sessió en aquest servidor. El servidor és compatible amb el/s següent/s tipus d\'inici de sessió: %1$s. +\n +\nVols iniciar sessió utilitzant un client web\? + No pots fer això des d\'Element per a mòbils + La cerca en sales xifrades encara no està disponible. + La sala encara no s\'ha acabat de crear. Vols cancel·lar la seva creació\? + No s\'ha trobat aquesta sala. Assegura\'t que existeixi. + Mostra detalls com per exemple noms de sala i contingut dels missatges. + No hem pogut convidar els usuaris. Comprova els usuaris que vols convidar i torna-ho a provar. + Estàs segur que vols eliminar aquest esdeveniment\? Tingues en compte que, si suprimeixes un nom de sala o es canvia el tema, podria ser que es revertís. + Una vegada activada, l\'encriptació d\'una sala no es pot desactivar. El servidor no pot llegir els missatges enviats en una sala encriptada, només els poden llegir els participants. Habilitar l\'encriptació pot fer que molts bots i enllaços no funcionin correctament. + Una vegada activada, l\'encriptació no es pot desactivar. + Notificacions + Els missatges d\'aquí no estan encriptats d\'extrem a extrem. + Els missatges d\'aquesta sala no estan encriptats d\'extrem a extrem. + Una vegada activada, l\'encriptació no es pot desactivar. + Si canvies la contrasenya es restabliran les claus d\'encriptació d\'extrem a extrem de totes les teves sessions de manera que l\'historial del xat no es podrà llegir. Configura una còpia de seguretat de les claus o exporta les teves claus de sala d\'una altra sessió abans de fer el canvi de contrasenya. + Has fet la sala accessible per a qualsevol que tingui l\'enllaç. + %1$s ha fet la sala accessible per a qualsevol que tingui l\'enllaç. + Silencia + Només mencions + Tots els missatges + Tots els missatges (amb so) + En aquesta sala no hi ha mitjans + En aquesta sala no hi ha fitxers + No s\'ha trobat cap resultat, utilitza Afegeix amb ID de matrix per a cercar al servidor. + La sala ha estat creada però algunes invitacions no s\'han enviat pel motiu següent: +\n +\n%s + No hi ha ginys actius + %1$s s %2$s i %3$s + Si deixes d\'ignorar aquest usuari, tornaràs a veure tots els seus missatges. + Deixa d\'ignorar + Si ignores aquest usuari s\'eliminaran els seus missatges de les sales que compartiu. +\n +\nPots desfer aquest canvi en qualsevol moment a la configuració general. + Ignora usuari + No podràs desfer aquest canvi ja que t\'estàs baixant de rang, si ets l\'últim usuari de la sala amb privilegis, et serà impossible recuperar-los. + No s\'ha configurat cap servidor d\'identitat. + Sense més resultats + Notificacions + Èxit + Copia + Penja + Rebutja + Accepta + Rebutja + No s\'ha pogut eliminar el giny + No s\'ha pogut afegir el giny + No pots iniciar una trucada amb tu mateix, espera que els participants acceptin la invitació + No pots iniciar una trucada amb tu mateix + Les reunions utilitzen les polítiques de seguretat i permisos de Jitsi. Tots els participants que es trobin dins sala veuran una invitació per unir-se mentre la teva reunió estigui en curs. + Inicia una reunió d\'àudio + Inicia una reunió de vídeo + Ja hi ha una videoconferència en curs! + No tens permís per iniciar una trucada + No tens permís per iniciar una trucada en aquesta sala + No tens permís per iniciar una videoconferència + No tens permís per iniciar una videoconferència en aquesta sala + Reinicia + Omet + Atura + Desconnecta + Revoca + Cap + Latn + \ No newline at end of file From 9755dd73ebd406ab66710fefead04790aa0d5769 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20J=C3=B5er=C3=BC=C3=BCt?= Date: Wed, 4 Nov 2020 14:49:45 +0000 Subject: [PATCH 02/66] Translated using Weblate (Estonian) Currently translated at 100.0% (1933 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/et/ --- vector/src/main/res/values-et/strings.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vector/src/main/res/values-et/strings.xml b/vector/src/main/res/values-et/strings.xml index 73a5a0dff8..152f5f03e2 100644 --- a/vector/src/main/res/values-et/strings.xml +++ b/vector/src/main/res/values-et/strings.xml @@ -2187,4 +2187,8 @@ Jututoa seadistused Teema Jututoa teema (kui soovid) + Ekspordi rakenduse taustakontrolli andmed + Otsevestlus + Lisa kaasa võtmevahetusega seotud päringute ajalugu + Rohkem otsingutulemusi pole \ No newline at end of file From eaa7fb71002de7cad0776b2f8e39e8d7521788e2 Mon Sep 17 00:00:00 2001 From: Marcelo Filho Date: Thu, 5 Nov 2020 22:44:39 +0000 Subject: [PATCH 03/66] Translated using Weblate (Portuguese (Brazil)) Currently translated at 99.7% (1929 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/pt_BR/ --- vector/src/main/res/values-pt-rBR/strings.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/vector/src/main/res/values-pt-rBR/strings.xml b/vector/src/main/res/values-pt-rBR/strings.xml index 55e904bc2e..674ce19759 100644 --- a/vector/src/main/res/values-pt-rBR/strings.xml +++ b/vector/src/main/res/values-pt-rBR/strings.xml @@ -361,7 +361,7 @@ Digite o ide ou o apelido de uma sala Pesquisar na lista pública - Buscando no diretório… + Buscando na lista… Favoritar Despriorizar @@ -516,7 +516,7 @@ Ativar criptografia· \n(atenção: não é possível desativar depois!) - Diretório + Lista %s tentou carregar um trecho específico da conversa desta sala, mas não conseguiu. @@ -573,15 +573,15 @@ Escolha uma lista pública de salas O servidor pode estar indisponível ou sobrecarregado - Entre com um servidor principal (homeserver) a partir do qual serão listadas as salas públicas + Digite um servidor local, a partir do qual serão listadas as salas públicas Endereço do servidor principal Todas as salas com o servidor %s Todas as salas nativas em %s Pesquisar no histórico - Desconectado + Offline Lista de usuários - LISTA DE USUÁRIAS(OS) (%s) + LISTA DE USUÁRIOS (%s) Iniciar com o sistema Esvaziar o cache de mídia Manter mídia @@ -1407,7 +1407,7 @@ Público Qualquer pessoa poderá entrar nesta sala Lista de Salas - Publicar esta sala na lista das salas + Publicar esta sala na lista de salas Ocorreu um erro ao receber informações de confiança Ocorreu um erro ao obter dados de backup de chaves Importar as chaves de arquivo \"%1$s\". @@ -1452,7 +1452,7 @@ Não consegue encontrar o que você está procurando\? Criar uma sala nova Enviar nova mensagem - Veja lista das salas + Veja lista de salas Nome ou ID (#example:matrix.org) Ativar o recurso de deslizar para responder nas conversas Adicione uma aba dedicada para notificações não lidas na tela principal. From 2a22d71e7cada85cfc0f43ec2f7bed8f80ad388a Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Thu, 5 Nov 2020 02:21:22 +0000 Subject: [PATCH 04/66] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (1933 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/zh_Hant/ --- vector/src/main/res/values-zh-rTW/strings.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vector/src/main/res/values-zh-rTW/strings.xml b/vector/src/main/res/values-zh-rTW/strings.xml index 6dc811aa28..8d019a7635 100644 --- a/vector/src/main/res/values-zh-rTW/strings.xml +++ b/vector/src/main/res/values-zh-rTW/strings.xml @@ -2149,4 +2149,8 @@ 主題 聊天室主題(選擇性) 聊天是名稱 + 匯出審核 + 直接訊息 + 傳送金鑰共享請求歷史 + 沒有更多結果 \ No newline at end of file From cb49c7d060a17be23c7233e03b623e56dc311965 Mon Sep 17 00:00:00 2001 From: "Auri B. P" Date: Thu, 5 Nov 2020 22:33:56 +0000 Subject: [PATCH 05/66] Translated using Weblate (Catalan) Currently translated at 100.0% (190 of 190 strings) Translation: Element Android/Element Android Sdk Translate-URL: https://translate.element.io/projects/element-android/element-sdk/ca/ --- .../src/main/res/values-ca/strings.xml | 234 ++++++++++++++---- 1 file changed, 186 insertions(+), 48 deletions(-) diff --git a/matrix-sdk-android/src/main/res/values-ca/strings.xml b/matrix-sdk-android/src/main/res/values-ca/strings.xml index 2dc2206c8c..8ba8c9acfd 100644 --- a/matrix-sdk-android/src/main/res/values-ca/strings.xml +++ b/matrix-sdk-android/src/main/res/values-ca/strings.xml @@ -1,79 +1,217 @@ - + %1$s: %2$s %1$s ha enviat una imatge. - - %1s ha sortit - %1s ha entrat + %1$s ha marxat de la sala + %1$s s\'ha unit a la sala Número de telèfon - Correu electrònic - Missatge encriptat - - la invitació de %s + Missatge xifrat + invitació de %s %1$s ha convidat a %2$s - %1$s us ha convidat + %1$s t\'ha convidat %1$s ha rebutjat la invitació - %1$s ha fet fora a %2$s - - - %1$s ha canviat el seu nom visible de %2$s a %3$s - %1$s ha eliminat el seu nom visible (%2$s) + %1$s ha expulsat %2$s + %1$s ha canviat el seu nom de visualització de %2$s a %3$s + %1$s ha eliminat el seu nom de visualització (era %2$s) %1$s ha canviat el tema a: %2$s %1$s ha canviat el nom de la sala a: %2$s - %s ha contestat la trucada. + %s ha respost a la trucada. %s ha finalitzat la trucada. - tots el membres de la sala, des del punt en què són convidats. - tots els membres de la sala. + tots el participants de la sala, des de que són convidats. + tots els participants de la sala. desconegut (%s). - %1$s ha activat l\'encriptació d\'extrem a extrem (%2$s) - + %1$s ha activat el xifrat d\'extrem a extrem (%2$s) %1$s ha sol·licitat una conferència VoIP - %1$s ha readmès a %2$s - %1$s ha vetat a %2$s + %1$s ha tret el veto a %2$s + %1$s ha vetat %2$s %1$s ha retirat la invitació de %2$s %1$s ha canviat el seu avatar - %1$s ha permès a %2$s veure l\'historial que es generi a partir d\'ara - tots els membres de la sala, des del punt en què hi entrin. + %1$s ha establert la visibilitat de l\'historial futur de la sala a %2$s + tots els participants de la sala, des de que s\'hi uneixen. qualsevol. S\'ha iniciat la conferència VoIP - S\'ha finalitzat la conferència de veu IP - - (s\'ha canviat també l\'avatar) + Ha finalitzat la conferència VoIP + (també ha canviat l\'avatar) %1$s ha eliminat el nom de la sala %1$s ha eliminat el tema de la sala %1$s ha actualitzat el seu perfil %2$s - %1$s ha enviat una invitació a %2$s per a entrar a la sala - %1$s ha acceptat la invitació per a %2$s - - ** No s\'ha pogut desencriptar: %s ** + %1$s ha enviat una invitació a %2$s perquè s\'uneixi a la sala + %1$s ha acceptat la invitació de %2$s + ** No s\'ha pogut desxifrar: %s ** El dispositiu del remitent no ens ha enviat les claus per aquest missatge. - No s\'ha pogut redactar No s\'ha pogut enviar el missatge - No s\'ha pogut pujar la imatge - - S\'ha produït un error de xarxa - S\'ha produït un error de Matrix - - Actualment no es pot tornar a entrar a una sala buida. - - %1$s a canviat el seu nom visible a %2$s - %s ha iniciat una trucada de vídeo. - %s ha iniciat una trucada de veu. - + Error de xarxa + Error de Matrix + Ara per ara no és possible tornar a unir-se a una sala buida. + %1$s a canviat el seu nom de visualització a %2$s + %s ha realitzat una videotrucada. + %s ha realitzat una trucada de veu. - Convidat per %s - Convideu a la sala + Invitació de %s + Convida a la sala %1$s i %2$s Sala buida %1$s i 1 altre %1$s i %2$d altres - - %1$s ha enviat un adhesiu. - - + %s s\'ha actualitzat aquí. + Ho has actualitzat aquí. + %s està sol·licitant la verificació de la teva clau, però el teu client no admet la verificació de clau des del xat. Hauràs d\'utilitzar la verificació de claus heretada per fer la verificació. + Has activat el xifrat d\'extrem a extrem (algorisme %1$s no reconegut). + %1$s ha activat el xifrat d\'extrem a extrem (algorisme %2$s no reconegut). + Has activat el xifrat d\'extrem a extrem. + %1$s ha activat el xifrat d\'extrem a extrem. + Has impedit que els convidats es puguin unir a la sala. + %1$s ha impedit que els convidats es puguin unir a la sala. + Has impedit que els convidats es puguin unir a la sala. + %1$s ha impedit que els convidats es puguin unir a la sala. + Has permès que els convidats s\'uneixin aquí. + %1$s ha permès que els convidats s\'uneixin aquí. + Has permès que els convidats s\'uneixin a la sala. + %1$s ha permès que els convidats s\'uneixin a la sala. + Has eliminat l\'adreça principal d\'aquesta sala. + %1$s ha eliminat l\'adreça principal d\'aquesta sala. + Has establert l\'adreça principal d\'aquesta sala a %1$s. + %1$s ha establert l\'adreça principal d\'aquesta sala a %2$s. + Has afegit %1$s i has eliminat %2$s d\'aquesta sala (adreces). + %1$s ha afegit %2$s i ha eliminat %3$s d\'aquesta sala (adreces). + + Has eliminat l\'adreça %1$s d\'aquesta sala. + Has eliminat les adreces %1$s d\'aquesta sala. + + + %1$s ha eliminat l\'adreça %2$s d\'aquesta sala. + %1$s ha eliminat les adreces %3$s d\'aquesta sala. + + + Has afegit l\'adreça %1$s a aquesta sala. + Has afegit les adreces %1$s a aquesta sala. + + + %1$s ha afegit l\'adreça %2$s a aquesta sala. + %1$s ha afegit les adreces %2$s a aquesta sala. + + Has revocat la invitació de %1$s perquè s\'uneixi a la sala. Motiu: %2$s + %1$s ha revocat la invitació de %2$s perquè s\'uneixi a la sala. Motiu: %3$s + Has revocat la invitació de %1$s + %1$s ha revocat la invitació de %2$s + Has revocat la invitació de %1$s perquè s\'uneixi a la sala + %1$s ha revocat la invitació de %2$s perquè s\'uneixi a la sala + Has retirat la invitació de %1$s. Motiu: %2$s + %1$s ha retirat la invitació de %2$s. Motiu: %3$s + Has acceptat la invitació de %1$s. Motiu: %2$s + %1$s ha acceptat la invitació de %2$s. Motiu: %3$s + Has enviat una invitació a %1$s perquè s\'uneixi a la sala. Motiu: %2$s + %1$s ha enviat una invitació a %2$s perquè s\'uneixi a la sala. Motiu: %3$s + Has vetat %1$s. Motiu: %2$s + %1$s ha vetat %2$s. Motiu: %3$s + Has tret el veto a %1$s. Motiu: %2$s + %1$s ha tret el veto a %2$s. Motiu: %3$s + Has vetat %1$s + Has marxat de la sala. Motiu: %1$s + %1$s ha marxat de la sala. Motiu: %2$s + Has marxat de la sala + %1$s ha marxat de la sala + Has marxat de la sala + Has expulsat %1$s + Has expulsat %1$s. Motiu: %2$s + %1$s ha expulsat %2$s. Motiu: %3$s + Has rebutjat la invitació. Motiu: %1$s + %1$s ha rebutjat la invitació. Motiu: %2$s + Has marxat. Motiu: %1$s + %1$s ha marxat. Motiu: %2$s + T\'has unit. Motiu: %1$s + %1$s s\'ha unit. Motiu: %2$s + T\'has unit a la sala. Motiu: %1$s + %1$s s\'ha unit a la sala. Motiu: %2$s + %1$s t\'ha convidat. Motiu: %2$s + Has convidat %1$s. Motiu: %2$s + %1$s ha convidat %2$s. Motiu: %3$s + La teva invitació. Motiu: %1$s + la invitació de %1$s. Motiu: %2$s + Esborra la cua d\'enviament + Enviant missatge… + Sincronització inicial: +\nImportant dades del compte + Sincronització inicial: +\nImportant comunitats + Sincronització inicial: +\nImportant sales que deixat + Sincronització inicial: +\nImportant compte… + Sincronització inicial: +\nImportant xifrat + Sincronització inicial: +\nImportant sales + Sincronització inicial: +\nImportant sales on hi estàs convidat + Sincronització inicial: +\nImportant sales on hi estàs unit + %1$s de %2$s a %3$s + %1$s ha canviat el nivell d\'autoritat de %2$s. + Has canviat el nivell d\'autoritat de %1$s. + Personalitzat + Personalitzat (%1$d) + Predeterminat + Moderador + Administrador + Has modificat el giny %1$s + %1$s ha modificat el giny %2$s + Has eliminat el giny %1$s + %1$s ha eliminat el giny %2$s + Has afegit el giny %1$s + %1$s ha afegit el giny %2$s + Has acceptat la invitació de %1$s + Has convidat a %1$s + %1$s ha convidat a %2$s + Has enviat una invitació a %1$s perquè s\'uneixi a la sala + Has actualitzat el teu perfil %1$s + Missatge eliminat per %1$s [motiu: %2$s] + Missatge eliminat [motiu: %1$s] + Missatge eliminat per %1$s + Missatge eliminat + Has eliminat l\'avatar de la sala + %1$s ha eliminat l\'avatar de la sala + Has eliminat el tema de la sala + Has eliminat el nom de la sala + Has sol·licitat una conferència VoIP + Has actualitzat aquesta sala. + %s ha actualitzat aquesta sala. + Has activat el xifrat d\'extrem a extrem (%1$s) + Has establert la visibilitat dels missatges futurs a %1$s + %1$s ha establert la visibilitat dels missatges futurs a %2$s + Has establert la visibilitat de l\'historial futur de la sala a %1$s + Has finalitzat la trucada. + Has respost a la trucada. + Has enviat dades per configurar la trucada. + %s ha enviat dades per configurar la trucada. + Has realitzat una trucada de veu. + Has realitzat una videotrucada. + Has canviat el nom de la sala a: %1$s + Has canviat l\'avatar de la sala + %1$s ha canviat l\'avatar de la sala + Has canviat el tema a: %1$s + Has eliminat el teu nom de visualització (era %1$s) + Has canviat el teu nom de visualització de %1$s a %2$s + Has canviat el teu nom de visualització a %1$s + Has canviat el teu avatar + Has retirat la invitació de %1$s + Has tret el veto a %1$s + Has rebutjat la invitació + Has creat la discussió + %1$s ha creat la discussió + T\'has unit + %1$s s\'ha unit + T\'has unit a la sala + Has convidat a %1$s + Has creat la sala + %1$s ha creat la sala + La teva invitació + Has enviat un adhesiu. + Has enviat una imatge. + \ No newline at end of file From 428062e1e430980d2a65bf1599154ba4e3173236 Mon Sep 17 00:00:00 2001 From: "Auri B. P" Date: Thu, 5 Nov 2020 01:30:06 +0000 Subject: [PATCH 06/66] Translated using Weblate (Catalan) Currently translated at 100.0% (4 of 4 strings) Translation: Element Android/Element Android Store Translate-URL: https://translate.element.io/projects/element-android/element-store/ca/ --- .../android/ca/changelogs/40100100.txt | 1 + .../metadata/android/ca/full_description.txt | 30 +++++++++++++++++++ .../metadata/android/ca/short_description.txt | 1 + fastlane/metadata/android/ca/title.txt | 1 + 4 files changed, 33 insertions(+) create mode 100644 fastlane/metadata/android/ca/changelogs/40100100.txt create mode 100644 fastlane/metadata/android/ca/full_description.txt create mode 100644 fastlane/metadata/android/ca/short_description.txt create mode 100644 fastlane/metadata/android/ca/title.txt diff --git a/fastlane/metadata/android/ca/changelogs/40100100.txt b/fastlane/metadata/android/ca/changelogs/40100100.txt new file mode 100644 index 0000000000..70b786d12e --- /dev/null +++ b/fastlane/metadata/android/ca/changelogs/40100100.txt @@ -0,0 +1 @@ +// TODO diff --git a/fastlane/metadata/android/ca/full_description.txt b/fastlane/metadata/android/ca/full_description.txt new file mode 100644 index 0000000000..b45a5488ea --- /dev/null +++ b/fastlane/metadata/android/ca/full_description.txt @@ -0,0 +1,30 @@ +Element és un nou tipus d'aplicació de missatgeria i col·laboració que: + +1. Et dóna a tu el control per preservar la teva privadesa +2. Et permet comunicar-te amb qualsevol persona de la xarxa Matrix i, fins i tot més enllà gràcies a integracions amb altres aplicacions com Slack +3. Et protegeix de la publicitat, l'obtenció no desitjada de dades i dels navegadors amb accés controlat +4. T'assegura a tu mitjançant l'encriptació d'extrem a extrem i amb signatures creuades per verificar els altres + +Element és completament diferent a les altres aplicacions de missatgeria i col·laboració ja que és descentralitzat i de codi obert. + +Element et deixa triar l'allotjament perquè disposis de privadesa, propietat i control de les teves dades i converses. Et dóna accés a una xarxa oberta perquè no et quedis únicament parlant amb els usuaris d'Element. + +Element pot fer tot això ja que opera sobre Matrix - l'estàndard per a les comunicacions obertes i descentralitzades. + +Element et dóna el control perquè et deixa escollir qui vols que allotgi les teves converses. Des de l'aplicació d'Element, pots triar l'allotjament de diferents maneres: + +1. Crea un compte gratuït al servidor públic de matrix.org allotjat pels desenvolupadors de Matrix o tria'n un entre els milers de servidors públics creats per voluntaris +2. Allotja tu mateix el teu compte en el teu propi servidor +3. Registra el compte en un servidor personalitzat subscrivint-te a la plataforma d'Element Matrix Services (EMS) + +Per què escollir Element? + +PROPIETAT DE LES TEVES DADES: Tu decideixes a on desar les teves dades i missatges. Tu les controles i n'ets el propietari, no una mega-corporació que s'aprofita de les teves dades o les cedeix a tercers. + +MISSATGERIA I COL·LABORACIÓ OBERTA: Pots parlar amb qualsevol que estigui a la xarxa Matrix, ja sigui amb Element o amb qualsevol altre aplicació Matrix, fins i tot encara que utilitzin sistemes de missatgeria diferents com Slack, IRC o XMPP. + +SUPER-SEGUR: Encriptació d'extrem a extrem real (només qui està conversant pot desxifrar els missatges), i amb signatures creuades per a verificar els dispositius dels participants en les converses. + +COMUNICACIÓ COMPLETA: Missatgeria, veu i video-trucades, compartició de fitxers, compartició de pantalla i un munt d'integracions, bots i ginys. Crea sales, comunitats, mantén-te en contacte i enllesteix el que et proposes. + +A TOT ARREU: Mantingues el contacte des de qualsevol lloc on siguis, amb un historial de missatges totalment sincronitzat entre tots els teus dispositius i també a la web: https://app.element.io. diff --git a/fastlane/metadata/android/ca/short_description.txt b/fastlane/metadata/android/ca/short_description.txt new file mode 100644 index 0000000000..1e842ec64e --- /dev/null +++ b/fastlane/metadata/android/ca/short_description.txt @@ -0,0 +1 @@ +Xat i VoIP segurs i descentralitzats. Protegeix les teves dades de tercers. diff --git a/fastlane/metadata/android/ca/title.txt b/fastlane/metadata/android/ca/title.txt new file mode 100644 index 0000000000..adc831006a --- /dev/null +++ b/fastlane/metadata/android/ca/title.txt @@ -0,0 +1 @@ +Element (anteriorment Riot.im) From ffd3b9a7a73c8a7c4c54b0d9cafa2518573b388c Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Thu, 5 Nov 2020 02:47:20 +0000 Subject: [PATCH 07/66] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (4 of 4 strings) Translation: Element Android/Element Android Store Translate-URL: https://translate.element.io/projects/element-android/element-store/zh_Hant/ --- .../android/zh_Hant/changelogs/40100100.txt | 1 + .../android/zh_Hant/full_description.txt | 30 +++++++++++++++++++ .../android/zh_Hant/short_description.txt | 1 + fastlane/metadata/android/zh_Hant/title.txt | 1 + 4 files changed, 33 insertions(+) create mode 100644 fastlane/metadata/android/zh_Hant/changelogs/40100100.txt create mode 100644 fastlane/metadata/android/zh_Hant/full_description.txt create mode 100644 fastlane/metadata/android/zh_Hant/short_description.txt create mode 100644 fastlane/metadata/android/zh_Hant/title.txt diff --git a/fastlane/metadata/android/zh_Hant/changelogs/40100100.txt b/fastlane/metadata/android/zh_Hant/changelogs/40100100.txt new file mode 100644 index 0000000000..3c21bcbeb6 --- /dev/null +++ b/fastlane/metadata/android/zh_Hant/changelogs/40100100.txt @@ -0,0 +1 @@ +// 待辦事項 diff --git a/fastlane/metadata/android/zh_Hant/full_description.txt b/fastlane/metadata/android/zh_Hant/full_description.txt new file mode 100644 index 0000000000..2fdf6fa478 --- /dev/null +++ b/fastlane/metadata/android/zh_Hant/full_description.txt @@ -0,0 +1,30 @@ +Element 是一種新型態的即時通訊軟體與協作應用程式: + +1. 自己的隱私自己掌控 +2. 讓您與任何在 Matrix 網路中的人通訊,甚至可與如 Slack 等的應用程式整合 +3. 保護您免受廣告、資料採礦與圍牆花園的侵害 +4. 透過端到端加密保護您,並使用交叉簽章來驗證其他人 + +Element 是去中心化且開放原始碼的應用程式,因此與其他即時通訊與協作軟體完全不同。 + +Element 讓您可以自架(或是自行選擇服務提供者)所以您擁有您資料與對話的隱私、所有權與控制權。它讓您可以存取開放的網路;因此,您不僅可以與其他 Matrix 使用者聊天。而且非常安全。 + +Element 能作到這些事情是因為它在 Matrix 上執行,這是一個開放的去中心化通訊的標準。 + +Element 讓您選擇您要在哪裡託管您的對話來將控制權還給您。在 Element 應用程式中,您可以選擇其他方式來託管: + +1. 在由 Matrix 開發者架設的 matrix.org 公開伺服器上取得免費的帳號,或是從數千個由志願者所架設的公開伺服器中選擇 +2. 在您自己的硬體上自行架設伺服器並建立帳號 +3. 訂閱 Element Matrix 服務託管平台並在自訂伺服氣上註冊帳號 + +為何選擇 Element? + +擁有您的資料:您決定您的資料與訊息要放在哪裡。您擁有並控制它,而非某些科技巨頭會挖掘您的資料並將其售予第三方。 + +開放的即時通訊與協作:您可以與 Matrix 網路中的任何人聊天,不管他們是使用 Element 或其他 Matrix 應用程式都可以,或甚至是其他的訊息系統,如 Slack、IRC 或 XMPP 也都可以。 + +超級安全:即時的端到端加密(僅有參與對話的人可以解密訊息),以及交叉簽章以驗證對話參與者的裝置。 + +完整通訊:即時通訊、語音與視訊通話、檔案分享、畫面分享與超多的整合、機器人與小工具。建立聊天室、保持聯繫並完成工作。 + +無論您身在何處:無論您身在何處,都可以透過 https://app.element.io 來在所有裝置與網路上保持訊息歷史同步。 diff --git a/fastlane/metadata/android/zh_Hant/short_description.txt b/fastlane/metadata/android/zh_Hant/short_description.txt new file mode 100644 index 0000000000..23bb82c04e --- /dev/null +++ b/fastlane/metadata/android/zh_Hant/short_description.txt @@ -0,0 +1 @@ +安全的去中心化聊天與 VoIP。確保您的資料不受第三方的影響。 diff --git a/fastlane/metadata/android/zh_Hant/title.txt b/fastlane/metadata/android/zh_Hant/title.txt new file mode 100644 index 0000000000..3be2260b73 --- /dev/null +++ b/fastlane/metadata/android/zh_Hant/title.txt @@ -0,0 +1 @@ +Element(曾名為 Riot.im) From f39b3365db4ca119cf2d5c5e9894538cf811fb86 Mon Sep 17 00:00:00 2001 From: Slavi Pantaleev Date: Sat, 7 Nov 2020 06:29:33 +0000 Subject: [PATCH 08/66] Translated using Weblate (Bulgarian) Currently translated at 100.0% (1933 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/bg/ --- vector/src/main/res/values-bg/strings.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vector/src/main/res/values-bg/strings.xml b/vector/src/main/res/values-bg/strings.xml index acd689387d..c62f245d88 100644 --- a/vector/src/main/res/values-bg/strings.xml +++ b/vector/src/main/res/values-bg/strings.xml @@ -2194,4 +2194,8 @@ Тема Тема на стаята (опция) Име на стая + Експортирай одит + Директно съобщение + Изпрати историята на заявките за споделяне на ключове + Няма повече резултати \ No newline at end of file From edc47b56a4ccd0fcca6870467fac3f53a0cf35a3 Mon Sep 17 00:00:00 2001 From: "Auri B. P" Date: Fri, 6 Nov 2020 20:30:52 +0000 Subject: [PATCH 09/66] Translated using Weblate (Catalan) Currently translated at 59.4% (1149 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/ca/ --- vector/src/main/res/values-ca/strings.xml | 109 ++++++++++++---------- 1 file changed, 58 insertions(+), 51 deletions(-) diff --git a/vector/src/main/res/values-ca/strings.xml b/vector/src/main/res/values-ca/strings.xml index 375133efc0..1fccac81d5 100644 --- a/vector/src/main/res/values-ca/strings.xml +++ b/vector/src/main/res/values-ca/strings.xml @@ -17,27 +17,27 @@ Missatges Sala Configuració - Detalls dels participants + Detalls del participant Historial - Informe d\'error + Informe d\'errors Detalls de la comunitat D\'acord Cancel·la Desa - Surt + Marxa Envia Reenvia - Suprimeix + Elimina Cita Comparteix Més tard Reenvia Enllaç permanent - Mostra el codi + Visualitza el codi font Visualitza el codi font desencriptat Elimina - Reanomena + Canvia el nom Informa del contingut Trucada activa Videoconferència en curs. @@ -46,17 +46,17 @@ Vídeo No es pot iniciar la trucada, prova-ho més tard Pot ser que algunes funcions no apareguin per falta de permisos… - Necessites permís per convidar a l\'inici d\'una videoconferència en aquesta sala + Necessites permisos d\'invitació per poder iniciar una conferència en aquesta sala No es pot iniciar la trucada Informació de la sessió - No s\'admeten videoconferències en sales xifrades + No s\'admeten conferències en sales xifrades Envia igualment o Convida Fora de línia Tanca la sessió - Trucada de veu + Trucada Videotrucada Cerca global Marca-ho tot com a llegit @@ -103,35 +103,35 @@ Convida Comunitats - No hi ha cap grup + No hi ha grups Envia els registres Envia els registres de fallada Envia una captura de pantalla Informa d\'un error - Descriviu l\'error. Què heu fet? Què esperàveu que passés? Què ha passat realment? - Descriviu el problema aquí - Els registres d\'aquest client s\'enviaran amb aquest informe d\'error per tal de diagnosticar problemes. Aquest informe d\'errors, així com també els registres i la captura de pantalla, no seran visibles de forma pública. Desmarqueu si preferiu enviar només el text: - Sembla que esteu prou frustrat per a estar sacsejant el telèfon. Voleu enviar un informe d\'error? - En l\'última execució l\'aplicació va fallar. Voleu enviar un informe d\'error? - L\'informe d\'error s\'ha enviat correctament - No s\'ha pogut enviar l\'informe d\'error (%s) + Descriu l\'error. Què has fet\? Què esperaves que passés\? Què ha passat realment\? + Descriu el problema aquí + Per tal de diagnosticar problemes, els registres d\'aquest client s\'enviaran juntament amb l\'informe d\'errors. Aquest informe d\'errors, així com també els registres i la captura de pantalla, no seran visibles públicament. Si prefereixes enviar només el text de dalt, desmarca: + Sembla que estàs sacsejant el telèfon amb frustració. Vols enviar un informe d\'errors\? + En l\'última execució l\'aplicació ha fallat. Vols obrir la pantalla d\'informe de fallada\? + L\'informe d\'errors s\'ha enviat correctament + No s\'ha pogut enviar l\'informe d\'errors (%s) En curs (%s%%) Envia a Llegit Uneix-te a la sala Nom d\'usuari Crear un compte - Entra - Desconnecta + Inicia sessió + Tanca la sessió URL del servidor URL del servidor d\'identitat Cerca - Inicia un xat nou - Inicia una trucada de veu - Inicia una vídeotrucada - Esteu segur que voleu començar una conversa amb %s? - Esteu segur que voleu començar una trucada de veu? - Esteu segur que voleu començar una trucada de vídeo? + Inicia un nou xat + Inicia una trucada + Inicia una videotrucada + Estàs segur que vols iniciar un nou xat amb %s\? + Estàs segur que vols iniciar una trucada\? + Estàs segur que vols iniciar una videotrucada\? Envia fitxers Fes una foto o un vídeo Fes una foto @@ -226,7 +226,7 @@ Trucant… Trucada d\'entrada Vídeotrucada d\'entrada - Trucada de veu d\'entrada + Trucada entrant Trucada en curs… No s\'està responent a la trucada. Ha fallat la connexió de mitjans @@ -300,7 +300,7 @@ No podràs desfer aquest canvi ja que estàs donant a l\'usuari el mateix nivell d\'autoritat que el teu. \nN\'estàs segur\? "Esteu segur que voleu convidar a %s a aquest xat?" - Esteu segur que voleu vetar aquest usuari en aquesta conversa? + Si vetes un usuari, se l\'expulsarà d\'aquesta sala i no podrà tornar a unir-s\'hi. Convida per ID CONTACTES LOCALS (%d) @@ -651,7 +651,7 @@ Atenció: es podria eliminar aquest fitxer si es desinstal·la l\'aplicació.Ignora la sol·licitut Avís! - Les trucades per a conferències estan en desenvolupament i poden no ser fiables. + Les conferències estan en desenvolupament i pot ser que no funcionin bé. Error de comandament Ordre no reconegut: %s @@ -691,7 +691,7 @@ Atenció: es podria eliminar aquest fitxer si es desinstal·la l\'aplicació.Només mencions Silencia Notificacions - Sacseja el dispositiu amb ràbia per a informar d\'un error + Sacseja el dispositiu amb ràbia per informar d\'un error Accions Llista de membres Sincronitzant… @@ -725,7 +725,7 @@ Atenció: es podria eliminar aquest fitxer si es desinstal·la l\'aplicació.%d missatges notificats no llegits - 1 canvi de membres + %d canvi de membres %d canvis de membres @@ -741,10 +741,10 @@ Atenció: es podria eliminar aquest fitxer si es desinstal·la l\'aplicació.Envia un adhesiu Envia un adhesiu Llicències de tercers - Descarrega + Baixa Parla - Neteja - Enviar veu + Esborra + Envia veu seguir amb… Ho sento, no s\'ha trobat cap aplicació externa per completar l\'acció. Tornar a demanar les claus d\'encriptació als teus altres dispositius. @@ -756,10 +756,10 @@ Atenció: es podria eliminar aquest fitxer si es desinstal·la l\'aplicació.No es pot dur a terme aquesta acció per falta de permisos. Error Alertes de sistema - Si és possible, escriviu si us plau la descripció en anglès. - Actualment no teniu cap conjunt d\'adhesius activat. - -En voleu afegir algun? + Si és possible, escriu la descripció en anglès. + Encara no tens cap paquet d\'adhesius activat. +\n +\nEn vols afegir algun\? %ds %ds @@ -862,7 +862,7 @@ En voleu afegir algun? Aquest servidor base ha assolit el seu límit màxim mensual d\'activitat d\'usuaris i alguns usuaris no podran identificar-s\'hi. Aquest servidor base ha assolit el seu límit mensual d\'activitat d\'usuaris. Si us plau %s per tal d\'incrementar aquest límit. - "Si us plau %s per continuar usant aquest servei." + Si us plau %s per continuar utilitzant aquest servei. Carrega en diferit els participants de la sala Millora el rendiment carregant només els participants de la sala a primera vista. El teu servidor encara no és compatible amb la càrrega en diferit dels participants d\'una sala. Prova-ho més tard. @@ -871,9 +871,9 @@ En voleu afegir algun? plega Accepta Trucada - Useu el to de Element per defecte per les trucades entrants + Utilitza el to de trucada d\'Element predeterminat per trucades entrants To de trucada entrant - Escolliu el to per les trucades: + Tria el to per les trucades: Expulsa Motiu Mostra la vista prèvia dels enllaços dins del xat en cas que el vostre servidor base suporti aquesta funcionalitat. @@ -885,10 +885,10 @@ En voleu afegir algun? Mostra els esdeveniments del compte Truca igualment Reviseu i accepteu les polítiques d\'aquest servidor base: - Trucada de vídeo en procés… + Videotrucada en procés… Executa les proves S\'està executant… (%1$d de %2$d) - El diagnòstic bàsic és correcte. Si encara no rebeu notificacions, envieu un informe d\'error per ajudar-nos a investigar. + El diagnòstic bàsic és correcte. Si encara no reps notificacions, envia un informe d\'errors per ajudar-nos a investigar-ho. Ha fallat una o més proves, proveu les solucions proposades. Paràmetres del sistema. Les notificacions són habilitades als paràmetres del sistema. @@ -941,7 +941,7 @@ A la pantalla següent se us demanarà que permeteu al Element executar-se sempr Importància de les notificacions per esdeveniment Diagnostica les notificacions Diagnòstic de la resolució de problemes - Ha fallat una o més proves, envieu un informe d\'error per ajudar-nos a investigar-ho. + Ha fallat una o més proves, envia un informe d\'errors per ajudar-nos a investigar-ho. Les notificacions no són permeses per a aquest dispositiu. Comproveu els paràmetres del Element. Paràmetres personalitzats. @@ -974,7 +974,7 @@ Aquest error és fora del control del Element i segons Google aquest error indic Comprova les restriccions del rerefons Ignora l\'optimització Configura les notificacions amb so - Configura les notificacions de les trucades + Configura les notificacions de trucada Configura les notificacions silencioses Seleccioneu el color de LED, la vibració, so… Gestió de claus criptogràfiques @@ -1018,8 +1018,8 @@ Avís: és possible que calgui suprimir el fitxer si es desinstal·la l\'aplicac Introduïu la clau de recuperació Recuperació de missatges Heu perdut la vostra clau de recuperació? Podeu establir una nova a les preferències. - "[%1$s] -Aquest error és fora del control del Element. Pot ocórrer per diferents raons. És possible que funcioni si ho torneu a provar més endavant. També podeu comprovar que el servei de Google Play no està restringit a l\'ús de dades a les preferències del sistema, o que el rellotge del dispositiu marca l\'hora correcta. També pot passar amb ROM personalitzades." + [%1$s] +\nAquest error està fora del control d\'Element. Pot ser causat diferents motius. És possible que torni a funcionar més endavant. També pots comprovar, a la configuració del sistema, que els Serveis de Google Play no tinguin cap restricció de dades o que l\'hora del dispositiu sigui la correcta. També pot passar amb ROMs personalitzades. [%1$s] Aquest error és fora del control del Element. No hi ha cap compte de Google al telèfon. Obrir el gestor de comptes i afegiu un compte de Google. Les restriccions de rerefons són inhabilitades per al Element. Aquesta prova s\'hauria d\'executar emprant dades mòbils (sense wifi). @@ -1066,7 +1066,7 @@ Les tasques que l\'aplicació intenta fer estaran restringides agressivament men La còpia de seguretat de les claus no ha finalitzat, espera… Si tanques sessió ara, perdràs els teus missatges xifrats S\'està fent la còpia de seguretat de les claus. Si tanques sessió ara, perdràs els teus missatges xifrats. - No vull els meus missatges encriptats + No vull els meus missatges xifrats Fent còpia de seguretat de les claus… Utilitza la còpia de seguretat de les claus N\'estàs segur\? @@ -1104,8 +1104,8 @@ Les tasques que l\'aplicació intenta fer estaran restringides agressivament men Signatura He sigut jo Còpia de seguretat nova de la clau - Per evitar la pèrdua d\'accés als teus missatges encriptats, hauries d\'activar la còpia de seguretat segura a totes les teves sessions. - Perdràs l\'accés als teus missatges encriptats si no fas una còpia de seguretat de les teves claus abans de tancar la sessió. + Per evitar la pèrdua d\'accés als teus missatges xifrats, hauries d\'activar la còpia de seguretat segura a totes les teves sessions. + Perdràs l\'accés als teus missatges xifrats si no fas una còpia de seguretat de les teves claus abans de tancar la sessió. Es desarà una còpia encriptada de les vostres claus al vostre servidor base. Protegiu la vostra còpia de seguretat amb una contrasenya per tal de mantenir-la segura. \n \nPer màxima seguretat, aquesta contrasenya hauria de ser diferent de la contrasenya del vostre compte. @@ -1333,10 +1333,10 @@ Les tasques que l\'aplicació intenta fer estaran restringides agressivament men Les reunions utilitzen les polítiques de seguretat i permisos de Jitsi. Tots els participants que es trobin dins sala veuran una invitació per unir-se mentre la teva reunió estigui en curs. Inicia una reunió d\'àudio Inicia una reunió de vídeo - Ja hi ha una videoconferència en curs! + Ja hi ha una conferència en curs! No tens permís per iniciar una trucada No tens permís per iniciar una trucada en aquesta sala - No tens permís per iniciar una videoconferència + No tens permís per iniciar una conferència No tens permís per iniciar una videoconferència en aquesta sala Reinicia Omet @@ -1345,4 +1345,11 @@ Les tasques que l\'aplicació intenta fer estaran restringides agressivament men Revoca Cap Latn + Trucada activa (%s) + Demana confirmació abans d\'iniciar una trucada + Evita trucada accidental + La descripció és massa curta + Envia l\'historial de sol·licituds de compartició de claus + Revisa + Reprodueix \ No newline at end of file From ad64651532657b1b46d2cc499397e6fe325819bb Mon Sep 17 00:00:00 2001 From: random Date: Sat, 7 Nov 2020 10:45:01 +0000 Subject: [PATCH 10/66] Translated using Weblate (Italian) Currently translated at 100.0% (1933 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/it/ --- vector/src/main/res/values-it/strings.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vector/src/main/res/values-it/strings.xml b/vector/src/main/res/values-it/strings.xml index ae1fed2d19..d7eb7a29d4 100644 --- a/vector/src/main/res/values-it/strings.xml +++ b/vector/src/main/res/values-it/strings.xml @@ -2250,4 +2250,8 @@ Argomento Argomento stanza (facoltativo) Nome stanza + Esporta revisione + Messaggio diretto + Invia cronologia di richieste condivisione chiave + Nessun altro risultato \ No newline at end of file From 4dd83c29fe8c538fd2ceeed9ce66fd2513cfa0a6 Mon Sep 17 00:00:00 2001 From: Thomas sivertsen Date: Wed, 11 Nov 2020 18:03:06 +0000 Subject: [PATCH 11/66] =?UTF-8?q?Added=20translation=20using=20Weblate=20(?= =?UTF-8?q?Norwegian=20Bokm=C3=A5l)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastlane/metadata/android/it/changelogs/40100100.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 fastlane/metadata/android/it/changelogs/40100100.txt diff --git a/fastlane/metadata/android/it/changelogs/40100100.txt b/fastlane/metadata/android/it/changelogs/40100100.txt new file mode 100644 index 0000000000..0c7cc8cc6c --- /dev/null +++ b/fastlane/metadata/android/it/changelogs/40100100.txt @@ -0,0 +1 @@ +// DA FARE From 8e9e4215ce31e34dd09a3489f64d0c3ee896d356 Mon Sep 17 00:00:00 2001 From: Thomas sivertsen Date: Wed, 11 Nov 2020 18:04:15 +0000 Subject: [PATCH 12/66] =?UTF-8?q?Translated=20using=20Weblate=20(Norwegian?= =?UTF-8?q?=20Bokm=C3=A5l)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 50.0% (2 of 4 strings) Translation: Element Android/Element Android Store Translate-URL: https://translate.element.io/projects/element-android/element-store/nb/ --- fastlane/metadata/android/nb/short_description.txt | 1 + fastlane/metadata/android/nb/title.txt | 1 + 2 files changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/nb/short_description.txt create mode 100644 fastlane/metadata/android/nb/title.txt diff --git a/fastlane/metadata/android/nb/short_description.txt b/fastlane/metadata/android/nb/short_description.txt new file mode 100644 index 0000000000..b7cad4c849 --- /dev/null +++ b/fastlane/metadata/android/nb/short_description.txt @@ -0,0 +1 @@ +Sikker desentralisert chat & VoIP. Beskytt dataene dine fra tredjeparter. diff --git a/fastlane/metadata/android/nb/title.txt b/fastlane/metadata/android/nb/title.txt new file mode 100644 index 0000000000..aacee5be54 --- /dev/null +++ b/fastlane/metadata/android/nb/title.txt @@ -0,0 +1 @@ +Element (tidligere Riot.im) From fe40e74809a01c182995ed535ff5d2f203934fa8 Mon Sep 17 00:00:00 2001 From: "Auri B. P" Date: Tue, 10 Nov 2020 22:49:07 +0000 Subject: [PATCH 13/66] Translated using Weblate (Catalan) Currently translated at 60.1% (1162 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/ca/ --- vector/src/main/res/values-ca/strings.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/vector/src/main/res/values-ca/strings.xml b/vector/src/main/res/values-ca/strings.xml index 1fccac81d5..91f4fad19c 100644 --- a/vector/src/main/res/values-ca/strings.xml +++ b/vector/src/main/res/values-ca/strings.xml @@ -1352,4 +1352,17 @@ Les tasques que l\'aplicació intenta fer estaran restringides agressivament men Envia l\'historial de sol·licituds de compartició de claus Revisa Reprodueix + Activa l\'HD + Desactiva l\'HD + Posterior + Frontal + Commuta la càmera + Auriculars sense fils + Auriculars + Altaveu + Mòbil + Selecciona el dispositiu d\'àudio + No m\'ho tornis a preguntar + Prova fent servir %s + La crida ha fallat per culpa d\'una mala configuració del servidor \ No newline at end of file From 7ca57d918ed21082e47ea6c01f105e15de92b8d6 Mon Sep 17 00:00:00 2001 From: Hivaa Date: Wed, 11 Nov 2020 15:28:09 +0000 Subject: [PATCH 14/66] Translated using Weblate (Persian) Currently translated at 98.2% (1899 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/fa/ --- vector/src/main/res/values-fa/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/res/values-fa/strings.xml b/vector/src/main/res/values-fa/strings.xml index e22d517789..8188cbf2c6 100644 --- a/vector/src/main/res/values-fa/strings.xml +++ b/vector/src/main/res/values-fa/strings.xml @@ -1100,7 +1100,7 @@ موفق! بازگشت به ورود هشدار - تنظیم نشانی رایانامه + ایمیل خود را وارد کنید رایانامه رایانامه (اختیاری) بعدی From 1a191c7d51ef661dd6ee239e91b16f3058f174b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20FERREIRA=20DE=20SOUSA?= Date: Mon, 9 Nov 2020 21:17:30 +0000 Subject: [PATCH 15/66] Translated using Weblate (French) Currently translated at 99.9% (1932 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/fr/ --- vector/src/main/res/values-fr/strings.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vector/src/main/res/values-fr/strings.xml b/vector/src/main/res/values-fr/strings.xml index 50793add88..e0ef74d067 100644 --- a/vector/src/main/res/values-fr/strings.xml +++ b/vector/src/main/res/values-fr/strings.xml @@ -2195,4 +2195,7 @@ Sujet Sujet du salon (facultatif) Nom du salon + Message direct + Inclure l\'historique d\'échange de clés + Plus aucun résultat \ No newline at end of file From 9df002fe4ec0e2d0f30eda6533207783c650dece Mon Sep 17 00:00:00 2001 From: Valere Date: Mon, 9 Nov 2020 20:36:56 +0000 Subject: [PATCH 16/66] Translated using Weblate (French) Currently translated at 99.9% (1932 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/fr/ --- vector/src/main/res/values-fr/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/res/values-fr/strings.xml b/vector/src/main/res/values-fr/strings.xml index e0ef74d067..573ec93f87 100644 --- a/vector/src/main/res/values-fr/strings.xml +++ b/vector/src/main/res/values-fr/strings.xml @@ -25,7 +25,7 @@ Appel en cours Téléconférence en cours. \nLa rejoindre en %1$s ou en %2$s - vocal + Audio vidéo Impossible d’initier l’appel, réessayez plus tard En raison de permissions manquantes, certaines fonctionnalités peuvent être absentes… From cf2ea0f51cdc2009b73cdea0aca7801a82c58d1e Mon Sep 17 00:00:00 2001 From: OLIVIER Thomas Date: Mon, 9 Nov 2020 20:34:49 +0000 Subject: [PATCH 17/66] Translated using Weblate (French) Currently translated at 99.9% (1932 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/fr/ --- vector/src/main/res/values-fr/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/res/values-fr/strings.xml b/vector/src/main/res/values-fr/strings.xml index 573ec93f87..e4ec77068c 100644 --- a/vector/src/main/res/values-fr/strings.xml +++ b/vector/src/main/res/values-fr/strings.xml @@ -2037,7 +2037,7 @@ Affichage de la notification Vous voyez la notification ! Cliquez-moi dessus ! La notification a été cliquée ! - Échec de l\'appel Element + Appel échoué Les messages de ce salon sont chiffrés de bout en bout. Vous avez créé et configuré ce salon. Confirmer le code pour le désactiver From ba5c42cc51ae9e9630dcb0a23bda9835574e72a4 Mon Sep 17 00:00:00 2001 From: notramo Date: Thu, 12 Nov 2020 18:49:34 +0000 Subject: [PATCH 18/66] Translated using Weblate (Hungarian) Currently translated at 94.9% (1835 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/hu/ --- vector/src/main/res/values-hu/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/res/values-hu/strings.xml b/vector/src/main/res/values-hu/strings.xml index d9e29c37bf..2b1247d7e3 100644 --- a/vector/src/main/res/values-hu/strings.xml +++ b/vector/src/main/res/values-hu/strings.xml @@ -424,7 +424,7 @@ Vedd figyelembe, hogy az alkalmazás újraindul ami sok időt vehet igénybe."< Alacsony prioritású Semmi Hozzáférés és láthatóság - Listázza ezt a szobát a szobák könyvtárba + Listázza ezt a szobát a szoba listában Szoba hozzáfárés Szoba előzmény olvashatósága Ki tud előzményt olvasni? From bf2a7c2efdea2afa71da13e1e6c74f1e83634b36 Mon Sep 17 00:00:00 2001 From: Kaede Date: Wed, 11 Nov 2020 13:36:48 +0000 Subject: [PATCH 19/66] Translated using Weblate (Japanese) Currently translated at 48.6% (941 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/ja/ --- vector/src/main/res/values-ja/strings.xml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/vector/src/main/res/values-ja/strings.xml b/vector/src/main/res/values-ja/strings.xml index 6a48529dbe..e0bfdb930d 100644 --- a/vector/src/main/res/values-ja/strings.xml +++ b/vector/src/main/res/values-ja/strings.xml @@ -806,7 +806,7 @@ Matrixでのメッセージの可視性は電子メールと同様です。メ 畳む メッセージとエラーの場合 とにかく通話する - 受け取る + 了承 このホームサーバーの方針を閲覧し承認してください: 通話設定画面 着信にElementの既定の着信音を使う @@ -1045,4 +1045,19 @@ Matrixでのメッセージの可視性は電子メールと同様です。メ 他の利用可能な言語 メッセージエディタ 環境設定 + このデバイスを設定 + セキュアバックアップをリセット + セキュアバックアップを設定 + 管理 + セキュアバックアップ + 部屋を作成中… + 招待されています + %s からの招待 + このセッションは正常に検証されました。 + 概ね完了しました。%s の画面にも同じシールドアイコンが表示されていますか? + 相手のユーザーのデバイスのコードをスキャンし、相互に安全性を検証します。 + 相手のコードをスキャン + スキャンできません + 断る + 検証リクエスト \ No newline at end of file From 44604c25098f04645043546c4c6321c24ddfde65 Mon Sep 17 00:00:00 2001 From: Deleted User Date: Wed, 11 Nov 2020 18:12:12 +0000 Subject: [PATCH 20/66] =?UTF-8?q?Translated=20using=20Weblate=20(Norwegian?= =?UTF-8?q?=20Bokm=C3=A5l)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 42.2% (816 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/nb_NO/ --- vector/src/main/res/values-nb-rNO/strings.xml | 184 ++---------------- 1 file changed, 21 insertions(+), 163 deletions(-) diff --git a/vector/src/main/res/values-nb-rNO/strings.xml b/vector/src/main/res/values-nb-rNO/strings.xml index 48f9e87737..42731a17c6 100644 --- a/vector/src/main/res/values-nb-rNO/strings.xml +++ b/vector/src/main/res/values-nb-rNO/strings.xml @@ -1,9 +1,8 @@ - + nb NO Latn - Lyst tema Mørkt tema Svart tema @@ -18,7 +17,6 @@ Send et klistremerke Er du sikker\? Laster… - OK Lukk Lagre @@ -51,7 +49,6 @@ Ignorer Gjennomgang Avslå - Avslutt Handlinger Logg ut @@ -59,15 +56,12 @@ Lukk Kopiert til utklippstavle Slå av - Advarsel Feil - Hjem Folk Rom Samfunn - Invitasjoner Lavprioritet Ingen treff @@ -76,12 +70,9 @@ Inviter Samfunn Ingen grupper - Meld fra om en bug Fremgang (%s%%) - Les - Bli med i rommet Brukernavn Opprett konto @@ -89,10 +80,8 @@ Logg ut Identitetstjener-URL Søk - Ta et bilde Spill inn en video - Logg inn Opprett konto Send @@ -106,26 +95,21 @@ Glemt passord\? Jeg har verifisert E-postadressen min Vennligst skriv inn en gyldig URL - Original Store Medium Små - I går I dag - Informasjon Lagret JA NEI Fortsett - Fjern Bli med Forhåndsvisning Avvis - Synkroniserer … 1sek @@ -143,9 +127,7 @@ 1d %dd - Lag - Tilkoblet Frakoblet Rolig @@ -154,7 +136,6 @@ Opphev utestengelse Spark ut %1$s %2$s - Søk Filen ble ikke funnet Stol på @@ -164,10 +145,8 @@ Filer Instillinger BLE MED - Avbryt opplastning Avbryt nedlasting - Ingen treff ROM ROM @@ -184,14 +163,10 @@ E-post Telefon Åpne Innstillinger - Slå på - Slå på - Vanlig Varslingslyd - Versjon Opphavsrettighet Retningslinjer for personvern @@ -206,14 +181,12 @@ Analyser Send analytiske data Ja, jeg vil hjelpe til! - ID Offentlig navn Sist sett Autentisering Passord: Send - Logget inn som Identitetstjener Brukergrensesnitt @@ -224,7 +197,6 @@ Nytt passord Bekreft nytt passord Passordene er ikke like - Land Telefonnummer Kode @@ -236,20 +208,16 @@ 1 uke 1 måned For alltid - Emne Lavprioritet Ingen - Varsler Alle Bannlyste brukere - Avansert Adresser Mappe Tema - Hendelsesinformasjon Bruker-ID Algoritme @@ -261,14 +229,11 @@ Eksporter Importer Svartelistet - ingen - Bekreft Svarteliste Hjemmetjener-URL Skriv her … - Rom Meg Skriftstørrelse @@ -278,40 +243,31 @@ Større Det største Enorm - Åpne i nettleser Din bruker-ID Ditt tema Modul-ID Rom-ID - - Tillat Bekreft Del Ignorer - Av Lag Eksempel eksempel - Hjem Folk Ble med Invitert Bli med igjen Glem rommet - Profilbilde - Deaktiver kontoen Deaktiver kontoen - Vennligst skriv inn et brukernavn. utvid skjul - Alltid %1$s: %1$s: %2$s @@ -321,7 +277,6 @@ Lagre som fil Erstatt Stopp - Uventet feil Er du sikker\? Aldri mist krypterte beskjeder @@ -329,23 +284,17 @@ Versjon Algoritme Signatur - Verifisert! Jeg forstår - Verifiseringsforespørsel Ukjent feil - Rediger Svar - Prøv igjen Invitert av %s - Reaksjoner Liker Reaksjoner - Endre Vennligst vent … Nytt rom @@ -355,20 +304,14 @@ Sikkerhet og personvern Ekspert Format: - Stemme og video Hjelp/Om - - Vis skjulte hendelser i tidslinjen - Venter … (redigert) - Vilkår for bruk Bytt ut identitetstjener Venter - Opprett et nytt rom Vis passord Skjul passord @@ -385,54 +328,41 @@ Registrer deg Logg inn Fortsett med SSO - Neste E-post Nytt passord - Fortsett - Jeg har verifisert E-postadressen min - Suksess! Passordet ditt har blitt tilbakestilt. Advarsel E-post E-post (valgfritt) Neste - Telefonnummer Neste - Skriv inn kode Neste - Brukernavn Passord Neste Advarsel Vennligst sjekk eposten din Sett av - Logg på Logg på Passord Instillinger Gjeldende økt Føyer til ¯\\_(ツ)_/¯ på en råtekstmelding - Video. Bilde. Lyd Fil - Du avbrøt Du aksepterte Verifiseringsforespørsel - - Du - Verifiser %s Verifiserte %s Sikkerhet @@ -444,24 +374,18 @@ Tilpasset Invitasjoner Brukere - Opphev ignorering - Tidslinje - Vil du skru på kryptering\? Bekreft Advarsel - Sesjoner Ja Advarsel: Bekreft fjerning Status.im-tema - Lytter etter hendelser Verifiser økten - Aktiv samtale Send loggbøker Send tilbakestillings-E-post @@ -474,7 +398,6 @@ %d medlemmer 1 medlem - %1$s nå %s skriver … Søk @@ -490,15 +413,12 @@ Element samler inn anonyme statistikker for å hjelpe oss med å forbedre programmet. %1$s @ %2$s Integreringsbehandler - Rommets navn Hvem kan lese historikken\? Hvem kan gå inn i dette rommet\? - Kun medlemmer (f.o.m. da denne innstillingen ble valgt) Kun medlemmer (f.o.m. da de ble invitert) Kun medlemmer (f.o.m. de ble med) - Kun folk som har blitt invitert Dette rommet viser ikke merkeskilter for noen samfunn Kopier rommets ID @@ -513,7 +433,6 @@ 1 rom %d rom - %1$s: 1 melding %1$s: %2$d meldinger @@ -522,7 +441,6 @@ %d varsel %d varsler - Ny hendelse Nye meldinger Ny invitasjon @@ -531,8 +449,6 @@ 1 aktiv modul %d aktive moduler - - Modul Last inn modul Ditt visningsnavn @@ -545,21 +461,17 @@ Velg rommets tema Stille Bråkete - Kryptert melding - Opprett et samfunn Samfunnsnavn Samfunns-ID Rom Ingen brukere - Rom 1 medlem %d medlemmer - 1 rom %d rom @@ -571,57 +483,45 @@ Begynn å bruke Nøkkelsikkerhetskopiering Det var meg Begynn å bruke Nøkkelsikkerhetskopiering - Sendte deg en invitasjon Rom Opprett et nytt rom Rom Direktemeldinger - Rommets navn URL: Direktemeldinger - Meldingsredigeringer Filtrer samtaler … Opprett et nytt rom Blir med i rommet … - Identitetstjener Skriv inn en ny identitetstjener Send vedlegg - Klistremerke Det er søppelpost Alle meldinger Kun nevninger Forlat rommet Uleste meldinger - Kom i gang - Velg en tjener Tilbakestill passordet på %1$s Advarsel! Velg en E-postadresse Velg et telefonnummer Godkjenn vilkårene for å fortsette - Avanserte innstillinger Utviklermodus Dersom dette først har blitt skrudd på, kan kryptering aldri bli skrudd av. - De samsvarer Ikke sikker Venter … Verifiser denne økten QR-kodebilde - Forlat rommet Forlater rommet … - Dersom dette først har blitt skrudd på, kan kryptering aldri bli skrudd av. - Aktive økter Vis alle økter Behandle økter @@ -629,18 +529,13 @@ Verifisert Betrodd Ikke betrodd - QR-kode - Nei - Utviklerverktøy Ny innlogging - Fjern … Bråkete notifikasjoner Stille notifikasjoner - Samfunnsdetaljer Sikkerhetskopiering av nøkler Bruk sikkerhetskopiering av nøkler @@ -653,9 +548,7 @@ Bruk sikkerhetskopiering av nøkler Sikkerhetskopi Du kommer til å miste tilgang til dine enkrypterte meldinger med mindre du sikkerhetskopierer nøklene dine før du logger av. - Tredjepartslinsenser - Bli Snakk Se dekryptert kilde @@ -686,9 +579,7 @@ Filtrer folk Filtrer romnavn Filtrer samfunnsnavn - Systemadvarsler - Samtaler Lokal adressebok Brukerkatalog @@ -696,14 +587,12 @@ Ingen samtaler Du ga ikke Element tilgang til dine lokale kontakter Ingen identitetsserver konfigurert. - Romkatalog Ingen offentlige rom tilgjengelig 1 bruker %d brukere - Send kjæsjlogg Send skjermbilde Vennligst forklar feilen. Hva gjorde du\? Hva forventet du at skulle skje\? Hva skjedde i stedet\? @@ -713,7 +602,6 @@ Det ser ut som du rister på telefonen i frustrasjon. Har du list til å åpne feilrapporteringsskjermen\? Applikasjonen kræsjet sist gang. Har du lyst til å åpne kræsjskjermen\? Sinnarist for å rapportere feil - Feilrapport har blitt sendt feilrapporten feilet å sendes (%s) Send inn i @@ -721,17 +609,13 @@ Start ny chat Start lydsamtale Start videosamtale - Send lydopptak - Er du sikker på du vil starte en samtale med %s\? Er du sikker på du vil starte en lydsamtale\? Er du sikker på du vil starte en videosamtale\? Spill av Pause Avslå - - Du har ikke rettigheter til å starte en konferansesamtale i dette rommet Det pågår allerede en konferanse! Start videomøte @@ -743,12 +627,10 @@ Kunne ikke fjerne utvidelse Kopier Suksess - Varsler Oppringing feilet som følge av feilkonfigurert tjener Prøv med %s Ikke spør meg igjen - Element samtale feilet Velg lydenhet Telefon @@ -760,17 +642,14 @@ Bak Slå HD av Slå HD på - Send filer Send klistremerke Ta bilde eller video Du har ingen pakker med klistremerker slått på. \n \nLegge til noen nå\? - fortsett med… Dessverre, kunne ikke finne en passende ekstern applikasjon for å utføre denne handlingen. - Logg på med single sign-on E-post eller brukernavn Brukernavn @@ -797,7 +676,6 @@ Forlat rommet %1$s for %2$s siden - Direktemeldinger Forlat dette rommet Fjern fra dette rommet @@ -805,9 +683,7 @@ Utnevn til admin Ignorer bruker Ignorer - Opphev ignorering - Bannlys bruker "%1$s, " %1$s og %2$s @@ -818,7 +694,6 @@ 1 ny melding %d nye meldinger - Romdetaljer 1 valgt @@ -827,13 +702,11 @@ INVITERT MELDINGER FILER - Opprett et rom Bli med i rommet Bli med i et rom Betingelser og vilkår Personvernregler - Legg til E-postadresse Legg til telefonnummer Avanserte varselsinnstillinger @@ -841,7 +714,6 @@ Kontoinnstillinger. Start ved systemoppstart Skru av restriksjoner - Batterioptimalisering Redusert privatliv Skru på varsler for denne kontoen @@ -850,7 +722,6 @@ Start ved systemoppstart Betingelser og vilkår Tøm mediemellomlager - Brukerinnstillinger Ignorerte brukere Integreringer @@ -863,23 +734,19 @@ Behandle dine oppdagelsesinnstillinger. Gi tillatelse Velg et annet alternativ - Gi tillatelse - Datasparingsmodus Øktinformasjon Hjemmetjener Tillat integreringer Integreringer er skrudd av Velg språk - Verifisering avventer Denne E-postadressen ble ikke funnet. Oppdater passord Telefonverifisering Standardkomprimering Merket som: - Tilgang og synlighet Romtilgang Punkt-til-punkt-kryptering @@ -891,10 +758,7 @@ %1$s i %2$s %1$s: %2$s %1$s: %2$s %3$s - Aktive moduler - - Last inn modulen på nytt Bruk kameraet Bruk mikrofonen @@ -903,25 +767,20 @@ Vennligst skriv inn passordet ditt. Samtalen fortsetter her Kontakt administrator - Beklager, det oppstod en feil - Opprett en passordfrase Bekreft passordfrasen Skriv inn passordfrase Passordfrasen samsvarer ikke Vennligst skriv inn en passordfrase Passordfrasen er for svak - (Avansert) Velg passordfrase Suksess! Gjenopprettingsnøkkel Skriv inn gjenopprettingsnøkkelen - Gjenopprett fra sikkerhetskopi Slett sikkerhetskopien - Slett sikkerhetskopien Begynn verifisering Du bruker ikke noen identitetstjenere @@ -931,35 +790,24 @@ Vis fjernede meldinger Vis en stattholder for fjernede meldinger Alle samfunn - Rom-arkiv Matrix SDK-versjon Hurtigreaksjoner - Send inn et forslag Krypterer filen … Navn eller ID (#example:matrix.org) - Filtrer etter brukernavn eller ID … - Vis redigeringshistorikk - MEDIA FILER %1$s, kl. %2$s Det er upassende IGNORER BRUKER - Ignorer bruker - Spoiler Du ignorerer ikke noen brukere - Langklikk på et rom for å se flere innstillinger - - Tilpassede og avanserte innstillinger - Koble til %1$s Adresse Sjekk innboksen din @@ -972,19 +820,14 @@ Du er logget av Du er logget av Tøm alle data - Se alle mine økter Skru på kryptering De samsvarer ikke Klistremerke - Skru på kryptering - Oppdater - Din gjenopprettingsnøkkel Avslutt - Kryptering er skrudd på Kryptering er ikke skrudd på Medlinger som inneholder @room @@ -993,9 +836,7 @@ Når rom blir oppgradert Feilsøk %1$s (%2$s) - Velg et nytt kontopassord … - Ukryptert Legg til medlemmer Inviterer brukere … @@ -1009,14 +850,12 @@ Opphev demping av mikrofonen Stopp kameraet Start kameraet - Sett opp Rommets navn Emne Kan ikke dekryptere SKJØNNER LÆR MER - Telefonkatalogen din er tom Telefonkatalog Søk i mine kontakter @@ -1025,4 +864,23 @@ Skriv inn PIN-koden din Glemt PIN-koden\? Skru på PIN-kode - + Sjekk e-postadressen din for å fortsette registreringen + Dette telefonnummeret er allerede definert. + Denne e-postadressen er allerede definert. + Passordet er for kort (min 6) + Brukernavn kan bare inneholde bokstaver, tall, prikker, bindestrek og understreker + Feil brukernavn og/eller passord + Angi en e-post for kontogjenoppretting. Bruk senere e-post eller telefon for å være mulig å oppdage av folk som kjenner deg. + Angi en e-post for kontogjenoppretting. Bruk senere e-post eller telefon for å være mulig å oppdage av folk som kjenner deg. + Sett en telefon, og senere for å bli valgbar for personer som kjenner deg. + Angi en e-post for gjenoppretting av kontoen, og senere for å være mulig å oppdage for folk som kjenner deg. + Send historikk om forespørsel om nøkkelandel + Ingen flere resultater + Legg på + Avslå + Godta + Du har ikke tillatelse til å starte en samtale + Du har ikke tillatelse til å starte en samtale i dette rommet + Du har ikke tillatelse til å starte en konferansesamtale + Tilbakestill + \ No newline at end of file From 5b2f95d270199d2d10875370849f6087d37f5c5c Mon Sep 17 00:00:00 2001 From: Marcelo Filho Date: Tue, 10 Nov 2020 20:23:47 +0000 Subject: [PATCH 21/66] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (1933 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/pt_BR/ --- vector/src/main/res/values-pt-rBR/strings.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vector/src/main/res/values-pt-rBR/strings.xml b/vector/src/main/res/values-pt-rBR/strings.xml index 674ce19759..c040882e80 100644 --- a/vector/src/main/res/values-pt-rBR/strings.xml +++ b/vector/src/main/res/values-pt-rBR/strings.xml @@ -2250,4 +2250,8 @@ Descrição Descrição da sala (opcional) Nome da sala + Enviar histórico de solicitações do compartilhamento de chaves + Não há mais resultados + Exportar auditoria + Enviar mensagem \ No newline at end of file From 38a98a51cbf53c7f4ce473e97983a0f644b9b189 Mon Sep 17 00:00:00 2001 From: "Auri B. P" Date: Thu, 12 Nov 2020 20:24:55 +0000 Subject: [PATCH 22/66] Translated using Weblate (Catalan) Currently translated at 60.5% (1170 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/ca/ --- vector/src/main/res/values-ca/strings.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/vector/src/main/res/values-ca/strings.xml b/vector/src/main/res/values-ca/strings.xml index 91f4fad19c..7e88fb1a45 100644 --- a/vector/src/main/res/values-ca/strings.xml +++ b/vector/src/main/res/values-ca/strings.xml @@ -1365,4 +1365,12 @@ Les tasques que l\'aplicació intenta fer estaran restringides agressivament men No m\'ho tornis a preguntar Prova fent servir %s La crida ha fallat per culpa d\'una mala configuració del servidor + Correu electrònic + Confirma la teva contrasenya + Motiu del veto + Veta usuari + Cancel·la invitació + Cancel·la invitació + Torna a la trucada + Error SSL. \ No newline at end of file From b9375a1b4e74ef65fe2d4cc0b4fc6c6e119e020d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20B=C3=BCchner?= Date: Fri, 13 Nov 2020 12:49:18 +0000 Subject: [PATCH 23/66] Translated using Weblate (German) Currently translated at 100.0% (1933 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/de/ --- vector/src/main/res/values-de/strings.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vector/src/main/res/values-de/strings.xml b/vector/src/main/res/values-de/strings.xml index 702e380e17..75ee23cb12 100644 --- a/vector/src/main/res/values-de/strings.xml +++ b/vector/src/main/res/values-de/strings.xml @@ -2244,4 +2244,8 @@ Raumeinstellungen Raum-Thema (optional) Raumname + Prüfung exportieren + Direktnachricht + Geschichte der Anfragen von Schlüsselfreigaben senden + Keine weiteren Ergebnisse \ No newline at end of file From 13f716a3955c7eab85a1ab26f292f0e425156c5e Mon Sep 17 00:00:00 2001 From: Victor Cuadrado Juan Date: Fri, 13 Nov 2020 13:33:45 +0000 Subject: [PATCH 24/66] Translated using Weblate (Spanish) Currently translated at 97.3% (1881 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/es/ --- vector/src/main/res/values-es/strings.xml | 622 +++------------------- 1 file changed, 79 insertions(+), 543 deletions(-) diff --git a/vector/src/main/res/values-es/strings.xml b/vector/src/main/res/values-es/strings.xml index c5ca0d5f1a..59237e8c5a 100644 --- a/vector/src/main/res/values-es/strings.xml +++ b/vector/src/main/res/values-es/strings.xml @@ -1,17 +1,15 @@ - + es ES - Mensajes Sala Ajustes Detalles de Miembro Histórico - Correcto Cancelar @@ -26,7 +24,7 @@ Reenviar Enlace Permanente Ver Fuente - Ver Fuente Descifrada + Ver Fuente Desencriptada Eliminar Renombrar Reportar contenido @@ -35,16 +33,15 @@ \nUnirse como %1$s o %2$s Voz Vídeo - No se puedo iniciar la llamada, por favor inténtelo de nuevo más tarde - Debido a que faltan permisos, pueden faltar algunas características… + No se puede iniciar la llamada, por favor inténtelo de nuevo más tarde + Debido a permisos insuficientes, pueden faltar algunas funciones… Necesitas permiso para invitar a iniciar una conferencia en esta sala No se puede iniciar la llamada Detalles de la sesión - No se admiten llamadas de conferencia en salas cifradas + No se admiten llamadas de conferencia en salas encriptadas Enviar de Todos Modos o Invitar - Cerrar sesión Llamada de Voz @@ -57,27 +54,22 @@ Cerrar Copiado al portapapeles Deshabilitar - Confirmación Advertencia - Inicio Favoritos Personas Salas - Filtrar salas Filtrar favoritos Filtrar personas Filtrar salas - Invitaciones Prioridad baja - Conversaciones Agenda de contactos local @@ -85,17 +77,15 @@ No hay conversaciones No permitiste que Element acceda a tus contactos locales No hay resultados - Salas Directorio de salas No hay salas No hay salas públicas disponibles - 1 usuario + %d usuario %d usuarios - Enviar registros Enviar registros de fallas Enviar captura de pantalla @@ -108,10 +98,8 @@ No se pudo enviar el informe de error (%s) Progreso (%s%%) La aplicación falló en la última sesión. ¿Te gustaría enviar un informe de error\? - Enviar en Leído - Unirse a la Sala Nombre de usuario Crear cuenta @@ -120,14 +108,11 @@ URL del Servidor Doméstico URL del Servidor de Identidad Buscar - Iniciar Nueva Conversación Iniciar Llamada de Voz Iniciar Llamada de Vídeo - Enviar archivos Tomar foto o vídeo - Iniciar sesión Crear cuenta @@ -176,7 +161,6 @@ Puedes añadir tu correo electrónico a tu perfil en ajustes. Tu contraseña fue restablecida. \n \nSe ha cerrado sesión en todas tus sesiones y ya no recibirás notificaciones push. Para volver a habilitar las notificaciones, vuelve a iniciar sesión en cada dispositivo. - La URL debe comenzar con http[s]:// No es posible iniciar sesión: Error de red @@ -185,7 +169,6 @@ Puedes añadir tu correo electrónico a tu perfil en ajustes. No es posible registrarse No es posible registrarse : falló la propiedad del correo electrónico Por favor introduce una URL válida - Nombre de usuario/contraseña inválidos No se reconoció el código de acceso especificado JSON mal formado @@ -193,36 +176,27 @@ Puedes añadir tu correo electrónico a tu perfil en ajustes. Se enviaron demasiadas solicitudes Este nombre de usuario ya está en uso El enlace del correo electrónico que aún no se ha seguido - - Lista de Recibos de Lectura - - Enviar como Original Grande Mediano Pequeño - "¿Cancelar la descarga? ¿Cancelar la subida? %d s %1$dm %2$ds - Ayer Hoy - - Nombre de la sala Tema de la sala - Llamada conectada Conectando llamada… @@ -232,21 +206,18 @@ Puedes añadir tu correo electrónico a tu perfil en ajustes. Llamada de Vídeo Entrante Llamada de Voz Entrante Llamada En Curso… - El lado remoto no contestó. Falló la Conexión de Medios No se puede iniciar la cámara llamada contestada en otra parte - Tomar una foto o un vídeo No se puede grabar vídeo - Información Element necesita permiso para acceder a tu biblioteca de fotos y vídeos para enviar y guardar archivos adjuntos. - -Por favor permite el acceso en la próxima ventana emergente para poder enviar archivos desde tu teléfono. +\n +\nPor favor permite el acceso en la próxima ventana emergente para poder enviar archivos desde tu teléfono. Element necesita permiso para acceder a tu cámara para tomar fotos y realizar llamadas de vídeo. " \n @@ -256,33 +227,28 @@ Por favor permite el acceso en la próxima ventana emergente para poder enviar a \n \nPor favor permite el acceso en la próxima ventana emergente para poder realizar la llamada." Element necesita permiso para acceder a tu cámara y micrófono para realizar llamadas de vídeo. - -Por favor permite el acceso en las próximas ventanas emergentes para poder realizar la llamada. +\n +\nPor favor permite el acceso en las próximas ventanas emergentes para poder realizar la llamada. Element necesita permiso para acceder a tu agenda de contactos para encontrar otros usuarios de Matrix por sus correos electrónicos y números telefónicos. Por favor permite el acceso en la próxima ventana emergente para descubrir usuarios accesibles desde Element en tu agenda de contactos. - Element necesita permiso para acceder a tu agenda de contactos para encontrar otros usuarios de Matrix por sus correos electrónicos y números telefónicos. - -¿Permitir que Element acceda a tus contactos ? - + Element necesita permiso para acceder a tu agenda de contactos para encontrar otros usuarios de Matrix por sus correos electrónicos y números telefónicos. +\n +\n¿Permitir que Element acceda a tus contactos \? Lo sentimos. Acción no realizada, debido a que faltan permisos - Guardado ¿Guardar en descargas? NO Continuar - Eliminar Unirse Vista Previa Rechazar - Ir al primer mensaje no leído. - Has sido invitado por %s a unirte a esta sala Esta invitación fue enviada a %s, que no esta asociado a esta cuenta. @@ -290,27 +256,22 @@ Quizás quieras iniciar sesión con otra cuenta, o añadir este correo electrón Estás intentando acceder a %s. ¿Quieres unirte para participar en la discusión? una sala Esta es una vista previa de esta sala. Las interacciones dentro de la sala se han deshabilitado. - Nueva Conversación Añadir miembro 1 miembro - Salir de la sala ¿Seguro que quieres salir de la sala? ¿Seguro que quieres eliminar a %s de esta conversación? Crear - En línea Desconectado En reposo - HERRAMIENTAS DE ADMINISTRACIÓN LLAMAR CONVERSACIONES DIRECTAS SESIONES - Invitar Salir de esta sala Eliminar de esta sala @@ -326,18 +287,14 @@ Quizás quieras iniciar sesión con otra cuenta, o añadir este correo electrón Mostrar Lista de Sesiones No podrás deshacer este cambio porque estás promoviendo al usuario para tener el mismo nivel de autoridad que tú. ¿Estás seguro? - ¿Seguro que quieres invitar a %s a esta conversación? - Invitar por ID CONTACTOS LOCALES (%d) Solo usuarios de Matrix - Invitar usuario por ID Por favor, ingresa una o más direcciones de correo electrónico o ID de Matrix Correo electrónico o ID de Matrix - Buscar %s está escribiendo… @@ -354,7 +311,6 @@ Quizás quieras iniciar sesión con otra cuenta, o añadir este correo electrón Eliminar mensajes no enviados Archivo no encontrado No tienes permiso para publicar en esta sala - Confiar No confiar @@ -367,7 +323,6 @@ Quizás quieras iniciar sesión con otra cuenta, o añadir este correo electrón El certificado cambió de uno que era confiable para tu teléfono. Esto es MUY INUSUAL. Se recomienda NO ACEPTAR este nuevo certificado. El certificado cambió de uno que era confiable a uno que no es confiable. El servidor puede haber renovado su certificado. Contacta al administrador del servidor para obtener la huella digital. Solo acepta el certificado si el administrador del servidor ha publicado una huella digital que coincide con la anterior. - Detalles de Sala Personas @@ -376,7 +331,6 @@ Quizás quieras iniciar sesión con otra cuenta, o añadir este correo electrón ID mal formada. Debería ser una dirección de correo electrónico o una ID de Matrix como \'@partelocal:dominio\' INVITADOS SE UNIERON - Motivo para reportar este contenido ¿Quieres ocultar todos los mensajes de este usuario? @@ -384,7 +338,6 @@ Quizás quieras iniciar sesión con otra cuenta, o añadir este correo electrón Ten en cuenta que esta acción reiniciará la aplicación y puede tardar algo de tiempo. Cancelar Subida Cancelar Descarga - Buscar Filtrar miembros de la sala @@ -393,7 +346,6 @@ Ten en cuenta que esta acción reiniciará la aplicación y puede tardar algo de MENSAJES PERSONAS ARCHIVOS - UNIRSE DIRECTORIO @@ -406,18 +358,15 @@ Ten en cuenta que esta acción reiniciará la aplicación y puede tardar algo de Unirse a la sala Unirse a una sala Escribe una ID o alias de sala - Explorar directorio Buscando directorio… - Agregar a Favoritos Dejar de priorizar Conversación Directa Salir de la Conversación Olvidar - Mensajes Ajustes @@ -426,9 +375,7 @@ Ten en cuenta que esta acción reiniciará la aplicación y puede tardar algo de Avisos de terceros Derechos de autor Política de privacidad - - Imagen de Perfil Nombre Público Correo Electrónico @@ -437,22 +384,18 @@ Ten en cuenta que esta acción reiniciará la aplicación y puede tardar algo de Añadir número telefónico Mostrar la pantalla de información de la aplicación de los ajustes del sistema. Información de la aplicación - Habilitar notificaciones para esta cuenta Habilitar notificaciones para esta sesión Enciende la pantalla por 3 segundos - Mensajes en conversaciones uno a uno Mensajes en conversaciones en grupo Cuando soy invitado a una sala Invitaciones de llamada Mensajes enviados por bot - Sincronización en segundo plano Habilitar sincronización en segundo plano Venció el tiempo de espera para la solicitud de sincronización Retraso entre cada sincronización - Versión versión de olm Términos y condiciones @@ -461,8 +404,6 @@ Ten en cuenta que esta acción reiniciará la aplicación y puede tardar algo de Política de privacidad Borrar caché - - Ajustes de usuario Notificaciones Usuarios ignorados @@ -488,19 +429,15 @@ Para continuar, ingresa tu contraseña por favor. Autenticación Contraseña: Enviar - Sesión iniciada como Servidor Doméstico Servidor de Identidad - Verificación Pendiente Por favor, consulta tu correo electrónico y haz clic en el enlace que contiene. Una vez hecho esto, haz clic en continuar. No es posible verificar la dirección de correo electrónico. Por favor, consulta tu correo electrónico y haz clic en el enlace que contiene. Una vez hecho esto, haz clic en continuar. - Esta dirección de correo electrónico ya está en uso. No se encontró esta dirección de correo electrónico. Este número telefónico ya está en uso. - Cambiar contraseña Contraseña actual Contraseña nueva @@ -510,13 +447,9 @@ Para continuar, ingresa tu contraseña por favor. ¿Mostrar todos los mensajes de %s? Ten en cuenta que esta acción reiniciará la aplicación y puede tardar algo de tiempo. - ¿Seguro que quieres eliminar este objetivo de notificaciones? - ¿Seguro que quieres eliminar los %1$s %2$s? - Elige un país - País Por favor, elige un país Número telefónico @@ -526,21 +459,17 @@ Ten en cuenta que esta acción reiniciará la aplicación y puede tardar algo de Ingresa un código de activación Error en la validación de tu número telefónico Código - - Imagen de Sala Nombre de Sala Tema Etiqueta de Sala Etiquetado como: - Agregar a Favoritos Prioridad baja Ninguno - Acceso y visibilidad Listar esta sala en el directorio de salas @@ -548,22 +477,18 @@ Ten en cuenta que esta acción reiniciará la aplicación y puede tardar algo de Legibilidad del Historial de la Sala ¿Quién puede leer el historial? ¿Quién puede acceder a esta sala? - Todos Solo miembros (desde el momento en que se selecciona esta opción) Solo miembros (desde que fueron invitados) Solo miembros (desde que se unieron) - Para crear un enlace a una sala, debe tener una dirección. Solo personas que han sido invitadas Cualquier persona que conozca el enlace a esta sala, excepto invitados Cualquier persona que conozca el enlace a esta sala, incluyendo invitados - Usuarios vetados - Avanzado La ID interna de esta sala @@ -575,35 +500,27 @@ Ten en cuenta que esta acción reiniciará la aplicación y puede tardar algo de Necesitas cerrar sesión para poder habilitar el cifrado. Cifrar solo a sesiones verificadas Nunca enviar mensajes cifrados a sesiones sin verificar en esta sala desde esta sesión. - Esta sala no tiene direcciones locales Dirección nueva (ej. #foo:matrix.org) - Formato de alias inválido \'%s\' no es un formato de alias válido No tendrás una dirección principal especificada para esta sala. Advertencias de la dirección principal - Establecer como Dirección Principal Dejar de Establecer como Dirección Principal Copiar ID de Sala Copiar Dirección de Sala - El cifrado está habilitado en esta sala. El cifrado está deshabilitado en esta sala. Habilitar cifrado (advertencia: ¡no se puede volver a deshabilitar!) - Directorio - %s estaba intentando cargar un momento específico en la línea de tiempo de esta sala pero no pudo encontrarlo. - Información de cifrado de extremo a extremo - Información de eventos ID de Usuario Clave de identidad Curve25519 @@ -611,7 +528,6 @@ Ten en cuenta que esta acción reiniciará la aplicación y puede tardar algo de Algoritmo ID de Sesión Error de descifrado - Información de la sesión emisora Nombre público Nombre público @@ -619,7 +535,6 @@ Ten en cuenta que esta acción reiniciará la aplicación y puede tardar algo de Clave de sesión Verificación Huella digital Ed25519 - Exportar claves de salas con Cifrado de Extremo a Extremo Exportar claves de sala Exportar las claves a un archivo local @@ -629,35 +544,28 @@ Ten en cuenta que esta acción reiniciará la aplicación y puede tardar algo de Las claves de salas con Cifrado de Extremo a Extremo se guardaron en \'%s\'. Advertencia: este archivo puede ser eliminado si la aplicación se desinstala. - Importar claves de salas con Cifrado de Extremo a Extremo Importar claves de sala Importar las claves desde un archivo local Importar Cifrar solo a sesiones verificadas Nunca enviar mensajes cifrados a sesiones sin verificar desde esta sesión. - SIN Verificar Verificado Prohibido - sesión desconocida ninguno - Verificar Anular Verificación Prohibir Dejar de Prohibir - Verificar sesión Para verificar que esta sesión es confiable, por favor contacta a su dueño por algún otro medio (ej. cara a cara o por teléfono) y pregúntale si la clave que ve en sus Ajustes de Usuario para esta sesión coincide con la clave a continuación: Si coincide, presione el botón de verificar a continuación. Si no coincide, entonces alguien está interceptando esta sesión y probablemente debería prohibirlo. En el futuro, este proceso de verificación será más sofisticado. Verifico que las claves coinciden - La sala contiene sesiones desconocidas Esta sala contiene sesiones desconocidas que no han sido verificados. Esto significa que no hay garantía de que las sesiones pertenezcan a los usuarios a los que dicen pertenecer. Recomendamos que pases por el proceso de verificación para cada sesión antes de continuar. Puedes reenviar el mensaje sin verificarlas si prefieres. Sesiones desconocidas: - Selecciona un directorio de salas El servidor puede estar no disponible o sobrecargado @@ -665,35 +573,27 @@ Advertencia: este archivo puede ser eliminado si la aplicación se desinstala.URL del Servidor Doméstico Todas las salas en el servidor %s Todas las salas nativas de %s - Buscar en el historial Interfaz de usuario Idioma Elige idioma - Iniciar en el arranque Borrar caché de medios Guardar medios - Mostrar marcas temporales de todos los mensajes - 3 días 1 semana 1 mes Para siempre - Desconectado - Modo de ahorro de datos - Tamaño de letra Pequeño Normal Grande Mayor Tema - Diminuto Más Grande Enorme @@ -702,30 +602,23 @@ Advertencia: este archivo puede ser eliminado si la aplicación se desinstala.Tema Claro Tema Oscuro Tema Negro - Sincronizando… - Detectar eventos + Captando eventos Notificaciones ruidosas Notificaciones silenciosas - Informe de error - Tomar foto Tomar vídeo - Llamar Sonido de notificación Mensajes que contienen mi nombre público Mensajes que contienen mi nombre de usuario Mostrar marcas temporales en formato de 12 horas - Análisis de Estadísticas - Necesitas permiso para gestionar los componentes en esta sala La creación del componente falló Crear llamadas de conferencia con jitsi ¿Seguro que quieres eliminar el widget de esta sala\? - No es posible crear el componente. El envío de la solicitud falló. @@ -737,60 +630,43 @@ Advertencia: este archivo puede ser eliminado si la aplicación se desinstala.La sala %s no está visible. Añadir aplicaciones de Matrix Utilizar cámara nativa - Añadiste una nueva sesión \'%s\', que está solicitando claves de cifrado. Tu sesión sin verificar \'%s\' está solicitando claves de cifrado. Iniciar verificación Compartir sin verificar Ignorar solicitud - ¡Advertencia! Las llamadas de conferencia están en desarrollo y pueden no ser confiables. - Error de comando Comando no reconocido: %s - Desactivado Ruidoso - Mensaje cifrado - Detalles de comunidad - Cargando… - Salir Comunidades - Filtrar comunidades - Invitar Comunidades No hay grupos - ¿Seguro que quieres iniciar una nueva conversación con %s? ¿Seguro que quieres iniciar una llamada de voz? ¿Seguro que quieres iniciar una llamada de vídeo? - Lista de Grupos - El usuario baneado lo echará de esta sala y evitará que se unan nuevamente. - Todos los mensajes (ruidoso) Todos los mensajes Solo menciones Silenciar - Añadir un Atajo a la Pantalla de Inicio - + Añadir a la Pantalla de Inicio Vistas previas de URL en línea Vibrar al mencionar un usuario - Insignia - Notificaciones Esta sala no está mostrando insignias para ninguna comunidad Nueva ID de comunidad (ej. +foo:matrix.org) @@ -798,48 +674,40 @@ Advertencia: este archivo puede ser eliminado si la aplicación se desinstala.Olvidar sala Volver a unirse \'%s\' no es una ID de comunidad válida - - Crear Crear Comunidad Nombre de comunidad Ejemplo ID de Comunidad ejemplo - Inicio Personas Salas No hay usuarios - Salas Se unió Invitado Filtrar miembros del grupo Filtrar salas del grupo - Has sido expulsado de %1$s por %2$s Has sido vetado de %1$s por %2$s Motivo: %1$s El administrador de la comunidad no ha redactado una descripción larga para esta comunidad. - Agitar con rabia para reportar un error - Acciones Listar miembros Sincronizando… - 1 miembro + %d miembro %d miembros - 1 mensaje nuevo + %d mensaje nuevo %d mensajes nuevos - - 1 sala + %d sala %d salas @@ -851,13 +719,12 @@ Advertencia: este archivo puede ser eliminado si la aplicación se desinstala.%d salas - 1 cambio de membresía + %d cambio de membresía %d cambios de membresía - Abrir título - 1 miembro activo + %d miembro activo %d miembros activos @@ -869,27 +736,21 @@ Advertencia: este archivo puede ser eliminado si la aplicación se desinstala.%d mensajes notificados sin leer %1$s en %2$s - 1 componente activo %d componentes activos - Enviar una pegatina - Actualmente no tienes ningún paquete de pegatinas habilitado. \n \n¿Añadir algunos ahora\? - Desactivar Cuenta Avatar - Avatar de recibo Avatar de aviso Para continuar utilizando el servidor doméstico %1$s, debes revisar y aceptar los términos y condiciones. Revisar ahora - Esto hará que tu cuenta quede permanentemente inutilizable. No podrás iniciar sesión, y nadie podrá volver a registrar la misma ID de usuario. Esto hará que tu cuenta salga de todas las salas en las cuales participa, y eliminará los datos de tu cuenta de tu servidor de identidad. Esta acción es irreversible. Desactivar tu cuenta no hace que por defecto olvidemos los mensajes que has enviado. Si quieres que olvidemos tus mensajes, por favor marca la casilla a continuación. @@ -898,7 +759,6 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Por favor, olvida todos los mensajes enviados al desactivar mi cuenta (Advertencia: esto provocará que los usuarios futuros vean conversaciones incompletas) Para continuar, ingresa tu contraseña por favor: Desactivar Cuenta - Privacidad de notificaciones Normal Privacidad reducida @@ -908,51 +768,37 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu • El contenido del mensaje de la notificación está ubicado de forma segura directamente desde el servidor doméstico de Matrix • Las notificaciones contienen datos de mensajes y metadatos • Las notificaciones no mostrarán el contenido del mensaje - Desactivar cuenta Desactivar mi cuenta - Descargar Sí, ¡quiero ayudar! - Conceder permiso Enviar audio - Enviar pegatina Un parámetro no es válido. Ingresa tu contraseña por favor. - Enviar mensaje de voz - Elige otra opción - Falta un parámetro requerido. Solicitud enviada Conversar Por favor, inicia Element en otro dispositivo que pueda descifrar el mensaje para que pueda enviar las claves a esta sesión. - Licencias de terceros - Borrar continuar con… Lo sentimos, no se encontró ninguna aplicación externa para completar esta acción. - Volver a solicitar las claves de cifrado de tus otras sesiones. - Solicitud de clave enviada. - Privacidad de Notificaciones Element puede ejecutarse en segundo plano para gestionar tus notificaciones de forma segura y privada. Esto podría afectar la duración de la batería. Enviar datos de análisis de estadísticas Element recopila análisis de estadísticas anónimas para permitirnos mejorar la aplicación. Por favor, habilita los análisis de estadísticas para ayudarnos a mejorar Element. Escribe aquí… - Si es posible, por favor escribe la descripción en inglés. Enviar una respuesta cifrada… Enviar una respuesta (sin cifrar)… Actualmente no eres miembro de ninguna comunidad. - Utilizar la tecla Intro del teclado para enviar mensajes Muestra la acción Veta al usuario con la ID dada @@ -966,73 +812,58 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Cambia tu apodo público Activar/Desactivar markdown Para reparar la gestión de las Aplicaciones de Matrix - Vista previa de medios antes de enviar - Esta sala ha sido reemplazada y ya no está activa La conversación continúa aquí Esta sala es una continuación de otra conversación Haz clic aquí para ver mensajes más antiguos - Degrada al usuario con la ID dada Alertas de Sistema - - Debido a que faltan permisos, esta acción no es posible. + Debido a permisos insuficientes, esta acción no es posible. - 1s + $d %ds - 1m - %dm + %dmin + %dmins - 1h + %dh %dh - 1d + %dd %dd - %1$s ahora hace %1$s %2$s - "%1$s, " %1$s y %2$s %1$s %2$s - - 1 seleccionado + $d seleccionado %d seleccionados 1 miembro %d miembros - 1 sala %d salas Límite de Recursos Excedido Contacta al Administrador - contacta al administrador de tu servicio - Este servidor doméstico ha excedido uno de sus límites de recursos, por lo que algunos usuarios no podrán iniciar sesión. Este servidor doméstico ha excedido uno de sus límites de recursos. - Este servidor doméstico ha alcanzado su límite Mensual de Usuarios Activos, por lo que algunos usuarios no podrán iniciar sesión. Este servidor doméstico ha alcanzado su límite Mensual de Usuarios Activos. - Por favor, %s para aumentar este límite. Por favor, %s para continuar utilizando este servicio. - Tema de Status.im - Error - Versión %s Por favor, crea una frase de contraseña para cifrar las claves exportadas. Necesitarás ingresar la misma frase de contraseña para poder importar las claves. Crear frase de contraseña @@ -1040,27 +871,19 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Utiliza carga diferida para los miembros de la sala Aumenta el rendimiento cargando los miembros de la sala solo en la primera vista. Tu servidor doméstico aún no admite la carga diferida de los miembros de la sala. Prueba más tarde. - Disculpas, ocurrió un error - expandir colapsar - - llamar de cada manera + Llamar de todos modos Aceptar - Por favor revisa y acepta las reglas de este servidor doméstico: - Llamadas Usar el tono de llamada normal de Element para llamadas entrantes Tono para llamadas entrantes Elegir sonido de llamadas: - Llamada de video en proceso… - Expulsar Razón - Diagnóstico de fallas Diagnóstico de errores Iniciar pruebas @@ -1068,7 +891,6 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Iniciando servicio Copia de seguridad de la clave Usar copia de seguridad de la clave - La copia de seguridad de la clave no ha finalizado, por favor espere… No quiero mis mensajes cifrados Creando copia de seguridad de las claves… @@ -1076,43 +898,36 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu ¿Estás seguro\? Copia de seguridad Perderá el acceso a sus mensajes cifrados si cierra sesión sin hacer una copia de seguridad de sus claves. - Quedarse Saltar Hecho Cancelar Ignorar - Marcar como leído Iniciar sesión con single-sign-on Tu dispositivo usa una versión anticuada e insegura del protocolo de seguridad TLS. Por tu seguridad no puedes conectarte Ajustes avanzados de notificaciones Importancia de notificación por evento - Ajustes de sistema. Las notificaciones están activadas en los ajustes de sistema. Las notificaciones están desactivadas en los ajustes del sistema. \nPor favor comprueba los ajustes de sistema. Abrir ajustes - Ajustes de cuenta. Las notificaciones están activadas para tu cuenta. Las notificaciones están desactivadas para tu cuenta. \nPor favor comprueba los ajustes de cuenta. Activar - Ajustes de sesión. Las notificaciones están activadas para esta sesión. Las notificaciones no están habilitadas para esta sesión. \nPor favor comprueba los ajustes Element. Activar - Ajustes personalizados. Ten en cuenta que algunos mensajes son silenciosos (producen una notificación sin sonido). Algunas notificaciones están desactivadas en tus ajustes personalizados. Error al cargar reglas personalizadas, por favor prueba de nuevo. Comprueba ajustes - Prueba de servicios Google Play APK de servicios de Google Play esta disponible y actualizado. Al cerrar la sesión se perderán los mensajes encriptados @@ -1121,13 +936,11 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu El diagnóstico base se ha completado con éxito. Si aun no recibes notificaciones, por favor mándanos un informe de error. Una o más pruebas han fallado, por favor prueba las soluciones propuestas. Una o más pruebas han fallado, por favor mándanos un informe de error para que podamos investigar. - Copia de seguridad en progreso. Si cierras sesión ahora perderás el acceso a tus mensajes encriptados. La copia de seguridad debería estar activa ahora en todas tus sesiones para evitar la pérdida del acceso a tus mensajes encriptados. Element usa los servicios de Google Play para entregar mensajes Push pero no parece estar configurado correctamente: \n%1$s solucionar error con los Servicios de Google Play - Token Base Token FCM recuperada correctamente:\n%1$s Error al recuperar token FCM:\n%1$s @@ -1135,45 +948,36 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu [%1$s]\nEste error esta fuera del control de Element. Puede ocurrir por numerosas razones. Probablemente funcione si vuelve a intentarlo mas tarde. También puede comprobar si los Servicios de Google Play están limitados por los ajustes del sistema o si la hora del dispositivo es correcta o si puede pasar en ROM personalizada. [%1$s] \nEste error esta fuera del control de Element. No hay cuenta de googled registrada en este dispositivo. Por favor abre el gestor dde cuentas y añade una cuenta de Google. - añadir cuenta - + Añadir cuenta Token de registro Token FCM registrado correctamente en el Servidor. Error al registrar el token FCM en el Servidor \n%1$s - Servicio de notificaciones El servicio de notificaciones esta funcionando. El servicio de notificaciones no esta funcionando. \nIntente reiniciar la aplicación. Borrando copia de seguridad… Error al borrar la copia de seguridad (%s) - Borrar copia de seguridad nueva copia de seguridad Ese era yo nunca se pierden mensajes cifrados Configurar copia de seguridad de las claves de cifrado - Nunca pierdas mensajes cifrados Nuevos mensajes clave cifrados Gestionar Copia de Seguridad - Guardando copia de seguridad… - Versión Algoritmo Reinicio automático del servicio de notificaciones Empezar servicio - El servicio se ha apagado y reiniciado automáticamente. Error al reiniciar el servicio - Inicio automático El servicio funcionará cuando reinicie el dispositivo. El servicio no se iniciará al reiniciar el dispositivo, no recibirá notificaciones hasta que Element haya sido abierto al menos 1 vez. - activar Inicio automático - + Activar Inicio automático Comprobar restricciones en segundo plano Las restricciones de segundo plano están desactivadas para Element. Este debería funcionar con datos móviles (sin WIFI). \n%1$s @@ -1181,19 +985,15 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu \nLa app estará completamente restringida mientras esté en segundo plano y esto podría afectar a las notificaciones. \n%1$s Desactivar restricciones - Optimización de la bateria A Element no le afecta la Optimización de la bateria. Si un usuario deja el dispositivo desenchufado e inmóvil durante cierto periodo de tiempo con la pantalla apagada, el dispositivo entrará en modo hibernación. Esto evita que las apps accedan a la red y postpone sus tareas, sincronizaciones y alarmas. ignorar optimización - Las apps no necesita conectarse al servidor doméstico en segundo plano, esto debería reducir el uso de la batería Configurar notificaciones de sonido Configurar notificaciones de llamada Configurar notificaciones silenciadas elegir Color de las luces LED, vibración. sonido… - - Administrar Claves de la criptografía Mostrar vistas previas de enlaces en el chat cuando el servidor doméstico soporte esta característica. Enviar notificaciones de escritura @@ -1208,31 +1008,24 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Incluye cambios en el avatar y en el nombre. Enviar mensaje con intro La tecla Intro enviará el mensaje en vez de añadir un salto de línea - Conexión en segundo plano Element necesita mantener una leve conexión en segundo plano para poder ofrecer notificaciones de confianza. \nEn la siguiente pantalla se le pedirá permisos para que Element siempre funcione en segundo plano, por favor acepte. Conceder permiso - El modo de guardado de datos aplica un filtro específico para que las actualizaciones de presencia y las notificaciones de escritura sean eliminadas. - Ha ocurrido un error mientras se verificaba tu dirección de correo electrónico. - Contraseña Actualizar contraseña La contraseña no es válida La contraseña no es correcta - Ha ocurrido un error tratando de verificar su número de teléfono. Información adicional: %s - Media Compresión predeterminada Seleccionar Seleccionar Recuperación de mensajes cifrados Gestionar copia de seguridad clave - %1$s: 1 mensaje %1$s: %2$d mensajes @@ -1241,49 +1034,39 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu %d notificación %d notificaciones - Nuevo evento Sala Nuevos mensajes Nueva invitación Yo ** Error al enviar - por favor abra la sala - "Lo sentimos, las llamadas grupales con Jitsi no se pueden mantener en dispositivos antiguos (dispositivos con Android inferior a 5.0)" - Iniciar la cámara del sistema en lugar de la pantalla de cámara personalizada. Esta opción requiere una aplicación de terceros para grabar los mensajes. - El comando \"%s\" necesita mas parámetros o algunos parámetros son incorrectos. Markdown activado. Markdown desactivado. - Silencioso Por favor introduzca un nombre de usuario. Mostrar el área de información Siempre Para mensajes y errores Solo para errores - %1$s: %1$s: %2$s +%d %d+ No se ha encontrado ningún APK válido de Servicios de Google Play. Las notificaciones podrían no funcionar correctamente. - Por favor introduzca una contraseña La contraseña que has introducido es muy débil - Por favor borra la contraseña si quieres que Element genere una clave de recuperación. No hay ninguna sesión de Matrix disponible - Nunca se pierden los mensajes cifrados Los mensajes en salas cifradas están asegurados con cifrado de extremo a extremo. Solo los integrantes de la sala y tu podéis leer estos mensajes. \n \nAsegúrate de guardar bien tus claves para evitar perderlas. (Avanzado) Exportar claves manualmente - Asegura tu copia de seguridad con una contraseña. Almacenaremos una copia cifrada de tus claves en tu servidor. Protege tu copia de seguridad con una contraseña para mantenerla segura. \n @@ -1305,7 +1088,6 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu La clave de recuperación ha sido guardada en \'%s\'. \n \nAtención: Este archivo podría borrarse si la aplicación es desinstalada. - Por favor, haga una copia Compartir clave de recuperación con… Generando clave de recuperación usando una contraseña, este proceso puede tardar varios segundos. @@ -1313,24 +1095,17 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Error inesperado Copia de seguridad iniciada Tus claves cifradas están siendo guardadas en segundo plano en tu servidor. La copia de seguridad inicial podría tardar varios minutos. - - Estás seguro\? Podrías perder el acceso a tus mensajes si te desconectas o pierdes este dispositivo. - Utiliza tu clave de recuperación para desbloquear tu historial de mensajes cifrados Utiliza tu clave de recuperación No sabes tu clave de recuperación\? puedes %s. - Utiliza tu clave de recuperación para desbloquear tu historial de mensajes cifrados Introduzca la clave de recuperación - Mensaje de recuperación - Has perdido tu clave de recuperación\? Puedes crear una nueva en ajustes. La copia de seguridad no se ha podido descifrar con esta contraseña: por favor verificar que has introducido la contraseña de recuperación correcta. Error de red: por favor comprueba tu conexión y vuelve a intentarlo. - Restaurando copia de seguridad: Creando clave de recuperación… Descargando claves… @@ -1338,7 +1113,6 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Desbloquear historial Por favor introduce una clave de recuperación La copia de seguridad no se ha podido descifrar con esta contraseña: por favor verificar que has introducido la contraseña de recuperación correcta. - Copia de seguridad restaurada %s ! Copia de seguridad restaurada con la clave %d. @@ -1348,36 +1122,27 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Se ha añadido %d como clave a esta sesión. Se han añadido %d como claves a esta sesión. - Error al recuperar la ultima versión de las claves (%s). La sesión crypto no esta activada - - Restaurada desde copia de seguridad Borrar copia de seguridad - La copia de seguridad ha sido correctamente activada para esta sesión. La copia de seguridad ha sido correctamente desactivada para esta sesión. Tus claves no están siendo guardadas en esta sesión. - La copia de seguridad tiene una firma de una sesión desconocida con el ID %s. La copia de seguridad tiene una firma valida de esta sesión. La copia de seguridad tiene una firma válida para la sesión verificada %s. Usar copia de seguridad de la clave - Todas las claves guardadas Cargando %d de la clave… Cargando %d de las claves… - Firma - autocompletar opciones del servidor Element 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 Configurar copia de seguridad de las claves de cifrado Obteniendo una versión de copia de seguridad… @@ -1385,18 +1150,14 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu La copia de seguridad tiene una firma inválida de la sesión verificada %s La copia de seguridad tiene una firma inválida de la sesión no verificada %s Error al conseguir información de confianza para la copia de seguridad (%s). - Para usar la copia de seguridad de la clave en esta sesión introduzca su contraseña o su clave de recuperación ahora. Desea borrar sus claves cifradas guardadas del servidor\? No podrás usar tu clave de recuperación para leer el historial de mensajes cifrados. - Una nueva copia de seguridad de mensajes ha sido detectada. \n \nSi no ha establecido un nuevo método de recuperación, alguien podría estar intentando acceder a su cuenta. Cambie su contraseña y establezca un nuevo método de recuperación inmediatamente en ajustes. Respuesta inválida del descubrimiento del servidor doméstico Reproducir sonido de cámara - Verificar sesión - ip desconocida Una nueva sesión solicita claves de cifrado. \nSesión: %1$s @@ -1406,53 +1167,42 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu \nSesión: %1$s \nVisto por última vez: %2$s \nSi no has iniciado sesión en otro dispositivo ignora esta solicitud. - Verificar Compartir Petición de compartición de clave Ignorar - Ya existe una copia de respaldo en tu servidor Parece que ya habías configurado una copia de seguridad para las claves en otra sesión. ¿Quieres reemplazarla por la nueva que has creado\? Reemplazar Parar - Comprobando copias de respaldo Tu sesión ha terminado por credenciales caducadas o inválidas. - Verificar comparando un texto corto. Para más seguridad, te recomendamos que hagas esto en persona o por otros medios confiables. Empezar verificación Solicitud de verificación Verifica esta sesión para marcarla como confiable. Confiar en sesiones de otros te da aún más tranquilidad cuando usas cifrado de mensajes de punto a punto. Verificar esta sesión la marcará como confiable, y también marcará como confiable tu sesión para la contraparte. - Verifica esta sesión confirmando los emojis que aparecen en la pantalla de la contraparte Verifica esta sesión confirmando que los siguietes números aparecen en la pantalla de la contraparte - Se ha recibido una solicitud de verificación. Ver solicitud Esperando confirmación de la contraparte… - ¡Verificado! Has verificado correctamente esta sesión. - Los mensajes con este usuario están cifrados punto a punto y no son legible por terceros. + Los mensajes con este usuario están cifrados punto a punto y no son legibles por terceros. Ok - ¿No aparece nada\? No todas las aplicaciones cliente soportan verificación interactiva. Usa la verificación clásica. Usar verificación clásica. - Verificación de clave Solicitud cancelada La contraparte canceló la verificación. \n%s La verificación ha sido cancelada. \nRazón: %s - Verificación de sesión interactiva Solicitud de verificación %s quiere verificar tu sesión - El usuario canceló la verificación La verificación ha superado el límite de espera La sesión recibió un mensaje inesperado @@ -1460,35 +1210,27 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Error en clave Error en usuario Error desconocido - - Editar Responder - Reintentar Unirse a una sala y empezar a usar la app. Alguien te envió una invitación Invitado por %s - No tienes más mensajes sin leer ¡Bienvenido! Conversaciones Tus conversaciones directas (1 a 1) se mostrarán aquí Salas Tus salas se mostrarán aquí - Reacciones De acuerdo Me gusta Añadir reacción Ver reacciones Reacciones - Evento borrado por el usuario Evento moderado por el administrador de la sala Última edición por %1$s on %2$s - - Evento con error, no se puede mostrar Crear sala No hay red, por favor comprueba tu conexión a internet. @@ -1496,13 +1238,10 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Cambiar red Espere por favor… Todas la comunidades - Esta sala no se puede previsualizar La previsualización de salas públicas no es posible todavía con Element - Salas Mensajes directos - Nueva sala CREAR Nombre de la sala @@ -1510,10 +1249,8 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Cualquiera puede unirse a esta sala Directorio de salas Publicar esta sala en el directorio de salas - Error obteniendo información de confiabilidad Error obteniendo claves para copias de respaldo - !Estás al día! Preferencias Seguridad & Privacidad @@ -1522,31 +1259,23 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Por favor escriba su sugerencia a continuación. Describa su sugerencia aquí Latn - Ninguno Revocar Desconectar Revisar Declinar - No se ha configurado un servidor de identidad. - La llamada ha fallado por un servidor mal configurado Intente usar %s No volver a preguntar - Para hacer esto, vaya a las opciones y añada un servidor de identidad. Confirme su contraseña Eso no se puede hacer en Element para móvil Se necesita autenticación - - Optimizado para batería Optimizado para operar en tiempo real Sin sincronización en segundo plano No se han podido actualizar las opciones. - - Integraciones Descubrimiento Gestione sus preferencias de descubrimiento. @@ -1562,7 +1291,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu El SAS no coincidió Pon un número de teléfono para que las personas que conoces te puedan encontrar. Se usará %s como asistencia cuando el servidor doméstico no la ofrezca (su dirección IP se compartirá durante una llamada) - Modo sincronización en segundo plano (Experimental) + Modo Sincronización en segundo plano Element se sincronizará en segundo plano de manera que se preserven los recursos del dispositivo (batería). \nDependiendo del estado de los recursos del dispositivo, la sincronización puede ser aplazada por el sistema operativo. Element se sincronizará en segundo plano periódicamente en un momento preciso (configurable). @@ -1575,7 +1304,6 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu \nLos Gestores de Integración reciben los datos de configuración y pueden modificar los widgets, enviar invitaciones a salas y establecer niveles de poder en su nombre. Permitir integraciones Adiministrador de integraciones - Nombre público (visible por las personas con quien te comuniques) Un nombre de sesión público es visible por las personas con quién te comunicas Widget @@ -1588,110 +1316,77 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Recargar widget Abrir en el navegador Revocar acceso para mi - Tu nombre visible La URL de tu avatar Tu ID de usuaria Tu tema ID de Widget ID de Sala - - Este widget quiere usar los siguientes recursos: Permitir Bloquear todos Usar la cámara Usar el micrófono Leer medios protegidos por DRM - No se ha configurado ningún administrador de integraciones. Para continuar es necesario que aceptes los Términos de este servicio. - La sesión no sabe nada de esa transacción La sesión no puede acordar el acuerdo de llaves, hash, MAC o método SAS El compromiso hash no ha coincidido No estás usando ningún Servidor de Identidad No hay ningún Servidor de Identidad configurado, esto es requerido para restablecer tu contraseña. - Parece que estás intentando conectarte a otro servidor doméstico. ¿Quieres cerrar sesión\? - Importar llaves E2E des del fichero \"%1$s\". - Versión del SDK de Matrix Otros avisos de terceros ¡Ya estas viendo esta sala! - Reacciones rápidas - Cuenta Experto Reglas Push No hay reglas push definidas No hay salidas push registradas - app_id: push_key: app_display_name: Url: Formato: - Ayuda y Acerca de - - Registrar token - Gracias, la sugerencia ha sido enviada correctamente El envio de la sugerencia ha fallado (%s) - Mostrar eventos ocultos en la línea de tiempo - Mensajes Directos - Esperando… Cifrando la miniatura… Enviando miniatura (%1$s / %2$s) Cifrando el archivo… Enviando el archivo (%1$s / %2$s) - Descargando archivo %1$s… ¡El archivo %1$s ha sido descargado! - (editado) - - Modificación de mensajes No se han encontrado modificaciones - Filtrar conversaciones… ¿No encuentras lo que buscas\? Crear una nueva sala Enviar un nuevo mensaje directo Ver el directorio de la sala - Nombre o ID (#ejemplo:servidor.org) - Habilitar \"desplazar para contestar\" en la línea de tiempo - Enlace copiado al portapapeles - Agregar por ID de matrix Creando sala… No se ha encontrado ningún resultado, utiliza \"Agregar usando ID de matrix\" para buscar en el servidor. Empieza a escribir para ver resultados Filtrar por usuario o ID… - Entrando en la sala… - Ver historial de modificaciones - Términos de Servicio Revisar Términos Ser descubierta por otros Utiliza Bots, puentes, widgets y packs de stickers - Leer en - - Servidor de identidad Desconectar servidor de identidad Configurar servidor de identidad @@ -1705,27 +1400,19 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Teléfonos para ser descubierto Te hemos enviado un correo de confirmación a %s, comprueba tu correo y haz click en el enlace de confirmación Pendiente - Entra en un nuevo servidor de identidad No se ha podido conectar al servidor de identidad Porfavor entra la url del servidor de identidad El servidor de identidad no tiene términos de servicio El servidor de identidad que has escojido no tiene términos de servicio. Solo continúa si confias en el propietario del servicio Un mensaje de texto ha sido enviado a %s. Porfavor escribe el código de verificación que contiene. - Actualmente estás compartiendo direcciones de correo electrónico o números de teléfono en el servidor de identidad %1$s. Necesitarás reconectarte a %2$s para dejar de compartirlos. Acepte los términos de servicio del servidor de identidad (%s) para permitir que sea descubierto por correo electrónico o número de teléfono. - Habilitar registros extensos. Los logs extensivos ayudarán a los desarrolladores proporcionando más información cuando envíes un \"RageShake\" (Sacudir el dispositivo). Incluso cuando esto está habilitado, la aplicación no registra el contenido de los mensajes ni ningún otro dato privado. - - Por favor, vuelva a intentarlo una vez que haya aceptado los términos y condiciones de su servidor. - Parece que el servidor está tardando demasiado en responder, esto puede ser causado por una mala conectividad o un error con el servidor. Por favor, inténtelo de nuevo en un rato. - Enviar el archivo adjunto - Abrir el cajón de navegación Abrir el menú de creación de sala Cerrar el menú de creación de sala… @@ -1735,17 +1422,14 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Mostrar contraseña Esconder contraseña Saltar al final - Leído por %1$s, %2$s y %3$s Leído por %1$s y %2$s Leído por %s - Leído por 1 usuario - Leído por %d usuarias + Leído por %d usuario + Leído por %d usuarios - El archivo \'%1$s\' (%2$s) es demasiado grande para ser subido. El límite es %3$s. - Ha ocurrido un error recuperando el archivo adjunto. Archivo Contacto @@ -1754,7 +1438,6 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Galería Pegatina No se han podido compartir los datos - Es spam Es inapropiado Reporte personalizado… @@ -1762,28 +1445,23 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Razón por la que se ha reportado el contenido REPORTAR BLOQUEAR USUARIO - Contenido reportado - El contenido ha sido reportado + El contenido ha sido reportado. \n -\nSi no quieres ver más contenido de este usuario, puedes bloquearlo para ocultar sus mensajes +\nSi no quieres ver más contenido de este usuario, puedes bloquearlo para ocultar sus mensajes. Reportar como spam Este contenido ha sido reportado como spam. \n -\nSi no quieres ver más contenido de este usuario, puedes bloquearlo para ocultar sus mensajes +\nSi no quieres ver más contenido de este usuario, puedes bloquearlo para ocultar sus mensajes. Reportado como inapropiado Este contenido fue reportado como inapropiado. \n -\nSi no quieres ver más contenido de este usuario, puedes bloquearlo para ocultar sus mensajes - +\nSi no quieres ver más contenido de este usuario, puedes bloquearlo para ocultar sus mensajes. Element necesita permiso para guardar tus claves E2E en la memória del dispositivo. \n \nPorfavor permite el acceso en el siguiente pop-up para poder exportar tus claves manualmente. - No hay conexión de red - Ignorar usuario - Todos los mensajes (sonido) Todos los mensajes Solo menciones @@ -1794,29 +1472,22 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Envía el mensaje como spoiler Revelación Escribe las palabras clave para encontrar una reacción. - No hay usuarios ignorados - Mantén pulsada una sala para ver más opciones - - %1$s ha hecho la sala pública para cualquier persona con el link. %1$s: Ahora la sala solo es accesible por invitación. Mensajes no leídos - - Es tu conversación. Me pertenece. + Es tu conversación. Hazla tuya. Envía mensajes a personas o grupos Mantén las conversaciones privadas con encriptación Extiende y personaliza tu experiencia Empieza - Selecciona un servidor Como el correo electrónico, las cuentas tienen un hogar, aunque se puede hablar con cualquiera Alojamiento de pago para organizaciones Saber más Otro Ajustes avanzados y de personalización - Continuar Conectarse a %1$s Conectarse a Element Matrix Services @@ -1828,7 +1499,6 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Alojamiento de pago para organizaciones Introduzca la dirección de Modular Element o servidor que quieres usar Introduzca la dirección del servidor Element al que quieres conectarte - Se produjo un error al cargar la página: %1$s (%2$d) "La aplicación no es capaz de iniciar sesión en este servidor. Este solo soporta el acceso mediante: %1$s. \n @@ -1837,25 +1507,18 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu La aplicación no fue capaz de crear una cuenta en este servidor. \n \n¿Quieres registrarte usando un cliente web\? - La dirección de coreo electrónico no está asociada a ninguna cuenta. - Reiniciar contraseña en %1$s ¡Las claves ya están al día! - Reproducir Pausar Descartar - - Copiar Correcto - Notificaciones Element Fallo la Llamada Fallo al intentar establecer conexion. \nTURN Server fallo. Por favor, contacte con el administrador de su Servidor y notifique el fallo. - Seleccionar Dispositivo de Sonido Telefono Altavoz @@ -1866,13 +1529,11 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Tracera Apagar HD Activar HD - Error SSl: la identidad del par no a sido verificada. Error SSL. Permitir servidor de asistencia de llamadas Llamada activa (%s) Regresar a la llamada - Cancelar invitación Ignorar Usuario Cancelar Invitacion @@ -1881,7 +1542,6 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Verifica este enlace Este link %1$s loredirecciona a otro sitio %2$s. . \nEsta seguro de continuar\? - Adicionar miembros INVITAR Invitando usuarios… @@ -1893,11 +1553,9 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Invitaciones enviadas a %$s y a %2$d más No se pudo invitar el usuario. Por favor, intente nuevamente. - Idioma actual Otros idiomas disponibles Cargando lenguajes disponibles… - Leer los terminos de %s Desconectarse del servidor de Identidad %s\? Servidor de identidad desactualizado. Element solo soporta API V2. @@ -1906,20 +1564,17 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Riot ahora es Element! Entendido Aprender Mas - Element - - Buscar en mis contactos Rechazar invitación Confirma PIN para desabilitarlo No posee permisos para iniciar una conferencia en esta sala Conferencia en progreso! - Iniciar Video Conferencia - Iniciar Audio Conferencia - No puedes hacer una llamada contigo mismo - No puedes hacer una llamada contigo mismo, espera a que los participantes acepten la invitación - Fallo al adicionar Widget + Iniciar Videoconferencia + Iniciar Audioconferencia + No puedes hacer llamarte a tí mismo + No puedes hacer llamarte a tí mismo, espera a que los participantes acepten la invitación + Fallo al añadir Widget Fallo al eliminar Widget Confirmar llamada Pedir confirmacion antes de iniciar una llamda @@ -1928,14 +1583,10 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Rason de baneo Desbanear usuario Desbanear usuario y permitir entrar a la sala nuevamente. - nombre_session: Adicionar pestaña dedicada para notificaciones no leidas en la pantalla principal. - Descripcion muy corta - Sincronización inicial… - Mostrar todas mis sessiones Opciones Avanzadas Modo Desarrollador @@ -1946,33 +1597,25 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Ajustes Sesión Actual Otras Sesiones - Mostrando solo el primer resultado, agregue mas letras… - Fallar rápido (Test) Element puede fallar con más frecuencia cuando ocurre un error inesperado - Antepone ¯\\_(ツ)_/¯ a un mensaje de texto sin formato - Habilitar encriptacion Una vez habilitada, el cifrado no se puede deshabilitar. - Su dominio de correo electrónico no está autorizado para registrarse en este servidor - Inicio de sesión no confiable Coinciden No coinciden Verifique a este usuario confirmando que el siguiente emoji único aparece en su pantalla, en el mismo orden. Para mayor seguridad, use otro medio de comunicación confiable o hágalo en persona. Busque el escudo verde para asegurarse de que se confía en un usuario. Confíe en todos los usuarios de una sala para asegurarse de que la sala sea segura. - No seguro Video. Imagen. Audio Archivo Sticker - Esperando… %s cancelada Cancelado por usted @@ -1982,21 +1625,15 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Solicitud de verificación Verifica esta Sesion Verificar manualmente - Usted - Escanee el código con el dispositivo del otro usuario para verificarse mutuamente de forma segura Escanear código Error al escanear Si no estás en persona, compara los emojis - Verificar comparando emojis - Verificar por emojis Si no puede escanear el código anterior, verifique comparando una selección breve y única de emoji. - Imagen de código QR - Verificar %s Verificado %s Esperando por %s… @@ -2014,109 +1651,78 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Archivos, Medias y Documentos Abandonar Sala Saliendo de la sala… - Administradores Moderadores Nivel Personalizado Invitados Usuarios - Administrador en %1$s Moderador en %1$s Nivel Personalizado en %1$s Nivel Personalizado (%1$d) en %2$s - Saltar para leer el recibo - Element no maneja eventos de tipo \'%1$s\' Element no maneja el mensaje de tipo \'%1$s\' Element encontró un problema al representar el contenido del evento con el ID \'%1$s\' - Dejar de ignorar - Salas recientes Otras salas - Envía el mensaje dado en colores Línea de tiempo - Editor de mensage - Encriptar (end-to-end) Una vez habilitado, el cifrado no se puede deshabilitar. - Encriptar \? Habilitar el cifrado - Firma cruzada Firma cruzada no habilitada - Sesiones Activas Mostrar todas las Sesiones Administrar Sesiones Cerrar Sesión - Verificar este inicio de sesión Otros usuarios pueden no confiar en la sesion Completar Seguridad - Verificar Verificada Precaucion - Error al obtener sesiones Sesiones Confirmado No es confiable - Inicializar Firmas Cruzadas Restablecer claves - Codigo QR - Correcto No - Sin conexión Modo Avión Activado - Herramientas de desarrollo Datos de cuenta Seleccionar Opcion Nuevo inicio de sesión - Advertencia: Remover… Razón Razón para redactar - Element Android - Refrescar - Nuevo inicio de sesión detectado . ¿Fue usted\? Toca para revisar y verificar Este no era yo Su cuenta puede estar comprometida - Verificación cancelada - Frase de contraseña de recuperación Clave de mensaje Contraseña de la cuenta - ¡Listo! Cifrado habilitado Sala creada y configurada por usted. - Esperando por %s… - Ajuste de Notificaciones Mensaje… - Introduza su %s para continuar Usar archivo - No se pudo guardar el archivo multimedia Verificar Sesión Confirmar PIN @@ -2128,27 +1734,20 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Numeros telefonicos Correos y numeros telefonicos Administre el correo y numero telefonico de su cuenta - Mostrar mensages eliminados Indicar marca de mensaje eliminado ARCHIVOS No se han subido archivos a la sala - Establecer notificaciones por eventos - Establecer una nueva contraseña… - Las reuniones utilizan políticas de seguridad y permisos de Jitsi. Todas las personas que se encuentren actualmente en la sala verán una invitación para unirse mientras se lleva a cabo la reunión. Aceptar Declinar Colgar - Este número de teléfono ya está definido. ¿Degradarte\? No podrá deshacer este cambio ya que se está degradando, si es el último usuario privilegiado en la sala, será imposible recuperar los privilegios. Degradar - - Si ignora a este usuario, se eliminarán sus mensajes de las salas que comparte. \n \n Puede revertir esta acción en cualquier momento en la configuración general. @@ -2164,7 +1763,6 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu No se ha agregado ningún correo electrónico a su cuenta ¿Elimina %s\? Asegúrese de haber hecho clic en el enlace del correo electrónico que le enviamos. - Copia de seguridad segura Gestionar Configurar copia de seguridad segura @@ -2173,47 +1771,34 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Protéjase contra la pérdida de acceso a los mensajes y datos cifrados haciendo una copia de seguridad de las claves de cifrado en su servidor. Genere una nueva llave de seguridad o establezca una nueva frase de seguridad para su copia de seguridad existente. Esto reemplazará su clave o frase actual. - Las integraciones están deshabilitadas Habilite \'Permitir integraciones\' en Configuración para hacer esto. - %d usuario prohibido %d usuarios prohibidos - Claves exportadas correctamente - %1$d/%2$d clave importada con éxito. %1$d/%2$d claves importadas con éxito. - %1$s: %2$s %1$s: %2$s %3$s - VER Widgets activos - - Gestionar integraciones Sin widgets activos La clave de recuperación se ha guardada. - Copia de seguridad segura Protéjase contra la pérdida de acceso a mensajes y datos cifrados - Configurar copia de seguridad segura - Mensaje borrado Se ha creado la sala, pero algunas invitaciones no se han enviado por el siguiente motivo: \n \n%s - Le enviamos un correo electrónico de confirmación %s, primero revise su correo electrónico y haga clic en el enlace de confirmación Código El código de verificación no es correcto. - %1$s, %2$s y %3$d otra lectura %1$s, %2$s y %3$d otras lecturas @@ -2226,61 +1811,49 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu No hiciste cambios Hiciste que la sala fuera pública para quien conozca el enlace. Hiciste la sala solo por invitación. - Únase a millones gratis en el servidor público más grande + Únase gratis a millones en el servidor público más grande Continuar con SSO - Dirección de servicios de Element Matrix Ingrese la dirección del servidor que desea utilizar - Se enviará un correo electrónico de verificación a su bandeja de entrada para confirmar la configuración de su nueva contraseña. Próximo Email Nueva contraseña - ¡Advertencia! Cambiar su contraseña restablecerá cualquier clave de cifrado de extremo a extremo en todas sus sesiones, haciendo ilegible el historial de chat cifrado. Configure Key Backup o exporte las llaves de su sala desde otra sesión antes de restablecer su contraseña. Seguir - Este correo electrónico no está vinculado a ninguna cuenta - Revisa tu correo Se envió un correo electrónico de verificación a %1$s. Toque el enlace para confirmar su nueva contraseña. Una vez que haya seguido el enlace que contiene, haga clic a continuación. He verificado mi dirección de correo electrónico - ¡Éxito! Tu contraseña ha sido restablecida. Ha cerrado sesión en todas las sesiones y ya no recibirá notificaciones automáticas. Para volver a habilitar las notificaciones, inicie sesión nuevamente en cada dispositivo. Volver a Iniciar sesión - Advertencia u contraseña aún no ha cambiado. \n \n¿Detener el proceso de cambio de contraseña\? - Establecer dirección de correo electrónico Configure un correo electrónico para recuperar su cuenta. Más tarde, opcionalmente, puede permitir que las personas que conoce lo descubran mediante su correo electrónico. Correo electrónico Email (opcional) Próximo - Establecer número de teléfono Configure un número de teléfono para permitir que las personas que conoce lo descubran opcionalmente. Utilice el formato internacional. Número de teléfono Numero de teléfono (opcional) Próximo - Confirmar número de teléfono Acabamos de mandar un codigo a %1$s. Ingréselo a continuación para verificar que es usted. Introduzca el código Enviar de nuevo Próximo - Utilice el formato internacional (el número de teléfono debe comenzar con \'+\') Los números de teléfono internacionales deben comenzar con \'+\' El número de teléfono parece no válido. Compruébelo por favor - Inscribirse a %1$s Nombre de usuario o correo electrónico Nombre de usuario @@ -2291,25 +1864,21 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Tu cuenta aún no está creada. \n \n ¿Detener el proceso de registro\? - Seleccione matrix.org Seleccionar servicios de matriz de elementos Seleccione un servidor doméstico personalizado Realiza el desafío de captcha Acepta los términos para continuar - Por favor revise su correo electrónico Acabamos de enviar un correo electrónico a %1$s. \nHaga clic en el enlace que contiene para continuar con la creación de la cuenta. El código introducido no es correcto. Por favor, compruebe. Servidor doméstico obsoleto Este servidor doméstico está ejecutando una versión demasiado antigua para conectarse. Pídale al administrador de su servidor doméstico que actualice. - Se han enviado demasiadas solicitudes. Puedes volver a intentarlo en %1$d segundo… Se han enviado demasiadas solicitudes. Puedes volver a intentarlo en %1$d segundos… - Alternativamente, si ya tiene una cuenta y conoce su identificador Matrix y su contraseña, puede usar este método: Iniciar sesión con Matrix ID Iniciar sesión con Matrix ID @@ -2318,9 +1887,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Si no conoce su contraseña, vuelva a restablecerla. "Este no es un identificador de usuario válido. Formato esperado: \'@user:homeserver.org\'" No se pudo encontrar un servidor de inicio válido. Por favor verifique su identificador - Visto por - Estás desconectado Puede deberse a varias razones: \n @@ -2330,7 +1897,6 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu \n \n• El administrador de su servidor ha invalidado su acceso por motivos de seguridad. Iniciar sesión de nuevo - Estás desconectado Registrarse "El administrador de su servidor doméstico (%1$s) ha cerrado la sesión de su cuenta %2$s (%3$s)." @@ -2342,14 +1908,12 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu \n \nBórrelo si terminó de usar este dispositivo o si desea iniciar sesión en otra cuenta. Borrar todos los datos - Borrar datos ¿Borrar todos los datos almacenados actualmente en este dispositivo\? \nVuelva a iniciar sesión para acceder a los datos y mensajes de su cuenta. Perderás el acceso a los mensajes seguros a menos que inicies sesión para recuperar tus claves de cifrado. Borrar datos La sesión actual es para el usuario %1$s y usted proporciona las credenciales para el usuario %2$s. Esto no es compatible con Element. Primero borre los datos, luego inicie sesión nuevamente con otra cuenta. - Su enlace matrix.to estaba mal formado El modo desarrollador activa funciones ocultas y también puede hacer que la aplicación sea menos estable. ¡Solo para desarrolladores! Uno de los siguientes puede verse comprometido: @@ -2357,7 +1921,6 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu \n- El servidor doméstico al que está conectado el usuario que estás verificando \n- La suya o la conexión a Internet de otros usuarios \n- El suyo o el dispositivo de otros usuarios - Para mayor seguridad, verifique %s verificando un código único en ambos dispositivos. \n \nPara máxima seguridad, hágalo en persona. @@ -2366,18 +1929,14 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu \nSus mensajes están protegidos con candados y solo usted y el destinatario tienen las claves únicas para desbloquearlos. Esta sesión no puede compartir esta verificación con sus otras sesiones. \nLa verificación se guardará localmente y se compartirá en una versión futura de la aplicación. - Envía el emote dado coloreado como un arcoíris - Una vez habilitado, el cifrado de una sala no se puede deshabilitar. Los mensajes enviados en una sala cifrada no pueden ser vistos por el servidor, solo por los participantes de la sala. Habilitar el cifrado puede evitar que muchos bots y puentes funcionen correctamente. Para estar seguro, verifique %s comprobando un código de un solo uso. Para estar seguro, hágalo en persona o use otra forma de comunicarse. - Compare los emoji únicos, asegurándose de que aparezcan en el mismo orden. Compare el código con el que se muestra en la pantalla del otro usuario. Los mensajes con este usuario están encriptados de extremo a extremo y no pueden ser leídos por terceros. Su nueva sesión ahora está verificada. Tiene acceso a sus mensajes cifrados y otros usuarios lo verán como de confianza. - La firma cruzada está habilitada \n Claves privadas en el dispositivo. La firma cruzada está habilitada @@ -2387,23 +1946,16 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu \nLas claves no son de confianza El administrador de su servidor ha desactivado el cifrado de extremo a extremo de forma predeterminada en salas privadas y mensajes directos. No hay información criptográfica disponible - Esta sesión es confiable para mensajería segura porque usted la verificó: Verifique esta sesión para marcarla como confiable y otorgarle acceso a mensajes encriptados. Si no inició sesión en esta sesión, su cuenta puede verse comprometida: - %d sesión activa %d sesiones activas - Utilice una sesión existente para verificar esta, otorgándole acceso a los mensajes cifrados. - - "Esta sesión es confiable para mensajería segura porque %1$s (%2$s) la verificó:" %1$s (%2$s) iniciado sesión con una nueva sesión: Hasta que este usuario confíe en esta sesión, los mensajes enviados hacia y desde ella se etiquetan con advertencias. Alternativamente, puede verificarlo manualmente. - - ¡Casi ahí! ¿Es %s muestra el mismo escudo\? %d voto @@ -2416,31 +1968,24 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Crea una encuesta simple Use una contraseña o clave de recuperación Si no puede acceder a una sesión existente - No puedo encontrar secretos almacenados Ingrese la contraseña de almacenamiento secreta Solo debe acceder al almacenamiento secreto desde un dispositivo confiable - ¿Quieres enviar este adjunto a %1$s\? Enviar imagen con el tamaño original Envía imágenes con el tamaño original - Confirmar eliminación ¿Está seguro de que desea eliminar (eliminar) este evento\? Tenga en cuenta que si elimina el nombre de una sala o el cambio de tema, podría deshacer el cambio. Evento eliminado por el usuario, motivo: %1$s Evento moderado por el administrador de la sala, motivo: %1$s - Solicitudes clave - Desbloquear el historial de mensajes cifrados - Utilice esta sesión para verificar su nuevo, otorgándole acceso a mensajes encriptados. Si cancela, no podrá leer mensajes encriptados en este dispositivo y otros usuarios no confiarán en él Si cancela, no podrá leer mensajes encriptados en su nuevo dispositivo y otros usuarios no confiarán en él No verificarás %1$s (%2$s) si cancelas ahora. Comience de nuevo en su perfil de usuario. - Uno de los siguientes puede verse comprometido: \n \n- Tu contraseña @@ -2449,29 +1994,21 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu \n- La conexión a Internet que está usando cualquiera de los dispositivos \n \nLe recomendamos que cambie su contraseña y clave de recuperación en Configuración de inmediato. - Verifique sus dispositivos desde Configuración. Establecer un %s Generar una clave de mensaje - Confirmar %s - "Ingrese su %s para continuar." - Proteja y desbloquee los mensajes cifrados y confíe en %s. Ingrese su %s nuevamente para confirmarlo. No use la contraseña de su cuenta. - Ingrese una frase de seguridad que solo usted conozca, que se usa para proteger secretos en su servidor. - Esto puede tardar varios segundos, tenga paciencia. Configurando la recuperación. Tu clave de recuperación Manténlo seguro Terminar - Utilice este %1$s como red de seguridad en caso de que olvide su %2$s. - Publicar claves de identidad creadas Generando clave segura a partir de frase de contraseña Definición de la clave predeterminada de SSSS @@ -2479,18 +2016,13 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Sincronización de la clave de usuario Sincronización de la clave de autofirma Configuración de copia de seguridad de claves - - Tus %2$s y %1$s ahora están configurados. \n \n¡Mantenlos a salvo! Los necesitará para desbloquear mensajes cifrados y proteger la información si pierde todas sus sesiones activas. - Imprímelo y guárdalo en un lugar seguro Guárdelo en una llave USB o unidad de respaldo Cópielo en su almacenamiento personal en la nube - No puedes hacer eso desde el móvil - Establecer una frase de contraseña de recuperación le permite proteger y desbloquear mensajes cifrados y de confianza. \n \nSi no desea establecer una contraseña de mensaje, genere una clave de mensaje. @@ -2498,35 +2030,28 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Si cancela ahora, puede perder mensajes y datos cifrados si pierde el acceso a sus inicios de sesión. \n \nTambién puede configurar la Copia de seguridad segura y administrar sus claves en Configuración. - Los mensajes de esta sala están cifrados de extremo a extremo. Obtenga más información y verifique a los usuarios en su perfil. Cifrado no habilitado El cifrado utilizado por esta sala no es compatible - %s creado y configurado la sala. ¡Casi ahí! ¿El otro dispositivo muestra el mismo escudo\? ¡Casi ahí! Esperando confirmación… No se pudieron importar las claves - Mensajes que contienen @room Mensajes cifrados en chats uno a uno Mensajes cifrados en chats grupales Cuando las salas son actualizadas Solucionar problemas Envía un mensaje como texto estándar, sin interpretarlo como Markdown - Nombre de usuario y / o contraseña incorrectos. La contraseña ingresada comienza o termina con espacios, verifíquela. Esta cuenta ha sido desactivada. - Mejora de encriptación disponible Habilitar la firma cruzada Verifíquese a usted mismo y a los demás para mantener sus chats seguros - Entrar %s Frase de contraseña de recuperación No es una clave de recuperación válida Por favor introduce una clave de recuperación - Comprobando la clave de respaldo Comprobando la clave de respaldo (%s) Obteniendo clave de curva @@ -2535,15 +2060,12 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Generando clave SSSS a partir de clave de recuperación Almacenar el secreto de la copia de seguridad de claves en SSSS %1$s (%2$s) - Ingrese su Frase de contraseña de respaldo de clave para continuar. use su clave de recuperación de Key Backup No conoces tu frase de contraseña de copia de seguridad clave, puedes %s. Clave de recuperación de copia de seguridad - Evitar capturas de pantalla de la aplicación Al habilitar esta configuración, se agrega FLAG_SECURE a todas las actividades. Reinicie la aplicación para que el cambio surta efecto. - Archivo multimedia agregado a la Galería No se pudo agregar el archivo multimedia a la Galería Utilice la última versión de Element en sus otros dispositivos, Element Web, Element Desktop, Element iOS, Element para Android u otro cliente Matrix con capacidad de firma cruzada @@ -2560,28 +2082,22 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Seleccione su clave de recuperación o introdúzcala manualmente escribiéndola o pegándola desde su portapapeles La copia de seguridad no se pudo descifrar con esta clave de recuperación: verifique que ingresó la clave de recuperación correcta. No se pudo acceder al almacenamiento seguro - Sin encriptar Cifrado por un dispositivo no verificado Revise dónde inició sesión Verifique todas sus sesiones para asegurarse de que su cuenta y sus mensajes estén seguros Verifique el nuevo inicio de sesión accediendo a su cuenta: %1$s - Verificar manualmente por texto Verificación interactiva por emoji Confirme su identidad verificando este inicio de sesión de una de sus otras sesiones, otorgándole acceso a los mensajes cifrados. Confirme su identidad verificando este inicio de sesión, otorgándole acceso a los mensajes cifrados. Marcar como de confianza - Lo sentimos, esta operación aún no es posible para las cuentas conectadas mediante el inicio de sesión único. - No pudimos crear tu DM. Marque los usuarios que desea invitar y vuelva a intentarlo. - Primero acepta los términos del servidor de identidad en la configuración. Para su privacidad, Element solo admite el envío de números de teléfono y correos electrónicos de usuario con hash. La asociación ha fallado. No hay asociación actual con este identificador. - Su servidor doméstico (%1$s) propone utilizar %2$s para su servidor de identidad Utilizar %1$s Alternativamente, puede ingresar cualquier otra URL del servidor de identidad @@ -2594,9 +2110,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Activar el sonido del micrófono Detén la cámara Enciende la cámara - Configurar copia de seguridad segura - Respaldo seguro Protéjase contra la pérdida de acceso a los mensajes y datos cifrados haciendo una copia de seguridad de las claves de cifrado en su servidor. Preparar @@ -2604,22 +2118,17 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Genere una clave de seguridad para almacenar en un lugar seguro, como un administrador de contraseñas o una caja fuerte. Utilice una frase de seguridad Ingrese una frase secreta que solo usted conozca y genere una clave de respaldo. - Guarde su llave de seguridad Guarde su llave de seguridad en un lugar seguro, como un administrador de contraseñas o una caja fuerte. - Establecer una frase de seguridad Ingrese una frase de seguridad que solo usted conozca, que se usa para proteger secretos en su servidor. Frase de seguridad Ingrese su Frase de seguridad nuevamente para confirmarla. - Guarde su llave de seguridad Guarde su llave de seguridad en un lugar seguro, como un administrador de contraseñas o una caja fuerte. - Nombre de la Sala Tema Cambiaste la configuración de la sala con éxito - No puedes acceder a este mensaje Esperando este mensaje, esto puede tardar un poco No se puede descifrar @@ -2628,22 +2137,17 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu No puede acceder a este mensaje porque el remitente no confía en su sesión No puede acceder a este mensaje porque el remitente no envió las claves a propósito Esperando el historial de cifrado - ¡Nos complace anunciar que hemos cambiado de nombre! Tu aplicación está actualizada y accediste a tu cuenta. Guardar la clave de recuperación en - Agregar desde mi directorio telefónico Tu directorio telefónico está vacío Directorio telefónico Recuperando tus contactos… Tu libro de contactos está vacío Libro de contactos - ¿Revocar la invitación a %1$s\? - Prohibido por %1$s No se pudo anular la prohibición del usuario - Las notificaciones push están deshabilitadas Revise su configuración para habilitar las notificaciones push @@ -2653,9 +2157,41 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu ¡Advertencia! ¡Último intento restante antes de cerrar sesión! Demasiados errores, se ha desconectado Elija un PIN por seguridad - No se pudo validar el PIN, toque uno nuevo. + No se pudo validar el PIN, por favor introduzca uno nuevo. Introduce tu PIN ¿Olvidó su PIN\? No se puede abrir una sala en la que está prohibido. No puedo encontrar esta sala. Asegúrate de que exista. - + Los mensajes en esta sala están encriptados punto-a-punto. + Mensaje directo + Salir + Preferencias + Los mensajes aquí están encriptados de punto a punto. +\n +\nTus mensajes están asegurados con un candado. Solo tú y tú destinatario tenéis las llaves especiales para desencriptarlos. + Los mensajes aquí no están encriptados de punto a punto. + Botones de Bot + Encuesta + Remover de Baja prioridad + Añadir a Baja prioridad + Rotar y recortar + + $d segundo + $d segundos + + Por favor, haz click en la notificación. Si no la ves, por favor revisa las preferencias del sistema. + Mostrar notificación + ¡Estás viendo la notificación! ¡Haz click en mí! + Fallo al recibir Push. La solución puede ser el reinstalar la aplicación. + La aplicación está recibiendo PUSH + La aplicación está esperando al PUSH + Probar Push + Búsquedas en salas encriptadas todavía no están soportadas. + Filtrar usuarios excluidos + Enviar la historia de peticiones de claves compartidas + No hay más resultados + No posee permisos para iniciar una llamada + No posee permisos para iniciar una llamada en esta sala + No posee permisos para iniciar una conferencia + Resetear + \ No newline at end of file From d9ceb32e2f58634d67ccea040223c09b2985019f Mon Sep 17 00:00:00 2001 From: Danial Behzadi Date: Fri, 13 Nov 2020 15:55:56 +0000 Subject: [PATCH 25/66] Translated using Weblate (Persian) Currently translated at 98.4% (1904 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/fa/ --- vector/src/main/res/values-fa/strings.xml | 153 +++++++++++----------- 1 file changed, 79 insertions(+), 74 deletions(-) diff --git a/vector/src/main/res/values-fa/strings.xml b/vector/src/main/res/values-fa/strings.xml index 8188cbf2c6..ae3292bb2c 100644 --- a/vector/src/main/res/values-fa/strings.xml +++ b/vector/src/main/res/values-fa/strings.xml @@ -421,8 +421,8 @@ %d اتاق - %d اعلان - %d اعلان‌ها + %d آگاهی + %d آگاهی زمینه‌تان افزودن کاره‌های ماتریکس @@ -894,12 +894,12 @@ ممکن است کارساز در دسترس نبوده یا شلوغ باشد این‌جا بنویسید… - %d اعلان خوانده‌نشده - %d اعلان‌های خوانده‌نشده + %d پیام آگاهی نخوانده + %d پیام آگاهی نخوانده - %d اعلان خوانده‌نشده - %d اعلان‌های خوانده‌نشده + %d پیام آگاهی نخوانده + %d پیام آگاهی نخوانده %1$s: %2$d پیام @@ -1021,7 +1021,7 @@ ورود کلید بازیابی بازیابی پیام محاسبهٔ کلید بازیابی… - لطفاً‌یک کلید بازیابی وارد کنید + لطفاً یک کلید بازیابی وارد کنید من بودم هرگز پیام‌های رمزشده را از دست ندهید شروع با استفاده از پشتیبان کلید @@ -1100,7 +1100,7 @@ موفق! بازگشت به ورود هشدار - ایمیل خود را وارد کنید + تنظیم نشانی رایانامه رایانامه رایانامه (اختیاری) بعدی @@ -1334,8 +1334,8 @@ اطّلاعات رویداد اطّلاعات رمزنگاری سرتاسری شاخه - فعال‌کردن رمزنگاری -\n(هشدار: نمی‌تواند دوباره غیر فعال شود!) + به کار انداختن رمزنگاری. +\n(هشدار: نمی‌تواند دوباره از کار بیفتد!) رمزنگاری در این اتاق از کار افتاده است. رونوشت از نشانی اتاق رونوشت از شناسهٔ اتاق @@ -1500,9 +1500,9 @@ المنت در پس زمینه همگام‌سازی می‌کند به گونه ای که منابع محدود دستگاه (باتری) حفظ می‌شود. \nبسته به شارژ گوشی شما، ممکن است همگام‌سازی توسط سیستم‌عامل به تعویق بیوفتد. روشن کردن صفحه برای ۳ ثانیه - • محتوای پیام در اعلان‌ها نمایش داده نمی‌شوند - • اعلان ها حاوی فرا داده و محتوای پیام هستند - • محتوای پیام اعلان به طور ایمن و مستقیم از سرور هیوا دریافت می‌شود + • آگاهی‌ها محتوای پیام را نشان نخواهند داد + • آگاهی‌ها شاکل فراداده و محتوای پیام هستند + • محتوای پیام آگاهی به طور ایمن و مستقیم از کارساز خانگی ماتریکس دریافت می‌شود • اعلان ها فقط حاوی فرا داده هستند • اعلان ها از طریق سرور Firebase ارسال می شوند اگر دستگاه برای مدتی از شارژر جدا باشد و از دستگاه نیز استفاده نشود، گوشی وارد حالت غیر هوشیار می‌شود. در این حالت از دسترسی برنامه‌ها به اینترنت جلوگیری می‌شود و همگام سازی و هشدارهای استاندارد آن‌ها به تعویق می‌افتد. @@ -1543,11 +1543,11 @@ تست‌ها را اجرا کن در حال تشخیص مشکل مطمئن شوید لینک فعال‌سازی‌ای را که به ایمیل شما ارسال شده، باز کرده‌اید. - %s حذف شود؟ - شماره تلفن‌های شما - هیچ آدرس ایمیلی تا کنون به حساب کاربری شما افزوده نشده است - آدرس ایمیل‌های شما - هیچ شماره تلفنی تا کنون به اکانت شما افزوده نشده است + برداشتن %s؟ + شماره تلفن‌ها + هیچ رایانامه‌ای به حسابتان افزوده نشده + نشانی‌های رایانامه + هیچ شماره تلفنی به حسابتان افزوده نشده قابلیت جستجو در اتاق‌های رمزشده هنوز پیاده‌سازی نشده است. نتیجه‌ای در پی نداشت فیلترکردن کاربران مسدود شده @@ -1565,7 +1565,7 @@ %d مورد پرونده‌ها - اعضا + افراد اطلاعات اتاق گواهی را تنها در صورتی تایید کنید که اثر انگشت آن با اثر انگشتی که ادمین سرور ارائه کرده‌است برابر باشد. گواهی سرور تغییر کرده‌است. ممکن است این اتفاق به دلیل تمدید گواهی سرور رخ داده باشد. توصیه می‌شود از ادمین سرور سوال کنید. @@ -1585,8 +1585,8 @@ شما نمی‌توانید این تغییر را بازگردانید. زیرا در حال ارتقای سطح کاربر دیگر به سطح خودتان هستید. \nآیا مطمئن هستید؟ شما در حال دسترسی به %s هستید. آیا می خواهید به این اتاق بپیوندید؟ - این دعوت به %s ارسال شده است، که هیچ ارتباطی با اکانت شما ندارد. -\nممکن است بخواهید با اکانت دیگری وارد شوید یا این ایمیل را به اکانت خود اضافه کنید. + این دعوت به %s ارسال شده که ارتباطی با این حساب ندارد. +\nممکن است بخواهید با حسابی دیگر وارد شده یا این رایانامه را به حسابتان بیفزایید. متاسفانه به دلیل عدم دسترسی، درخواست شما امکان پذیر نمی باشد هیوا می‌تواند با دیدن دفترچه تلفن شما کاربرهای دیگر هیوا را بر اساس ایمبل و شماره تلفنشان پیدا کند. \n @@ -1648,7 +1648,7 @@ %2$s و %1$s شما تنظیم شد. \n \nآن‌ها را در جای مطمئن و امن نگهداری کنید! درصورتی که همه‌ی نشست‌های خود را از دست بدهید، به این دو جهت رمزگشایی پیام‌های رمزشده‌ی قبلی و اطلاعات امن نیاز دارید. - تنظیم پشتیبان‌گیری از کلید + برپایی پشتیبان‌گیری از کلید همگام‌سازی کلید Self Signing همگام‌سازی کلید کاربر همگام‌سازی کلید اصلی @@ -1724,9 +1724,9 @@ دسترسی به پیام‌های رمزشده را از دست خواهید داد مگر اینکه برای بازیابی کلیدهای رمزگذاری خود، به حساب خود وارد شوید. آیا تمامی اطلاعات ذخیره‌شده در این دستگاه پاک شود؟ \nبرای دسترسی به اطلاعات و پیام‌های حساب خود، دوباره وارد شوید. - هشدار: اطلاعات شخصی شما (شامل کلید‌های رمزنگاری) همچنان روی این دستگاه ذخیره شده‌اند. + هشدار: داده‌های شخصیتان (شامل کلید‌های رمزنگاری) همچنان روی این افزاره ذخیره شده‌اند. \n -\nاگر نمی‌خواهید از این دستگاه استفاده کنید، یا می‌خواهید با اکانت دیگری وارد شوید، این اطلاعات را حذف کنید. +\nاگر کارتان با این افزاره تمام شده یا می‌خواهید به حساب دیگری وارد شوید، پاکشان کنید. برای بازیابی کلیدهای رمزگذاری ذخیره شده در این دستگاه، وارد حساب خود شوید. شما برای خواندن همه پیام‌های رمزشده‌ی خود در هر دستگاهی به این کلید‌ها نیاز دارید. ادمین سرور (%1$s) شما را از حسابتان خارج کرده‌است %2$s (%3$s). این می تواند به دلایل مختلف باشد: @@ -1888,7 +1888,7 @@ توضیح در مورد اتاق (اختیاری) نام اتاق پیام پاک شد - به نظر می‌رسد که شما در حال تلاش برای اتصال به یک سرور دیگر هستید. آیا می خواهید از اکانت خود خارج شوید؟ + به نظر می‌رسد تلاش می‌کنید تا به کارساز خانگی دیگری وصل شوید. می‌خواهید خارج شوید؟ برای بازنشانی گذرواژه‌ی خود نیاز به پیکربندی سرور هویت‌سنجی دارید. شما از سرور هویت‌سنجی استفاده نمی‌کنید خطای نامشخص @@ -1899,30 +1899,30 @@ SAS تطابق نداشت Hash تطابق نداشت نشست نمی تواند در مورد روش‌های فرآیند تائید: hash ، MAC یا روش SAS به توافق برسد - نشست از آن تعامل اطلاعی ندارد - زمان فرآیند تائید به پایان رسید - کاربر فرآیند تائید را لغو کرد - %s می‌خواهد نشست شما را تائید کند - درخواست فرآیند تائید - تائید تعاملی نشست - فرآیند تائید لغو شد. + نشست، اطّلاعی از آن تعامل ندارد + زمان فرایند تأیید به پایان رسید + کاربر تأیید را لغو کرد + %s می‌خواهد نشستتان را تأیید کند + درخواست تأیید + تأیید تعاملی نشست + تأیید لغو شد. \nدلیل: %s - طرف مقابل فرآیند تائید را لغو کرد. + طرف مقابل تأیید را لغو کرد. \n%s - از روش قدیمی برای فرآیند تائید استفاده کنید. - چیزی نمایش داده نشده‌است؟ هنوز تمام کلاینت‌ها از امکان تائید به روش تعاملی پشتیبانی نمی‌کنند. از تائید به روش قدیمی استفاده کنید. - شما با موفقیت این نشست را تائید کردید. - منتظر تائید طرف مقابل… - شما یک درخواست فرآیند تأئید داخلی دریافت کرده اید. - این نشست را با تصدیق اعداد زیر که روی صفحه‌ی طرف مقابل نیز ظاهر شده‌است، تائید کنید - با تأئید یکسان بودن شکلک‌های زیر در صفحه طرف مقابل، این نشست را تأئید کنید - با تأئید این نشست، آن را به عنوان معتمد علامت‌گذاری می‌کنیم و همچنین نشست خود را به عنوان معتمد برای طرف مقابل علامت‌گذاری می کنیم. - فرآیند تائید کلید + استفاده از تأیید قدیمی. + چیزی ظاهر نمی‌شود؟ هنوز تمامی کارخواه‌ها از تأیید تعاملی پشتیبانی نمی‌کنند. از تأیید قدیمی استفاده کنید. + این نشست را با موفّقیت تأیید کردید. + منتظر تأیید طرف مقابل… + درخواست تأییدی دریافت کردید. + با تأیید ظاهر شدن عددهای زیر روی صفحهٔ طرف مقابل، این نشست را تأیید کنید + با تأیید ظاهر شدن شکلک‌های زیر روی صفحهٔ طرف مقابل، این نشست را تأیید کنید + تأیید این نشست، آن را برای خودتان و طرف مقابل، به عنوان مطمئن علامت خواهد زد. + تأیید کلید نمایش درخواست درخواست لغو شد فهمیدم - محتوای گفتگوی امن شما با این کاربر رمزنگاری سرتاسر شده و امکان دسترسی به آن‌ها توسط فرد سومی مقدور نیست. - نشست تائید شد! + پیام‌های امن با این کاربر به صورت سرتاسری رمزنگاری شده و قابل خوانده شدن به دست دیگران نیست. + تأییدشده! این نشست را تأیید کنید تا به عنوان معتمد علامت‌گذاری شود. اعتماد به نشست‌ها هنگام استفاده از پیام های رمزشده به صورت سرتاسر ، به شما اطمینان بیشتری از امنیت گفتگو‌ها می‌دهد. درخواست فرآیند تأیید داخلی شروع فرآیند تایید کردن @@ -1975,17 +1975,17 @@ پشتیبان با %d کلید بازیابی شد. پشتیبان با %d کلید بازیابی شد. - رمزگشایی با این کلید بازیابی امکان‌پذیر نیست: لطفاً بررسی کنید که کلید بازیابی را به درستی وارد کرده‌اید. - رمزگشایی پیام‌های قبلی - بارگذاری کلید‌ها… - در حال دریافت کلید‌های بازیابی… - بازیابی نسخه پشتیبان: + پشتیبان نتپانست با این کلید بازیابی رمزگشایی شود: لطفاً تأیید کنید که کلید بازیابی درستی را وارد کرده‌اید. + قفل‌گشایی تاریخچه + بارگذاری کردن کلید‌ها… + بارگیری کردن کلید‌ها… + بازیابی پشتیبان: خطای شبکه: لطفاً اتصال خود را بررسی کنید و دوباره امتحان کنید. رمزگشایی با این کلید امنیتی امکان‌پذیر نیست: لطفاً بررسی کنید که کلید امنیتی را به درستی وارد کرده‌اید. کلید بازیابی خود را گم کرده‌اید؟ می‌توانید کلید جدیدی را در تنظیمات تنظیم کنید. از کلید بازیابی برای رمزگشایی پیام‌های رمزشده‌ی قبلی خود استفاده کنید کلید امنیتی خود را نمی‌دانید؟ شما می‌توانید %s. - از کلید امنیتی برای رمزگشایی پیام‌های رمزشده‌ی قبلی خود استفاده کنید + برای قفل‌گشایی تاریخچهٔ پیام‌های رمزشده‌تان از عبارت عبور بازیابیتان استفاده کنید اگر از دستگاه خارج شوید یا دستگاه خود را از دست دهید، ممکن است امکان دسترسی به پیام های خود را نداشته باشید. کلیدهای رمزگذاری شما اکنون در پس زمینه در حال پشتیبان‌گیری بر روی سرور است. تهیه نسخه‌ی پشتیبان اولیه ممکن است چند دقیقه طول بکشد. در حال تولید کلید پشتیبان با استفاده از کلید امنیتی، این ممکن است چند ثانیه زمان ببرد. @@ -2003,17 +2003,17 @@ ما یک نسخه رمزگذاری شده از کلیدهای شما را در سرور ذخیره خواهیم کرد. با استفاده از کلید امنیتی قوی، از نسخه‌ی پشتیبان خود محافظت کنید. \n \nبرای حداکثر امنیت، کلید امنیتی باید با رمز ورود حساب شما متفاوت باشد. - پیام‌های موجود در اتاق های رمزگذاری شده به صورت سرتاسری رمز و ایمن می‌شوند. کلیدهای این پیام‌ها فقط در دسترس شما و گیرنده‌(ها) می‌باشد. + پیام‌‌ها در اتاق‌های رمزشده، با رمزنگاری سرتاسری امن شده‌اند. فقط شما و گیرنده(ها) کلیدهای خواندم این پیام‌ها را دارید. \n -\nبرای جلوگیری از از دست دادن کلیدهای خود به طور ایمن از آنها پشتیبان تهیه کنید. +\nبرای جلوگیری از گم کردن کلیدهایتان، از آن‌ها به صورت امن، پشتیبان بگیرید. هیچ نشست ماتریکسی موجود نیست - اگر می خواهید المنت یک کلید بازیابی ایجاد کند، لطفاً کلید امنیتی را حذف کنید. - کلید امنیتی بسیار ضعیف است - لطفا کلید امنیتی را وارد کنید - کلید امنیتی یکسان نبود - ورود کلید امنیتی - تائید کلید امنیتی - ایجاد کلید امنیتی + اگر می خواهید المنت یک کلید بازیابی ایجاد کند، لطفاً عبارت عبور را حذف کنید. + عبارت عبور بیش از حد ضعیف است + لطفاً عبارت عبوری وارد کنید + عبارت عبور، مطابق نبود + ورود عبارت عبور + تأیید عبارت عبور + ایجاد عبارت عبور APK معتبر Google Play Services پیدا نشد. اعلان‌ها ممکن است به درستی کار نکنند. %d+ +%d @@ -2048,12 +2048,12 @@ فعال و غیرفعال کردن markdown نام مستعار شما را تغییر می‌دهد اخراج کاربر با شناسه داده شده - بیشتر درباره‌ی اتاق توضیح دهید + تنظیم موضوع اتاق ترک اتاق با نام مستعار داده‌شده به اتاق بپیوندید کاربر با شناسه داده شده را به این اتاق دعوت می کند کاربر با شناسه داده شده را غیر‌فعال می‌کند - سطح اختیارات و دسترسی کاربر را مشخص می‌کند + سطح قدرت کاربر را تعریف می‌کند کاربر با شناسه داده شده را رفع مسدودیت می کند کاربر با شناسه داده شده را مسدود می کند نمایش اقدام @@ -2061,10 +2061,10 @@ دستور ناشناخته: %s خطا در اجرای دستور قابلیت همایش تصویری در حال توسعه بوده و ممکن است به درستی کار نکند. - یک نشست تایید نشده، درخواست کلید‌های رمزنگاری را دارد. + یک نشست تایید نشده، کلید‌های رمزنگاری را درخواست می‌کند. \nنام نشست: %1$s \nآخرین بازدید: %2$s -\nاگر در دستگاه دیگری وارد اکانت خود نشده‌اید این درخواست را نادیده بگیرید. +\nاگر به نشست دیگری وارد نشده‌اید، این درخواست را نادیده بگیرید. نشست تایید نشده‌ی شما \\\'%s\\\' درخواست کلید‌های رمزنگاری را دارد. نشست جدید درخواست دریافت کلید‌های رمزنگاری را دارد. \nنام نشست: %1$s @@ -2080,7 +2080,7 @@ %d دعوت %d دعوت - آدرس سرور + نشانی کارساز خانگی این اتاق شامل نشست‌های تایید نشده هستند. \nهیچ تضمینی وجود ندارد این نشست‌های تائیدنشده متعلق به کاربرانی باشد که فکر می‌کنید. \nتوضیه می‌شود افراد نشست‌های خود را تائید کنند. هر چند در صورتی که تمایلی به این کار ندارید، همچنان می‌توانید پیام ارسال کنید. @@ -2105,27 +2105,27 @@ این اتاق در هیچ اجتماع خاصی قرار نگرفته‌است هر کسی که لینک اتاق را دارد ( حتی اگر کاربر مهمان باشد) هر کسی که لینک اتاق را دارد (به جز کاربران مهمان‌) - تنها افرادی که دعوت شده‌اند - برای لینک دادن به یک اتاق، آن اتاق باید آدرس داشته باشد. + تنها کسانی که دعوت شده‌اند + برای پیوند به یک اتاق، باید نشانی داشته باشد. اجتماع - پخش صدای شاتر دوربین - انتخاب کنید - منبع پیش‌فرض رسانه - انتخاب کنید + پخش صدای شاتر + گزینش + منبع رسانهٔ پیش‌گزیده + گزینش فشرده سازی پیش‌فرض رسانه اطلاعات اضافه: %s خطایی هنگام تایید شماره تلفن رخ داده است. - کد + رمز خطایی هنگام تایید شماره تلفن رخ داده است - کد فعال‌سازی را وارد کنید + رمز فعّال‌سازی‌ای را وارد کنید ما یک پیام کوتاه با کد فعال‌سازی ارسال کرده‌ایم. لطفاً این کد را در زیر وارد کنید. تایید شماره تلفن شماره تلفن نامعتبر برای کشور مورد نظر شماره تلفن - لطفا یک کشور را انتخاب نمائید + لطفاً کشوری را برگزینید کشور - انتخاب کشور + گزینش یک کشور آیا از حذف %1$s %2$s مطمئن هستید؟ خطایی در هنگام تایید ایمیل شما رخ داده است. این شماره تلفن قبلا استفاده شده‌است. @@ -2154,4 +2154,9 @@ ارسال داده های تجزیه و تحلیل تجزیه و تحلیل مجوز دادن + تخصیص شکست خورد. + قطع اتّصال از کارساز هویت %s؟ + پیام مستقیم + ارسال تاریخچهٔ درخواست‌های هم‌رسانی کلید + نتایج بیش‌تری نیست \ No newline at end of file From 71a70ffafa579da8513f7f8cc31b7a8650158e33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20FERREIRA=20DE=20SOUSA?= Date: Fri, 13 Nov 2020 16:31:06 +0000 Subject: [PATCH 26/66] Translated using Weblate (French) Currently translated at 100.0% (1933 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/fr/ --- vector/src/main/res/values-fr/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/vector/src/main/res/values-fr/strings.xml b/vector/src/main/res/values-fr/strings.xml index e4ec77068c..26b09f1f2c 100644 --- a/vector/src/main/res/values-fr/strings.xml +++ b/vector/src/main/res/values-fr/strings.xml @@ -2198,4 +2198,5 @@ Message direct Inclure l\'historique d\'échange de clés Plus aucun résultat + Exporter le rapport d\'audit \ No newline at end of file From 8e7d5ddfd491c15bc5b546993c7cedfb2ba668d4 Mon Sep 17 00:00:00 2001 From: XoseM Date: Sat, 14 Nov 2020 06:27:19 +0000 Subject: [PATCH 27/66] Translated using Weblate (Galician) Currently translated at 27.3% (529 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/gl/ --- vector/src/main/res/values-gl/strings.xml | 174 +++++----------------- 1 file changed, 35 insertions(+), 139 deletions(-) diff --git a/vector/src/main/res/values-gl/strings.xml b/vector/src/main/res/values-gl/strings.xml index 6ef0b9437d..45a6091093 100644 --- a/vector/src/main/res/values-gl/strings.xml +++ b/vector/src/main/res/values-gl/strings.xml @@ -1,16 +1,13 @@ - + gl ES - Tema claro Tema escuro Tema negro - - Sincronizando + Sincronizando… Notificacións con son Notificacións silenciosas - Mensaxes Sala Configuración @@ -18,9 +15,7 @@ Histórico Informar de erros Detalles da comunidade - Cargando… - Aceptar Cancelar Gardar @@ -40,7 +35,8 @@ A escoita de eventos Adiante Informar sobre contido - Conferencia en curso.\nÚnase con %1$s ou %2$s. + Conferencia en curso. +\nÚnete con %1$s ou %2$s voz vídeo Non se pode iniciar a chamada, inténteo máis tarde @@ -53,7 +49,6 @@ ou Convidar Fóra de liña - Saír Accións Saír @@ -67,53 +62,43 @@ Pechar Copiado ao portaretallos Desactivar - Confirmación Aviso - Inicio Favoritas Xente Salas Comunidades - Buscar salas Buscar favoritas Buscar a xente Buscar salas Buscar comunidades - Convites Baixa prioridade - Conversas Axenda de enderezos local Directorio de usuario Só contactos Matrix Sen conversas - "Non lle permitiu acceder aos contactos locais a Element " + Non lle permitiches a Element acceder ós contactos locais Sen resultados - Salas Directorio de salas Sen salas Sen salas públicas accesibles Enviar unha icona - Licenzas de terceiras partes - Descargar Falar Limpar - 1 usuario - %d usuarios + 1 usuaria + %d usuarias - Convidar Comunidades Sen grupos - Enviar informes Enviar informes de fallos Enviar captura de pantalla @@ -126,10 +111,8 @@ Enviouse o informe de erros correctamente Houbo un problema enviando o informe de erros (%s) Progreso (%s%%) - Enviar a Ler - Unirse a sala Nome de usuario Rexistrar @@ -138,25 +121,20 @@ URL do servidor local URL do servidor de identidade Buscar - Iniciar conversa Iniciar chamada de voz Iniciar videochamada - Seguro que quere comezar a conversar con %s? Seguro que quere comezar unha chamada de audio? Seguro que quere comezar unha chamada de vídeo? - Enviar ficheiros Enviar iconas Sacar unha foto ou vídeo Sacar foto Sacar vídeo - - Non ten ningún paquete de iconas activado. - -Quere engadir algún? - + Non tes paquetes de pegatinas activados. +\n +\nQueres engadir algún\? Acceder Rexistrarse Enviar @@ -187,9 +165,9 @@ Quere engadir algún? Esqueceu o contrasinal? Usar configuracións de servidor personalizadas (avanzado) Comprobe o seu correo para continuar co rexistro - O rexistro tanto co correo como co número non se acepta dentro desta api. Só se vai a ter en conta o número de teléfono. - -Pode engadir a dirección de correo na sección de configuración de perfil. + O rexistro simultáneo co email e o número de teléfono non está soportado ata que o api exista. Só se terá en conta o número de teléfono. +\n +\nPoderás engadir o teu email ó perfil nos axustes. Este servidor local quere asegurarse de que non é un robot Nome de usuario empregado Servidor local: @@ -200,22 +178,16 @@ Pode engadir a dirección de correo na sección de configuración de perfil.Debe introducir un novo contrasinal. Fallo na verificación do enderezo de correo: asegúrese de ter picado na ligazón do correo Petición de chave enviada. - Enviar como Onte Hoxe - Chamar Continuar - Eliminar Rexeitar - Ir á primeira mensaxe non lida. - Deixar a sala Crear - En liña Fóra de liña En pausa @@ -235,13 +207,11 @@ Pode engadir a dirección de correo na sección de configuración de perfil.Non ten permiso para comentar nesta sala 1 mensaxe nova - %d mensaxe nova + %d mensaxes novas - Confiar Desconectar Ignorar - Xente Ficheiros Configuracións @@ -252,14 +222,12 @@ Pode engadir a dirección de correo na sección de configuración de perfil.MENSAXES XENTE FICHEIROS - Convites Iniciar conversa Crear sala Unirse á sala Unirse á sala Buscando cartafol… - Todas as mensaxes (alto) Todas as mensaxes Só mencións @@ -274,20 +242,17 @@ Pode engadir a dirección de correo na sección de configuración de perfil.Versión Copyright Política de privacidade - Correo electrónico Engadir enderezo correo electrónico Teléfono Engada número de teléfono Activar notificacións para esta conta Mensaxes enviadas por bot - Versión versións anteriores Limpar o caché Limpar o caché de imaxes Manter as imaxes - Configuracións dos usuarios Notificacións Outro @@ -296,14 +261,12 @@ Pode engadir a dirección de correo na sección de configuración de perfil.Dispositivos Activar por defecto as vistas previas en liña de URL Mostrar sempre marcas de tempo - "Mostrar marcas de tempo con formato 12 horas (ex. 2:30pm)" + Mostrar marcas de tempo con formato 12-horas Desactivar a miña conta - Analytics Enviar datos de análises Element recolle información analítica anónima para permitirnos mellorar o aplicativo. - Si, quero axuda - + Si, quero axudar! ID Nome Nome do dispositivo @@ -312,55 +275,42 @@ Pode engadir a dirección de correo na sección de configuración de perfil.Autenticación Contrasinal: Enviar - Idioma da Interface Verificación pendente Comprobe o seu correo electrónico e pulse na ligazón que contén. Unha vez feito iso prema continuar. - Xa se está a usar este correo - Xa se está a usar este teléfono - + Xa se está a usar este correo. + Xa se está a usar este teléfono. novo contrasinal confirmar o contrasinal Escolla un país - País Número de teléfono Verificación do teléfono Código - - Aura - 3 días 1 semana 1 mes Para sempre - Foto da sala Nome da sala Asunto Etiqueta de sala Marcado como: - Favorita Prioridade baixa Ningún - Notificacións Quen pode ler o histórico? Quen pode acceder a esta sala? - Calquera Só membros (desde o momento en que se selecciona esta opción) Só membros (desde que foron convidados) Só membros (desde que se uniron) - Só persoas que foron convidadas Calquera que coñeza o enderezo da sala, aparte das convidadas Calquera que coñeza a ligazón a sala, incluíndo as convidadas - Usuarios excluídos - Avanzado Enderezos Labs @@ -369,12 +319,9 @@ Pode engadir a dirección de correo na sección de configuración de perfil.Formato de alias non válido Copiar a ID da sala Copiar a dirección da sala - Directorio Tema - Información do cifrado extremo-a-extremo - Información do evento ID de usuario Chave de identidade Curve25519 @@ -382,15 +329,13 @@ Pode engadir a dirección de correo na sección de configuración de perfil.Algoritmo ID de sesión Fallo ao descifrar - Información do dispositivo do remitente Nome do dispositivo Nome - ID de dispositivo + ID de sesión Chave do dispositivo Validación pegada Ed25519 - Exportar chaves E2E da sala Exportar chaves da sala Exportar @@ -399,49 +344,40 @@ Pode engadir a dirección de correo na sección de configuración de perfil.Importar chaves E2E da sala Importar chaves de sala Importar - Nunca enviar mensaxes cifradas aos dispositivos que non estean verificados neste dispositivo - + Non enviar mensaxes cifradas desde esta sesión a sesións non verificadas. SEN Verificar Verificados Omitidos - dispositivo descoñecido ningún - Verificar Retirar verificación Por na lista negra Quitar da lista negra - Verificar dispositivo Certifico que coinciden as chaves - A sala contén dispositivos descoñecidos Escoller unha sala principal O servidor podería non estar dispoñible ou sobrecargado Escriba un servidor local para saber cales son todas súas as salas públicas URL do servidor local - "Todas as salas do servidor %s " + Todas as salas do servidor %s Todas as salas de %s nativas - Escriba aquí… - - 1 notificación sen ler + %d notificación sen ler %d notificacións sen ler - 1 notificación sen ler + %d notificación sen ler %d notificacións sen ler - 1 sala + %d sala %d salas %1$s en %2$s - Buscar no histórico - Tamaño da letra Anana Pequena @@ -450,13 +386,11 @@ Pode engadir a dirección de correo na sección de configuración de perfil.Máis grande Aínda máis grande Enorme - Fallou a creación do trebello - 1 trebello activo - %d trebellos activos + %d widget activo + %d widgets activos - Non se puido crear o trebello. Fallo ao enviar a petición. O nivel de poder ten que ser un enteiro positivo. @@ -469,63 +403,47 @@ Pode engadir a dirección de correo na sección de configuración de perfil.Hai un parámetro que non é válido. Engadir aplicacións de Matrix Usar a cámara nativa - Iniciar verificación Compartir sen verificar Ignorar petición - Aviso! As chamadas de reunión poderían non ser totalmente estables xa que están en desenvolvemento. - Erro na orde Comandos que non se recoñecen: %s - Off Ruidoso - Mensaxe cifrada - Crear Crear comunidade Nome da comunidade Exemplo ID da comunidade exemplo - Inicio Xente Salas Sen usuarios - Salas Uniuse Convidada Filtrar os membros do grupo Filtrar as salas dos grupos - O administrador da comunidade non fixo unha descrición longa desta comunidade. - Foi expulsado de %1$s por %2$s Foi bloqueado de %1$s por %2$s Motivo: %1$s Volver a unirse Esquecer sala - Avatar de recepción Avatar de aviso Avatar - Revisar agora - Desactivar conta Para continuar introduza o seu contrasinal: Desactivar conta - Enviar voz - continuar con… Non se atopou unha aplicación que poida completar iso. - Enviouse un correo a %s. Unha vez abra a ligazón que contén prema abaixo. A URL ten que comezar con http[s]:// Non se puido acceder: erro da rede @@ -534,51 +452,40 @@ Pode engadir a dirección de correo na sección de configuración de perfil.Non se puido rexistrar Non se puido rexistrar: erro coa propiedade do correo electrónico Introduza unha URL válida - Usuario/contrasinal incorrecto JSON con defectos Non contiña unha JSON correcta Enviáronse demasiadas peticións Este nome de usuario xa se está a usar Unha ligazón de correo na que aínda non se premeu - Volver a pedir as chaves de cifrado do outro dispositivo seu. - Petición enviada Inicie Element noutro dispositivo que poida descifrar esta mensaxe e que despois desde alí lle poida enviar as chaves a este dispositivo. - - 1 cambio de membros - %d cambio de membros + 1 cambio de participantes + %d cambios de participantes - Autor Inicial Mediano Pequeno - Cancelar a descarga? Cancelar a subida? %d s %1$dm %2$ds - Nome da sala Tema da sala - Chamada establecida Chamada finalizada Chamando… Chamada entrante Videochamada entrante Chamada de audio entrante - Chamada en activo - + Chamada activa… Fallou a conexión desde o outro lado. Non se deu iniciado a cámara chamara respondida noutro lugar - Saque unha foto ou video Non foi posible gravar vídeo - Información Gardado Gardar nas descargas? @@ -586,11 +493,10 @@ Pode engadir a dirección de correo na sección de configuración de perfil.NON Unirse Vista previa - O convite envióuselle a %s, mais non é alguén que estea asociado con esta conta. -Seguramente queira conectarse cunha conta distinta, ou engadir este correo a súa conta. + Este convite enviouse a %s, que non está asociada a esta conta. +\nPodes conectarte cunha conta diferente, ou engadir este email á túa conta. unha sala Esta é unha vista previa desta sala. Desactiváronse as interaccións coa sala. - Nova conversa Engadir membro @@ -598,14 +504,12 @@ Seguramente queira conectarse cunha conta distinta, ou engadir este correo a sú %d participantes activos - 1 membro - %d membros + 1 participante + %d participantes 1 membro - Chamar DISPOSITIVOS - Deixar a sala Borrar desta sala Mensaxes non enviadas. %1$s ou %2$s agora? @@ -613,10 +517,8 @@ Seguramente queira conectarse cunha conta distinta, ou engadir este correo a sú Pegada (%s): CONVIDADO UNIUSE - Cancelar a subida Cancelar a descarga - UNIRSE DIRECTORIO FAVORITOS @@ -636,7 +538,6 @@ Seguramente queira conectarse cunha conta distinta, ou engadir este correo a sú • O contido da mensaxe das notificacións está provén dun xeito seguro e directo do servidor local de Matrix • As notificacións conteñen metadatos e os datos da mensaxe • As notificacións non van a mostrar o contido da mensaxe - Son das notificacións Activar notificacións para este dispositivo Petición de sincronización esgotada @@ -651,22 +552,17 @@ Seguramente queira conectarse cunha conta distinta, ou engadir este correo a sú Element pode estar agochado e seguir traballando na xestión das notificacións dun xeito seguro e privado (inda que iso podería afectar ao uso da batería). Outorgar permisos Escolla outra opción - Accedeuse como Servidor de identidade - Seguro que quere eliminar este tipo de notificacións? - O ID interno desta sala é Precisa saír da aplicación primeiro para poder activar o cifrado. Nunca enviar mensaxes cifradas aos dispositivos que non estean verificados nesta sala desde este dispositivo. - O cifrado está activado nesta sala. - " Para verificar que se pode confiar neste dispositivo, contacte co seu dono utilizando algún outro medio (ex. en persoa ou chamada de teléfono) e pregúntelle se a clave que ven nos axustes de usuario do se dispositivo coincide coa clave inferior:" + Comfirma comparando o seguinte cos Axustes de Usuaria na túa outra sesión: Engadiu un novo dispositivo «%s» que está a solicitar as chaves de cifrado. O seu dispositivo sen verificar «%s» está solicitando as chaves de cifrado. Para continuar usando o servidor %1$s ten que revisar primeiro os seus termos e condicións. Esquezan todas as mensaxes que eu enviara no momento en que elimine a miña conta. (Aviso: iso suporá que os seguintes participantes só verán unha versión incompleta das conversas.) Introduza o seu contrasinal. - - + \ No newline at end of file From daf1362d28dc5477fce4b8415228444772469744 Mon Sep 17 00:00:00 2001 From: notramo Date: Thu, 12 Nov 2020 19:12:47 +0000 Subject: [PATCH 28/66] Translated using Weblate (Hungarian) Currently translated at 94.9% (1835 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/hu/ --- vector/src/main/res/values-hu/strings.xml | 68 +++++++++++------------ 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/vector/src/main/res/values-hu/strings.xml b/vector/src/main/res/values-hu/strings.xml index 2b1247d7e3..60171a30d1 100644 --- a/vector/src/main/res/values-hu/strings.xml +++ b/vector/src/main/res/values-hu/strings.xml @@ -188,7 +188,7 @@ A hívott fél nem vette fel. Médiacsatlakozás sikertelen A kamera nem készíthető elő - a hívást máshol vették fel + a hívás más eszközön lett felvéve Kép vagy videó készítése Videorögzítés sikertelen Információ @@ -206,8 +206,8 @@ A Elementnek engedélyre van szüksége a mikrofonod és kamerád eléréséhez, hogy videohívást tudj indítani. \n \nEngedélyezd a hozzáférést a következő felugró ablakon, hogy hívást tudj indítani. - A Element a névjegyekben lévő e-mail és telefonszám alapján képes felkutatni más Matrix felhasználókar. Ha egyetértesz a névjegyek ilyen célú megosztásával, kérlek engedélyezd a hozzáférést a következő felugró üzenetben. - A Element a névjegyekben lévő e-mail és telefonszám alapján képes felkutatni más Matrix felhasználókar. + A Element a névjegyekben lévő e-mail és telefonszám alapján képes felkutatni más Matrix felhasználókat. Ha egyetértesz a névjegyek ilyen célú megosztásával, kérlek engedélyezd a hozzáférést a következő felugró üzenetben. + A Element a névjegyekben lévő e-mail és telefonszám alapján képes felkutatni más Matrix felhasználókat. \n \nEgyetértesz a névjegyek ilyen célú megosztásával\? "Elnézést. A művelet nem lett végre hajtva hiányzó engedélyek miatt" @@ -505,7 +505,7 @@ Figyelmeztetés: ez a fájl törlésre kerülhet, ha az alkalmazást törli.Eltávolítás feketelistáról Munkamenet hitelesítése Hogy ellenőrizni lehessen, hogy ez a munkamenet megbízható, kérlek használj más kommunikáció módot a tulajdonossal (pl.: személyesen vagy telefonon keresztül) és kérdezd meg hogy a kulcs amit lát a Felhasználói Beállítások alatt megegyezik-e az alábbi kulccsal: - Ha egyezik, nyomja meg a hitelesítés gombot. Ha nem, akkor valaki más elfogta ezt a munkamenetet és érdemes lenne tiltólistára tenni. A jövőben ez a hitelesítési mód kényelmesebbé lesz téve. + Ha nem egyeznek, akkor a kommunikáció biztonsága kompromittálva lehet. A jövőben ez a hitelesítési mód kényelmesebbé lesz téve. Hitelesítem, hogy a kulcsok egyeznek Szoba ismeretlen munkameneteket tartalmaz Ez a szoba ismeretlen munkameneteket tartalmaz. @@ -515,7 +515,7 @@ Figyelmeztetés: ez a fájl törlésre kerülhet, ha az alkalmazást törli. Válassz egy szoba könyvtárat A szerver lehet nem elérhető vagy túltöltött - Írj be egy Matrix szervert hogy listázza belőle a nyilvános szobákat + Írj be egy Matrix szervert, az ott található nyilvános szobák listázásához Matrix szerver URL Összes szoba a %s szerveren Összes anyanyelvi %s szoba @@ -763,7 +763,7 @@ Matrixban az üzenetek láthatósága hasonlít az e-mailre. Az üzenet törlés Matrix-kisalkalmazás-token törlése Ez a szoba le lett cserélve és már nem aktív A beszélgetés itt folytatódik - Ez a szoba a folytatása egy másik beszélgetésnek + Ez a szoba egy másik beszélgetés folytatása Régebbi üzenetek megjelenítéséhez kattints ide A műveletet a hiányzó engedélyek miatt nem lehet végrehajtani. @@ -803,7 +803,7 @@ Matrixban az üzenetek láthatósága hasonlít az e-mailre. Az üzenet törlés Erőforrás korlát túllépve Kapcsolatfelvétel az adminisztrátorral vedd fel a kapcsolatot a szolgáltatás adminisztrátorával - Ez a Matrix szerver túllépte valamely erőforrás korlátot így néhány felhasználó nem tud bejelentkezni. + Ez a Matrix szerver túllépte valamely erőforrás korlátot így néhány felhasználó nem tud majd bejelentkezni. Ez a Matrix szerver túllépte egyik erőforrás korlátját. Ez a Matrix szerver elérte a havi aktív felhasználói korlátját így néhány felhasználó nem tud bejelentkezni. Ez a Matrix szerver elérte a havi aktív felhasználói korlátját. @@ -963,9 +963,9 @@ Helyezd biztonságba a kulcsokat, hogy ne vesszenek el. A Visszaállítási Kulcs ide lett mentve: \'%s\'. Figyelmeztetés: ez a fájl törlésre kerülhet, ha az alkalmazást törlik. - Kérlek készíts egy másolatot + Kérlek, készíts egy másolatot! Visszaállítási Kulcs megosztása… - Visszaállítási Kulcs készítése jelmondatból, ez néhány másodpercet is igénybe vehet. + Visszaállítási Kulcs készítése jelmondatból, ez néhány másodpercet igénybe vehet. Visszaállítási Kulcs Váratlan hiba Mentés elkezdődött @@ -1032,9 +1032,9 @@ Figyelmeztetés: ez a fájl törlésre kerülhet, ha az alkalmazást törlik.(Haladó) Kulcsok kimentése kézzel Védd a mentésedet jelmondattal. - "A kulcsaid másolatait titkosítva a Matrix szerverünkön fogjuk tárolni. Védd a mentést jelszóval a biztonság érdekében. - -A maximális biztonság eléréséhez, használja más jelmondatot mint amit a felhasználói fiókhoz használtál." + A kulcsaid másolatait titkosítva a Matrix szervereden fogjuk tárolni. Védd jelszóval a mentést, a biztonság érdekében. +\n +\nA maximális biztonság eléréséhez, használj más jelszót, mint amit a bejelentkezéshez használtál. Mentés készítése Vagy védd a mentésedet egy Visszaállítási Kulccsal amit tárolj biztonságos helyen. (Haladó) Beállítás Visszaállítási Kulccsal @@ -1043,7 +1043,7 @@ A maximális biztonság eléréséhez, használja más jelmondatot mint amit a f A Visszaállítási Kulcs egy biztosíték amit használhatsz a titkosított üzenet hozzáférések visszaállítására, ha a jelmondatot elfelejtetted. A Visszaállítási Kulcsot tartsd biztonságos helyen, mint pl. egy jelszókezelő (vagy széf) A Visszaállítási Kulcsot tartsd biztonságos helyen, mint pl. egy jelszókezelő (vagy széf) - Készítettem másolatot + Készítettem egy másolatot Megosztás Soha ne veszíts el titkosított üzenetet Kulcs Mentés használatának megkezdése @@ -1127,7 +1127,7 @@ Ha nem te állítottad be a visszaállítási metódust, akkor egy támadó pró Ellenőrzési kérés érkezett Munkamenet ellenőrzése és beállítás megbízhatónak. A partnerek munkameneteiben való megbízás megnyugtató lehet, ha végponttól végpontig titkosítást használsz. A munkamenet ellenőrzése megbízhatónak fogja jelezni az eszközt és a partnernél a te munkamenetedet szintén megbízhatónak fogja jelezni. - Munkamenet ellenőrzése az alábbi emodzsik a partner képernyőjén való megjelenésének megerősítésével történik + Munkamenet ellenőrzése azáltal, hogy összehasonlítjátok, hogy a másik felhasználó képernyőjén is ugyan azok az emojik jelennek-e meg. Munkamenet ellenőrzése az alábbi számok a partner képernyőjén való megjelenésének megerősítésével történik Bejövő ellenőrzési kérés érkezett. Kérés megjelenítése @@ -1307,7 +1307,7 @@ Ha nem te állítottad be a visszaállítási metódust, akkor egy támadó pró A munkamenet nyilvános neve látható azoknál akikkel beszélgetsz Nem használsz Azonosítási Szervert Nincs beállítva azonosítási szerver amire a jelszó visszaállításához szükség van. - Úgy látszik másik matrix szerverhez szeretnél csatlakozni. Kijelentkezel\? + Úgy tűnik, másik Matrix szerverhez szeretnél csatlakozni. Ki szeretnél jelentkezni\? Azonosítási szerver Azonosítási szerverről lecsatlakozás Azonosítási szerver beállítása @@ -1430,18 +1430,18 @@ Ha nem te állítottad be a visszaállítási metódust, akkor egy támadó pró %1$s hozzáférhetővé tette a szobát bárkinek, aki ismeri a linket. %1$s beállította, hogy a szobába csak meghívóval lehessen belépni. Olvasatlan üzenetek - Szabadítsd fel a kommunikációdat. + A te beszélgetésed. Vedd birtokba! Beszélgess másokkal közvetlenül vagy csoportosan Beszélgess bizalmasan, titkosítást használva Bővítsd és szabd testre a élményt Kezdj neki Válassz szervert Hasonlóan az e-mailhez, egy fiókod van, de bárkivel tudsz beszélgetni - Milliók csatlakoznak ingyen a legnagyobb nyilvános szerveren - Prémium üzemeltetés szervezetek részére + Csatlakozz a milliónyi felhasználóhoz a legnagyobb nyilvános szerveren + Prémium szerver üzemeltetés szervezetek részére Tudj meg többet - Más - Személyre szabott szerver cím beállítása + Egyéni + Másik szerver cím megadása Folytatás Csatlakozás ide: %1$s Csatlakozás Element Matrix Services hoz @@ -1452,7 +1452,7 @@ Ha nem te állítottad be a visszaállítási metódust, akkor egy támadó pró SSO-val való folytatás Element Matrix Services Cím Cím - Prémium üzemeltetés szervezetek részére + Prémium szerverüzemeltetés szervezetek részére Add meg az általad használt Modular szerver, vagy a hozzá tartozó Element címét Add meg a szerver vagy Element címét amihez csatlakozni szeretnél Az oldal betöltésekor hiba történt: %1$s (%2$d) @@ -1529,13 +1529,13 @@ Ha nem te állítottad be a visszaállítási metódust, akkor egy támadó pró Látták: Kijelentkeztél - A következő okok miatt lehet: -\n -\n• Másik munkamenetedben megváltoztattad a jelszavadat. -\n -\n• Törölted ezt a munkamenetedet egy másik munkamenetből. -\n -\n• A matrix szerver adminisztrátora biztonsági okokból érvénytelenítette a hozzáférésed. + A következő okok miatt lehet: +\n +\n• Másik munkamenetedben megváltoztattad a jelszavadat. +\n +\n• Törölted ezt a munkamenetedet egy másik munkamenetből. +\n +\n• Az általad használt Matrix szerver adminisztrátora biztonsági okokból érvénytelenítette a hozzáférésed. Lépj be újra Kijelentkeztél Bejelentkezés @@ -1546,7 +1546,7 @@ Ha nem te állítottad be a visszaállítási metódust, akkor egy támadó pró Személyes adatok törlése Figyelmeztetés: A személyes adataid (beleértve a titkosító kulcsokat is) továbbra is az eszközön vannak tárolva. \n -\nHa az eszközt nem használod tovább vagy másik fiókba szeretnél bejelentkezni, töröld őket. +\nHa az eszközt nem használod tovább, vagy másik fiókba szeretnél bejelentkezni, töröld őket. Minden adat törlése Adat törlése Biztos vagy benne, hogy minden az eszközön tárolt adatot törölni szeretnél\? @@ -1554,7 +1554,7 @@ Ha nem te állítottad be a visszaállítási metódust, akkor egy támadó pró Elveszted a hozzáférésedet a titkosított üzeneteidhez ha nem jelentkezel be a titkosítási kulcsok visszaállításához. Adat törlése A jelenlegi munkamenet %1$s felhasználóhoz tartozik és %2$s azonosítási adatait adtad meg. Ez Element-ben nem támogatott. -\nElőször töröld az adatokat, majd a másik felhasználói fiókba lépj be. +\nElőször töröld az adatokat, utána lépj be a másik fiókba! A matrix.to linked hibás A leírás túl rövid Első szinkronizáció… @@ -1579,7 +1579,7 @@ Ha nem te állítottad be a visszaállítási metódust, akkor egy támadó pró Megbízhatatlan belépés Egyeznek Nem egyeznek - Hitelesítheted a felhasználót, ha megerősíted, hogy az alábbi egyedi emodzsik azok amik ugyanabban a sorrendben megjelentek a képernyőjén. + Hitelesítheted a felhasználót, ha megerősíted, hogy ugyan azok az emojik jelennek meg az ő képernyőjén is, ugyan abban a sorrendben. A legnagyobb biztonság érdekében használj megbízható kommunikációs csatornát vagy tedd meg személyesen. Keresd a zöld pajzsot, hogy biztos lehess abban, hogy a felhasználó megbízható. Bízz meg a szoba minden felhasználójában, hogy a szoba biztonságos lehessen. Nem biztonságos @@ -1607,9 +1607,9 @@ Ha nem te állítottad be a visszaállítási metódust, akkor egy támadó pró Kód beolvasása Nem lehet beolvasni Ha nem vagy ott személyesen akkor inkább hasonlítsd össze az emodzsikat - Ellenőrzés emodzsikkal + Ellenőrzés emojik összehasonlításával Ellenőrzés emodzsival - Ha az alábbi kódot nem tudod beolvasni, ellenőrizd a rövid egyedi emodzsik összehasonlításával. + Ha az alábbi kódot nem tudod beolvasni, ellenőrizd a felhasználót néhány egyedi emoji összehasonlításával. QR kód kép Ellenőrzés: %s Ellenőrizve: %s @@ -1797,7 +1797,7 @@ Ha nem te állítottad be a visszaállítási metódust, akkor egy támadó pró \nHa nem akarsz Üzenet Jelszót beállítani, hozz létre inkább Üzenet Kulcsot. Az Visszaállítási Jelmondat beállításával biztonságba helyezheted és hozzáférhetsz a titkosított üzeneteidhez valamint a bizalomhoz. Titkosítás bekapcsolva - Ebben a szobában az üzenetek végpontok között titkosítottak. További információkért és ellenőrzéshez nyisd meg a felhasználók profilját. + Ebben a szobában az üzenetek végpontok között titkosítottak. További információkért és ellenőrzéshez nyisd meg a felhasználók profiljait! Titkosítás nincs engedélyezve A szobában használt titkosítás nem támogatott %s elkészítette és beállította a szobát. From fa3035f9cf80cd0bfb7eb30969433f02df74073a Mon Sep 17 00:00:00 2001 From: LinAGKar Date: Thu, 12 Nov 2020 19:42:08 +0000 Subject: [PATCH 29/66] Translated using Weblate (Swedish) Currently translated at 100.0% (1933 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/sv/ --- vector/src/main/res/values-sv/strings.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vector/src/main/res/values-sv/strings.xml b/vector/src/main/res/values-sv/strings.xml index 97075ac975..4f71783b20 100644 --- a/vector/src/main/res/values-sv/strings.xml +++ b/vector/src/main/res/values-sv/strings.xml @@ -2187,4 +2187,8 @@ Rumsinställningar Rumsämne (valfritt) Rumsnamn + Exportera granskning + Direktmeddelande + Skicka historik över nyckeldelningsförfrågningar + Inga fler resultat \ No newline at end of file From b739aa35f23a992832ca0b283eb39b0cd00c5c3c Mon Sep 17 00:00:00 2001 From: sr093906 Date: Sat, 14 Nov 2020 12:00:39 +0000 Subject: [PATCH 30/66] Translated using Weblate (Chinese (Simplified)) Currently translated at 99.1% (1917 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/zh_Hans/ --- vector/src/main/res/values-zh-rCN/strings.xml | 107 +++++++++--------- 1 file changed, 52 insertions(+), 55 deletions(-) diff --git a/vector/src/main/res/values-zh-rCN/strings.xml b/vector/src/main/res/values-zh-rCN/strings.xml index 17bf14161c..bcb449cabb 100644 --- a/vector/src/main/res/values-zh-rCN/strings.xml +++ b/vector/src/main/res/values-zh-rCN/strings.xml @@ -186,14 +186,16 @@ 此主服务器想确认您不是机器人 一封电子邮件已发送至 %s。点击了其中的链接后,请点击下面。 电子邮箱地址验证失败:请确保您已点击邮件中的链接 - 密码已重置。 您已从所有设备注销并且不再接受推送通知。要重新启用通知,请重新在相应设备上登录。 + 密码已重置。 +\n +\n您已经退出所有会话,将不再收到推送通知。要重新启用通知,请在每台设备上重新登录。 原始 %d 秒 通话已连接 通话正在连接… - 为了发送或保存附件,Element 需要访问您的图片和视频库。 - -请在接下来弹出的窗口中授权允许访问。 + 为了发送或保存附件,Element 需要访问您的图片和视频库。 +\n +\n请在接下来弹出的窗口中授权允许访问,以便应用能够从您的手机发送文件。 为了拍照或进行视频通话,Element 需要访问您的相机。 为了进行语音通话,Element 需要访问您的麦克风。 您试图访问聊天室 %s。您是否愿意加入这个聊天室? @@ -238,9 +240,9 @@ 设置 已邀请 已加入 - 您要隐藏所有来自这个用户的消息吗? - -注意,此操作会重启应用并将花费一些时间。 + 您要隐藏所有来自这个用户的消息吗? +\n +\n注意,此操作会重启应用并将花费一些时间。 取消上传 取消下载 收藏夹 @@ -268,13 +270,13 @@ 通知 已忽略的用户 通讯录权限 - 这个操作需要额外的身份认证。 -请输入您的密码以继续。 + 这个操作需要额外的身份认证。 +\n请输入您的密码以继续。 身份认证 当前密码 - 是否重新显示所有来自 %s 的消息? - -注意,此操作会重启应用并将花费一些时间。 + 是否重新显示所有来自 %s 的消息? +\n +\n注意,此操作会重启应用并将花费一些时间。 选择国家 国家 请选择一个国家 @@ -309,8 +311,8 @@ “%s” 不是有效的别名格式 这个聊天室已启用加密。 这个聊天室已禁用加密。 - 启用加密 -(警告:无法再禁用!) + 启用加密 +\n(警告:无法再禁用!) 目录 端对端加密信息 事件信息 @@ -353,9 +355,9 @@ 问题反馈发送失败(%s) 阅读 无效令牌 - 在出现相应的 API 前,暂不支持同时使用电子邮箱地址与手机号码注册。只有手机号码会被添加到此帐户。 - -您可在设置中将电子邮箱添加到你的账户。 + api存在之前,不支持同时通过电子邮件和电话号码进行注册。我们只考虑电话号码。 +\n +\n您可以在设置中添加您的电子邮件到您的个人资料。 用户名已被使用 无法注册:电子邮箱所有权验证失败 无法识别指定的访问令牌 @@ -378,17 +380,18 @@ " \n \n请在接下来弹出的窗口中授权允许访问。" - 为了进行视频通话,Element 需要访问您的相机和麦克风。 - -请在接下来弹出的窗口中授权允许访问。 + Element需要许可才能访问您的摄像机和麦克风来执行视频通话。 +\n +\n请在接下来弹出的窗口中授权允许访问。 对不起。因为权限不足,操作已取消 保存至下载? 移除 - 此邀请已发送至未与此账户关联的 %s。 您可能希望用一个不同的账户登录,或者把这个电子邮箱加入到这个账户。 + 此邀请已发送至未与此账户关联的 %s。 +\n您可能希望用一个不同的账户登录,或者把这个电子邮箱加入到你的账户。 这是此聊天室的预览。与聊天室的交互已禁用。 通话 - 您将不能撤销这个修改,因为您正在让这个用户和您拥有相同的特权级别。 -您确定吗? + 您将不能撤销这个修改,因为您正在让这个用户和您拥有相同的特权级别。 +\n您确定吗? 这可能意味着有人在恶意劫持您的通讯,或者您的手机不信任远程服务器的数字证书。 如果服务器管理员说这是正常的,请确保以下的指纹与管理员提供的指纹相符。 报告这个内容的原因 @@ -442,9 +445,9 @@ Element 需要访问您的通讯录,才能根据电子邮箱地址和手机号码查找其他 Matrix 用户。 请在接下来的弹出窗口中授权允许访问。 - Element 需要访问您的通讯录,才能根据电子邮箱地址和手机号码查找其他 Matrix 用户。 - -允许 Element 访问您的通讯录? + Element可以检查您的通讯录,以根据电子邮件和电话号码找到其他Matrix用户。 +\n +\n你同意为此目的分享你的通讯录吗\? 空闲 仅 Matrix 用户 您的手机信任的证书已被更改。这非常反常。建议您不要接受此新证书。 @@ -472,9 +475,7 @@ %s 已尝试在这个聊天室的时间线上加载一个特定的时间点,但无法找到它。 公开名称 为验证此设备是否可信,请通过其他方式(例如面对面交换或拨打电话)与其拥有者联系,并询问他们该设备的用户设置中的密钥是否与以下密钥匹配: - 如果匹配,请点击下面的验证按钮。 -\n如果不匹配,那么这可能说明其他人正在盗用此设备,而您应当将其拉入黑名单。 -\n未来,这个验证过程将会变得更加精致、巧妙一些。 + 如果它们不匹配,您通信的安全性可能会受到影响。 这个聊天室包含未经验证的未知设备。 \n这意味着无法保证该设备属于其声称的用户。 \n我们建议您在继续操作之前,先验证每个设备,但如果您愿意也可以不验证而重新发送消息。 @@ -701,11 +702,7 @@ 请允许资料分析以帮助我们改进 Element。 是的,我愿意帮助! 停用账户 - 这将使您的账户永远不再可用。您将不能登录,或使用相同的用户 ID 重新注册。您的账户将退出所有已加入的聊天室,身份服务器上的账户信息也会被删除。此操作是不可逆的。 - -停用您的账户不会默认忘记您发送的消息。如果您希望我们忘记您发送的消息,请勾选下面的选择框。 - -Matrix 中的消息可见性类似于电子邮件。我们忘记您的消息意味着您发送的消息不会被发给新注册或未注册的用户,但是已收到您的消息的注册用户依旧可以看到他们的副本。 + 请在我停用账户的同时忘记我发送的所有消息(警告:这将导致未来的用户看到残缺的对话) 请输入您的密码以继续: 停用账户 @@ -821,17 +818,17 @@ Matrix 中的消息可见性类似于电子邮件。我们忘记您的消息意 系统设置。 通知已在系统设置中启用。 通知已在系统设置中禁用。 -请检查系统设置。 +\n请检查系统设置。 打开设置 帐号设置。 您的帐号已启用通知。 - 您的帐号已禁用通知。 -请检查帐号设置。 + 您的账户已禁用通知。 +\n请检查账户设置。 启用 设备设置。 已为此设备启用通知。 - 已为此设备禁用通知。 -请检查 Element 设置。 + 此会话未启用通知。 +\n请检查 Element 设置。 启用 Play 服务检查 Google Play 服务的 APK 文件可用且为最新版本。 @@ -840,17 +837,17 @@ Matrix 中的消息可见性类似于电子邮件。我们忘记您的消息意 修复 Play 服务 Firebase 令牌 成功获取 FCM Token: -%1$s - FCM Token 获取失败: -%1$s +\n%1$s + FCM Token 获取失败: +\n%1$s 注册 Token FCM Token 已成功注册至主服务器。 - 将 FCM Token 注册至主服务器时失败: -%1$s + 未能将FCM Token 注册到主服务器: +\n %1$s 通知服务 通知服务正在运行。 - 通知服务尚未运行。 -请尝试重启本应用程序。 + 通知服务未在运行。 +\n请尝试重启本应用程序。 启动服务 调用系统相机应用而非使用 Element 内置的相机界面。 此选项需要第三方应用录制消息。 @@ -870,8 +867,8 @@ Matrix 中的消息可见性类似于电子邮件。我们忘记您的消息意 显示账户变动事件 包括头像与显示名称的变动。 后台连接 - Element需要保持一个低影响的后台连接才能保证可靠的通知。 -在下一个弹出窗口中,系统将提示您允许 Element 始终在后台运行,请点击“允许“。 + Element需要保持低影响的后台连接,以便获得可靠的通知。 +\n下一个屏幕中,系统将提示您允许 Element 始终在后台运行,请点击“允许“。 授予权限 在验证您的电子邮件地址时发生了一个错误。 密码 @@ -899,11 +896,11 @@ Matrix 中的消息可见性类似于电子邮件。我们忘记您的消息意 服务重启失败 服务将在设备重启后启动。 服务不会在设备重启后启动,在您打开 Element 一次之前您将不会收到消息通知。 - 对 Element 的后台限制已被关闭。此测试应在移动数据(无Wi-Fi)环境下进行。 -%1$s - 对 Element 的后台限制已开启。 -Element 在后台时的工作将被显著的限制,这可能会影响消息通知。 -%1$s + 已禁用对 Element 的后台限制。此测试应使用移动数据(非Wi-Fi)进行。 +\n%1$s + 已启用对 Element 的后台限制。 +\nElement 在后台时的工作将被显著地限制,这可能会影响消息通知。 +\n%1$s 关闭后台限制 Element 未被电池优化影响。 如果设备在未充电的情况下关屏静置一段时间,其将进入打盹模式(Doze)。这将阻止应用访问网络并延后其运行、同步、与响铃。 @@ -1371,7 +1368,7 @@ Element 在后台时的工作将被显著的限制,这可能会影响消息通 正在加密文件… 正在发送文件 (%1$s / %2$s) 正在下载文件 %1$s… - "文件 %1$s 已下载!" + 文件%1$s 已被下载! 消息编辑 未找到编辑 过滤对话… @@ -1922,7 +1919,7 @@ Element 在后台时的工作将被显著的限制,这可能会影响消息通 无法添加媒体文件到相册 无法保存媒体文件 选择新的账户密码… - 在您的其他设备上使用最新的 Element,Element Web,Element Desktop,Element iOS,Element for Android,或其他能够交叉签名的 Matrix 客户端 + 在您的其他设备上使用最新的 Element、Element Web、Element Desktop、Element iOS、Element for Android,或其他能够交叉签名的 Matrix 客户端 Element Web \nElement Desktop Element iOS From 032d46d8e62ad94b495fd0636beb6de60ae17e99 Mon Sep 17 00:00:00 2001 From: Danial Behzadi Date: Fri, 13 Nov 2020 15:51:26 +0000 Subject: [PATCH 31/66] Translated using Weblate (Persian) Currently translated at 100.0% (190 of 190 strings) Translation: Element Android/Element Android Sdk Translate-URL: https://translate.element.io/projects/element-android/element-sdk/fa/ --- matrix-sdk-android/src/main/res/values-fa/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/matrix-sdk-android/src/main/res/values-fa/strings.xml b/matrix-sdk-android/src/main/res/values-fa/strings.xml index 042fda7ddd..11a786f5ac 100644 --- a/matrix-sdk-android/src/main/res/values-fa/strings.xml +++ b/matrix-sdk-android/src/main/res/values-fa/strings.xml @@ -181,8 +181,8 @@ نشانی‌های %1$s را به این اتاق افزودید. - نشانی %1$s ار از این اتاق برداشتید. - نشانی‌های %1$s ار از این اتاق برداشتید. + نشانی %1$s را از این اتاق برداشتید. + نشانی‌های %1$s را از این اتاق برداشتید. نشانی %1$s ار افزوده و %2$s را از این اتاق برداشتید. نشانی اصلی این اتاق را به %1$s تنظیم کردید. From b24608891ed526381f6d043ce4005989476d22c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pol=20G=C3=B3mez=20Riquelme?= Date: Sun, 15 Nov 2020 13:45:46 +0000 Subject: [PATCH 32/66] Translated using Weblate (Catalan) Currently translated at 60.5% (1171 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/ca/ --- vector/src/main/res/values-ca/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/vector/src/main/res/values-ca/strings.xml b/vector/src/main/res/values-ca/strings.xml index 7e88fb1a45..ed6128702b 100644 --- a/vector/src/main/res/values-ca/strings.xml +++ b/vector/src/main/res/values-ca/strings.xml @@ -1373,4 +1373,5 @@ Les tasques que l\'aplicació intenta fer estaran restringides agressivament men Cancel·la invitació Torna a la trucada Error SSL. + La trucada d\'Element ha fallat \ No newline at end of file From cf5d112e3161944eb8a756a8768881118246e9f8 Mon Sep 17 00:00:00 2001 From: Victor Cuadrado Juan Date: Sun, 15 Nov 2020 22:29:57 +0000 Subject: [PATCH 33/66] Translated using Weblate (Spanish) Currently translated at 100.0% (1933 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/es/ --- vector/src/main/res/values-es/strings.xml | 310 +++++++++++++--------- 1 file changed, 184 insertions(+), 126 deletions(-) diff --git a/vector/src/main/res/values-es/strings.xml b/vector/src/main/res/values-es/strings.xml index 59237e8c5a..edde547f1e 100644 --- a/vector/src/main/res/values-es/strings.xml +++ b/vector/src/main/res/values-es/strings.xml @@ -146,8 +146,8 @@ Utilizar opciones personalizadas del servidor (avanzado) Por favor consulta tu correo electrónico para continuar con el registro Todavía no es posible registrarse con correo electrónico y número telefónico a la vez, hasta que exista la API. Solo se tendrá en cuenta el número telefónico. - -Puedes añadir tu correo electrónico a tu perfil en ajustes. +\n +\nPuedes añadir tu correo electrónico a tu perfil en ajustes. Este Servidor Doméstico quiere asegurarse de que no eres un robot Nombre de usuario en uso Servidor Doméstico: @@ -190,7 +190,7 @@ Puedes añadir tu correo electrónico a tu perfil en ajustes. "¿Cancelar la descarga? ¿Cancelar la subida? %d s - %1$dm %2$ds + %1$dmin %2$dseg Ayer Hoy @@ -252,7 +252,7 @@ Por favor permite el acceso en la próxima ventana emergente para descubrir usua Has sido invitado por %s a unirte a esta sala Esta invitación fue enviada a %s, que no esta asociado a esta cuenta. -Quizás quieras iniciar sesión con otra cuenta, o añadir este correo electrónico a esta cuenta. +\nQuizás quieras iniciar sesión con otra cuenta, o añadir este correo electrónico a esta cuenta. Estás intentando acceder a %s. ¿Quieres unirte para participar en la discusión? una sala Esta es una vista previa de esta sala. Las interacciones dentro de la sala se han deshabilitado. @@ -285,8 +285,8 @@ Quizás quieras iniciar sesión con otra cuenta, o añadir este correo electrón ID de Usuario, Nombre o correo electrónico Mencionar Mostrar Lista de Sesiones - No podrás deshacer este cambio porque estás promoviendo al usuario para tener el mismo nivel de autoridad que tú. -¿Estás seguro? + No podrás deshacer este cambio porque estás ascendiendo al usuario al mismo nivel de autoridad que tú. +\n¿Estás seguro\? ¿Seguro que quieres invitar a %s a esta conversación? Invitar por ID @@ -300,7 +300,7 @@ Quizás quieras iniciar sesión con otra cuenta, o añadir este correo electrón %s está escribiendo… %1$s y %2$s están escribiendo… %1$s y %2$s y otros están escribiendo… - Enviar un mensaje cifrado… + Enviar un mensaje encriptado… Enviar un mensaje (sin cifrar)… Se perdió la conexión con el servidor. Los mensajes no se enviaron. ¿%1$s o %2$s ahora? @@ -333,9 +333,9 @@ Quizás quieras iniciar sesión con otra cuenta, o añadir este correo electrón SE UNIERON Motivo para reportar este contenido - ¿Quieres ocultar todos los mensajes de este usuario? - -Ten en cuenta que esta acción reiniciará la aplicación y puede tardar algo de tiempo. + ¿Quieres ocultar todos los mensajes de este usuario\? +\n +\nTen en cuenta que esta acción reiniciará la aplicación y puede tardar algo de tiempo. Cancelar Subida Cancelar Descarga @@ -425,7 +425,7 @@ Ten en cuenta que esta acción reiniciará la aplicación y puede tardar algo de Visto por última vez %1$s @ %2$s Esta operación requiere autenticación adicional. -Para continuar, ingresa tu contraseña por favor. +\nPara continuar, introduce tu contraseña por favor. Autenticación Contraseña: Enviar @@ -444,9 +444,9 @@ Para continuar, ingresa tu contraseña por favor. Confirmar contraseña No se pudo actualizar la contraseña Tu contraseña ha sido actualizada - ¿Mostrar todos los mensajes de %s? - -Ten en cuenta que esta acción reiniciará la aplicación y puede tardar algo de tiempo. + ¿Mostrar todos los mensajes de %s\? +\n +\nTen en cuenta que esta acción reiniciará la aplicación y puede tomar algo de tiempo. ¿Seguro que quieres eliminar este objetivo de notificaciones? ¿Seguro que quieres eliminar los %1$s %2$s? Elige un país @@ -495,11 +495,11 @@ Ten en cuenta que esta acción reiniciará la aplicación y puede tardar algo de Direcciones Laboratorios Estas son funcionalidades experimentales que pueden romperse de maneras inesperadas. Utilizar con precaución. - Cifrado de Extremo a Extremo - El Cifrado de Extremo a Extremo está activo - Necesitas cerrar sesión para poder habilitar el cifrado. + Encriptación de Extremo a Extremo + La encriptación de Extremo a Extremo está activa + Necesitas cerrar sesión para poder habilitar la encriptación. Cifrar solo a sesiones verificadas - Nunca enviar mensajes cifrados a sesiones sin verificar en esta sala desde esta sesión. + Nunca enviar mensajes encriptados a sesiones sin verificar en esta sala desde esta sesión. Esta sala no tiene direcciones locales Dirección nueva (ej. #foo:matrix.org) @@ -511,23 +511,23 @@ Ten en cuenta que esta acción reiniciará la aplicación y puede tardar algo de Dejar de Establecer como Dirección Principal Copiar ID de Sala Copiar Dirección de Sala - El cifrado está habilitado en esta sala. - El cifrado está deshabilitado en esta sala. - Habilitar cifrado -(advertencia: ¡no se puede volver a deshabilitar!) + La encriptación está habilitada en esta sala. + La encriptación está deshabilitada en esta sala. + Habilitar encriptado +\n(advertencia: ¡no se puede volver a deshabilitar!) Directorio %s estaba intentando cargar un momento específico en la línea de tiempo de esta sala pero no pudo encontrarlo. - Información de cifrado de extremo a extremo + Información de encriptación Extremo-a-Extremo Información de eventos ID de Usuario Clave de identidad Curve25519 Clave de huella digital Ed25519 reclamada Algoritmo ID de Sesión - Error de descifrado + Error de desencriptación Información de la sesión emisora Nombre público Nombre público @@ -535,21 +535,21 @@ Ten en cuenta que esta acción reiniciará la aplicación y puede tardar algo de Clave de sesión Verificación Huella digital Ed25519 - Exportar claves de salas con Cifrado de Extremo a Extremo + Exportar claves de salas con encriptación Extremo-a-Extremo Exportar claves de sala Exportar las claves a un archivo local Exportar Ingresar frase de contraseña Confirmar frase de contraseña - Las claves de salas con Cifrado de Extremo a Extremo se guardaron en \'%s\'. - -Advertencia: este archivo puede ser eliminado si la aplicación se desinstala. - Importar claves de salas con Cifrado de Extremo a Extremo + Las claves de salas con encriptado de Extremo-a-Extremo se guardaron en \'%s\'. +\n +\nAdvertencia: este archivo puede ser eliminado si la aplicación se desinstala. + Importar claves de salas con encriptación Extremo-a-Extremo Importar claves de sala Importar las claves desde un archivo local Importar Cifrar solo a sesiones verificadas - Nunca enviar mensajes cifrados a sesiones sin verificar desde esta sesión. + Nunca enviar mensajes encriptados a sesiones sin verificar desde esta sesión. SIN Verificar Verificado Prohibido @@ -565,7 +565,11 @@ Advertencia: este archivo puede ser eliminado si la aplicación se desinstala.Verifico que las claves coinciden La sala contiene sesiones desconocidas - Esta sala contiene sesiones desconocidas que no han sido verificados. Esto significa que no hay garantía de que las sesiones pertenezcan a los usuarios a los que dicen pertenecer. Recomendamos que pases por el proceso de verificación para cada sesión antes de continuar. Puedes reenviar el mensaje sin verificarlas si prefieres. Sesiones desconocidas: + Esta sala contiene sesiones desconocidas que no han sido verificadas. +\nEsto significa que no hay garantía de que las sesiones pertenezcan a los usuarios a los que dicen pertenecer. +\nRecomendamos que hagas el proceso de verificación por cada sesión antes de continuar. Pero puedes reenviar el mensaje sin verificarlas si prefieres. +\n +\nSesiones desconocidas: Selecciona un directorio de salas El servidor puede estar no disponible o sobrecargado @@ -631,8 +635,8 @@ Advertencia: este archivo puede ser eliminado si la aplicación se desinstala.Añadir aplicaciones de Matrix Utilizar cámara nativa - Añadiste una nueva sesión \'%s\', que está solicitando claves de cifrado. - Tu sesión sin verificar \'%s\' está solicitando claves de cifrado. + Has añadido una nueva sesión \'%s\', que está solicitando claves de encriptación. + Tu sesión sin verificar \'%s\' está solicitando claves de encriptación. Iniciar verificación Compartir sin verificar Ignorar solicitud @@ -645,7 +649,7 @@ Advertencia: este archivo puede ser eliminado si la aplicación se desinstala. Desactivado Ruidoso - Mensaje cifrado + Mensaje encriptado Detalles de comunidad Cargando… Salir @@ -715,7 +719,7 @@ Advertencia: este archivo puede ser eliminado si la aplicación se desinstala.%1$s salas encontradas para %2$s - 1 sala + %d sala %d salas @@ -728,16 +732,16 @@ Advertencia: este archivo puede ser eliminado si la aplicación se desinstala.%d miembros activos - 1 mensaje sin leer + %d mensaje sin leer %d mensajes sin leer - 1 mensaje notificado sin leer + %d mensaje notificado sin leer %d mensajes notificados sin leer %1$s en %2$s - 1 componente activo + %d componente activo %d componentes activos @@ -752,10 +756,10 @@ Advertencia: este archivo puede ser eliminado si la aplicación se desinstala.Para continuar utilizando el servidor doméstico %1$s, debes revisar y aceptar los términos y condiciones. Revisar ahora Esto hará que tu cuenta quede permanentemente inutilizable. No podrás iniciar sesión, y nadie podrá volver a registrar la misma ID de usuario. Esto hará que tu cuenta salga de todas las salas en las cuales participa, y eliminará los datos de tu cuenta de tu servidor de identidad. Esta acción es irreversible. - -Desactivar tu cuenta no hace que por defecto olvidemos los mensajes que has enviado. Si quieres que olvidemos tus mensajes, por favor marca la casilla a continuación. - -La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Que olvidemos tus mensajes implica que los mensajes que hayas enviado no se compartirán con ningún usuario nuevo o no registrado, pero aquellos usuarios registrados que ya tengan acceso a estos mensajes seguirán teniendo acceso a su copia. +\n +\nDesactivar tu cuenta no hace que por defecto olvidemos los mensajes que has enviado. Si quieres que olvidemos tus mensajes, por favor marca la casilla a continuación. +\n +\nLa visibilidad de mensajes en Matrix es similar a la del correo electrónico. Que olvidemos tus mensajes implica que los mensajes que hayas enviado no se compartirán con ningún usuario nuevo o no registrado, pero aquellos usuarios registrados que ya tengan acceso a estos mensajes seguirán teniendo acceso a su copia. Por favor, olvida todos los mensajes enviados al desactivar mi cuenta (Advertencia: esto provocará que los usuarios futuros vean conversaciones incompletas) Para continuar, ingresa tu contraseña por favor: Desactivar Cuenta @@ -787,7 +791,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Borrar continuar con… Lo sentimos, no se encontró ninguna aplicación externa para completar esta acción. - Volver a solicitar las claves de cifrado de tus otras sesiones. + Volver a solicitar las claves de encriptado de tus otras sesiones. Solicitud de clave enviada. Privacidad de Notificaciones Element puede ejecutarse en segundo plano para gestionar tus notificaciones de forma segura y privada. Esto podría afectar la duración de la batería. @@ -846,11 +850,11 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu %d seleccionados - 1 miembro + %d miembro %d miembros - 1 sala + %d sala %d salas Límite de Recursos Excedido @@ -892,12 +896,12 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Copia de seguridad de la clave Usar copia de seguridad de la clave La copia de seguridad de la clave no ha finalizado, por favor espere… - No quiero mis mensajes cifrados + No quiero mis mensajes encriptados Creando copia de seguridad de las claves… Usar copia de seguridad de la clave ¿Estás seguro\? Copia de seguridad - Perderá el acceso a sus mensajes cifrados si cierra sesión sin hacer una copia de seguridad de sus claves. + Perderá el acceso a sus mensajes encriptados si cierra sesión sin hacer una copia de seguridad de sus claves. Quedarse Saltar Hecho @@ -937,7 +941,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Una o más pruebas han fallado, por favor prueba las soluciones propuestas. Una o más pruebas han fallado, por favor mándanos un informe de error para que podamos investigar. Copia de seguridad en progreso. Si cierras sesión ahora perderás el acceso a tus mensajes encriptados. - La copia de seguridad debería estar activa ahora en todas tus sesiones para evitar la pérdida del acceso a tus mensajes encriptados. + La copia de seguridad debería estar activa ahora en todas tus sesiones para evitar la pérdida de acceso a tus mensajes encriptados. Element usa los servicios de Google Play para entregar mensajes Push pero no parece estar configurado correctamente: \n%1$s solucionar error con los Servicios de Google Play @@ -962,10 +966,10 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Borrar copia de seguridad nueva copia de seguridad Ese era yo - nunca se pierden mensajes cifrados - Configurar copia de seguridad de las claves de cifrado - Nunca pierdas mensajes cifrados - Nuevos mensajes clave cifrados + Nunca pierda mensajes encriptados + Configurar copia de seguridad de las claves de encriptado + Nunca pierdas mensajes encriptados + Nuevas claves de encriptación de mensajes Gestionar Copia de Seguridad Guardando copia de seguridad… Versión @@ -1024,10 +1028,10 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Compresión predeterminada Seleccionar Seleccionar - Recuperación de mensajes cifrados + Recuperación de mensajes encriptados Gestionar copia de seguridad clave - %1$s: 1 mensaje + %1$s: %2$d mensaje %1$s: %2$d mensajes @@ -1040,7 +1044,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Nueva invitación Yo ** Error al enviar - por favor abra la sala - "Lo sentimos, las llamadas grupales con Jitsi no se pueden mantener en dispositivos antiguos (dispositivos con Android inferior a 5.0)" + Lo sentimos, las llamadas de grupo con Jitsi no están soportadas en dispositivos antiguos (dispositivos con Android inferior a 5.0) Iniciar la cámara del sistema en lugar de la pantalla de cámara personalizada. Esta opción requiere una aplicación de terceros para grabar los mensajes. El comando \"%s\" necesita mas parámetros o algunos parámetros son incorrectos. @@ -1061,8 +1065,8 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu La contraseña que has introducido es muy débil Por favor borra la contraseña si quieres que Element genere una clave de recuperación. No hay ninguna sesión de Matrix disponible - Nunca se pierden los mensajes cifrados - Los mensajes en salas cifradas están asegurados con cifrado de extremo a extremo. Solo los integrantes de la sala y tu podéis leer estos mensajes. + Nunca perder los mensajes encriptados + Los mensajes en salas encriptadas están asegurados con encriptación Extremo-a-Extremo. Solo los integrantes de la sala y tu podéis leer estos mensajes. \n \nAsegúrate de guardar bien tus claves para evitar perderlas. (Avanzado) @@ -1074,10 +1078,10 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Introduce una contraseña Creando copia de seguridad O, asegura tu copia de seguridad con una clave de recuperación, guardándola en algún lugar seguro. - "(Avanzado) preparar clave de recuperación" + (Avanzado) Establecer clave de recuperación Completado! Tus claves se están guardando. - Tu clave de recuperación es una red de seguridad - Puedes usarla para recuperar el acceso a tus mensajes cifrados si olvidas tu contraseña. + Tu clave de recuperación es una red de seguridad - puedes usarla para recuperar el acceso a tus mensajes encriptados si olvidas tu contraseña. \nMantén tu clave de recuperación en algún lugar muy seguro como un administrador de contraseñas (o en una caja fuerte) Mantén tu clave de recuperación en algún lugar muy seguro como un administrador de contraseñas (o en una caja fuerte) Hecho @@ -1097,10 +1101,10 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Tus claves cifradas están siendo guardadas en segundo plano en tu servidor. La copia de seguridad inicial podría tardar varios minutos. Estás seguro\? Podrías perder el acceso a tus mensajes si te desconectas o pierdes este dispositivo. - Utiliza tu clave de recuperación para desbloquear tu historial de mensajes cifrados + Utiliza tu clave de recuperación para desbloquear tu historial de mensajes encriptados Utiliza tu clave de recuperación No sabes tu clave de recuperación\? puedes %s. - Utiliza tu clave de recuperación para desbloquear tu historial de mensajes cifrados + Utiliza tu clave de recuperación para desbloquear tu historial de mensajes encriptados Introduzca la clave de recuperación Mensaje de recuperación Has perdido tu clave de recuperación\? Puedes crear una nueva en ajustes. @@ -1144,14 +1148,14 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu \n%2$s Configuración de uso Origen predeterminado de medios - Configurar copia de seguridad de las claves de cifrado + Configurar copia de seguridad de las claves de encriptación Obteniendo una versión de copia de seguridad… La copia de seguridad tiene una firma valida de la sesión no verificada %s La copia de seguridad tiene una firma inválida de la sesión verificada %s La copia de seguridad tiene una firma inválida de la sesión no verificada %s Error al conseguir información de confianza para la copia de seguridad (%s). Para usar la copia de seguridad de la clave en esta sesión introduzca su contraseña o su clave de recuperación ahora. - Desea borrar sus claves cifradas guardadas del servidor\? No podrás usar tu clave de recuperación para leer el historial de mensajes cifrados. + Deseas borrar tus claves de encriptación guardadas en el servidor\? No podrás usar tu clave de recuperación para leer el historial de mensajes encriptados. Una nueva copia de seguridad de mensajes ha sido detectada. \n \nSi no ha establecido un nuevo método de recuperación, alguien podría estar intentando acceder a su cuenta. Cambie su contraseña y establezca un nuevo método de recuperación inmediatamente en ajustes. @@ -1159,13 +1163,13 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Reproducir sonido de cámara Verificar sesión ip desconocida - Una nueva sesión solicita claves de cifrado. -\nSesión: %1$s -\nVisto por última vez: %2$s + Una nueva sesión solicita claves de encriptación. +\nSesión: %1$s +\nVisto por última vez: %2$s \nSi no has iniciado sesión en otro dispositivo ignora esta solicitud. - Una sesión no verificada solicita claves de cifrado. -\nSesión: %1$s -\nVisto por última vez: %2$s + Una sesión no verificada solicita claves de encriptación. +\nSesión: %1$s +\nVisto por última vez: %2$s \nSi no has iniciado sesión en otro dispositivo ignora esta solicitud. Verificar Compartir @@ -1181,7 +1185,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Para más seguridad, te recomendamos que hagas esto en persona o por otros medios confiables. Empezar verificación Solicitud de verificación - Verifica esta sesión para marcarla como confiable. Confiar en sesiones de otros te da aún más tranquilidad cuando usas cifrado de mensajes de punto a punto. + Verifica esta sesión para marcarla de confianza. Marcar sesiones de otros como de confianza te da aún más tranquilidad cuando usas encriptacion de Extremo-a-Extremo. Verificar esta sesión la marcará como confiable, y también marcará como confiable tu sesión para la contraparte. Verifica esta sesión confirmando los emojis que aparecen en la pantalla de la contraparte Verifica esta sesión confirmando que los siguietes números aparecen en la pantalla de la contraparte @@ -1190,7 +1194,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Esperando confirmación de la contraparte… ¡Verificado! Has verificado correctamente esta sesión. - Los mensajes con este usuario están cifrados punto a punto y no son legibles por terceros. + Los mensajes con este usuario están encriptados de Extremo-a-Extremo y no son legibles por terceros. Ok ¿No aparece nada\? No todas las aplicaciones cliente soportan verificación interactiva. Usa la verificación clásica. Usar verificación clásica. @@ -1244,7 +1248,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Mensajes directos Nueva sala CREAR - Nombre de la sala + Nombre Público Cualquiera puede unirse a esta sala Directorio de salas @@ -1500,9 +1504,9 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Introduzca la dirección de Modular Element o servidor que quieres usar Introduzca la dirección del servidor Element al que quieres conectarte Se produjo un error al cargar la página: %1$s (%2$d) - "La aplicación no es capaz de iniciar sesión en este servidor. Este solo soporta el acceso mediante: %1$s. + La aplicación no es capaz de iniciar sesión en este servidor. Éste solo soporta el acceso mediante: %1$s. \n -\n¿Quieres acceder usando un cliente web\?" +\n¿Quieres acceder usando un cliente web\? Lo sentimos, este servidor no acepta nuevas cuentas. La aplicación no fue capaz de crear una cuenta en este servidor. \n @@ -1540,8 +1544,9 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Por favor, elija un nombre de usuario. Por favor, elija una contraseña. Verifica este enlace - Este link %1$s loredirecciona a otro sitio %2$s. . -\nEsta seguro de continuar\? + Este link %1$s lo redirecciona a otro sitio %2$s. +\n +\n¿Está seguro de continuar\? Adicionar miembros INVITAR Invitando usuarios… @@ -1602,7 +1607,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Element puede fallar con más frecuencia cuando ocurre un error inesperado Antepone ¯\\_(ツ)_/¯ a un mensaje de texto sin formato Habilitar encriptacion - Una vez habilitada, el cifrado no se puede deshabilitar. + Una vez habilitada, la encriptación no se puede deshabilitar. Su dominio de correo electrónico no está autorizado para registrarse en este servidor Inicio de sesión no confiable Coinciden @@ -1615,7 +1620,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Imagen. Audio Archivo - Sticker + Pegatina Esperando… %s cancelada Cancelado por usted @@ -1637,7 +1642,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Verificar %s Verificado %s Esperando por %s… - Los mensages en esta sala no están encriptados punto a punto. + Los mensajes en esta sala no están encriptados de Extremo-a-Extremo. Seguridad Saber mas Mas @@ -1671,9 +1676,9 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Línea de tiempo Editor de mensage Encriptar (end-to-end) - Una vez habilitado, el cifrado no se puede deshabilitar. + Una vez habilitada, la encriptación no se puede deshabilitar. Encriptar \? - Habilitar el cifrado + Habilitar la encriptación Firma cruzada Firma cruzada no habilitada Sesiones Activas @@ -1716,7 +1721,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Clave de mensaje Contraseña de la cuenta ¡Listo! - Cifrado habilitado + Encriptación habilitada Sala creada y configurada por usted. Esperando por %s… Ajuste de Notificaciones @@ -1728,7 +1733,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Confirmar PIN Resetear PIN Nuevo PIN - Para resetear su PIN, debe iniciar sección y crear uno nuevo. + Para resetear su PIN, debe iniciar sesión y crear uno nuevo. Establecer PIN Si decea resetear su PIN, toque Olvidé PIN para cerrar sesión y restablecer. Numeros telefonicos @@ -1768,7 +1773,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Configurar copia de seguridad segura Restablecer copia de seguridad segura Configurar en este dispositivo - Protéjase contra la pérdida de acceso a los mensajes y datos cifrados haciendo una copia de seguridad de las claves de cifrado en su servidor. + Protéjase contra la pérdida de acceso a los mensajes y datos encriptados haciendo una copia de seguridad de las claves de encriptado en su servidor. Genere una nueva llave de seguridad o establezca una nueva frase de seguridad para su copia de seguridad existente. Esto reemplazará su clave o frase actual. Las integraciones están deshabilitadas @@ -1790,7 +1795,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Sin widgets activos La clave de recuperación se ha guardada. Copia de seguridad segura - Protéjase contra la pérdida de acceso a mensajes y datos cifrados + Protéjase contra la pérdida de acceso a mensajes y datos encriptados Configurar copia de seguridad segura Mensaje borrado Se ha creado la sala, pero algunas invitaciones no se han enviado por el siguiente motivo: @@ -1820,7 +1825,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Email Nueva contraseña ¡Advertencia! - Cambiar su contraseña restablecerá cualquier clave de cifrado de extremo a extremo en todas sus sesiones, haciendo ilegible el historial de chat cifrado. Configure Key Backup o exporte las llaves de su sala desde otra sesión antes de restablecer su contraseña. + Cambiar su contraseña restablecerá cualquier clave de encriptado de Extremo-a-Extremo en todas sus sesiones, haciendo ilegible el historial de chat encriptado. Configure la Copia de seguridad de claves o exporte las claves de su sala desde otra sesión antes de restablecer su contraseña. Seguir Este correo electrónico no está vinculado a ninguna cuenta Revisa tu correo @@ -1845,12 +1850,12 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Utilice el formato internacional. Número de teléfono Numero de teléfono (opcional) - Próximo + Siguiente Confirmar número de teléfono Acabamos de mandar un codigo a %1$s. Ingréselo a continuación para verificar que es usted. Introduzca el código Enviar de nuevo - Próximo + Siguiente Utilice el formato internacional (el número de teléfono debe comenzar con \'+\') Los números de teléfono internacionales deben comenzar con \'+\' El número de teléfono parece no válido. Compruébelo por favor @@ -1858,7 +1863,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Nombre de usuario o correo electrónico Nombre de usuario Contraseña - Próximo + Siguiente Ese nombre de usuario está siendo usado Advertencia Tu cuenta aún no está creada. @@ -1885,7 +1890,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Si configura una cuenta en un servidor doméstico, use su ID de Matrix (por ejemplo, @user: dominio.com) y contraseña a continuación. ID de Matrix Si no conoce su contraseña, vuelva a restablecerla. - "Este no es un identificador de usuario válido. Formato esperado: \'@user:homeserver.org\'" + Éste no es un identificador de usuario válido. Formato esperado: \'@user:homeserver.org\' No se pudo encontrar un servidor de inicio válido. Por favor verifique su identificador Visto por Estás desconectado @@ -1899,44 +1904,46 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Iniciar sesión de nuevo Estás desconectado Registrarse - "El administrador de su servidor doméstico (%1$s) ha cerrado la sesión de su cuenta %2$s (%3$s)." - Inicie sesión para recuperar las claves de cifrado almacenadas exclusivamente en este dispositivo. Los necesita para leer todos sus mensajes seguros en cualquier dispositivo. + El administrador de su servidor privado (%1$s) ha cerrado la sesión de su cuenta %2$s (%3$s). + Inicie sesión para recuperar las claves de encriptación almacenadas exclusivamente en este dispositivo. Los necesita para leer todos sus mensajes seguros en cualquier dispositivo. Registrarse Contraseña Borrar datos personales - Advertencia: sus datos personales (incluidas las claves de cifrado) todavía se almacenan en este dispositivo. + Advertencia: sus datos personales (incluidas las claves de encriptación) todavía están almacenadas en este dispositivo. \n \nBórrelo si terminó de usar este dispositivo o si desea iniciar sesión en otra cuenta. Borrar todos los datos Borrar datos ¿Borrar todos los datos almacenados actualmente en este dispositivo\? \nVuelva a iniciar sesión para acceder a los datos y mensajes de su cuenta. - Perderás el acceso a los mensajes seguros a menos que inicies sesión para recuperar tus claves de cifrado. + Perderás el acceso a los mensajes seguros a menos que inicies sesión para recuperar tus claves de encriptación. Borrar datos - La sesión actual es para el usuario %1$s y usted proporciona las credenciales para el usuario %2$s. Esto no es compatible con Element. Primero borre los datos, luego inicie sesión nuevamente con otra cuenta. + La sesión actual es para el usuario %1$s y usted proporciona las credenciales para el usuario %2$s. Esto no está suportado por Element. +\nPrimero borre los datos, luego inicie sesión nuevamente con otra cuenta. Su enlace matrix.to estaba mal formado El modo desarrollador activa funciones ocultas y también puede hacer que la aplicación sea menos estable. ¡Solo para desarrolladores! - Uno de los siguientes puede verse comprometido: -\n- Tu servidor doméstico -\n- El servidor doméstico al que está conectado el usuario que estás verificando -\n- La suya o la conexión a Internet de otros usuarios -\n- El suyo o el dispositivo de otros usuarios + Uno de los siguientes puede verse comprometido: +\n +\n- Tu servidor privado +\n- El servidor privado al que está conectado el usuario que estás verificando +\n- Su conexión a internet o la de otros usuarios +\n- Su dispositivo o el de otros usuarios Para mayor seguridad, verifique %s verificando un código único en ambos dispositivos. \n \nPara máxima seguridad, hágalo en persona. - Los mensajes de esta sala están cifrados de extremo a extremo. + Los mensajes de esta sala están encriptados de Extremo-a-Extremo. \n \nSus mensajes están protegidos con candados y solo usted y el destinatario tienen las claves únicas para desbloquearlos. Esta sesión no puede compartir esta verificación con sus otras sesiones. \nLa verificación se guardará localmente y se compartirá en una versión futura de la aplicación. Envía el emote dado coloreado como un arcoíris - Una vez habilitado, el cifrado de una sala no se puede deshabilitar. Los mensajes enviados en una sala cifrada no pueden ser vistos por el servidor, solo por los participantes de la sala. Habilitar el cifrado puede evitar que muchos bots y puentes funcionen correctamente. + Una vez habilitado, la encriptación de una sala no se puede deshabilitar. Los mensajes enviados en una sala encriptada no pueden ser vistos por el servidor, solo por los participantes de la sala. Habilitar la encriptación puede impedir que muchos bots y puentes funcionen correctamente. Para estar seguro, verifique %s comprobando un código de un solo uso. Para estar seguro, hágalo en persona o use otra forma de comunicarse. Compare los emoji únicos, asegurándose de que aparezcan en el mismo orden. Compare el código con el que se muestra en la pantalla del otro usuario. Los mensajes con este usuario están encriptados de extremo a extremo y no pueden ser leídos por terceros. - Su nueva sesión ahora está verificada. Tiene acceso a sus mensajes cifrados y otros usuarios lo verán como de confianza. + Su nueva sesión ahora está verificada. Tiene acceso a sus mensajes encriptados y otros usuarios lo verán como de confianza. La firma cruzada está habilitada \n Claves privadas en el dispositivo. La firma cruzada está habilitada @@ -1944,7 +1951,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu \nNo se conocen las claves privadas La firma cruzada está habilitada. \nLas claves no son de confianza - El administrador de su servidor ha desactivado el cifrado de extremo a extremo de forma predeterminada en salas privadas y mensajes directos. + El administrador de su servidor ha desactivado la encriptación de Extremo-a-Extremo de forma predeterminada en salas privadas y mensajes directos. No hay información criptográfica disponible Esta sesión es confiable para mensajería segura porque usted la verificó: Verifique esta sesión para marcarla como confiable y otorgarle acceso a mensajes encriptados. Si no inició sesión en esta sesión, su cuenta puede verse comprometida: @@ -1952,8 +1959,8 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu %d sesión activa %d sesiones activas - Utilice una sesión existente para verificar esta, otorgándole acceso a los mensajes cifrados. - "Esta sesión es confiable para mensajería segura porque %1$s (%2$s) la verificó:" + Utilice una sesión existente para verificar ésta, otorgándole acceso a los mensajes encriptados. + Esta sesión es de confianza para mensajería segura porque %1$s (%2$s) la ha verificado: %1$s (%2$s) iniciado sesión con una nueva sesión: Hasta que este usuario confíe en esta sesión, los mensajes enviados hacia y desde ella se etiquetan con advertencias. Alternativamente, puede verificarlo manualmente. ¡Casi ahí! ¿Es %s muestra el mismo escudo\? @@ -1981,7 +1988,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Evento eliminado por el usuario, motivo: %1$s Evento moderado por el administrador de la sala, motivo: %1$s Solicitudes clave - Desbloquear el historial de mensajes cifrados + Desbloquear el historial de mensajes encriptados Utilice esta sesión para verificar su nuevo, otorgándole acceso a mensajes encriptados. Si cancela, no podrá leer mensajes encriptados en este dispositivo y otros usuarios no confiarán en él Si cancela, no podrá leer mensajes encriptados en su nuevo dispositivo y otros usuarios no confiarán en él @@ -1998,8 +2005,8 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Establecer un %s Generar una clave de mensaje Confirmar %s - "Ingrese su %s para continuar." - Proteja y desbloquee los mensajes cifrados y confíe en %s. + Ingrese su %s para continuar. + Proteja y desbloquee los mensajes encriptados y confíe en %s. Ingrese su %s nuevamente para confirmarlo. No use la contraseña de su cuenta. Ingrese una frase de seguridad que solo usted conozca, que se usa para proteger secretos en su servidor. @@ -2018,28 +2025,28 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Configuración de copia de seguridad de claves Tus %2$s y %1$s ahora están configurados. \n -\n¡Mantenlos a salvo! Los necesitará para desbloquear mensajes cifrados y proteger la información si pierde todas sus sesiones activas. +\n¡Mantenlos a salvo! Los necesitará para desbloquear mensajes encriptados y proteger la información si pierde todas sus sesiones activas. Imprímelo y guárdalo en un lugar seguro Guárdelo en una llave USB o unidad de respaldo Cópielo en su almacenamiento personal en la nube No puedes hacer eso desde el móvil - Establecer una frase de contraseña de recuperación le permite proteger y desbloquear mensajes cifrados y de confianza. + Establecer una frase de contraseña de recuperación le permite proteger y desbloquear mensajes encriptados y de confianza. \n \nSi no desea establecer una contraseña de mensaje, genere una clave de mensaje. - Establecer una frase de contraseña de recuperación le permite proteger y desbloquear mensajes cifrados y de confianza. - Si cancela ahora, puede perder mensajes y datos cifrados si pierde el acceso a sus inicios de sesión. + Establecer una frase de contraseña de recuperación le permite proteger y desbloquear mensajes encriptados y de confianza. + Si cancela ahora, puede perder mensajes y datos encriptados si pierde el acceso a sus inicios de sesión. \n \nTambién puede configurar la Copia de seguridad segura y administrar sus claves en Configuración. - Los mensajes de esta sala están cifrados de extremo a extremo. Obtenga más información y verifique a los usuarios en su perfil. - Cifrado no habilitado - El cifrado utilizado por esta sala no es compatible + Los mensajes de esta sala están encriptados de Extremo-a-Extremo. Obtenga más información y verifique a los usuarios en su perfil. + Encriptación no habilitada + La encriptación usada por esta sala no es compatible %s creado y configurado la sala. ¡Casi ahí! ¿El otro dispositivo muestra el mismo escudo\? ¡Casi ahí! Esperando confirmación… No se pudieron importar las claves Mensajes que contienen @room - Mensajes cifrados en chats uno a uno - Mensajes cifrados en chats grupales + Mensajes encriptados en chats 1:1 + Mensajes encriptados en chats de grupo Cuando las salas son actualizadas Solucionar problemas Envía un mensaje como texto estándar, sin interpretarlo como Markdown @@ -2083,14 +2090,14 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu La copia de seguridad no se pudo descifrar con esta clave de recuperación: verifique que ingresó la clave de recuperación correcta. No se pudo acceder al almacenamiento seguro Sin encriptar - Cifrado por un dispositivo no verificado + Encriptado por un dispositivo no verificado Revise dónde inició sesión Verifique todas sus sesiones para asegurarse de que su cuenta y sus mensajes estén seguros Verifique el nuevo inicio de sesión accediendo a su cuenta: %1$s Verificar manualmente por texto Verificación interactiva por emoji - Confirme su identidad verificando este inicio de sesión de una de sus otras sesiones, otorgándole acceso a los mensajes cifrados. - Confirme su identidad verificando este inicio de sesión, otorgándole acceso a los mensajes cifrados. + Confirme su identidad verificando este inicio de sesión de una de sus otras sesiones, otorgándole acceso a los mensajes encriptados. + Confirme su identidad verificando este inicio de sesión, otorgándole acceso a los mensajes encriptados. Marcar como de confianza Lo sentimos, esta operación aún no es posible para las cuentas conectadas mediante el inicio de sesión único. No pudimos crear tu DM. Marque los usuarios que desea invitar y vuelva a intentarlo. @@ -2112,7 +2119,7 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Enciende la cámara Configurar copia de seguridad segura Respaldo seguro - Protéjase contra la pérdida de acceso a los mensajes y datos cifrados haciendo una copia de seguridad de las claves de cifrado en su servidor. + Protéjase contra la pérdida de acceso a los mensajes y datos encriptados haciendo una copia de seguridad de las claves de encriptación en su servidor. Preparar Usa una llave de seguridad Genere una clave de seguridad para almacenar en un lugar seguro, como un administrador de contraseñas o una caja fuerte. @@ -2132,11 +2139,11 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu No puedes acceder a este mensaje Esperando este mensaje, esto puede tardar un poco No se puede descifrar - Debido al cifrado de extremo a extremo, es posible que deba esperar a que llegue el mensaje de alguien porque las claves de cifrado no se le enviaron correctamente. + Debido a la encriptación de Extremo-a-Extremo, es posible que deba esperar a que llegue el mensaje de alguien porque las claves de encriptación no se le enviaron correctamente. No puede acceder a este mensaje porque ha sido bloqueado por el remitente No puede acceder a este mensaje porque el remitente no confía en su sesión No puede acceder a este mensaje porque el remitente no envió las claves a propósito - Esperando el historial de cifrado + Esperando al historial de encriptación ¡Nos complace anunciar que hemos cambiado de nombre! Tu aplicación está actualizada y accediste a tu cuenta. Guardar la clave de recuperación en Agregar desde mi directorio telefónico @@ -2166,10 +2173,10 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu Mensaje directo Salir Preferencias - Los mensajes aquí están encriptados de punto a punto. + Los mensajes aquí están encriptados de Extremo-a-Extremo. \n \nTus mensajes están asegurados con un candado. Solo tú y tú destinatario tenéis las llaves especiales para desencriptarlos. - Los mensajes aquí no están encriptados de punto a punto. + Los mensajes aquí no están encriptados de Extremo-a-Extremo. Botones de Bot Encuesta Remover de Baja prioridad @@ -2194,4 +2201,55 @@ La visibilidad de mensajes en Matrix es similar a la del correo electrónico. Qu No posee permisos para iniciar una llamada en esta sala No posee permisos para iniciar una conferencia Resetear + Descartar cambios + Hay cambios sin salvar. ¿Descartar los cambios\? + La sala todavía no ha sido creada. ¿Cancelar la creación\? + El link está malformado + PIN es requerido cada vez que se abre Element. + PIN es necesario después de no usar Element por 2 minutos. + Requerir PIN después de 2 minutos + Sólo mostrar el número de mensajes no leídos en una notificación sencilla. + Mostrar detalles, como nombres de salas y contenido de mensajes. + Mostrar contenido de notificaciones + Element sólo puede ser desbloqueado via Código PIN. + Activar biometría de este dispositivo en particular, como huellas dactilares o reconocimiento facial. + Activar biometría + Configurar protecciones + Restringir acceso usando PIN y biométricos. + Restringir acceso + + Mostrar el dispositivo con el que puede verificar ahora + Mostrar %d dispositivos con los que puede verificar ahora + + Reiniciará sin historia, mensajes, dispositivos o usuarios verificados + Si resetea todo + Solo haga esto si no tiene otro dispositivo con el que verificar éste. + Resetear todo + ¿Ha perdido o olvidado todas las opciones de recuperación\? Resetear todo + Tú te has unido. + %s se ha unido. + Exportar inspección + ¿Borrar los datos de cuenta de typo %1$s\? +\n +\nPrecaución, puede causar funcionamiento inesperado. + Resultado de la verificación + Reaccionó con: %s + Este servidor particular usa una versión antigua. Pregunta a su administrador si puede actualizarlo. Puedes continuar usándolo, pero algunas características pueden no funcionar. + Tú has configurado como sólo con invitación. + %1$s ha configurado como sólo con invitación. + Añadir imagen de + Mostrar la historia completa en salas encriptadas + Ajustes de la sala + Tema + Tema de la sala (opcional) + Nombre de la sala + %1$s y %2$s + %1$s en %2$s y %3$s + + %d invitación + %d invitaciones + + Incluye invitar/unirse/expulsar/prohibir/mostrar cambios de nombre. + Mostrar eventos de los miembros de la sala + ¡La notificación ha sido cliqueada! \ No newline at end of file From 7223959fdac7d98662762519e0028e21c84d28ae Mon Sep 17 00:00:00 2001 From: Rob Johnson Date: Sun, 15 Nov 2020 21:36:15 +0000 Subject: [PATCH 34/66] Translated using Weblate (Spanish) Currently translated at 100.0% (1933 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/es/ --- vector/src/main/res/values-es/strings.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vector/src/main/res/values-es/strings.xml b/vector/src/main/res/values-es/strings.xml index edde547f1e..a26c4c91d6 100644 --- a/vector/src/main/res/values-es/strings.xml +++ b/vector/src/main/res/values-es/strings.xml @@ -1481,7 +1481,7 @@ Por favor permite el acceso en la próxima ventana emergente para descubrir usua %1$s ha hecho la sala pública para cualquier persona con el link. %1$s: Ahora la sala solo es accesible por invitación. Mensajes no leídos - Es tu conversación. Hazla tuya. + Es tu conversación. Sé su dueño. Envía mensajes a personas o grupos Mantén las conversaciones privadas con encriptación Extiende y personaliza tu experiencia @@ -1821,7 +1821,7 @@ Por favor permite el acceso en la próxima ventana emergente para descubrir usua Dirección de servicios de Element Matrix Ingrese la dirección del servidor que desea utilizar Se enviará un correo electrónico de verificación a su bandeja de entrada para confirmar la configuración de su nueva contraseña. - Próximo + Siguiente Email Nueva contraseña ¡Advertencia! @@ -1844,7 +1844,7 @@ Por favor permite el acceso en la próxima ventana emergente para descubrir usua Configure un correo electrónico para recuperar su cuenta. Más tarde, opcionalmente, puede permitir que las personas que conoce lo descubran mediante su correo electrónico. Correo electrónico Email (opcional) - Próximo + Siguiente Establecer número de teléfono Configure un número de teléfono para permitir que las personas que conoce lo descubran opcionalmente. Utilice el formato internacional. @@ -2183,8 +2183,8 @@ Por favor permite el acceso en la próxima ventana emergente para descubrir usua Añadir a Baja prioridad Rotar y recortar - $d segundo - $d segundos + % segundo + %d segundos Por favor, haz click en la notificación. Si no la ves, por favor revisa las preferencias del sistema. Mostrar notificación From a8f2fd3f4b0f0cfa87fca805cc98f716f7c2ce84 Mon Sep 17 00:00:00 2001 From: AlexanderLevchenkoTechs Date: Mon, 16 Nov 2020 22:19:55 +0000 Subject: [PATCH 35/66] Translated using Weblate (Ukrainian) Currently translated at 43.6% (844 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/uk/ --- vector/src/main/res/values-uk/strings.xml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/vector/src/main/res/values-uk/strings.xml b/vector/src/main/res/values-uk/strings.xml index 22ebb6c885..fdc69678fd 100644 --- a/vector/src/main/res/values-uk/strings.xml +++ b/vector/src/main/res/values-uk/strings.xml @@ -1002,4 +1002,20 @@ Резервне копіювання ключів… Якщо вийти зараз, ви втратите свої зашифровані повідомлення Перевірка сеансу + Стікер + Галерея + Файл + Додати зображення з + Контакт + Камера + Аудіо + Створити нову кімнату + Кімнати + Пошук в зашифрованих кімнатах не підтримується на даний момент. + Запитувати підтвердження перед початком дзвінку + Запобігати випадковим дзвінкам + Мені не потрібні мої зашифровані повідомлення + Скасувати зміни + SSL помилка. + Ви не можете здійснити дзвінок із самим собою, дочекайтесь, доки інші учасники приймуть ваше запрошення \ No newline at end of file From 14bf0038a921490af4d64571be7845bfdf9d2028 Mon Sep 17 00:00:00 2001 From: Victor Cuadrado Juan Date: Sun, 15 Nov 2020 22:57:08 +0000 Subject: [PATCH 36/66] Translated using Weblate (Spanish) Currently translated at 100.0% (190 of 190 strings) Translation: Element Android/Element Android Sdk Translate-URL: https://translate.element.io/projects/element-android/element-sdk/es/ --- .../src/main/res/values-es/strings.xml | 104 +++++++----------- 1 file changed, 42 insertions(+), 62 deletions(-) diff --git a/matrix-sdk-android/src/main/res/values-es/strings.xml b/matrix-sdk-android/src/main/res/values-es/strings.xml index e2d09c7857..3648ca3a72 100644 --- a/matrix-sdk-android/src/main/res/values-es/strings.xml +++ b/matrix-sdk-android/src/main/res/values-es/strings.xml @@ -1,9 +1,7 @@ - + - %1$s: %2$s %1$s envió una imagen. - la invitación de %s %1$s invitó a %2$s %1$s te ha invitado @@ -30,61 +28,44 @@ todos los miembros de la sala. todos. desconocido (%s). - %1$s activó el cifrado de extremo a extremo (%2$s) - + %1$s ha activado la encriptación de Extremo-a-Extremo (%2$s) %1$s solicitó una conferencia de vozIP conferencia de vozIP iniciada conferencia de vozIP finalizada - (el avatar también se cambió) %1$s eliminó el nombre de la sala %1$s eliminó el tema de la sala %1$s actualizó su perfil %2$s %1$s invitó a %2$s a unirse a la sala %1$s aceptó la invitación para %2$s - ** No es posible descifrar: %s ** El dispositivo emisor no nos ha enviado las claves para este mensaje. - No se pudo redactar No es posible enviar el mensaje - No se pudo cargar la imagen - Error de red Error de Matrix - - - - Actualmente no es posible volver a unirse a una sala vacía. - - Mensaje cifrado - + Mensaje encriptado Dirección de correo electrónico Número telefónico - %1$s envió una pegatina. - Invitación de %s Invitación a Sala %1$s y %2$s Sala vacía - %1$s y 1 otro %1$s y %2$d otros - - Mensaje eliminado Mensaje eliminado por %1$s Mensaje eliminado [motivo: %1$s] @@ -98,10 +79,8 @@ \nImportando Comunidades Sincronización Inicial: \nImportando Datos de la Cuenta - Enviando mensaje… Borrar cola de envío - %1$s ha invitado a %2$s. Razón: %3$s %1$s te ha invitado. Razón: %2$s %1$s se ha unido. Razón: %2$s @@ -111,9 +90,7 @@ %1$s ha baneado a %2$s. Razón: %3$s %1$s ha aceptado la invitación para %2$s. Razón: %3$s %1$s ha eliminado la dirección principal para esta sala. - %s ha actualizado la sala. - Sincronización Inicial: \nImportando criptografía Sincronización Inicial: @@ -127,32 +104,25 @@ %1$s envió una invitación a %2$s para que se una a la sala. Razón: %3$s %1$s revocó la invitación de %2$s para unirse a la sala. Razón: %3$s %1$s ha retirado la invitación de %2$s. Razón: %3$s - %1$s ha añadido %2$s como alias de esta sala. %1$s ha añadido %2$s como alias de esta sala. - - %1$s ha quitado %2$s como alias de esta habitación. - %1$s ha quitado %2$s como alias de esta habitación. + %1$s ha quitado %2$s como alias de esta sala. + %1$s ha quitado %2$s como alias de esta sala. - %1$s ha establecido la dirección principal de esta sala a %2$s. %1$s ha permitido que los invitados se unan a la sala. %1$s ha impedido que los invitados se unan a la sala. - %1$s ha activado la encriptación extremo a extremo. %1$s ha activado la encriptación de extremo a extremo (algoritmo no reconocido %2$s). - %s solicita verificar su clave, pero su cliente no soporta la verificación de la clave en chat. Necesitará usar la verificación de claves clásica para poder verificar las claves. - Enviaste una imagen. Enviaste un sticker. - Tu invitación - %1$s creó la habitación - Tu creaste la habitación + %1$s creó la sala + Creaste la sala Invitaste a %1$s Te uniste a la Sala Dejaste la Sala @@ -167,8 +137,8 @@ Quitaste tu nombre para mostrar (era %1$s) Cambiaste el tema a: %1$s %1$s cambió el avatar de la sala - Cambiaste el avatar de la habitación - Cambiaste el nombre de la habitación a: %1$s + Cambiaste el avatar de la sala + Cambiaste el nombre de la sala a: %1$s Hiciste una videollamada. Hiciste una llamada de voz. %s envió datos para configurar la llamada. @@ -176,40 +146,35 @@ Respondiste la llamada. Terminaste la llamada. Hiciste visible el futuro historial de la %1$s - Activó el cifrado de un extremo a otro (%1$s) - Has mejorado esta habitación. - + Has activado la encriptación de Extremo-a-Extremo (%1$s) + Has actualizado esta sala. Solicitaste una conferencia de VoIP Quitaste el nombre de la sala Quitaste el tema de la sala - %1$s eliminó el avatar de la habitación - Quitaste el avatar de la habitación + %1$s eliminó el avatar de la sala + Quitaste el avatar de la sala Actualizaste tu perfil %1$s Enviaste una invitación a %1$s para unirse a la sala Revocaste la invitación para que %1$s se una a la sala Aceptaste la invitación para %1$s - %1$s agrego el widget %2$s Agregaste el widget %1$s %1$s eliminó el widget %2$s Quitaste el widget %1$s %1$s modifico el widget %2$s Modificaste el widget %1$s - Administrador Moderador Por defecto Personalizado (%1$d) Personalizado - Cambiaste el nivel de potencia de %1$s. %1$s cambió el nivel de potencia de %2$s. %1$s de %2$s a %3$s - Tu invitación. Razón: %1$s - "nvitaste a %1$s. Razón: %2$s" - Te uniste a la habitación. Razón: %1$s - Dejaste la habitación. Razón: %1$s + Invitaste a %1$s. Razón: %2$s + Te uniste a la sala. Razón: %1$s + Dejaste la sala. Razón: %1$s Rechazaste la invitación. Razón: %1$s Pateaste a %1$s. Motivo: %2$s Has desactivado a %1$s. Motivo: %2$s @@ -218,27 +183,42 @@ Revocaste la invitación para que %1$s se una a la sala. Motivo: %2$s Aceptaste la invitación para %1$s. Motivo: %2$s Retiró la invitación de %1$s\'s. Motivo: %2$s - Agregaste %1$s como dirección para esta sala. Agregaste %1$s como direcciones para esta sala. - Quitaste %1$s como dirección para esta sala. Quitaste %1$s como direcciones para esta sala. - - "%1$s agregó %2$s y eliminó %3$s como direcciones para esta sala." + %1$s añadió %2$s y eliminó %3$s como alias para esta sala. Agregaste %1$s y quitaste %2$s como direcciones para esta sala. - Estableciste la dirección principal de esta sala en %1$s. Quitaste la dirección principal de esta sala. - Ha permitido que los invitados se unan a la sala. Ha impedido que los invitados se unan a la sala. - - Activó el cifrado de extremo a extremo. - Activó el cifrado de un extremo a otro (algoritmo %1$s no reconocido). - - + Tu has activado la encriptación de Extremo-a-Extremo. + Has activado la encriptación de Extremo-a-Extremo (algoritmo %1$s no reconocido). + Has impedido que invitados se unan a la sala. + Has permitido a invitados unirse aquí. + Te has ido. Razón: %1$s + Has revocado la invitación de %1$s + Has invitado a %1$s + Has actualizado aquí. + Has hecho futuros mensajes visibles a %1$s + Te saliste de la sala + Te uniste + Creaste la conversación + %1$s ha impedido que invitados se unan a la sala. + %1$s ha permitido a invitados a unirse aquí. + %1$s se ha ido. Razón: %2$s + Tu te has unido. Razón: %1$s + %1$s se ha unido. Razón: %2$s + %1$s ha revocado la invitación de %2$s + %1$s ha invitado %2$s + %s ha actualizado aquí. + %1$s ha hecho futuros mensajes visibles a %2$s + %1$s ha salido de la sala + %1$s se ha unido + %1$s ha creado la conversación + \ No newline at end of file From c81c5c48019cc481fec9c4402fa2ec81ff2fea11 Mon Sep 17 00:00:00 2001 From: Victor Cuadrado Juan Date: Sun, 15 Nov 2020 23:10:21 +0000 Subject: [PATCH 37/66] Translated using Weblate (Spanish) Currently translated at 100.0% (4 of 4 strings) Translation: Element Android/Element Android Store Translate-URL: https://translate.element.io/projects/element-android/element-store/es/ --- .../android/es/changelogs/40100100.txt | 1 + .../metadata/android/es/full_description.txt | 28 +++++++++---------- .../metadata/android/es/short_description.txt | 2 +- fastlane/metadata/android/es/title.txt | 2 +- 4 files changed, 17 insertions(+), 16 deletions(-) create mode 100644 fastlane/metadata/android/es/changelogs/40100100.txt diff --git a/fastlane/metadata/android/es/changelogs/40100100.txt b/fastlane/metadata/android/es/changelogs/40100100.txt new file mode 100644 index 0000000000..70b786d12e --- /dev/null +++ b/fastlane/metadata/android/es/changelogs/40100100.txt @@ -0,0 +1 @@ +// TODO diff --git a/fastlane/metadata/android/es/full_description.txt b/fastlane/metadata/android/es/full_description.txt index 860a1f19c3..8c9915a735 100644 --- a/fastlane/metadata/android/es/full_description.txt +++ b/fastlane/metadata/android/es/full_description.txt @@ -1,30 +1,30 @@ Element es un nuevo tipo de aplicación de mensajería y colaboración que: -1. Le da el control para preservar su privacidad -2. Le permite comunicarse con cualquier persona en la red Matrix e incluso más allá al integrarse con aplicaciones como Slack. -3. Te protege de la publicidad, la minería de datos y los jardines vallados. -4. Lo protege a través del cifrado de un extremo a otro, con firma cruzada para verificar a otros +1. Te da el control para preservar su privacidad +2. Te permite comunicarse con cualquier persona en la red Matrix e incluso más allá al integrarse con aplicaciones como Slack +3. Te protege de la publicidad, la minería de datos y los jardines vallados +4. Te protege a través de encriptación de Extremo-a-Extremo, con firma cruzada para verificar a otros Element es completamente diferente de otras aplicaciones de mensajería y colaboración porque es descentralizado y de código abierto. -Element le permite autohospedarse, o elegir un host, para que tenga privacidad, propiedad y control de sus datos y conversaciones. Te da acceso a una red abierta; para que no se quede atascado hablando solo con otros usuarios de Element. Y es muy seguro. +Element te permite tener su propio servidor privado, o elegir uno público, para que tenga privacidad, posesión, y control de sus datos y conversaciones. Te da acceso a una red abierta; para que no se quede atrapado hablando solo con otros usuarios de Element. Y es muy seguro. Element puede hacer todo esto porque opera en Matrix, el estándar para la comunicación abierta y descentralizada. -Element te da el control permitiéndote elegir quién aloja tus conversaciones. Desde la aplicación Element, puede elegir hospedar de diferentes maneras: +Element te da el control permitiéndote elegir quién aloja tus conversaciones. Desde la aplicación Element, puedes elegir hospedar de diferentes maneras: -1. Obtenga una cuenta gratuita en el servidor público de matrix.org alojado por los desarrolladores de Matrix, o elija entre miles de servidores públicos alojados por voluntarios -2. Autohospede su cuenta ejecutando un servidor en su propio hardware -3. Regístrese para obtener una cuenta en un servidor personalizado simplemente suscribiéndose a la plataforma de alojamiento de Element Matrix Services +1. Obtén una cuenta gratuita en el servidor público de matrix.org alojado por los desarrolladores de Matrix, o elije entre miles de servidores públicos alojados por voluntarios +2. Autohospeda tu cuenta con un servidor en tu propio hardware +3. Regístrate para obtener una cuenta en un servidor personalizado simplemente suscribiéndote a la plataforma de alojamiento de Element Matrix Services ¿Por qué elegir Element? -POSEE SUS DATOS: Tú decides dónde guardar tus datos y mensajes. Usted es el propietario y lo controla, no algún MEGACORP que extraiga sus datos o dé acceso a terceros. +TOMA POSESIÓN DE TUS DATOS: Tú decides dónde guardar tus datos y mensajes. Tú eres el propietario y quien lo controla, no alguna MEGACORP que extrae tu datos o da acceso a terceros. -MENSAJERÍA ABIERTA Y COLABORACIÓN: Puede chatear con cualquier otra persona en la red de Matrix, ya sea que estén usando Element u otra aplicación de Matrix, e incluso si están usando un sistema de mensajería diferente como Slack, IRC o XMPP. +MENSAJERÍA ABIERTA Y COLABORACIÓN: Puede chatear con cualquier otra persona en la red de Matrix, tanto si usan Element u otra aplicación de Matrix, e incluso si están usando un sistema de mensajería diferente como Slack, IRC o XMPP. -SUPER SEGURO: Cifrado real de extremo a extremo (solo aquellos en la conversación pueden descifrar mensajes) y firma cruzada para verificar los dispositivos de los participantes de la conversación. +SUPER SEGURO: Encriptación de Extremo-a-Extremo real (solo aquellos en la conversación pueden descifrar mensajes) y firma cruzada para verificar los dispositivos de los participantes de la conversación. -COMUNICACIÓN COMPLETA: Mensajería, llamadas de voz y video, uso compartido de archivos, uso compartido de pantalla y un montón de integraciones, bots y widgets. Construya salas, comunidades, manténgase en contacto y haga las cosas. +COMUNICACIÓN COMPLETA: Mensajería, llamadas de voz y video, uso compartido de archivos, uso compartido de pantalla y un montón de integraciones, bots y widgets. Crea salas, comunidades, mantente en contacto y organízate con eficacia. -EN TODAS PARTES: Manténgase en contacto donde quiera que esté con un historial de mensajes totalmente sincronizado en todos sus dispositivos y en la web en https://app.element.io. +EN TODAS PARTES: Mantente en contacto donde quiera que estés con un historial de mensajes totalmente sincronizado en todos sus dispositivos y en la web en https://app.element.io. diff --git a/fastlane/metadata/android/es/short_description.txt b/fastlane/metadata/android/es/short_description.txt index 0562213351..473228e0df 100644 --- a/fastlane/metadata/android/es/short_description.txt +++ b/fastlane/metadata/android/es/short_description.txt @@ -1 +1 @@ -Chat y VoIP descentralizados seguros. Mantenga sus datos a salvo de terceros. +Chat y VoIP descentralizados y seguros. Mantén tus datos a salvo de terceros. diff --git a/fastlane/metadata/android/es/title.txt b/fastlane/metadata/android/es/title.txt index adc831006a..971e5cf146 100644 --- a/fastlane/metadata/android/es/title.txt +++ b/fastlane/metadata/android/es/title.txt @@ -1 +1 @@ -Element (anteriorment Riot.im) +Element (previamente Riot.im) From 5bf4fffd2f4687cf6681bce845be105027cb80d2 Mon Sep 17 00:00:00 2001 From: Rintan Date: Tue, 17 Nov 2020 09:41:04 +0000 Subject: [PATCH 38/66] Translated using Weblate (Japanese) Currently translated at 50.5% (978 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/ja/ --- vector/src/main/res/values-ja/strings.xml | 38 +++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/vector/src/main/res/values-ja/strings.xml b/vector/src/main/res/values-ja/strings.xml index e0bfdb930d..e764f5001b 100644 --- a/vector/src/main/res/values-ja/strings.xml +++ b/vector/src/main/res/values-ja/strings.xml @@ -1060,4 +1060,42 @@ Matrixでのメッセージの可視性は電子メールと同様です。メ スキャンできません 断る 検証リクエスト + 通話の開始前に確認する + 意図しない通話を阻止する + お使いの端末は脆弱性のある古いTLSセキュリティプロトコルを使用しています、このセキュリティでは接続できません + SSLエラー + SSLエラー:相手のアイデンティティが認証されていません。 + このURLからホームサーバーに接続できませんでした、ご確認ください + 有効なMatrixサーバーアドレスではありません + このURLは検索結果に表示できません、ご確認ください + この電話番号はすでに使用されています。 + 復旧用のメールアドレスを設定します。後からオプションでメールアドレスや電話番号を使用して知人に見つけてもらえるようにできます。 + シングルサインオンを使用してサインインする + HDを使用する + HDを使用しない + 背面 + 前面 + カメラの切り替え + ワイヤレスヘッドセット + ヘッドセット + スピーカー + 電話 + サウンドデバイスを選択 + リアルタイム接続を確立できませんでした。 +\nホームサーバーの管理者に、通話が正常に動作するためにTURNを設定するようご連絡ください。 + 再び表示しない + アイデンティティサーバーが設定されていません。 + 終了 + 拒否 + 承諾 + 中止 + ウィジェットを削除できませんでした + ウィジェットを追加できませんでした + ビデオ通話を開始 + 会議が進行中です! + 通話を開始する権限がありません + このルームで通話を開始する権限がありません + グループ通話を開始する権限がありません + リセット + なし \ No newline at end of file From 8a44ee9d5063b82e8655af017b16811e34218971 Mon Sep 17 00:00:00 2001 From: Rintan Date: Tue, 17 Nov 2020 09:53:17 +0000 Subject: [PATCH 39/66] Translated using Weblate (Japanese) Currently translated at 42.6% (81 of 190 strings) Translation: Element Android/Element Android Sdk Translate-URL: https://translate.element.io/projects/element-android/element-sdk/ja/ --- .../src/main/res/values-ja/strings.xml | 44 ++++++++++++------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/matrix-sdk-android/src/main/res/values-ja/strings.xml b/matrix-sdk-android/src/main/res/values-ja/strings.xml index 366c743494..add19edfaf 100644 --- a/matrix-sdk-android/src/main/res/values-ja/strings.xml +++ b/matrix-sdk-android/src/main/res/values-ja/strings.xml @@ -1,10 +1,8 @@ - + - %1$s: %2$s %1$sが画像を送信しました。 %1$sがスタンプを送信しました。 - %sの招待 %1$sが%2$sを招待しました %1$sがあなたを招待しました @@ -29,11 +27,9 @@ 部屋への招待 %1$sと%2$s 空の部屋 - %1$sと他%2$d名 - %1$sは、今後の部屋履歴を%2$sに表示させました 部屋のメンバー全員、招待された時点から。 部屋のメンバー全員、参加した時点から。 @@ -41,34 +37,50 @@ 誰でも。 不明 (%s)。 %1$s がエンドツーエンド暗号化を有効にしました (%2$s) - %1$s がVoIP会議をリクエストしました VoIP会議が開始されました VoIP会議が終了しました - (アバターも変更された) %1$s が部屋名を削除しました %1$s がルームトピックを削除しました %1$s がプロフィール %2$s を更新しました %1$s は %2$s に部屋に参加するよう招待状を送りました %1$sは%2$sの招待を受け入れました - ** 解読できません: %s ** 送信者の端末からこのメッセージのキーが送信されていません。 - 修正できませんでした メッセージを送信できません - 画像のアップロードに失敗しました - ネットワークエラー Matrixエラー - 現在空の部屋に再参加することはできません。 - 暗号化されたメッセージ - メールアドレス 電話番号 - - + ルームのアバターを変更しました + %1$sがルームのアバターを変更しました + トピックを%1$sに変更しました + 表示名を削除しました(%1$sでした) + 表示名を%1$sから%2$sに変更しました + 表示名を%1$sに設定しました + アバターを変更しました + %1$sの招待を取り下げました + %1$sをBANしました + %1$sのBANを解除しました + %1$sを退出させました + 招待を拒否しました + ルームから退出しました + %1$sがルームから退出しました + ルームから退出しました + 参加しました + %1$sが参加しました + ルームに参加しました + %1$sを招待しました + ディスカッションを作成しました + %1$sがディスカッションを作成しました + ルームを作成しました + %1$sがルームを作成しました + 招待 + ステッカーを送信しました。 + 画像を送信しました。 + \ No newline at end of file From 029d8574f1ed8cb72975317f1dc6de5201993aea Mon Sep 17 00:00:00 2001 From: Besnik Bleta Date: Wed, 18 Nov 2020 15:35:19 +0000 Subject: [PATCH 40/66] Translated using Weblate (Albanian) Currently translated at 99.4% (1923 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/sq/ --- vector/src/main/res/values-sq/strings.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vector/src/main/res/values-sq/strings.xml b/vector/src/main/res/values-sq/strings.xml index 81d64d9669..ce76f7c387 100644 --- a/vector/src/main/res/values-sq/strings.xml +++ b/vector/src/main/res/values-sq/strings.xml @@ -2177,4 +2177,8 @@ Subjekt Subjekt dhome (në daçi) Emër dhome + Eksporto Auditim + Mesazh i drejtpërdrejtë + Dërgo historik kërkesash për dhënie kyçesh + S’ka më përfundime \ No newline at end of file From e8d084b85557610239fba56fa4a8d85c69183ecf Mon Sep 17 00:00:00 2001 From: TR-SLimey <37966924+TR-SLimey@users.noreply.github.com> Date: Fri, 6 Nov 2020 13:04:21 +0000 Subject: [PATCH 41/66] Add ability to share profile by QR code --- AUTHORS.md | 8 +- CHANGES.md | 2 +- .../createdirect/CreateDirectRoomActivity.kt | 74 ++++--- .../CreateDirectRoomByQrCodeFragment.kt | 108 ++++++++++ .../createdirect/CreateDirectRoomViewModel.kt | 2 +- .../room/filtered/FilteredRoomFooterItem.kt | 4 +- .../home/room/list/RoomListFragment.kt | 28 ++- .../home/room/list/widget/DmsFabMenuView.kt | 102 +++++++++ .../{FabMenuView.kt => NotifsFabMenuView.kt} | 8 +- .../features/navigation/DefaultNavigator.kt | 4 +- .../app/features/navigation/Navigator.kt | 2 +- .../roomdirectory/picker/RoomDirectoryItem.kt | 4 +- .../RoomMemberProfileFragment.kt | 20 +- .../main/res/drawable/ic_fab_add_by_mxid.xml | 30 +++ .../res/drawable/ic_fab_add_by_qr_code.xml | 30 +++ .../main/res/layout/dialog_share_qr_code.xml | 16 ++ .../main/res/layout/fragment_room_list.xml | 20 +- .../res/layout/motion_dms_fab_menu_merge.xml | 79 +++++++ ...e.xml => motion_notifs_fab_menu_merge.xml} | 2 +- vector/src/main/res/values/strings.xml | 9 + .../res/xml/motion_scene_dms_fab_menu.xml | 199 ++++++++++++++++++ ...u.xml => motion_scene_notifs_fab_menu.xml} | 0 22 files changed, 680 insertions(+), 71 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomByQrCodeFragment.kt create mode 100644 vector/src/main/java/im/vector/app/features/home/room/list/widget/DmsFabMenuView.kt rename vector/src/main/java/im/vector/app/features/home/room/list/widget/{FabMenuView.kt => NotifsFabMenuView.kt} (88%) create mode 100644 vector/src/main/res/drawable/ic_fab_add_by_mxid.xml create mode 100644 vector/src/main/res/drawable/ic_fab_add_by_qr_code.xml create mode 100644 vector/src/main/res/layout/dialog_share_qr_code.xml create mode 100644 vector/src/main/res/layout/motion_dms_fab_menu_merge.xml rename vector/src/main/res/layout/{motion_fab_menu_merge.xml => motion_notifs_fab_menu_merge.xml} (98%) create mode 100644 vector/src/main/res/xml/motion_scene_dms_fab_menu.xml rename vector/src/main/res/xml/{motion_scene_fab_menu.xml => motion_scene_notifs_fab_menu.xml} (100%) diff --git a/AUTHORS.md b/AUTHORS.md index 823dbc7311..ad20133d83 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -39,7 +39,7 @@ We do not forget all translators, for their work of translating Element into man Feel free to add your name below, when you contribute to the project! -Name | Matrix ID | GitHub ---------|---------------------|-------------------------------------- -gjpower | @gjpower:matrix.org | [gjpower](https://github.com/gjpower) - +Name | Matrix ID | GitHub +----------|-----------------------------|-------------------------------------- +gjpower | @gjpower:matrix.org | [gjpower](https://github.com/gjpower) +TR_SLimey | @tr_slimey:an-atom-in.space | [TR-SLimey](https://github.com/TR-SLimey) diff --git a/CHANGES.md b/CHANGES.md index 80bb2c66b8..4873a999b6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,7 +2,7 @@ Changes in Element 1.0.11 (2020-XX-XX) =================================================== Features ✨: - - + - Create DMs with users by scanning their QR code (#2025) Improvements 🙌: - New room creation tile with quick action (#2346) diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt index 10ab1673e4..2035ee50f6 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt @@ -22,6 +22,7 @@ import android.content.Context import android.content.Intent import android.os.Bundle import android.view.View +import android.widget.Toast import androidx.appcompat.app.AlertDialog import com.airbnb.mvrx.Async import com.airbnb.mvrx.Fail @@ -37,6 +38,8 @@ import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.SimpleFragmentActivity import im.vector.app.core.platform.WaitingViewData import im.vector.app.core.utils.PERMISSIONS_FOR_MEMBERS_SEARCH +import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO +import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_READ_CONTACTS import im.vector.app.core.utils.allGranted import im.vector.app.core.utils.checkPermissions @@ -72,35 +75,45 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() { super.onCreate(savedInstanceState) toolbar.visibility = View.GONE sharedActionViewModel = viewModelProvider.get(UserDirectorySharedActionViewModel::class.java) - sharedActionViewModel - .observe() - .subscribe { sharedAction -> - when (sharedAction) { - UserDirectorySharedAction.OpenUsersDirectory -> - addFragmentToBackstack(R.id.container, UserDirectoryFragment::class.java) - UserDirectorySharedAction.Close -> finish() - UserDirectorySharedAction.GoBack -> onBackPressed() - is UserDirectorySharedAction.OnMenuItemSelected -> onMenuItemSelected(sharedAction) - UserDirectorySharedAction.OpenPhoneBook -> openPhoneBook() - }.exhaustive - } - .disposeOnDestroy() - if (isFirstCreation()) { - addFragment( - R.id.container, - KnownUsersFragment::class.java, - KnownUsersFragmentArgs( - title = getString(R.string.fab_menu_create_chat), - menuResId = R.menu.vector_create_direct_room, - isCreatingRoom = true - ) - ) + if (intent?.getBooleanExtra(BY_QR_CODE, false)!!) { + if (isFirstCreation()) { openAddByQrCode() } + } else { + sharedActionViewModel + .observe() + .subscribe { sharedAction -> + when (sharedAction) { + UserDirectorySharedAction.OpenUsersDirectory -> + addFragmentToBackstack(R.id.container, UserDirectoryFragment::class.java) + UserDirectorySharedAction.Close -> finish() + UserDirectorySharedAction.GoBack -> onBackPressed() + is UserDirectorySharedAction.OnMenuItemSelected -> onMenuItemSelected(sharedAction) + UserDirectorySharedAction.OpenPhoneBook -> openPhoneBook() + }.exhaustive + } + .disposeOnDestroy() + if (isFirstCreation()) { + addFragment( + R.id.container, + KnownUsersFragment::class.java, + KnownUsersFragmentArgs( + title = getString(R.string.fab_menu_create_chat), + menuResId = R.menu.vector_create_direct_room, + isCreatingRoom = true + ) + ) + } } viewModel.selectSubscribe(this, CreateDirectRoomViewState::createAndInviteState) { renderCreateAndInviteState(it) } } + private fun openAddByQrCode() { + if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this, PERMISSION_REQUEST_CODE_LAUNCH_CAMERA, 0)) { + addFragment(R.id.container, CreateDirectRoomByQrCodeFragment::class.java) + } + } + private fun openPhoneBook() { // Check permission first if (checkPermissions(PERMISSIONS_FOR_MEMBERS_SEARCH, @@ -116,6 +129,13 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() { if (allGranted(grantResults)) { if (requestCode == PERMISSION_REQUEST_CODE_READ_CONTACTS) { doOnPostResume { addFragmentToBackstack(R.id.container, ContactsBookFragment::class.java) } + } else if (requestCode == PERMISSION_REQUEST_CODE_LAUNCH_CAMERA && intent?.getBooleanExtra(BY_QR_CODE, false)!!) { + addFragment(R.id.container, CreateDirectRoomByQrCodeFragment::class.java) + } + } else { + Toast.makeText(baseContext, R.string.missing_permissions_error, Toast.LENGTH_SHORT).show() + if (requestCode == PERMISSION_REQUEST_CODE_LAUNCH_CAMERA && intent?.getBooleanExtra(BY_QR_CODE, false)!!) { + finish() } } } @@ -178,8 +198,12 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() { } companion object { - fun getIntent(context: Context): Intent { - return Intent(context, CreateDirectRoomActivity::class.java) + private const val BY_QR_CODE = "BY_QR_CODE" + + fun getIntent(context: Context, byQrCode: Boolean = false): Intent { + return Intent(context, CreateDirectRoomActivity::class.java).apply { + putExtra(BY_QR_CODE, byQrCode) + } } } } diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomByQrCodeFragment.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomByQrCodeFragment.kt new file mode 100644 index 0000000000..f03368fdd5 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomByQrCodeFragment.kt @@ -0,0 +1,108 @@ +/* + * Copyright 2020 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.app.features.createdirect + +import android.widget.Toast +import com.airbnb.mvrx.activityViewModel +import com.google.zxing.Result +import com.google.zxing.ResultMetadataType +import im.vector.app.R +import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.features.userdirectory.PendingInvitee +import kotlinx.android.synthetic.main.fragment_qr_code_scanner.* +import me.dm7.barcodescanner.zxing.ZXingScannerView +import org.matrix.android.sdk.api.session.permalinks.PermalinkData +import org.matrix.android.sdk.api.session.permalinks.PermalinkParser +import org.matrix.android.sdk.api.session.user.model.User +import javax.inject.Inject + +class CreateDirectRoomByQrCodeFragment @Inject constructor() : VectorBaseFragment(), ZXingScannerView.ResultHandler { + + private val viewModel: CreateDirectRoomViewModel by activityViewModel() + + override fun getLayoutResId() = R.layout.fragment_qr_code_scanner + + override fun onResume() { + super.onResume() + // Register ourselves as a handler for scan results. + scannerView.setResultHandler(null) + // Start camera on resume + scannerView.startCamera() + } + + override fun onPause() { + super.onPause() + // Stop camera on pause + scannerView.stopCamera() + } + + // Copied from https://github.com/markusfisch/BinaryEye/blob/ + // 9d57889b810dcaa1a91d7278fc45c262afba1284/app/src/main/kotlin/de/markusfisch/android/binaryeye/activity/CameraActivity.kt#L434 + private fun getRawBytes(result: Result): ByteArray? { + val metadata = result.resultMetadata ?: return null + val segments = metadata[ResultMetadataType.BYTE_SEGMENTS] ?: return null + var bytes = ByteArray(0) + @Suppress("UNCHECKED_CAST") + for (seg in segments as Iterable) { + bytes += seg + } + // byte segments can never be shorter than the text. + // Zxing cuts off content prefixes like "WIFI:" + return if (bytes.size >= result.text.length) bytes else null + } + + private fun addByQrCode(value: String) { + val mxid = (PermalinkParser.parse(value) as? PermalinkData.UserLink)?.userId + + if (mxid === null) { + Toast.makeText(requireContext(), R.string.invalid_qr_code_uri, Toast.LENGTH_SHORT).show() + requireActivity().finish() + } else { + val existingDm = viewModel.session.getExistingDirectRoomWithUser(mxid) + + if (existingDm === null) { + // The following assumes MXIDs are case insensitive + if (mxid.equals(other = viewModel.session.myUserId, ignoreCase = true)) { + Toast.makeText(requireContext(), R.string.cannot_dm_self, Toast.LENGTH_SHORT).show() + requireActivity().finish() + } else { + // Try to get user from known users and fall back to creating a User object from MXID + val qrInvitee = if (viewModel.session.getUser(mxid) != null) viewModel.session.getUser(mxid)!! else User(mxid, null, null) + + viewModel.handle( + CreateDirectRoomAction.CreateRoomAndInviteSelectedUsers(setOf(PendingInvitee.UserPendingInvitee(qrInvitee))) + ) + } + } else { + navigator.openRoom(requireContext(), existingDm, null, false) + requireActivity().finish() + } + } + } + + override fun handleResult(result: Result?) { + if (result === null) { + Toast.makeText(requireContext(), R.string.qr_code_not_scanned, Toast.LENGTH_SHORT).show() + requireActivity().finish() + } else { + val rawBytes = getRawBytes(result) + val rawBytesStr = rawBytes?.toString(Charsets.ISO_8859_1) + val value = rawBytesStr ?: result.text + addByQrCode(value) + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt index be9449b77a..d074c93587 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt @@ -38,7 +38,7 @@ import org.matrix.android.sdk.rx.rx class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted initialState: CreateDirectRoomViewState, private val rawService: RawService, - private val session: Session) + val session: Session) : VectorViewModel(initialState) { @AssistedInject.Factory diff --git a/vector/src/main/java/im/vector/app/features/home/room/filtered/FilteredRoomFooterItem.kt b/vector/src/main/java/im/vector/app/features/home/room/filtered/FilteredRoomFooterItem.kt index 0884844777..42bef2ddae 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/filtered/FilteredRoomFooterItem.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/filtered/FilteredRoomFooterItem.kt @@ -22,7 +22,7 @@ import com.airbnb.epoxy.EpoxyModelClass import im.vector.app.R import im.vector.app.core.epoxy.VectorEpoxyHolder import im.vector.app.core.epoxy.VectorEpoxyModel -import im.vector.app.features.home.room.list.widget.FabMenuView +import im.vector.app.features.home.room.list.widget.NotifsFabMenuView @EpoxyModelClass(layout = R.layout.item_room_filter_footer) abstract class FilteredRoomFooterItem : VectorEpoxyModel() { @@ -46,7 +46,7 @@ abstract class FilteredRoomFooterItem : VectorEpoxyModel(R.id.roomFilterFooterOpenRoomDirectory) } - interface FilteredRoomFooterItemListener : FabMenuView.Listener { + interface FilteredRoomFooterItemListener : NotifsFabMenuView.Listener { fun createRoom(initialName: String) } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt index f1d35a74d5..e47072d0b0 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt @@ -45,7 +45,8 @@ import im.vector.app.features.home.room.list.actions.RoomListActionsArgs import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedAction import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel -import im.vector.app.features.home.room.list.widget.FabMenuView +import im.vector.app.features.home.room.list.widget.DmsFabMenuView +import im.vector.app.features.home.room.list.widget.NotifsFabMenuView import im.vector.app.features.notifications.NotificationDrawerManager import kotlinx.android.parcel.Parcelize import kotlinx.android.synthetic.main.fragment_room_list.* @@ -66,8 +67,7 @@ class RoomListFragment @Inject constructor( val roomListViewModelFactory: RoomListViewModel.Factory, private val notificationDrawerManager: NotificationDrawerManager, private val sharedViewPool: RecyclerView.RecycledViewPool - -) : VectorBaseFragment(), RoomSummaryController.Listener, OnBackPressed, FabMenuView.Listener { +) : VectorBaseFragment(), RoomSummaryController.Listener, OnBackPressed, DmsFabMenuView.Listener, NotifsFabMenuView.Listener { private var modelBuildListener: OnModelBuildFinishedListener? = null private lateinit var sharedActionViewModel: RoomListQuickActionsSharedActionViewModel @@ -111,6 +111,7 @@ class RoomListFragment @Inject constructor( }.exhaustive } + createDmFabMenu.listener = this createChatFabMenu.listener = this sharedActionViewModel @@ -129,6 +130,7 @@ class RoomListFragment @Inject constructor( roomListView.cleanup() roomController.listener = null stateRestorer.clear() + createDmFabMenu.listener = null createChatFabMenu.listener = null super.onDestroyView() } @@ -140,33 +142,32 @@ class RoomListFragment @Inject constructor( private fun setupCreateRoomButton() { when (roomListParams.displayMode) { RoomListDisplayMode.NOTIFICATIONS -> createChatFabMenu.isVisible = true - RoomListDisplayMode.PEOPLE -> createChatRoomButton.isVisible = true + RoomListDisplayMode.PEOPLE -> createDmFabMenu.isVisible = true RoomListDisplayMode.ROOMS -> createGroupRoomButton.isVisible = true else -> Unit // No button in this mode } - createChatRoomButton.debouncedClicks { - createDirectChat() - } createGroupRoomButton.debouncedClicks { openRoomDirectory() } - // Hide FAB when list is scrolling + // Hide FABs when list is scrolling roomListView.addOnScrollListener( object : RecyclerView.OnScrollListener() { override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { + createDmFabMenu.removeCallbacks(showFabRunnable) createChatFabMenu.removeCallbacks(showFabRunnable) when (newState) { RecyclerView.SCROLL_STATE_IDLE -> { + createDmFabMenu.postDelayed(showFabRunnable, 250) createChatFabMenu.postDelayed(showFabRunnable, 250) } RecyclerView.SCROLL_STATE_DRAGGING, RecyclerView.SCROLL_STATE_SETTLING -> { when (roomListParams.displayMode) { RoomListDisplayMode.NOTIFICATIONS -> createChatFabMenu.hide() - RoomListDisplayMode.PEOPLE -> createChatRoomButton.hide() + RoomListDisplayMode.PEOPLE -> createDmFabMenu.hide() RoomListDisplayMode.ROOMS -> createGroupRoomButton.hide() else -> Unit } @@ -191,6 +192,10 @@ class RoomListFragment @Inject constructor( navigator.openCreateDirectRoom(requireActivity()) } + override fun createDirectChatByQrCode() { + navigator.openCreateDirectRoom(requireContext(), true) + } + private fun setupRecyclerView() { val layoutManager = LinearLayoutManager(context) stateRestorer = LayoutManagerStateRestorer(layoutManager).register() @@ -209,7 +214,7 @@ class RoomListFragment @Inject constructor( if (isAdded) { when (roomListParams.displayMode) { RoomListDisplayMode.NOTIFICATIONS -> createChatFabMenu.show() - RoomListDisplayMode.PEOPLE -> createChatRoomButton.show() + RoomListDisplayMode.PEOPLE -> createDmFabMenu.show() RoomListDisplayMode.ROOMS -> createGroupRoomButton.show() else -> Unit } @@ -338,6 +343,9 @@ class RoomListFragment @Inject constructor( } override fun onBackPressed(toolbarButton: Boolean): Boolean { + if (createDmFabMenu.onBackPressed()) { + return true + } if (createChatFabMenu.onBackPressed()) { return true } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/widget/DmsFabMenuView.kt b/vector/src/main/java/im/vector/app/features/home/room/list/widget/DmsFabMenuView.kt new file mode 100644 index 0000000000..9659b7b12b --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/list/widget/DmsFabMenuView.kt @@ -0,0 +1,102 @@ +/* + * 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.app.features.home.room.list.widget + +import android.content.Context +import android.util.AttributeSet +import androidx.constraintlayout.motion.widget.MotionLayout +import androidx.core.view.isVisible +import com.google.android.material.floatingactionbutton.FloatingActionButton +import im.vector.app.R +import kotlinx.android.synthetic.main.motion_dms_fab_menu_merge.view.* + +class DmsFabMenuView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, + defStyleAttr: Int = 0) : MotionLayout(context, attrs, defStyleAttr) { + + var listener: Listener? = null + + init { + inflate(context, R.layout.motion_dms_fab_menu_merge, this) + } + + override fun onFinishInflate() { + super.onFinishInflate() + + listOf(createDmByMxid, createDmByMxidLabel) + .forEach { + it.setOnClickListener { + closeFabMenu() + listener?.createDirectChat() + } + } + listOf(createDmByQrCode, createDmByQrCodeLabel) + .forEach { + it.setOnClickListener { + closeFabMenu() + listener?.createDirectChatByQrCode() + } + } + + dmsCreateRoomTouchGuard.setOnClickListener { + closeFabMenu() + } + } + + override fun transitionToEnd() { + super.transitionToEnd() + + dmsCreateRoomButton.contentDescription = context.getString(R.string.a11y_create_menu_close) + } + + override fun transitionToStart() { + super.transitionToStart() + + dmsCreateRoomButton.contentDescription = context.getString(R.string.a11y_create_menu_open) + } + + fun show() { + isVisible = true + dmsCreateRoomButton.show() + } + + fun hide() { + dmsCreateRoomButton.hide(object : FloatingActionButton.OnVisibilityChangedListener() { + override fun onHidden(fab: FloatingActionButton?) { + super.onHidden(fab) + isVisible = false + } + }) + } + + private fun closeFabMenu() { + transitionToStart() + } + + fun onBackPressed(): Boolean { + if (currentState == R.id.constraint_set_fab_menu_open) { + closeFabMenu() + return true + } + + return false + } + + interface Listener { + fun createDirectChat() + fun createDirectChatByQrCode() + } +} diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/widget/FabMenuView.kt b/vector/src/main/java/im/vector/app/features/home/room/list/widget/NotifsFabMenuView.kt similarity index 88% rename from vector/src/main/java/im/vector/app/features/home/room/list/widget/FabMenuView.kt rename to vector/src/main/java/im/vector/app/features/home/room/list/widget/NotifsFabMenuView.kt index f9058840d2..7c96f40dbf 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/widget/FabMenuView.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/widget/NotifsFabMenuView.kt @@ -22,15 +22,15 @@ import androidx.constraintlayout.motion.widget.MotionLayout import androidx.core.view.isVisible import com.google.android.material.floatingactionbutton.FloatingActionButton import im.vector.app.R -import kotlinx.android.synthetic.main.motion_fab_menu_merge.view.* +import kotlinx.android.synthetic.main.motion_notifs_fab_menu_merge.view.* -class FabMenuView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = 0) : MotionLayout(context, attrs, defStyleAttr) { +class NotifsFabMenuView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, + defStyleAttr: Int = 0) : MotionLayout(context, attrs, defStyleAttr) { var listener: Listener? = null init { - inflate(context, R.layout.motion_fab_menu_merge, this) + inflate(context, R.layout.motion_notifs_fab_menu_merge, this) } override fun onFinishInflate() { diff --git a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt index 2d0ca86d52..9ff103113f 100644 --- a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt +++ b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt @@ -203,8 +203,8 @@ class DefaultNavigator @Inject constructor( context.startActivity(intent) } - override fun openCreateDirectRoom(context: Context) { - val intent = CreateDirectRoomActivity.getIntent(context) + override fun openCreateDirectRoom(context: Context, byQrCode: Boolean) { + val intent = CreateDirectRoomActivity.getIntent(context, byQrCode) context.startActivity(intent) } diff --git a/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt b/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt index 504fccb63a..23d24b709c 100644 --- a/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt +++ b/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt @@ -56,7 +56,7 @@ interface Navigator { fun openCreateRoom(context: Context, initialName: String = "") - fun openCreateDirectRoom(context: Context) + fun openCreateDirectRoom(context: Context, byQrCode: Boolean = false) fun openInviteUsersToRoom(context: Context, roomId: String) diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryItem.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryItem.kt index 8f57acee47..7b2e329b6a 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryItem.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryItem.kt @@ -62,7 +62,7 @@ abstract class RoomDirectoryItem : VectorEpoxyModel() holder.avatarView.isInvisible = directoryAvatarUrl.isNullOrBlank() && includeAllNetworks holder.nameView.text = directoryName - holder.descritionView.setTextOrHide(directoryDescription) + holder.descriptionView.setTextOrHide(directoryDescription) } class Holder : VectorEpoxyHolder() { @@ -70,6 +70,6 @@ abstract class RoomDirectoryItem : VectorEpoxyModel() val avatarView by bind(R.id.itemRoomDirectoryAvatar) val nameView by bind(R.id.itemRoomDirectoryName) - val descritionView by bind(R.id.itemRoomDirectoryDescription) + val descriptionView by bind(R.id.itemRoomDirectoryDescription) } } diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt index d60b5580fa..e994a3c3ec 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt @@ -294,12 +294,20 @@ class RoomMemberProfileFragment @Inject constructor( } private fun handleShareRoomMemberProfile(permalink: String) { - startSharePlainTextIntent( - fragment = this, - activityResultLauncher = null, - chooserTitle = null, - text = permalink - ) + val view = layoutInflater.inflate(R.layout.dialog_share_qr_code, null) + val qrCode = view.findViewById(R.id.itemShareQrCodeImage) + qrCode.setData(permalink) + AlertDialog.Builder(requireContext()) + .setView(view) + .setNeutralButton(R.string.ok, null) + .setPositiveButton(R.string.share_by_text) { _, _ -> + startSharePlainTextIntent( + fragment = this, + activityResultLauncher = null, + chooserTitle = null, + text = permalink + ) + }.show() } private fun onAvatarClicked(view: View, userMatrixItem: MatrixItem) { diff --git a/vector/src/main/res/drawable/ic_fab_add_by_mxid.xml b/vector/src/main/res/drawable/ic_fab_add_by_mxid.xml new file mode 100644 index 0000000000..50768871ab --- /dev/null +++ b/vector/src/main/res/drawable/ic_fab_add_by_mxid.xml @@ -0,0 +1,30 @@ + + + + + + + + + diff --git a/vector/src/main/res/drawable/ic_fab_add_by_qr_code.xml b/vector/src/main/res/drawable/ic_fab_add_by_qr_code.xml new file mode 100644 index 0000000000..50768871ab --- /dev/null +++ b/vector/src/main/res/drawable/ic_fab_add_by_qr_code.xml @@ -0,0 +1,30 @@ + + + + + + + + + diff --git a/vector/src/main/res/layout/dialog_share_qr_code.xml b/vector/src/main/res/layout/dialog_share_qr_code.xml new file mode 100644 index 0000000000..d209376edb --- /dev/null +++ b/vector/src/main/res/layout/dialog_share_qr_code.xml @@ -0,0 +1,16 @@ + + + + + + diff --git a/vector/src/main/res/layout/fragment_room_list.xml b/vector/src/main/res/layout/fragment_room_list.xml index f0bc336cbd..855c45f7c5 100644 --- a/vector/src/main/res/layout/fragment_room_list.xml +++ b/vector/src/main/res/layout/fragment_room_list.xml @@ -14,29 +14,25 @@ android:overScrollMode="always" tools:listitem="@layout/item_room" /> - - + + + + + + + + + + + + + + + + + + diff --git a/vector/src/main/res/layout/motion_fab_menu_merge.xml b/vector/src/main/res/layout/motion_notifs_fab_menu_merge.xml similarity index 98% rename from vector/src/main/res/layout/motion_fab_menu_merge.xml rename to vector/src/main/res/layout/motion_notifs_fab_menu_merge.xml index e564d16aaf..8130ea0637 100644 --- a/vector/src/main/res/layout/motion_fab_menu_merge.xml +++ b/vector/src/main/res/layout/motion_notifs_fab_menu_merge.xml @@ -4,7 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - app:layoutDescription="@xml/motion_scene_fab_menu" + app:layoutDescription="@xml/motion_scene_notifs_fab_menu" tools:motionProgress="0.65" tools:parentTag="androidx.constraintlayout.motion.widget.MotionLayout" tools:showPaths="true"> diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index cbfb95dc85..1eb602e4c3 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -1761,6 +1761,7 @@ Link copied to clipboard Add by matrix ID + Add by QR code "Creating room…" "No result found, use Add by matrix ID to search on server." "Start typing to get results" @@ -1828,6 +1829,8 @@ Open the create room menu Close the create room menu… Create a new direct conversation + Create a new direct conversation by Matrix ID + Create a new direct conversation by scanning a QR code Create a new room Close keys backup banner Show password @@ -2674,4 +2677,10 @@ The room is not yet created. Cancel the room creation? There are unsaved changes. Discard the changes? Discard changes + + + Share by text + Cannot DM yourself! + Invalid QR code (Invalid URI)! + QR code not scanned! diff --git a/vector/src/main/res/xml/motion_scene_dms_fab_menu.xml b/vector/src/main/res/xml/motion_scene_dms_fab_menu.xml new file mode 100644 index 0000000000..8bb1c55df5 --- /dev/null +++ b/vector/src/main/res/xml/motion_scene_dms_fab_menu.xml @@ -0,0 +1,199 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vector/src/main/res/xml/motion_scene_fab_menu.xml b/vector/src/main/res/xml/motion_scene_notifs_fab_menu.xml similarity index 100% rename from vector/src/main/res/xml/motion_scene_fab_menu.xml rename to vector/src/main/res/xml/motion_scene_notifs_fab_menu.xml From 1070c23608240e1780be7a2a6a48bcb01e86d092 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 19 Nov 2020 13:11:41 +0100 Subject: [PATCH 42/66] QR code invite flow support - invite friends Author: Valere --- CHANGES.md | 3 + .../android/sdk/api/auth/login/LoginWizard.kt | 2 +- vector/src/main/AndroidManifest.xml | 1 + .../im/vector/app/core/di/FragmentModule.kt | 18 +- .../im/vector/app/core/di/ScreenComponent.kt | 4 + .../im/vector/app/core/di/ViewModelModule.kt | 6 +- .../im/vector/app/core/epoxy/CheckBoxItem.kt | 47 ++++ .../im/vector/app/core/extensions/EditText.kt | 2 +- .../im/vector/app/core/utils/SystemUtils.kt | 8 +- .../contactsbook/ContactsBookFragment.kt | 24 +-- .../createdirect/CreateDirectRoomActivity.kt | 88 ++++---- .../CreateDirectRoomByQrCodeFragment.kt | 54 +++-- .../app/features/home/HomeDrawerFragment.kt | 30 +++ .../home/HomeSharedActionViewModel.kt | 3 +- .../home/room/list/RoomListFragment.kt | 25 +-- .../home/room/list/widget/DmsFabMenuView.kt | 102 --------- .../HomeServerCapabilitiesViewModel.kt | 4 +- .../invite/InviteUsersToRoomActivity.kt | 64 +++--- .../features/matrixto/MatrixToBottomSheet.kt | 67 ++++++ .../features/navigation/DefaultNavigator.kt | 4 +- .../app/features/navigation/Navigator.kt | 2 +- .../RoomMemberProfileController.kt | 11 + .../usercode/QRCodeBitmapDecodeHelper.kt | 85 ++++++++ .../features/usercode/ScanUserCodeFragment.kt | 135 ++++++++++++ .../features/usercode/ShowUserCodeFragment.kt | 59 +++++ .../app/features/usercode/UserCodeActions.kt | 27 +++ .../app/features/usercode/UserCodeActivity.kt | 126 +++++++++++ .../usercode/UserCodeShareViewEvents.kt | 28 +++ .../usercode/UserCodeSharedViewModel.kt | 161 ++++++++++++++ .../app/features/usercode/UserCodeState.kt | 33 +++ .../app/features/userdirectory/ActionItem.kt | 53 +++++ .../userdirectory/ContactDetailItem.kt | 47 ++++ .../app/features/userdirectory/ContactItem.kt | 46 ++++ .../userdirectory/DirectoryUsersController.kt | 139 ------------ .../userdirectory/KnownUsersController.kt | 122 ----------- .../userdirectory/UserDirectoryFragment.kt | 94 -------- .../userdirectory/UserDirectoryViewModel.kt | 153 ------------- ...erDirectoryAction.kt => UserListAction.kt} | 12 +- .../userdirectory/UserListController.kt | 197 +++++++++++++++++ ...wnUsersFragment.kt => UserListFragment.kt} | 133 +++++++----- ...ragmentArgs.kt => UserListFragmentArgs.kt} | 4 +- .../userdirectory/UserListHeaderItem.kt | 39 ++++ ...haredAction.kt => UserListSharedAction.kt} | 14 +- ...el.kt => UserListSharedActionViewModel.kt} | 2 +- ...oryViewEvents.kt => UserListViewEvents.kt} | 4 +- .../userdirectory/UserListViewModel.kt | 204 ++++++++++++++++++ ...ctoryViewState.kt => UserListViewState.kt} | 15 +- vector/src/main/res/drawable/ic_book.xml | 21 ++ .../main/res/drawable/ic_invite_people.xml | 10 + .../src/main/res/drawable/ic_picture_icon.xml | 29 +++ .../src/main/res/drawable/ic_qr_code_add.xml | 72 +++++++ .../src/main/res/layout/activity_simple.xml | 24 ++- .../main/res/layout/fragment_home_drawer.xml | 70 +++++- .../res/layout/fragment_matrix_to_card.xml | 70 ++++++ .../res/layout/fragment_qr_code_scanner.xml | 24 +++ .../fragment_qr_code_scanner_with_button.xml | 51 +++++ .../main/res/layout/fragment_room_list.xml | 16 +- .../res/layout/fragment_user_code_show.xml | 183 ++++++++++++++++ ...known_users.xml => fragment_user_list.xml} | 65 ++---- vector/src/main/res/layout/item_checkbox.xml | 13 ++ .../main/res/layout/item_contact_action.xml | 31 +++ .../main/res/layout/item_user_list_header.xml | 14 ++ .../res/layout/motion_dms_fab_menu_merge.xml | 79 ------- vector/src/main/res/values/strings.xml | 27 ++- .../res/xml/motion_scene_dms_fab_menu.xml | 199 ----------------- 65 files changed, 2311 insertions(+), 1188 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/core/epoxy/CheckBoxItem.kt delete mode 100644 vector/src/main/java/im/vector/app/features/home/room/list/widget/DmsFabMenuView.kt create mode 100644 vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt create mode 100644 vector/src/main/java/im/vector/app/features/usercode/QRCodeBitmapDecodeHelper.kt create mode 100644 vector/src/main/java/im/vector/app/features/usercode/ScanUserCodeFragment.kt create mode 100644 vector/src/main/java/im/vector/app/features/usercode/ShowUserCodeFragment.kt create mode 100644 vector/src/main/java/im/vector/app/features/usercode/UserCodeActions.kt create mode 100644 vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt create mode 100644 vector/src/main/java/im/vector/app/features/usercode/UserCodeShareViewEvents.kt create mode 100644 vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt create mode 100644 vector/src/main/java/im/vector/app/features/usercode/UserCodeState.kt create mode 100644 vector/src/main/java/im/vector/app/features/userdirectory/ActionItem.kt create mode 100644 vector/src/main/java/im/vector/app/features/userdirectory/ContactDetailItem.kt create mode 100644 vector/src/main/java/im/vector/app/features/userdirectory/ContactItem.kt delete mode 100644 vector/src/main/java/im/vector/app/features/userdirectory/DirectoryUsersController.kt delete mode 100644 vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersController.kt delete mode 100644 vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryFragment.kt delete mode 100644 vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewModel.kt rename vector/src/main/java/im/vector/app/features/userdirectory/{UserDirectoryAction.kt => UserListAction.kt} (71%) create mode 100644 vector/src/main/java/im/vector/app/features/userdirectory/UserListController.kt rename vector/src/main/java/im/vector/app/features/userdirectory/{KnownUsersFragment.kt => UserListFragment.kt} (57%) rename vector/src/main/java/im/vector/app/features/userdirectory/{KnownUsersFragmentArgs.kt => UserListFragmentArgs.kt} (91%) create mode 100644 vector/src/main/java/im/vector/app/features/userdirectory/UserListHeaderItem.kt rename vector/src/main/java/im/vector/app/features/userdirectory/{UserDirectorySharedAction.kt => UserListSharedAction.kt} (59%) rename vector/src/main/java/im/vector/app/features/userdirectory/{UserDirectorySharedActionViewModel.kt => UserListSharedActionViewModel.kt} (85%) rename vector/src/main/java/im/vector/app/features/userdirectory/{UserDirectoryViewEvents.kt => UserListViewEvents.kt} (85%) create mode 100644 vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt rename vector/src/main/java/im/vector/app/features/userdirectory/{UserDirectoryViewState.kt => UserListViewState.kt} (78%) create mode 100644 vector/src/main/res/drawable/ic_book.xml create mode 100644 vector/src/main/res/drawable/ic_invite_people.xml create mode 100644 vector/src/main/res/drawable/ic_picture_icon.xml create mode 100644 vector/src/main/res/drawable/ic_qr_code_add.xml create mode 100644 vector/src/main/res/layout/fragment_matrix_to_card.xml create mode 100644 vector/src/main/res/layout/fragment_qr_code_scanner_with_button.xml create mode 100644 vector/src/main/res/layout/fragment_user_code_show.xml rename vector/src/main/res/layout/{fragment_known_users.xml => fragment_user_list.xml} (68%) create mode 100644 vector/src/main/res/layout/item_checkbox.xml create mode 100644 vector/src/main/res/layout/item_contact_action.xml create mode 100644 vector/src/main/res/layout/item_user_list_header.xml delete mode 100644 vector/src/main/res/layout/motion_dms_fab_menu_merge.xml delete mode 100644 vector/src/main/res/xml/motion_scene_dms_fab_menu.xml diff --git a/CHANGES.md b/CHANGES.md index 4873a999b6..e1731433c3 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,8 @@ Changes in Element 1.0.11 (2020-XX-XX) Features ✨: - Create DMs with users by scanning their QR code (#2025) + - Add Invite friends quick invite actions (#2348) + - Add friend by scanning QR code, show your code to friends (#2025) Improvements 🙌: - New room creation tile with quick action (#2346) @@ -12,6 +14,7 @@ Improvements 🙌: - Handle events of type "m.room.server_acl" (#890) - Room creation form: add advanced section to disable federation (#1314) - Move "Enable Encryption" from room setting screen to room profile screen (#2394) + - Improve Invite user screen (seamless search for matrix ID) Bugfix 🐛: - Fix crash on AttachmentViewer (#2365) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt index 645fb55bb9..48705ee7b7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt @@ -27,7 +27,7 @@ interface LoginWizard { * @param password the password field * @param deviceName the initial device name * @param callback the matrix callback on which you'll receive the result of authentication. - * @return return a [Cancelable] + * @return a [Cancelable] */ fun login(login: String, password: String, diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml index fb4764b3be..7d2ca11813 100644 --- a/vector/src/main/AndroidManifest.xml +++ b/vector/src/main/AndroidManifest.xml @@ -229,6 +229,7 @@ + diff --git a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt index acdad5407c..32c98922fb 100644 --- a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt @@ -111,8 +111,8 @@ import im.vector.app.features.settings.threepids.ThreePidsSettingsFragment import im.vector.app.features.share.IncomingShareFragment import im.vector.app.features.signout.soft.SoftLogoutFragment import im.vector.app.features.terms.ReviewTermsFragment -import im.vector.app.features.userdirectory.KnownUsersFragment -import im.vector.app.features.userdirectory.UserDirectoryFragment +import im.vector.app.features.usercode.ShowUserCodeFragment +import im.vector.app.features.userdirectory.UserListFragment import im.vector.app.features.widgets.WidgetFragment @Module @@ -255,13 +255,8 @@ interface FragmentModule { @Binds @IntoMap - @FragmentKey(UserDirectoryFragment::class) - fun bindUserDirectoryFragment(fragment: UserDirectoryFragment): Fragment - - @Binds - @IntoMap - @FragmentKey(KnownUsersFragment::class) - fun bindKnownUsersFragment(fragment: KnownUsersFragment): Fragment + @FragmentKey(UserListFragment::class) + fun bindUserListFragment(fragment: UserListFragment): Fragment @Binds @IntoMap @@ -582,4 +577,9 @@ interface FragmentModule { @IntoMap @FragmentKey(SearchFragment::class) fun bindSearchFragment(fragment: SearchFragment): Fragment + + @Binds + @IntoMap + @FragmentKey(ShowUserCodeFragment::class) + fun bindShowUserCodeFragment(fragment: ShowUserCodeFragment): Fragment } diff --git a/vector/src/main/java/im/vector/app/core/di/ScreenComponent.kt b/vector/src/main/java/im/vector/app/core/di/ScreenComponent.kt index fde40f9195..818a32fca3 100644 --- a/vector/src/main/java/im/vector/app/core/di/ScreenComponent.kt +++ b/vector/src/main/java/im/vector/app/core/di/ScreenComponent.kt @@ -50,6 +50,7 @@ import im.vector.app.features.invite.InviteUsersToRoomActivity import im.vector.app.features.invite.VectorInviteView import im.vector.app.features.link.LinkHandlerActivity import im.vector.app.features.login.LoginActivity +import im.vector.app.features.matrixto.MatrixToBottomSheet import im.vector.app.features.media.BigImageViewerActivity import im.vector.app.features.media.VectorAttachmentViewerActivity import im.vector.app.features.navigation.Navigator @@ -72,6 +73,7 @@ import im.vector.app.features.share.IncomingShareActivity import im.vector.app.features.signout.soft.SoftLogoutActivity import im.vector.app.features.terms.ReviewTermsActivity import im.vector.app.features.ui.UiStateRepository +import im.vector.app.features.usercode.UserCodeActivity import im.vector.app.features.widgets.WidgetActivity import im.vector.app.features.widgets.permissions.RoomWidgetPermissionBottomSheet import im.vector.app.features.workers.signout.SignOutBottomSheetDialogFragment @@ -140,6 +142,7 @@ interface ScreenComponent { fun inject(activity: VectorAttachmentViewerActivity) fun inject(activity: VectorJitsiActivity) fun inject(activity: SearchActivity) + fun inject(activity: UserCodeActivity) /* ========================================================================================== * BottomSheets @@ -158,6 +161,7 @@ interface ScreenComponent { fun inject(bottomSheet: RoomWidgetsBottomSheet) fun inject(bottomSheet: CallControlsBottomSheet) fun inject(bottomSheet: SignOutBottomSheetDialogFragment) + fun inject(bottomSheet: MatrixToBottomSheet) /* ========================================================================================== * Others diff --git a/vector/src/main/java/im/vector/app/core/di/ViewModelModule.kt b/vector/src/main/java/im/vector/app/core/di/ViewModelModule.kt index 836dab00c5..7ae8bc9c2e 100644 --- a/vector/src/main/java/im/vector/app/core/di/ViewModelModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/ViewModelModule.kt @@ -35,7 +35,7 @@ import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedA import im.vector.app.features.reactions.EmojiChooserViewModel import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel import im.vector.app.features.roomprofile.RoomProfileSharedActionViewModel -import im.vector.app.features.userdirectory.UserDirectorySharedActionViewModel +import im.vector.app.features.userdirectory.UserListSharedActionViewModel @Module interface ViewModelModule { @@ -87,8 +87,8 @@ interface ViewModelModule { @Binds @IntoMap - @ViewModelKey(UserDirectorySharedActionViewModel::class) - fun bindUserDirectorySharedActionViewModel(viewModel: UserDirectorySharedActionViewModel): ViewModel + @ViewModelKey(UserListSharedActionViewModel::class) + fun bindUserListSharedActionViewModel(viewModel: UserListSharedActionViewModel): ViewModel @Binds @IntoMap diff --git a/vector/src/main/java/im/vector/app/core/epoxy/CheckBoxItem.kt b/vector/src/main/java/im/vector/app/core/epoxy/CheckBoxItem.kt new file mode 100644 index 0000000000..4e53b293d3 --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/epoxy/CheckBoxItem.kt @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020 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.app.core.epoxy + +import android.widget.CompoundButton +import com.airbnb.epoxy.EpoxyAttribute +import com.airbnb.epoxy.EpoxyModelClass +import com.google.android.material.checkbox.MaterialCheckBox +import im.vector.app.R +import kotlinx.android.synthetic.main.vector_preference_push_rule.view.* + +@EpoxyModelClass(layout = R.layout.item_checkbox) +abstract class CheckBoxItem : VectorEpoxyModel() { + + @EpoxyAttribute + var checked: Boolean = false + + @EpoxyAttribute lateinit var title: String + + @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) + var checkChangeListener: CompoundButton.OnCheckedChangeListener? = null + + override fun bind(holder: Holder) { + super.bind(holder) + holder.checkbox.isChecked = checked + holder.checkbox.text = title + holder.checkbox.setOnCheckedChangeListener(checkChangeListener) + } + + class Holder : VectorEpoxyHolder() { + val checkbox by bind(R.id.checkbox) + } +} diff --git a/vector/src/main/java/im/vector/app/core/extensions/EditText.kt b/vector/src/main/java/im/vector/app/core/extensions/EditText.kt index 355dd8442f..05b70def3d 100644 --- a/vector/src/main/java/im/vector/app/core/extensions/EditText.kt +++ b/vector/src/main/java/im/vector/app/core/extensions/EditText.kt @@ -26,7 +26,7 @@ import androidx.annotation.DrawableRes import im.vector.app.R import im.vector.app.core.platform.SimpleTextWatcher -fun EditText.setupAsSearch(@DrawableRes searchIconRes: Int = R.drawable.ic_filter, +fun EditText.setupAsSearch(@DrawableRes searchIconRes: Int = R.drawable.ic_search, @DrawableRes clearIconRes: Int = R.drawable.ic_x_gray) { addTextChangedListener(object : SimpleTextWatcher() { override fun afterTextChanged(s: Editable) { diff --git a/vector/src/main/java/im/vector/app/core/utils/SystemUtils.kt b/vector/src/main/java/im/vector/app/core/utils/SystemUtils.kt index d228adab12..2348b07c7b 100644 --- a/vector/src/main/java/im/vector/app/core/utils/SystemUtils.kt +++ b/vector/src/main/java/im/vector/app/core/utils/SystemUtils.kt @@ -136,13 +136,19 @@ fun startSharePlainTextIntent(fragment: Fragment, activityResultLauncher: ActivityResultLauncher?, chooserTitle: String?, text: String, - subject: String? = null) { + subject: String? = null, + extraTitle: String? = null) { val share = Intent(Intent.ACTION_SEND) share.type = "text/plain" share.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT) // Add data to the intent, the receiving app will decide what to do with it. share.putExtra(Intent.EXTRA_SUBJECT, subject) share.putExtra(Intent.EXTRA_TEXT, text) + + extraTitle?.let { + share.putExtra(Intent.EXTRA_TITLE, it) + } + val intent = Intent.createChooser(share, chooserTitle) try { if (activityResultLauncher != null) { diff --git a/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookFragment.kt b/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookFragment.kt index 23d21f5240..6c3ec06f75 100644 --- a/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookFragment.kt +++ b/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookFragment.kt @@ -30,10 +30,10 @@ import im.vector.app.core.extensions.configureWith import im.vector.app.core.extensions.hideKeyboard import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.features.userdirectory.PendingInvitee -import im.vector.app.features.userdirectory.UserDirectoryAction -import im.vector.app.features.userdirectory.UserDirectorySharedAction -import im.vector.app.features.userdirectory.UserDirectorySharedActionViewModel -import im.vector.app.features.userdirectory.UserDirectoryViewModel +import im.vector.app.features.userdirectory.UserListAction +import im.vector.app.features.userdirectory.UserListSharedAction +import im.vector.app.features.userdirectory.UserListSharedActionViewModel +import im.vector.app.features.userdirectory.UserListViewModel import kotlinx.android.synthetic.main.fragment_contacts_book.* import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.user.model.User @@ -46,16 +46,16 @@ class ContactsBookFragment @Inject constructor( ) : VectorBaseFragment(), ContactsBookController.Callback { override fun getLayoutResId() = R.layout.fragment_contacts_book - private val viewModel: UserDirectoryViewModel by activityViewModel() + private val viewModel: UserListViewModel by activityViewModel() // Use activityViewModel to avoid loading several times the data private val contactsBookViewModel: ContactsBookViewModel by activityViewModel() - private lateinit var sharedActionViewModel: UserDirectorySharedActionViewModel + private lateinit var sharedActionViewModel: UserListSharedActionViewModel override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - sharedActionViewModel = activityViewModelProvider.get(UserDirectorySharedActionViewModel::class.java) + sharedActionViewModel = activityViewModelProvider.get(UserListSharedActionViewModel::class.java) setupRecyclerView() setupFilterView() setupConsentView() @@ -110,7 +110,7 @@ class ContactsBookFragment @Inject constructor( private fun setupCloseView() { phoneBookClose.debouncedClicks { - sharedActionViewModel.post(UserDirectorySharedAction.GoBack) + sharedActionViewModel.post(UserListSharedAction.GoBack) } } @@ -122,13 +122,13 @@ class ContactsBookFragment @Inject constructor( override fun onMatrixIdClick(matrixId: String) { view?.hideKeyboard() - viewModel.handle(UserDirectoryAction.SelectPendingInvitee(PendingInvitee.UserPendingInvitee(User(matrixId)))) - sharedActionViewModel.post(UserDirectorySharedAction.GoBack) + viewModel.handle(UserListAction.SelectPendingInvitee(PendingInvitee.UserPendingInvitee(User(matrixId)))) + sharedActionViewModel.post(UserListSharedAction.GoBack) } override fun onThreePidClick(threePid: ThreePid) { view?.hideKeyboard() - viewModel.handle(UserDirectoryAction.SelectPendingInvitee(PendingInvitee.ThreePidPendingInvitee(threePid))) - sharedActionViewModel.post(UserDirectorySharedAction.GoBack) + viewModel.handle(UserListAction.SelectPendingInvitee(PendingInvitee.ThreePidPendingInvitee(threePid))) + sharedActionViewModel.post(UserListSharedAction.GoBack) } } diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt index 2035ee50f6..2e21d04d06 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt @@ -45,23 +45,23 @@ import im.vector.app.core.utils.allGranted import im.vector.app.core.utils.checkPermissions import im.vector.app.features.contactsbook.ContactsBookFragment import im.vector.app.features.contactsbook.ContactsBookViewModel -import im.vector.app.features.userdirectory.KnownUsersFragment -import im.vector.app.features.userdirectory.KnownUsersFragmentArgs -import im.vector.app.features.userdirectory.UserDirectoryFragment -import im.vector.app.features.userdirectory.UserDirectorySharedAction -import im.vector.app.features.userdirectory.UserDirectorySharedActionViewModel -import im.vector.app.features.userdirectory.UserDirectoryViewModel +import im.vector.app.features.userdirectory.UserListFragment +import im.vector.app.features.userdirectory.UserListFragmentArgs +import im.vector.app.features.userdirectory.UserListSharedAction +import im.vector.app.features.userdirectory.UserListSharedActionViewModel +import im.vector.app.features.userdirectory.UserListViewModel +import im.vector.app.features.userdirectory.UserListViewState import kotlinx.android.synthetic.main.activity.* import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure import java.net.HttpURLConnection import javax.inject.Inject -class CreateDirectRoomActivity : SimpleFragmentActivity() { +class CreateDirectRoomActivity : SimpleFragmentActivity(), UserListViewModel.Factory { private val viewModel: CreateDirectRoomViewModel by viewModel() - private lateinit var sharedActionViewModel: UserDirectorySharedActionViewModel - @Inject lateinit var userDirectoryViewModelFactory: UserDirectoryViewModel.Factory + private lateinit var sharedActionViewModel: UserListSharedActionViewModel + @Inject lateinit var userListViewModelFactory: UserListViewModel.Factory @Inject lateinit var createDirectRoomViewModelFactory: CreateDirectRoomViewModel.Factory @Inject lateinit var contactsBookViewModelFactory: ContactsBookViewModel.Factory @Inject lateinit var errorFormatter: ErrorFormatter @@ -71,37 +71,36 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() { injector.inject(this) } + override fun create(initialState: UserListViewState, args: UserListFragmentArgs): UserListViewModel { + return userListViewModelFactory.create(initialState, args) + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) toolbar.visibility = View.GONE - sharedActionViewModel = viewModelProvider.get(UserDirectorySharedActionViewModel::class.java) - if (intent?.getBooleanExtra(BY_QR_CODE, false)!!) { - if (isFirstCreation()) { openAddByQrCode() } - } else { - sharedActionViewModel - .observe() - .subscribe { sharedAction -> - when (sharedAction) { - UserDirectorySharedAction.OpenUsersDirectory -> - addFragmentToBackstack(R.id.container, UserDirectoryFragment::class.java) - UserDirectorySharedAction.Close -> finish() - UserDirectorySharedAction.GoBack -> onBackPressed() - is UserDirectorySharedAction.OnMenuItemSelected -> onMenuItemSelected(sharedAction) - UserDirectorySharedAction.OpenPhoneBook -> openPhoneBook() - }.exhaustive - } - .disposeOnDestroy() - if (isFirstCreation()) { - addFragment( - R.id.container, - KnownUsersFragment::class.java, - KnownUsersFragmentArgs( - title = getString(R.string.fab_menu_create_chat), - menuResId = R.menu.vector_create_direct_room, - isCreatingRoom = true - ) - ) - } + + sharedActionViewModel = viewModelProvider.get(UserListSharedActionViewModel::class.java) + sharedActionViewModel + .observe() + .subscribe { action -> + when (action) { + UserListSharedAction.Close -> finish() + UserListSharedAction.GoBack -> onBackPressed() + is UserListSharedAction.OnMenuItemSelected -> onMenuItemSelected(action) + UserListSharedAction.OpenPhoneBook -> openPhoneBook() + UserListSharedAction.AddByQrCode -> openAddByQrCode() + }.exhaustive + } + .disposeOnDestroy() + if (isFirstCreation()) { + addFragment( + R.id.container, + UserListFragment::class.java, + UserListFragmentArgs( + title = getString(R.string.fab_menu_create_chat), + menuResId = R.menu.vector_create_direct_room + ) + ) } viewModel.selectSubscribe(this, CreateDirectRoomViewState::createAndInviteState) { renderCreateAndInviteState(it) @@ -129,22 +128,22 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() { if (allGranted(grantResults)) { if (requestCode == PERMISSION_REQUEST_CODE_READ_CONTACTS) { doOnPostResume { addFragmentToBackstack(R.id.container, ContactsBookFragment::class.java) } - } else if (requestCode == PERMISSION_REQUEST_CODE_LAUNCH_CAMERA && intent?.getBooleanExtra(BY_QR_CODE, false)!!) { + } else if (requestCode == PERMISSION_REQUEST_CODE_LAUNCH_CAMERA) { addFragment(R.id.container, CreateDirectRoomByQrCodeFragment::class.java) } } else { Toast.makeText(baseContext, R.string.missing_permissions_error, Toast.LENGTH_SHORT).show() - if (requestCode == PERMISSION_REQUEST_CODE_LAUNCH_CAMERA && intent?.getBooleanExtra(BY_QR_CODE, false)!!) { + if (requestCode == PERMISSION_REQUEST_CODE_LAUNCH_CAMERA) { finish() } } } - private fun onMenuItemSelected(action: UserDirectorySharedAction.OnMenuItemSelected) { + private fun onMenuItemSelected(action: UserListSharedAction.OnMenuItemSelected) { if (action.itemId == R.id.action_create_direct_room) { viewModel.handle(CreateDirectRoomAction.CreateRoomAndInviteSelectedUsers( action.invitees, - action.existingDmRoomId + null )) } } @@ -198,12 +197,9 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() { } companion object { - private const val BY_QR_CODE = "BY_QR_CODE" - fun getIntent(context: Context, byQrCode: Boolean = false): Intent { - return Intent(context, CreateDirectRoomActivity::class.java).apply { - putExtra(BY_QR_CODE, byQrCode) - } + fun getIntent(context: Context): Intent { + return Intent(context, CreateDirectRoomActivity::class.java) } } } diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomByQrCodeFragment.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomByQrCodeFragment.kt index f03368fdd5..3fee3a3285 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomByQrCodeFragment.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomByQrCodeFragment.kt @@ -21,7 +21,11 @@ import com.airbnb.mvrx.activityViewModel import com.google.zxing.Result import com.google.zxing.ResultMetadataType import im.vector.app.R +import im.vector.app.core.extensions.hideKeyboard import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO +import im.vector.app.core.utils.checkPermissions +import im.vector.app.core.utils.registerForPermissionsResult import im.vector.app.features.userdirectory.PendingInvitee import kotlinx.android.synthetic.main.fragment_qr_code_scanner.* import me.dm7.barcodescanner.zxing.ZXingScannerView @@ -36,16 +40,32 @@ class CreateDirectRoomByQrCodeFragment @Inject constructor() : VectorBaseFragmen override fun getLayoutResId() = R.layout.fragment_qr_code_scanner - override fun onResume() { - super.onResume() - // Register ourselves as a handler for scan results. - scannerView.setResultHandler(null) + private val openCameraActivityResultLauncher = registerForPermissionsResult { allGranted -> + if (allGranted) { + startCamera() + } + } + + private fun startCamera() { // Start camera on resume scannerView.startCamera() } + override fun onResume() { + super.onResume() + view?.hideKeyboard() + // Register ourselves as a handler for scan results. + scannerView.setResultHandler(this) + // Start camera on resume + if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), openCameraActivityResultLauncher)) { + startCamera() + } + } + override fun onPause() { super.onPause() + // Unregister ourselves as a handler for scan results. + scannerView.setResultHandler(null) // Stop camera on pause scannerView.stopCamera() } @@ -73,23 +93,17 @@ class CreateDirectRoomByQrCodeFragment @Inject constructor() : VectorBaseFragmen requireActivity().finish() } else { val existingDm = viewModel.session.getExistingDirectRoomWithUser(mxid) - - if (existingDm === null) { - // The following assumes MXIDs are case insensitive - if (mxid.equals(other = viewModel.session.myUserId, ignoreCase = true)) { - Toast.makeText(requireContext(), R.string.cannot_dm_self, Toast.LENGTH_SHORT).show() - requireActivity().finish() - } else { - // Try to get user from known users and fall back to creating a User object from MXID - val qrInvitee = if (viewModel.session.getUser(mxid) != null) viewModel.session.getUser(mxid)!! else User(mxid, null, null) - - viewModel.handle( - CreateDirectRoomAction.CreateRoomAndInviteSelectedUsers(setOf(PendingInvitee.UserPendingInvitee(qrInvitee))) - ) - } - } else { - navigator.openRoom(requireContext(), existingDm, null, false) + // The following assumes MXIDs are case insensitive + if (mxid.equals(other = viewModel.session.myUserId, ignoreCase = true)) { + Toast.makeText(requireContext(), R.string.cannot_dm_self, Toast.LENGTH_SHORT).show() requireActivity().finish() + } else { + // Try to get user from known users and fall back to creating a User object from MXID + val qrInvitee = if (viewModel.session.getUser(mxid) != null) viewModel.session.getUser(mxid)!! else User(mxid, null, null) + + viewModel.handle( + CreateDirectRoomAction.CreateRoomAndInviteSelectedUsers(setOf(PendingInvitee.UserPendingInvitee(qrInvitee)), existingDm) + ) } } } diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDrawerFragment.kt b/vector/src/main/java/im/vector/app/features/home/HomeDrawerFragment.kt index e267248fc3..1a60d8e219 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDrawerFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDrawerFragment.kt @@ -18,15 +18,19 @@ package im.vector.app.features.home import android.os.Bundle import android.view.View +import androidx.core.app.ActivityOptionsCompat +import androidx.core.view.ViewCompat import androidx.core.view.isVisible import im.vector.app.BuildConfig import im.vector.app.R import im.vector.app.core.extensions.observeK import im.vector.app.core.extensions.replaceChildFragment import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.utils.startSharePlainTextIntent import im.vector.app.features.grouplist.GroupListFragment import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.VectorSettingsActivity +import im.vector.app.features.usercode.UserCodeActivity import im.vector.app.features.workers.signout.SignOutUiWorker import kotlinx.android.synthetic.main.fragment_home_drawer.* import org.matrix.android.sdk.api.session.Session @@ -75,6 +79,32 @@ class HomeDrawerFragment @Inject constructor( SignOutUiWorker(requireActivity()).perform() } + homeDrawerQRCodeButton.debouncedClicks { + UserCodeActivity.newIntent(requireContext(), sharedActionViewModel.session.myUserId).let { + val options = + ActivityOptionsCompat.makeSceneTransitionAnimation( + requireActivity(), + homeDrawerHeaderAvatarView, + ViewCompat.getTransitionName(homeDrawerHeaderAvatarView) ?: "" + ) + startActivity(it, options.toBundle()) + } + } + + homeDrawerInviteFriendButton.debouncedClicks { + session.permalinkService().createPermalink(sharedActionViewModel.session.myUserId)?.let { permalink -> + val text = getString(R.string.invite_friends_text, permalink) + + startSharePlainTextIntent( + fragment = this, + activityResultLauncher = null, + chooserTitle = getString(R.string.invite_friends), + text = text, + extraTitle = getString(R.string.invite_friends_rich_title) + ) + } + } + // Debug menu homeDrawerHeaderDebugView.isVisible = BuildConfig.DEBUG && vectorPreferences.developerMode() homeDrawerHeaderDebugView.debouncedClicks { diff --git a/vector/src/main/java/im/vector/app/features/home/HomeSharedActionViewModel.kt b/vector/src/main/java/im/vector/app/features/home/HomeSharedActionViewModel.kt index 58747a4c18..b695f48ee5 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeSharedActionViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeSharedActionViewModel.kt @@ -17,6 +17,7 @@ package im.vector.app.features.home import im.vector.app.core.platform.VectorSharedActionViewModel +import org.matrix.android.sdk.api.session.Session import javax.inject.Inject -class HomeSharedActionViewModel @Inject constructor() : VectorSharedActionViewModel() +class HomeSharedActionViewModel @Inject constructor(val session: Session) : VectorSharedActionViewModel() diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt index e47072d0b0..60c2745b44 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt @@ -45,7 +45,6 @@ import im.vector.app.features.home.room.list.actions.RoomListActionsArgs import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedAction import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel -import im.vector.app.features.home.room.list.widget.DmsFabMenuView import im.vector.app.features.home.room.list.widget.NotifsFabMenuView import im.vector.app.features.notifications.NotificationDrawerManager import kotlinx.android.parcel.Parcelize @@ -67,7 +66,7 @@ class RoomListFragment @Inject constructor( val roomListViewModelFactory: RoomListViewModel.Factory, private val notificationDrawerManager: NotificationDrawerManager, private val sharedViewPool: RecyclerView.RecycledViewPool -) : VectorBaseFragment(), RoomSummaryController.Listener, OnBackPressed, DmsFabMenuView.Listener, NotifsFabMenuView.Listener { +) : VectorBaseFragment(), RoomSummaryController.Listener, OnBackPressed, NotifsFabMenuView.Listener { private var modelBuildListener: OnModelBuildFinishedListener? = null private lateinit var sharedActionViewModel: RoomListQuickActionsSharedActionViewModel @@ -111,7 +110,6 @@ class RoomListFragment @Inject constructor( }.exhaustive } - createDmFabMenu.listener = this createChatFabMenu.listener = this sharedActionViewModel @@ -130,7 +128,6 @@ class RoomListFragment @Inject constructor( roomListView.cleanup() roomController.listener = null stateRestorer.clear() - createDmFabMenu.listener = null createChatFabMenu.listener = null super.onDestroyView() } @@ -142,32 +139,33 @@ class RoomListFragment @Inject constructor( private fun setupCreateRoomButton() { when (roomListParams.displayMode) { RoomListDisplayMode.NOTIFICATIONS -> createChatFabMenu.isVisible = true - RoomListDisplayMode.PEOPLE -> createDmFabMenu.isVisible = true + RoomListDisplayMode.PEOPLE -> createChatRoomButton.isVisible = true RoomListDisplayMode.ROOMS -> createGroupRoomButton.isVisible = true else -> Unit // No button in this mode } + createChatRoomButton.debouncedClicks { + createDirectChat() + } createGroupRoomButton.debouncedClicks { openRoomDirectory() } - // Hide FABs when list is scrolling + // Hide FAB when list is scrolling roomListView.addOnScrollListener( object : RecyclerView.OnScrollListener() { override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { - createDmFabMenu.removeCallbacks(showFabRunnable) createChatFabMenu.removeCallbacks(showFabRunnable) when (newState) { RecyclerView.SCROLL_STATE_IDLE -> { - createDmFabMenu.postDelayed(showFabRunnable, 250) createChatFabMenu.postDelayed(showFabRunnable, 250) } RecyclerView.SCROLL_STATE_DRAGGING, RecyclerView.SCROLL_STATE_SETTLING -> { when (roomListParams.displayMode) { RoomListDisplayMode.NOTIFICATIONS -> createChatFabMenu.hide() - RoomListDisplayMode.PEOPLE -> createDmFabMenu.hide() + RoomListDisplayMode.PEOPLE -> createChatRoomButton.hide() RoomListDisplayMode.ROOMS -> createGroupRoomButton.hide() else -> Unit } @@ -192,10 +190,6 @@ class RoomListFragment @Inject constructor( navigator.openCreateDirectRoom(requireActivity()) } - override fun createDirectChatByQrCode() { - navigator.openCreateDirectRoom(requireContext(), true) - } - private fun setupRecyclerView() { val layoutManager = LinearLayoutManager(context) stateRestorer = LayoutManagerStateRestorer(layoutManager).register() @@ -214,7 +208,7 @@ class RoomListFragment @Inject constructor( if (isAdded) { when (roomListParams.displayMode) { RoomListDisplayMode.NOTIFICATIONS -> createChatFabMenu.show() - RoomListDisplayMode.PEOPLE -> createDmFabMenu.show() + RoomListDisplayMode.PEOPLE -> createChatRoomButton.show() RoomListDisplayMode.ROOMS -> createGroupRoomButton.show() else -> Unit } @@ -343,9 +337,6 @@ class RoomListFragment @Inject constructor( } override fun onBackPressed(toolbarButton: Boolean): Boolean { - if (createDmFabMenu.onBackPressed()) { - return true - } if (createChatFabMenu.onBackPressed()) { return true } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/widget/DmsFabMenuView.kt b/vector/src/main/java/im/vector/app/features/home/room/list/widget/DmsFabMenuView.kt deleted file mode 100644 index 9659b7b12b..0000000000 --- a/vector/src/main/java/im/vector/app/features/home/room/list/widget/DmsFabMenuView.kt +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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.app.features.home.room.list.widget - -import android.content.Context -import android.util.AttributeSet -import androidx.constraintlayout.motion.widget.MotionLayout -import androidx.core.view.isVisible -import com.google.android.material.floatingactionbutton.FloatingActionButton -import im.vector.app.R -import kotlinx.android.synthetic.main.motion_dms_fab_menu_merge.view.* - -class DmsFabMenuView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = 0) : MotionLayout(context, attrs, defStyleAttr) { - - var listener: Listener? = null - - init { - inflate(context, R.layout.motion_dms_fab_menu_merge, this) - } - - override fun onFinishInflate() { - super.onFinishInflate() - - listOf(createDmByMxid, createDmByMxidLabel) - .forEach { - it.setOnClickListener { - closeFabMenu() - listener?.createDirectChat() - } - } - listOf(createDmByQrCode, createDmByQrCodeLabel) - .forEach { - it.setOnClickListener { - closeFabMenu() - listener?.createDirectChatByQrCode() - } - } - - dmsCreateRoomTouchGuard.setOnClickListener { - closeFabMenu() - } - } - - override fun transitionToEnd() { - super.transitionToEnd() - - dmsCreateRoomButton.contentDescription = context.getString(R.string.a11y_create_menu_close) - } - - override fun transitionToStart() { - super.transitionToStart() - - dmsCreateRoomButton.contentDescription = context.getString(R.string.a11y_create_menu_open) - } - - fun show() { - isVisible = true - dmsCreateRoomButton.show() - } - - fun hide() { - dmsCreateRoomButton.hide(object : FloatingActionButton.OnVisibilityChangedListener() { - override fun onHidden(fab: FloatingActionButton?) { - super.onHidden(fab) - isVisible = false - } - }) - } - - private fun closeFabMenu() { - transitionToStart() - } - - fun onBackPressed(): Boolean { - if (currentState == R.id.constraint_set_fab_menu_open) { - closeFabMenu() - return true - } - - return false - } - - interface Listener { - fun createDirectChat() - fun createDirectChatByQrCode() - } -} diff --git a/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewModel.kt b/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewModel.kt index f6c60f6a6d..fe7a8006e0 100644 --- a/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewModel.kt @@ -28,7 +28,7 @@ import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel import im.vector.app.features.raw.wellknown.getElementWellknown import im.vector.app.features.raw.wellknown.isE2EByDefault -import im.vector.app.features.userdirectory.KnownUsersFragment +import im.vector.app.features.userdirectory.UserListFragment import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.matrix.android.sdk.api.extensions.tryOrNull @@ -50,7 +50,7 @@ class HomeServerCapabilitiesViewModel @AssistedInject constructor( companion object : MvRxViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: HomeServerCapabilitiesViewState): HomeServerCapabilitiesViewModel? { - val fragment: KnownUsersFragment = (viewModelContext as FragmentViewModelContext).fragment() + val fragment: UserListFragment = (viewModelContext as FragmentViewModelContext).fragment() return fragment.homeServerCapabilitiesViewModelFactory.create(state) } diff --git a/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt b/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt index 087b7c2f55..513fbb5d83 100644 --- a/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt +++ b/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt @@ -21,6 +21,7 @@ import android.content.Intent import android.os.Bundle import android.os.Parcelable import android.view.View +import android.widget.Toast import androidx.appcompat.app.AlertDialog import com.airbnb.mvrx.MvRx import com.airbnb.mvrx.viewModel @@ -29,7 +30,6 @@ import im.vector.app.core.di.ScreenComponent import im.vector.app.core.error.ErrorFormatter import im.vector.app.core.extensions.addFragment import im.vector.app.core.extensions.addFragmentToBackstack -import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.SimpleFragmentActivity import im.vector.app.core.platform.WaitingViewData import im.vector.app.core.utils.PERMISSIONS_FOR_MEMBERS_SEARCH @@ -39,12 +39,12 @@ import im.vector.app.core.utils.checkPermissions import im.vector.app.core.utils.toast import im.vector.app.features.contactsbook.ContactsBookFragment import im.vector.app.features.contactsbook.ContactsBookViewModel -import im.vector.app.features.userdirectory.KnownUsersFragment -import im.vector.app.features.userdirectory.KnownUsersFragmentArgs -import im.vector.app.features.userdirectory.UserDirectoryFragment -import im.vector.app.features.userdirectory.UserDirectorySharedAction -import im.vector.app.features.userdirectory.UserDirectorySharedActionViewModel -import im.vector.app.features.userdirectory.UserDirectoryViewModel +import im.vector.app.features.userdirectory.UserListFragment +import im.vector.app.features.userdirectory.UserListFragmentArgs +import im.vector.app.features.userdirectory.UserListSharedAction +import im.vector.app.features.userdirectory.UserListSharedActionViewModel +import im.vector.app.features.userdirectory.UserListViewModel +import im.vector.app.features.userdirectory.UserListViewState import kotlinx.android.parcel.Parcelize import kotlinx.android.synthetic.main.activity.* import org.matrix.android.sdk.api.failure.Failure @@ -54,11 +54,11 @@ import javax.inject.Inject @Parcelize data class InviteUsersToRoomArgs(val roomId: String) : Parcelable -class InviteUsersToRoomActivity : SimpleFragmentActivity() { +class InviteUsersToRoomActivity : SimpleFragmentActivity(), UserListViewModel.Factory { private val viewModel: InviteUsersToRoomViewModel by viewModel() - private lateinit var sharedActionViewModel: UserDirectorySharedActionViewModel - @Inject lateinit var userDirectoryViewModelFactory: UserDirectoryViewModel.Factory + private lateinit var sharedActionViewModel: UserListSharedActionViewModel + @Inject lateinit var userListViewModelFactory: UserListViewModel.Factory @Inject lateinit var inviteUsersToRoomViewModelFactory: InviteUsersToRoomViewModel.Factory @Inject lateinit var contactsBookViewModelFactory: ContactsBookViewModel.Factory @Inject lateinit var errorFormatter: ErrorFormatter @@ -68,32 +68,40 @@ class InviteUsersToRoomActivity : SimpleFragmentActivity() { injector.inject(this) } + override fun create(initialState: UserListViewState, args: UserListFragmentArgs): UserListViewModel { + return userListViewModelFactory.create(initialState, args) + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) toolbar.visibility = View.GONE - sharedActionViewModel = viewModelProvider.get(UserDirectorySharedActionViewModel::class.java) + + sharedActionViewModel = viewModelProvider.get(UserListSharedActionViewModel::class.java) sharedActionViewModel .observe() .subscribe { sharedAction -> when (sharedAction) { - UserDirectorySharedAction.OpenUsersDirectory -> - addFragmentToBackstack(R.id.container, UserDirectoryFragment::class.java) - UserDirectorySharedAction.Close -> finish() - UserDirectorySharedAction.GoBack -> onBackPressed() - is UserDirectorySharedAction.OnMenuItemSelected -> onMenuItemSelected(sharedAction) - UserDirectorySharedAction.OpenPhoneBook -> openPhoneBook() - }.exhaustive + UserListSharedAction.Close -> finish() + UserListSharedAction.GoBack -> onBackPressed() + is UserListSharedAction.OnMenuItemSelected -> onMenuItemSelected(sharedAction) + UserListSharedAction.OpenPhoneBook -> openPhoneBook() + // not exhaustive because it's a sharedAction + else -> { + } + } } .disposeOnDestroy() if (isFirstCreation()) { + val args: InviteUsersToRoomArgs? = intent.extras?.getParcelable(MvRx.KEY_ARG) addFragment( R.id.container, - KnownUsersFragment::class.java, - KnownUsersFragmentArgs( + UserListFragment::class.java, + UserListFragmentArgs( title = getString(R.string.invite_users_to_room_title), menuResId = R.menu.vector_invite_users_to_room, - excludedUserIds = viewModel.getUserIdsOfRoomMembers() + excludedUserIds = viewModel.getUserIdsOfRoomMembers(), + existingRoomId = args?.roomId ) ) } @@ -101,6 +109,12 @@ class InviteUsersToRoomActivity : SimpleFragmentActivity() { viewModel.observeViewEvents { renderInviteEvents(it) } } + private fun onMenuItemSelected(action: UserListSharedAction.OnMenuItemSelected) { + if (action.itemId == R.id.action_invite_users_to_room_invite) { + viewModel.handle(InviteUsersToRoomAction.InviteSelectedUsers(action.invitees)) + } + } + private fun openPhoneBook() { // Check permission first if (checkPermissions(PERMISSIONS_FOR_MEMBERS_SEARCH, @@ -117,12 +131,8 @@ class InviteUsersToRoomActivity : SimpleFragmentActivity() { if (requestCode == PERMISSION_REQUEST_CODE_READ_CONTACTS) { doOnPostResume { addFragmentToBackstack(R.id.container, ContactsBookFragment::class.java) } } - } - } - - private fun onMenuItemSelected(action: UserDirectorySharedAction.OnMenuItemSelected) { - if (action.itemId == R.id.action_invite_users_to_room_invite) { - viewModel.handle(InviteUsersToRoomAction.InviteSelectedUsers(action.invitees)) + } else { + Toast.makeText(baseContext, R.string.missing_permissions_error, Toast.LENGTH_SHORT).show() } } diff --git a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt new file mode 100644 index 0000000000..3f3706699f --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2020 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.app.features.matrixto + +import android.os.Bundle +import android.view.View +import im.vector.app.R +import im.vector.app.core.di.ScreenComponent +import im.vector.app.core.extensions.setTextOrHide +import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment +import im.vector.app.features.home.AvatarRenderer +import kotlinx.android.synthetic.main.fragment_matrix_to_card.* +import org.matrix.android.sdk.api.util.MatrixItem +import javax.inject.Inject + +class MatrixToBottomSheet(private val matrixItem: MatrixItem) : VectorBaseBottomSheetDialogFragment() { + + @Inject lateinit var avatarRenderer: AvatarRenderer + + interface InteractionListener { + fun didTapStartMessage(matrixItem: MatrixItem) + } + + override fun injectWith(injector: ScreenComponent) { + injector.inject(this) + } + + private var interactionListener: InteractionListener? = null + + override fun getLayoutResId() = R.layout.fragment_matrix_to_card + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + matrixToCardSendMessageButton.debouncedClicks { + interactionListener?.didTapStartMessage(matrixItem) + dismiss() + } + + matrixToCardNameText.setTextOrHide(matrixItem.displayName) + matrixToCardUserIdText.setTextOrHide(matrixItem.id) + avatarRenderer.render(matrixItem, matrixToCardAvatar) + } + + companion object { + const val ARGS = "MatrixToFragment.Args" + + fun create(matrixItem: MatrixItem, listener: InteractionListener?): MatrixToBottomSheet { + return MatrixToBottomSheet(matrixItem).apply { + interactionListener = listener + } + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt index 9ff103113f..2d0ca86d52 100644 --- a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt +++ b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt @@ -203,8 +203,8 @@ class DefaultNavigator @Inject constructor( context.startActivity(intent) } - override fun openCreateDirectRoom(context: Context, byQrCode: Boolean) { - val intent = CreateDirectRoomActivity.getIntent(context, byQrCode) + override fun openCreateDirectRoom(context: Context) { + val intent = CreateDirectRoomActivity.getIntent(context) context.startActivity(intent) } diff --git a/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt b/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt index 23d24b709c..504fccb63a 100644 --- a/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt +++ b/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt @@ -56,7 +56,7 @@ interface Navigator { fun openCreateRoom(context: Context, initialName: String = "") - fun openCreateDirectRoom(context: Context, byQrCode: Boolean = false) + fun openCreateDirectRoom(context: Context) fun openInviteUsersToRoom(context: Context, roomId: String) diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileController.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileController.kt index 2e91091443..e29c197ab8 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileController.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileController.kt @@ -79,6 +79,17 @@ class RoomMemberProfileController @Inject constructor( divider = false, action = { callback?.onIgnoreClicked() } ) + if (!state.isMine) { + buildProfileSection(stringProvider.getString(R.string.room_profile_section_more)) + + buildProfileAction( + id = "direct", + editable = false, + title = stringProvider.getString(R.string.room_member_open_or_create_dm), + dividerColor = dividerColor, + action = { callback?.onOpenDmClicked() } + ) + } } private fun buildRoomMemberActions(state: RoomMemberProfileViewState) { diff --git a/vector/src/main/java/im/vector/app/features/usercode/QRCodeBitmapDecodeHelper.kt b/vector/src/main/java/im/vector/app/features/usercode/QRCodeBitmapDecodeHelper.kt new file mode 100644 index 0000000000..178a283d2c --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/usercode/QRCodeBitmapDecodeHelper.kt @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2020 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.app.features.usercode + +import android.graphics.Bitmap +import com.google.zxing.BarcodeFormat +import com.google.zxing.BinaryBitmap +import com.google.zxing.DecodeHintType +import com.google.zxing.LuminanceSource +import com.google.zxing.MultiFormatReader +import com.google.zxing.RGBLuminanceSource +import com.google.zxing.ReaderException +import com.google.zxing.Result +import com.google.zxing.common.HybridBinarizer + +// Some helper code from BinaryEye +object QRCodeBitmapDecodeHelper { + + private val multiFormatReader = MultiFormatReader() + private val decoderHints = mapOf(DecodeHintType.POSSIBLE_FORMATS to listOf(BarcodeFormat.QR_CODE)) + + fun decodeQRFromBitmap(bitmap: Bitmap): Result? = + decode(bitmap, false) ?: decode(bitmap, true) + + private fun decode(bitmap: Bitmap, invert: Boolean = false): Result? { + val pixels = IntArray(bitmap.width * bitmap.height) + return decode(pixels, bitmap, invert) + } + + private fun decode( + pixels: IntArray, + bitmap: Bitmap, + invert: Boolean = false + ): Result? { + val width = bitmap.width + val height = bitmap.height + if (bitmap.config != Bitmap.Config.ARGB_8888) { + bitmap.copy(Bitmap.Config.ARGB_8888, true) + } else { + bitmap + }.getPixels(pixels, 0, width, 0, 0, width, height) + return decodeLuminanceSource( + RGBLuminanceSource(width, height, pixels), + invert + ) + } + + private fun decodeLuminanceSource( + source: LuminanceSource, + invert: Boolean + ): Result? { + return decodeLuminanceSource( + if (invert) { + source.invert() + } else { + source + } + ) + } + + private fun decodeLuminanceSource(source: LuminanceSource): Result? { + val bitmap = BinaryBitmap(HybridBinarizer(source)) + return try { + multiFormatReader.decode(bitmap, decoderHints) + } catch (e: ReaderException) { + null + } finally { + multiFormatReader.reset() + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/usercode/ScanUserCodeFragment.kt b/vector/src/main/java/im/vector/app/features/usercode/ScanUserCodeFragment.kt new file mode 100644 index 0000000000..8b4820b06d --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/usercode/ScanUserCodeFragment.kt @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2020 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.app.features.usercode + +import android.app.Activity +import android.os.Bundle +import android.view.View +import android.widget.Toast +import com.airbnb.mvrx.activityViewModel +import com.google.zxing.Result +import com.google.zxing.ResultMetadataType +import im.vector.app.R +import im.vector.app.core.extensions.registerStartForActivityResult +import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO +import im.vector.app.core.utils.checkPermissions +import im.vector.app.core.utils.registerForPermissionsResult +import im.vector.lib.multipicker.MultiPicker +import im.vector.lib.multipicker.utils.ImageUtils +import kotlinx.android.synthetic.main.fragment_qr_code_scanner_with_button.* +import me.dm7.barcodescanner.zxing.ZXingScannerView +import org.matrix.android.sdk.api.extensions.tryOrNull +import javax.inject.Inject + +class ScanUserCodeFragment @Inject constructor() + : VectorBaseFragment(), + ZXingScannerView.ResultHandler { + + override fun getLayoutResId() = R.layout.fragment_qr_code_scanner_with_button + + val sharedViewModel: UserCodeSharedViewModel by activityViewModel() + + var autoFocus = true + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + userCodeMyCodeButton.debouncedClicks { + sharedViewModel.handle(UserCodeActions.SwitchMode(UserCodeState.Mode.SHOW)) + } + + userCodeOpenGalleryButton.debouncedClicks { + MultiPicker.get(MultiPicker.IMAGE).single().startWith(pickImageActivityResultLauncher) + } + } + + private val openCameraActivityResultLauncher = registerForPermissionsResult { allGranted -> + if (allGranted) { + startCamera() + } + } + + private val pickImageActivityResultLauncher = registerStartForActivityResult { activityResult -> + if (activityResult.resultCode == Activity.RESULT_OK) { + MultiPicker + .get(MultiPicker.IMAGE) + .getSelectedFiles(requireActivity(), activityResult.data) + .firstOrNull() + ?.contentUri + ?.let { uri -> + // try to see if it is a valid matrix code + val bitmap = ImageUtils.getBitmap(requireContext(), uri) + ?: return@let Unit.also { + Toast.makeText(requireContext(), getString(R.string.qr_code_not_scanned), Toast.LENGTH_SHORT).show() + } + handleResult(tryOrNull { QRCodeBitmapDecodeHelper.decodeQRFromBitmap(bitmap) }) + } + } + } + + private fun startCamera() { + userCodeScannerView.startCamera() + userCodeScannerView.setAutoFocus(autoFocus) + userCodeScannerView.debouncedClicks { + this.autoFocus = !autoFocus + userCodeScannerView.setAutoFocus(autoFocus) + } + } + + override fun onResume() { + super.onResume() + // Register ourselves as a handler for scan results. + userCodeScannerView.setResultHandler(this) + // Start camera on resume + if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), openCameraActivityResultLauncher)) { + startCamera() + } + } + + override fun onPause() { + super.onPause() + // Stop camera on pause + userCodeScannerView.stopCamera() + } + + override fun handleResult(result: Result?) { + if (result === null) { + Toast.makeText(requireContext(), R.string.qr_code_not_scanned, Toast.LENGTH_SHORT).show() + requireActivity().finish() + } else { + val rawBytes = getRawBytes(result) + val rawBytesStr = rawBytes?.toString(Charsets.ISO_8859_1) + val value = rawBytesStr ?: result.text + sharedViewModel.handle(UserCodeActions.DecodedQRCode(value)) + } + } + + // Copied from https://github.com/markusfisch/BinaryEye/blob/ + // 9d57889b810dcaa1a91d7278fc45c262afba1284/app/src/main/kotlin/de/markusfisch/android/binaryeye/activity/CameraActivity.kt#L434 + private fun getRawBytes(result: Result): ByteArray? { + val metadata = result.resultMetadata ?: return null + val segments = metadata[ResultMetadataType.BYTE_SEGMENTS] ?: return null + var bytes = ByteArray(0) + @Suppress("UNCHECKED_CAST") + for (seg in segments as Iterable) { + bytes += seg + } + // byte segments can never be shorter than the text. + // Zxing cuts off content prefixes like "WIFI:" + return if (bytes.size >= result.text.length) bytes else null + } +} diff --git a/vector/src/main/java/im/vector/app/features/usercode/ShowUserCodeFragment.kt b/vector/src/main/java/im/vector/app/features/usercode/ShowUserCodeFragment.kt new file mode 100644 index 0000000000..ab88f79bef --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/usercode/ShowUserCodeFragment.kt @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020 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.app.features.usercode + +import android.os.Bundle +import android.view.View +import com.airbnb.mvrx.activityViewModel +import com.airbnb.mvrx.withState +import im.vector.app.R +import im.vector.app.core.extensions.setTextOrHide +import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.features.home.AvatarRenderer +import kotlinx.android.synthetic.main.fragment_user_code_show.* +import javax.inject.Inject + +class ShowUserCodeFragment @Inject constructor( + private val avatarRenderer: AvatarRenderer +) : VectorBaseFragment() { + + override fun getLayoutResId() = R.layout.fragment_user_code_show + + val sharedViewModel: UserCodeSharedViewModel by activityViewModel() + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + showUserCodeClose.debouncedClicks { + sharedViewModel.handle(UserCodeActions.DismissAction) + } + showUserCodeScanButton.debouncedClicks { + doOpenQRCodeScanner() + } + } + + private fun doOpenQRCodeScanner() { + sharedViewModel.handle(UserCodeActions.SwitchMode(UserCodeState.Mode.SCAN)) + } + + override fun invalidate() = withState(sharedViewModel) { state -> + state.matrixItem?.let { avatarRenderer.render(it, showUserCodeAvatar) } + state.shareLink?.let { showUserCodeQRImage.setData(it) } + showUserCodeCardNameText.setTextOrHide(state.matrixItem?.displayName) + showUserCodeCardUserIdText.setTextOrHide(state.matrixItem?.id) + Unit + } +} diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeActions.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActions.kt new file mode 100644 index 0000000000..0611e0f8c3 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActions.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020 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.app.features.usercode + +import im.vector.app.core.platform.VectorViewModelAction +import org.matrix.android.sdk.api.util.MatrixItem + +sealed class UserCodeActions : VectorViewModelAction { + object DismissAction : UserCodeActions() + data class SwitchMode(val mode: UserCodeState.Mode) : UserCodeActions() + data class DecodedQRCode(val code: String) : UserCodeActions() + data class StartChattingWithUser(val matrixItem: MatrixItem) : UserCodeActions() +} diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt new file mode 100644 index 0000000000..388dc220a8 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2020 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.app.features.usercode + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.os.Parcelable +import android.widget.Toast +import androidx.core.app.ActivityCompat +import androidx.core.view.isVisible +import androidx.fragment.app.Fragment +import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.viewModel +import com.airbnb.mvrx.withState +import im.vector.app.R +import im.vector.app.core.di.ScreenComponent +import im.vector.app.core.extensions.exhaustive +import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.features.matrixto.MatrixToBottomSheet +import kotlinx.android.parcel.Parcelize +import kotlinx.android.synthetic.main.activity_simple.* +import org.matrix.android.sdk.api.util.MatrixItem +import javax.inject.Inject +import kotlin.reflect.KClass + +class UserCodeActivity + : VectorBaseActivity(), UserCodeSharedViewModel.Factory, MatrixToBottomSheet.InteractionListener { + + @Inject lateinit var viewModelFactory: UserCodeSharedViewModel.Factory + + val sharedViewModel: UserCodeSharedViewModel by viewModel() + + @Parcelize + data class Args( + val userId: String + ) : Parcelable + + override fun getLayoutRes() = R.layout.activity_simple + + override fun injectWith(injector: ScreenComponent) { + injector.inject(this) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + if (isFirstCreation()) { + // should be there early for shared element transition + showFragment(ShowUserCodeFragment::class, Bundle.EMPTY) + } + + sharedViewModel.selectSubscribe(this, UserCodeState::mode) { mode -> + when (mode) { + UserCodeState.Mode.SHOW -> showFragment(ShowUserCodeFragment::class, Bundle.EMPTY) + UserCodeState.Mode.SCAN -> showFragment(ScanUserCodeFragment::class, Bundle.EMPTY) + is UserCodeState.Mode.RESULT -> { + showFragment(ShowUserCodeFragment::class, Bundle.EMPTY) + MatrixToBottomSheet.create(mode.matrixItem, this).show(supportFragmentManager, "MatrixToBottomSheet") + } + } + } + + sharedViewModel.observeViewEvents { + when (it) { + is UserCodeShareViewEvents.InviteFriend -> TODO() + UserCodeShareViewEvents.Dismiss -> ActivityCompat.finishAfterTransition(this) + UserCodeShareViewEvents.ShowWaitingScreen -> simpleActivityWaitingView.isVisible = true + UserCodeShareViewEvents.HideWaitingScreen -> simpleActivityWaitingView.isVisible = false + is UserCodeShareViewEvents.ToastMessage -> Toast.makeText(this, it.message, Toast.LENGTH_LONG).show() + is UserCodeShareViewEvents.NavigateToRoom -> navigator.openRoom(this, it.roomId) + }.exhaustive + } + } + + private fun showFragment(fragmentClass: KClass, bundle: Bundle) { + if (supportFragmentManager.findFragmentByTag(fragmentClass.simpleName) == null) { + supportFragmentManager.beginTransaction().let { + it.setCustomAnimations(R.anim.fade_in, R.anim.fade_out, R.anim.fade_in, R.anim.fade_out) + it.replace(R.id.simpleFragmentContainer, + fragmentClass.java, + bundle, + fragmentClass.simpleName + ) + it.commit() + } + } + } + + override fun didTapStartMessage(matrixItem: MatrixItem) { + sharedViewModel.handle(UserCodeActions.StartChattingWithUser(matrixItem)) + } + + override fun onBackPressed() = withState(sharedViewModel) { + when (it.mode) { + UserCodeState.Mode.SHOW -> super.onBackPressed() + is UserCodeState.Mode.RESULT, + UserCodeState.Mode.SCAN -> sharedViewModel.handle(UserCodeActions.SwitchMode(UserCodeState.Mode.SHOW)) + } + } + + override fun create(initialState: UserCodeState, args: Args) = + viewModelFactory.create(initialState, args) + + companion object { + fun newIntent(context: Context, userId: String): Intent { + return Intent(context, UserCodeActivity::class.java).apply { + putExtra(MvRx.KEY_ARG, Args(userId)) + } + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeShareViewEvents.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeShareViewEvents.kt new file mode 100644 index 0000000000..26fcffadd2 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeShareViewEvents.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2020 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.app.features.usercode + +import im.vector.app.core.platform.VectorViewEvents + +sealed class UserCodeShareViewEvents : VectorViewEvents { + data class InviteFriend(val permalink: String) : UserCodeShareViewEvents() + object Dismiss : UserCodeShareViewEvents() + object ShowWaitingScreen : UserCodeShareViewEvents() + object HideWaitingScreen : UserCodeShareViewEvents() + data class ToastMessage(val message: String) : UserCodeShareViewEvents() + data class NavigateToRoom(val roomId: String) : UserCodeShareViewEvents() +} diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt new file mode 100644 index 0000000000..17dd97cffa --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2020 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.app.features.usercode + +import androidx.lifecycle.viewModelScope +import com.airbnb.mvrx.ActivityViewModelContext +import com.airbnb.mvrx.FragmentViewModelContext +import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.ViewModelContext +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject +import im.vector.app.R +import im.vector.app.core.platform.VectorViewModel +import im.vector.app.core.resources.StringProvider +import im.vector.app.features.raw.wellknown.getElementWellknown +import im.vector.app.features.raw.wellknown.isE2EByDefault +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.raw.RawService +import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.permalinks.PermalinkData +import org.matrix.android.sdk.api.session.permalinks.PermalinkParser +import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams +import org.matrix.android.sdk.api.session.user.model.User +import org.matrix.android.sdk.api.util.toMatrixItem +import org.matrix.android.sdk.internal.util.awaitCallback + +class UserCodeSharedViewModel @AssistedInject constructor( + @Assisted val initialState: UserCodeState, + @Assisted val args: UserCodeActivity.Args, + private val session: Session, + private val stringProvider: StringProvider, + private val rawService: RawService) : VectorViewModel(initialState) { + + companion object : MvRxViewModelFactory { + override fun create(viewModelContext: ViewModelContext, state: UserCodeState): UserCodeSharedViewModel? { + val args = viewModelContext.args() + val factory = when (viewModelContext) { + is FragmentViewModelContext -> viewModelContext.fragment as? Factory + is ActivityViewModelContext -> viewModelContext.activity as? Factory + } + return factory?.create(state, args) ?: error("You should let your activity/fragment implements Factory interface") + } + + override fun initialState(viewModelContext: ViewModelContext): UserCodeState? { + return UserCodeState(viewModelContext.args().userId) + } + } + + init { + val user = session.getUser(args.userId) + setState { + copy( + matrixItem = user?.toMatrixItem(), + shareLink = session.permalinkService().createPermalink(args.userId) + ) + } + } + + private fun handleInviteFriend() { + session.permalinkService().createPermalink(initialState.userId)?.let { permalink -> + _viewEvents.post(UserCodeShareViewEvents.InviteFriend(permalink)) + } + } + + @AssistedInject.Factory + interface Factory { + fun create(initialState: UserCodeState, args: UserCodeActivity.Args): UserCodeSharedViewModel + } + + override fun handle(action: UserCodeActions) { + when (action) { + UserCodeActions.DismissAction -> _viewEvents.post(UserCodeShareViewEvents.Dismiss) + is UserCodeActions.SwitchMode -> setState { copy(mode = action.mode) } + is UserCodeActions.DecodedQRCode -> handleQrCodeDecoded(action) + is UserCodeActions.StartChattingWithUser -> handleStartChatting(action) + } + } + + private fun handleStartChatting(withUser: UserCodeActions.StartChattingWithUser) { + val mxId = withUser.matrixItem.id + val existing = session.getExistingDirectRoomWithUser(mxId) + setState { + copy(mode = UserCodeState.Mode.SHOW) + } + if (existing != null) { + // navigate to this room + _viewEvents.post(UserCodeShareViewEvents.NavigateToRoom(existing)) + } else { + // we should create the room then navigate + _viewEvents.post(UserCodeShareViewEvents.ShowWaitingScreen) + viewModelScope.launch(Dispatchers.IO) { + val adminE2EByDefault = rawService.getElementWellknown(session.myUserId) + ?.isE2EByDefault() + ?: true + + val roomParams = CreateRoomParams() + .apply { + invitedUserIds.add(mxId) + setDirectMessage() + enableEncryptionIfInvitedUsersSupportIt = adminE2EByDefault + } + + val roomId = + try { + awaitCallback { session.createRoom(roomParams, it) } + } catch (failure: Throwable) { + _viewEvents.post(UserCodeShareViewEvents.ToastMessage(stringProvider.getString(R.string.invite_users_to_room_failure))) + return@launch + } finally { + _viewEvents.post(UserCodeShareViewEvents.HideWaitingScreen) + } + _viewEvents.post(UserCodeShareViewEvents.NavigateToRoom(roomId)) + } + } + } + + private fun handleQrCodeDecoded(action: UserCodeActions.DecodedQRCode) { + val linkedId = PermalinkParser.parse(action.code) + if (linkedId is PermalinkData.FallbackLink) { + _viewEvents.post(UserCodeShareViewEvents.ToastMessage(stringProvider.getString(R.string.not_a_valid_qr_code))) + return + } + _viewEvents.post(UserCodeShareViewEvents.ShowWaitingScreen) + viewModelScope.launch(Dispatchers.IO) { + when (linkedId) { + is PermalinkData.RoomLink -> TODO() + is PermalinkData.UserLink -> { + var user = session.getUser(linkedId.userId) ?: awaitCallback> { + session.searchUsersDirectory(linkedId.userId, 10, emptySet(), it) + }.firstOrNull { it.userId == linkedId.userId } + // Create raw Uxid in case the user is not searchable + ?: User(linkedId.userId, null, null) + + setState { + copy( + mode = UserCodeState.Mode.RESULT(user.toMatrixItem()) + ) + } + } + is PermalinkData.GroupLink -> TODO() + is PermalinkData.FallbackLink -> TODO() + } + _viewEvents.post(UserCodeShareViewEvents.HideWaitingScreen) + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeState.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeState.kt new file mode 100644 index 0000000000..3be882af3d --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeState.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020 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.app.features.usercode + +import com.airbnb.mvrx.MvRxState +import org.matrix.android.sdk.api.util.MatrixItem + +data class UserCodeState( + val userId: String, + val matrixItem: MatrixItem? = null, + val shareLink: String? = null, + val mode: Mode = Mode.SHOW +) : MvRxState { + sealed class Mode { + object SHOW : Mode() + object SCAN : Mode() + data class RESULT(val matrixItem: MatrixItem) : Mode() + } +} diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/ActionItem.kt b/vector/src/main/java/im/vector/app/features/userdirectory/ActionItem.kt new file mode 100644 index 0000000000..2307640634 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/userdirectory/ActionItem.kt @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2020 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.app.features.userdirectory + +import android.view.View +import android.widget.ImageView +import android.widget.TextView +import androidx.annotation.DrawableRes +import com.airbnb.epoxy.EpoxyAttribute +import com.airbnb.epoxy.EpoxyModelClass +import im.vector.app.R +import im.vector.app.core.epoxy.VectorEpoxyHolder +import im.vector.app.core.epoxy.VectorEpoxyModel +import im.vector.app.core.extensions.setTextOrHide + +@EpoxyModelClass(layout = R.layout.item_contact_action) +abstract class ActionItem : VectorEpoxyModel() { + + @EpoxyAttribute var title: CharSequence? = null + @EpoxyAttribute @DrawableRes var actionIconRes: Int? = null + @EpoxyAttribute var clickAction: View.OnClickListener? = null + + override fun bind(holder: Holder) { + super.bind(holder) + holder.view.setOnClickListener(clickAction) + // If name is empty, use userId as name and force it being centered + holder.actionTitleText.setTextOrHide(title) + if (actionIconRes != null) { + holder.actionTitleImageView.setImageResource(actionIconRes!!) + } else { + holder.actionTitleImageView.setImageDrawable(null) + } + } + + class Holder : VectorEpoxyHolder() { + val actionTitleText by bind(R.id.actionTitleText) + val actionTitleImageView by bind(R.id.actionIconImageView) + } +} diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/ContactDetailItem.kt b/vector/src/main/java/im/vector/app/features/userdirectory/ContactDetailItem.kt new file mode 100644 index 0000000000..ee96c34f45 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/userdirectory/ContactDetailItem.kt @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020 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.app.features.userdirectory + +import android.widget.TextView +import com.airbnb.epoxy.EpoxyAttribute +import com.airbnb.epoxy.EpoxyModelClass +import im.vector.app.R +import im.vector.app.core.epoxy.ClickListener +import im.vector.app.core.epoxy.VectorEpoxyHolder +import im.vector.app.core.epoxy.VectorEpoxyModel +import im.vector.app.core.epoxy.onClick +import im.vector.app.core.extensions.setTextOrHide + +@EpoxyModelClass(layout = R.layout.item_contact_detail) +abstract class ContactDetailItem : VectorEpoxyModel() { + + @EpoxyAttribute lateinit var threePid: String + @EpoxyAttribute var matrixId: String? = null + @EpoxyAttribute var clickListener: ClickListener? = null + + override fun bind(holder: Holder) { + super.bind(holder) + holder.view.onClick(clickListener) + holder.nameView.text = threePid + holder.matrixIdView.setTextOrHide(matrixId) + } + + class Holder : VectorEpoxyHolder() { + val nameView by bind(R.id.contactDetailName) + val matrixIdView by bind(R.id.contactDetailMatrixId) + } +} diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/ContactItem.kt b/vector/src/main/java/im/vector/app/features/userdirectory/ContactItem.kt new file mode 100644 index 0000000000..d9f424d961 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/userdirectory/ContactItem.kt @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 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.app.features.userdirectory + +import android.widget.ImageView +import android.widget.TextView +import com.airbnb.epoxy.EpoxyAttribute +import com.airbnb.epoxy.EpoxyModelClass +import im.vector.app.R +import im.vector.app.core.contacts.MappedContact +import im.vector.app.core.epoxy.VectorEpoxyHolder +import im.vector.app.core.epoxy.VectorEpoxyModel +import im.vector.app.features.home.AvatarRenderer + +@EpoxyModelClass(layout = R.layout.item_contact_main) +abstract class ContactItem : VectorEpoxyModel() { + + @EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer + @EpoxyAttribute lateinit var mappedContact: MappedContact + + override fun bind(holder: Holder) { + super.bind(holder) + // If name is empty, use userId as name and force it being centered + holder.nameView.text = mappedContact.displayName + avatarRenderer.render(mappedContact, holder.avatarImageView) + } + + class Holder : VectorEpoxyHolder() { + val nameView by bind(R.id.contactDisplayName) + val avatarImageView by bind(R.id.contactAvatar) + } +} diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/DirectoryUsersController.kt b/vector/src/main/java/im/vector/app/features/userdirectory/DirectoryUsersController.kt deleted file mode 100644 index e68d9855dd..0000000000 --- a/vector/src/main/java/im/vector/app/features/userdirectory/DirectoryUsersController.kt +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2020 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.app.features.userdirectory - -import com.airbnb.epoxy.EpoxyController -import com.airbnb.mvrx.Fail -import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.Success -import com.airbnb.mvrx.Uninitialized -import im.vector.app.R -import im.vector.app.core.epoxy.errorWithRetryItem -import im.vector.app.core.epoxy.loadingItem -import im.vector.app.core.epoxy.noResultItem -import im.vector.app.core.error.ErrorFormatter -import im.vector.app.core.resources.StringProvider -import im.vector.app.features.home.AvatarRenderer -import org.matrix.android.sdk.api.MatrixPatterns -import org.matrix.android.sdk.api.session.Session -import org.matrix.android.sdk.api.session.user.model.User -import org.matrix.android.sdk.api.util.toMatrixItem -import javax.inject.Inject - -class DirectoryUsersController @Inject constructor(private val session: Session, - private val avatarRenderer: AvatarRenderer, - private val stringProvider: StringProvider, - private val errorFormatter: ErrorFormatter) : EpoxyController() { - - private var state: UserDirectoryViewState? = null - - var callback: Callback? = null - - init { - requestModelBuild() - } - - fun setData(state: UserDirectoryViewState) { - this.state = state - requestModelBuild() - } - - override fun buildModels() { - val currentState = state ?: return - val hasSearch = currentState.directorySearchTerm.isNotBlank() - when (val asyncUsers = currentState.directoryUsers) { - is Uninitialized -> renderEmptyState(false) - is Loading -> renderLoading() - is Success -> renderSuccess( - computeUsersList(asyncUsers(), currentState.directorySearchTerm), - currentState.getSelectedMatrixId(), - hasSearch - ) - is Fail -> renderFailure(asyncUsers.error) - } - } - - /** - * Eventually add the searched terms, if it is a userId, and if not already present in the result - */ - private fun computeUsersList(directoryUsers: List, searchTerms: String): List { - return directoryUsers + - searchTerms - .takeIf { terms -> MatrixPatterns.isUserId(terms) && !directoryUsers.any { it.userId == terms } } - ?.let { listOf(User(it)) } - .orEmpty() - } - - private fun renderLoading() { - loadingItem { - id("loading") - } - } - - private fun renderFailure(failure: Throwable) { - errorWithRetryItem { - id("error") - text(errorFormatter.toHumanReadable(failure)) - listener { callback?.retryDirectoryUsersRequest() } - } - } - - private fun renderSuccess(users: List, - selectedUsers: List, - hasSearch: Boolean) { - if (users.isEmpty()) { - renderEmptyState(hasSearch) - } else { - renderUsers(users, selectedUsers) - } - } - - private fun renderUsers(users: List, selectedUsers: List) { - for (user in users) { - if (user.userId == session.myUserId) { - continue - } - val isSelected = selectedUsers.contains(user.userId) - userDirectoryUserItem { - id(user.userId) - selected(isSelected) - matrixItem(user.toMatrixItem()) - avatarRenderer(avatarRenderer) - clickListener { _ -> - callback?.onItemClick(user) - } - } - } - } - - private fun renderEmptyState(hasSearch: Boolean) { - val noResultRes = if (hasSearch) { - R.string.no_result_placeholder - } else { - R.string.direct_room_start_search - } - noResultItem { - id("noResult") - text(stringProvider.getString(noResultRes)) - } - } - - interface Callback { - fun onItemClick(user: User) - fun retryDirectoryUsersRequest() - } -} diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersController.kt b/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersController.kt deleted file mode 100644 index 4fbb9bbb41..0000000000 --- a/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersController.kt +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2020 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.app.features.userdirectory - -import com.airbnb.epoxy.EpoxyModel -import com.airbnb.epoxy.paging.PagedListEpoxyController -import com.airbnb.mvrx.Async -import com.airbnb.mvrx.Incomplete -import com.airbnb.mvrx.Uninitialized -import im.vector.app.R -import im.vector.app.core.epoxy.EmptyItem_ -import im.vector.app.core.epoxy.loadingItem -import im.vector.app.core.epoxy.noResultItem -import im.vector.app.core.resources.StringProvider -import im.vector.app.core.utils.createUIHandler -import im.vector.app.features.home.AvatarRenderer -import org.matrix.android.sdk.api.session.Session -import org.matrix.android.sdk.api.session.user.model.User -import org.matrix.android.sdk.api.util.toMatrixItem -import javax.inject.Inject - -class KnownUsersController @Inject constructor(private val session: Session, - private val avatarRenderer: AvatarRenderer, - private val stringProvider: StringProvider) : PagedListEpoxyController( - modelBuildingHandler = createUIHandler() -) { - - private var selectedUsers: List = emptyList() - private var users: Async> = Uninitialized - private var isFiltering: Boolean = false - - var callback: Callback? = null - - init { - requestModelBuild() - } - - fun setData(state: UserDirectoryViewState) { - this.isFiltering = !state.filterKnownUsersValue.isEmpty() - val newSelection = state.getSelectedMatrixId() - this.users = state.knownUsers - if (newSelection != selectedUsers) { - this.selectedUsers = newSelection - requestForcedModelBuild() - } - submitList(state.knownUsers()) - } - - override fun buildItemModel(currentPosition: Int, item: User?): EpoxyModel<*> { - return if (item == null) { - EmptyItem_().id(currentPosition) - } else { - val isSelected = selectedUsers.contains(item.userId) - UserDirectoryUserItem_() - .id(item.userId) - .selected(isSelected) - .matrixItem(item.toMatrixItem()) - .avatarRenderer(avatarRenderer) - .clickListener { _ -> - callback?.onItemClick(item) - } - } - } - - override fun addModels(models: List>) { - if (users is Incomplete) { - renderLoading() - } else if (models.isEmpty()) { - renderEmptyState() - } else { - var lastFirstLetter: String? = null - for (model in models) { - if (model is UserDirectoryUserItem) { - if (model.matrixItem.id == session.myUserId) continue - val currentFirstLetter = model.matrixItem.firstLetterOfDisplayName() - val showLetter = !isFiltering && currentFirstLetter.isNotEmpty() && lastFirstLetter != currentFirstLetter - lastFirstLetter = currentFirstLetter - - UserDirectoryLetterHeaderItem_() - .id(currentFirstLetter) - .letter(currentFirstLetter) - .addIf(showLetter, this) - - model.addTo(this) - } else { - continue - } - } - } - } - - private fun renderLoading() { - loadingItem { - id("loading") - } - } - - private fun renderEmptyState() { - noResultItem { - id("noResult") - text(stringProvider.getString(R.string.direct_room_no_known_users)) - } - } - - interface Callback { - fun onItemClick(user: User) - } -} diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryFragment.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryFragment.kt deleted file mode 100644 index 70ea9141e7..0000000000 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryFragment.kt +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2020 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.app.features.userdirectory - -import android.os.Bundle -import android.view.View -import com.airbnb.mvrx.activityViewModel -import com.airbnb.mvrx.withState -import com.jakewharton.rxbinding3.widget.textChanges -import im.vector.app.R -import im.vector.app.core.extensions.cleanup -import im.vector.app.core.extensions.configureWith -import im.vector.app.core.extensions.hideKeyboard -import im.vector.app.core.extensions.setupAsSearch -import im.vector.app.core.extensions.showKeyboard -import im.vector.app.core.platform.VectorBaseFragment -import kotlinx.android.synthetic.main.fragment_user_directory.* -import org.matrix.android.sdk.api.session.user.model.User -import javax.inject.Inject - -class UserDirectoryFragment @Inject constructor( - private val directRoomController: DirectoryUsersController -) : VectorBaseFragment(), DirectoryUsersController.Callback { - - override fun getLayoutResId() = R.layout.fragment_user_directory - private val viewModel: UserDirectoryViewModel by activityViewModel() - - private lateinit var sharedActionViewModel: UserDirectorySharedActionViewModel - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - sharedActionViewModel = activityViewModelProvider.get(UserDirectorySharedActionViewModel::class.java) - setupRecyclerView() - setupSearchByMatrixIdView() - setupCloseView() - } - - override fun onDestroyView() { - userDirectoryRecyclerView.cleanup() - directRoomController.callback = null - super.onDestroyView() - } - - private fun setupRecyclerView() { - directRoomController.callback = this - userDirectoryRecyclerView.configureWith(directRoomController) - } - - private fun setupSearchByMatrixIdView() { - userDirectorySearchById.setupAsSearch(searchIconRes = 0) - userDirectorySearchById - .textChanges() - .subscribe { - viewModel.handle(UserDirectoryAction.SearchDirectoryUsers(it.toString())) - } - .disposeOnDestroyView() - userDirectorySearchById.showKeyboard(andRequestFocus = true) - } - - private fun setupCloseView() { - userDirectoryClose.debouncedClicks { - sharedActionViewModel.post(UserDirectorySharedAction.GoBack) - } - } - - override fun invalidate() = withState(viewModel) { - directRoomController.setData(it) - } - - override fun onItemClick(user: User) { - view?.hideKeyboard() - viewModel.handle(UserDirectoryAction.SelectPendingInvitee(PendingInvitee.UserPendingInvitee(user))) - sharedActionViewModel.post(UserDirectorySharedAction.GoBack) - } - - override fun retryDirectoryUsersRequest() { - val currentSearch = userDirectorySearchById.text.toString() - viewModel.handle(UserDirectoryAction.SearchDirectoryUsers(currentSearch)) - } -} diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewModel.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewModel.kt deleted file mode 100644 index 0a24b85ce2..0000000000 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewModel.kt +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (c) 2020 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.app.features.userdirectory - -import androidx.fragment.app.FragmentActivity -import arrow.core.Option -import com.airbnb.mvrx.ActivityViewModelContext -import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory -import com.airbnb.mvrx.ViewModelContext -import com.jakewharton.rxrelay2.BehaviorRelay -import com.squareup.inject.assisted.Assisted -import com.squareup.inject.assisted.AssistedInject -import im.vector.app.core.extensions.exhaustive -import im.vector.app.core.extensions.toggle -import im.vector.app.core.platform.VectorViewModel -import im.vector.app.features.createdirect.CreateDirectRoomActivity -import im.vector.app.features.invite.InviteUsersToRoomActivity -import io.reactivex.Single -import io.reactivex.android.schedulers.AndroidSchedulers -import org.matrix.android.sdk.api.session.Session -import org.matrix.android.sdk.api.util.toMatrixItem -import org.matrix.android.sdk.rx.rx -import java.util.concurrent.TimeUnit - -private typealias KnowUsersFilter = String -private typealias DirectoryUsersSearch = String - -class UserDirectoryViewModel @AssistedInject constructor(@Assisted - initialState: UserDirectoryViewState, - private val session: Session) - : VectorViewModel(initialState) { - - @AssistedInject.Factory - interface Factory { - fun create(initialState: UserDirectoryViewState): UserDirectoryViewModel - } - - private val knownUsersFilter = BehaviorRelay.createDefault>(Option.empty()) - private val directoryUsersSearch = BehaviorRelay.create() - - companion object : MvRxViewModelFactory { - - override fun create(viewModelContext: ViewModelContext, state: UserDirectoryViewState): UserDirectoryViewModel? { - return when (viewModelContext) { - is FragmentViewModelContext -> (viewModelContext.fragment() as KnownUsersFragment).userDirectoryViewModelFactory.create(state) - is ActivityViewModelContext -> { - when (viewModelContext.activity()) { - is CreateDirectRoomActivity -> viewModelContext.activity().userDirectoryViewModelFactory.create(state) - is InviteUsersToRoomActivity -> viewModelContext.activity().userDirectoryViewModelFactory.create(state) - else -> error("Wrong activity or fragment") - } - } - else -> error("Wrong activity or fragment") - } - } - } - - init { - observeKnownUsers() - observeDirectoryUsers() - } - - override fun handle(action: UserDirectoryAction) { - when (action) { - is UserDirectoryAction.FilterKnownUsers -> knownUsersFilter.accept(Option.just(action.value)) - is UserDirectoryAction.ClearFilterKnownUsers -> knownUsersFilter.accept(Option.empty()) - is UserDirectoryAction.SearchDirectoryUsers -> directoryUsersSearch.accept(action.value) - is UserDirectoryAction.SelectPendingInvitee -> handleSelectUser(action) - is UserDirectoryAction.RemovePendingInvitee -> handleRemoveSelectedUser(action) - }.exhaustive - } - - private fun handleRemoveSelectedUser(action: UserDirectoryAction.RemovePendingInvitee) = withState { state -> - val selectedUsers = state.pendingInvitees.minus(action.pendingInvitee) - setState { - copy( - pendingInvitees = selectedUsers, - existingDmRoomId = getExistingDmRoomId(selectedUsers) - ) - } - } - - private fun handleSelectUser(action: UserDirectoryAction.SelectPendingInvitee) = withState { state -> - // Reset the filter asap - directoryUsersSearch.accept("") - val selectedUsers = state.pendingInvitees.toggle(action.pendingInvitee) - setState { - copy( - pendingInvitees = selectedUsers, - existingDmRoomId = getExistingDmRoomId(selectedUsers) - ) - } - } - - private fun getExistingDmRoomId(selectedUsers: Set): String? { - return selectedUsers - .takeIf { it.size == 1 } - ?.filterIsInstance(PendingInvitee.UserPendingInvitee::class.java) - ?.firstOrNull() - ?.let { invitee -> session.getExistingDirectRoomWithUser(invitee.user.userId) } - } - - private fun observeDirectoryUsers() = withState { state -> - directoryUsersSearch - .debounce(300, TimeUnit.MILLISECONDS) - .switchMapSingle { search -> - val stream = if (search.isBlank()) { - Single.just(emptyList()) - } else { - session.rx() - .searchUsersDirectory(search, 50, state.excludedUserIds ?: emptySet()) - .map { users -> - users.sortedBy { it.toMatrixItem().firstLetterOfDisplayName() } - } - } - stream.toAsync { - copy(directoryUsers = it, directorySearchTerm = search) - } - } - .subscribe() - .disposeOnClear() - } - - private fun observeKnownUsers() = withState { state -> - knownUsersFilter - .throttleLast(300, TimeUnit.MILLISECONDS) - .observeOn(AndroidSchedulers.mainThread()) - .switchMap { - session.rx().livePagedUsers(it.orNull(), state.excludedUserIds) - } - .execute { async -> - copy( - knownUsers = async, - filterKnownUsersValue = knownUsersFilter.value ?: Option.empty() - ) - } - } -} diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryAction.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListAction.kt similarity index 71% rename from vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryAction.kt rename to vector/src/main/java/im/vector/app/features/userdirectory/UserListAction.kt index f4f3fb8cd4..0c2c4b1f4b 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryAction.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListAction.kt @@ -18,10 +18,10 @@ package im.vector.app.features.userdirectory import im.vector.app.core.platform.VectorViewModelAction -sealed class UserDirectoryAction : VectorViewModelAction { - data class FilterKnownUsers(val value: String) : UserDirectoryAction() - data class SearchDirectoryUsers(val value: String) : UserDirectoryAction() - object ClearFilterKnownUsers : UserDirectoryAction() - data class SelectPendingInvitee(val pendingInvitee: PendingInvitee) : UserDirectoryAction() - data class RemovePendingInvitee(val pendingInvitee: PendingInvitee) : UserDirectoryAction() +sealed class UserListAction : VectorViewModelAction { + data class SearchUsers(val value: String) : UserListAction() + object ClearSearchUsers : UserListAction() + data class SelectPendingInvitee(val pendingInvitee: PendingInvitee) : UserListAction() + data class RemovePendingInvitee(val pendingInvitee: PendingInvitee) : UserListAction() + object ComputeMatrixToLinkForSharing : UserListAction() } diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListController.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListController.kt new file mode 100644 index 0000000000..6cd76401fd --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListController.kt @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2020 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.app.features.userdirectory + +import android.view.View +import com.airbnb.epoxy.EpoxyController +import com.airbnb.mvrx.Fail +import com.airbnb.mvrx.Loading +import com.airbnb.mvrx.Success +import com.airbnb.mvrx.Uninitialized +import im.vector.app.R +import im.vector.app.core.epoxy.errorWithRetryItem +import im.vector.app.core.epoxy.loadingItem +import im.vector.app.core.epoxy.noResultItem +import im.vector.app.core.error.ErrorFormatter +import im.vector.app.core.resources.StringProvider +import im.vector.app.features.home.AvatarRenderer +import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.identity.ThreePid +import org.matrix.android.sdk.api.session.user.model.User +import org.matrix.android.sdk.api.util.toMatrixItem +import javax.inject.Inject + +class UserListController @Inject constructor(private val session: Session, + private val avatarRenderer: AvatarRenderer, + private val stringProvider: StringProvider, + private val errorFormatter: ErrorFormatter) : EpoxyController() { + + private var state: UserListViewState? = null + + var callback: Callback? = null + + fun setData(state: UserListViewState) { + this.state = state + requestModelBuild() + } + + override fun buildModels() { + val currentState = state ?: return + + // Build generic items + if (currentState.searchTerm.isBlank()) { + // For now we remove this option if in invite to existing room flow (and not create DM) + if (currentState.pendingInvitees.isEmpty() + // For now we remove this option if in invite to existing room flow (and not create DM) + && currentState.existingRoomId == null) { + actionItem { + id(R.drawable.ic_invite_people) + title(stringProvider.getString(R.string.invite_friends)) + actionIconRes(R.drawable.ic_invite_people) + clickAction(View.OnClickListener { + callback?.onInviteFriendClick() + }) + } + } + actionItem { + id(R.drawable.ic_book) + title(stringProvider.getString(R.string.contacts_book_title)) + actionIconRes(R.drawable.ic_book) + clickAction(View.OnClickListener { + callback?.onContactBookClick() + }) + } + if (currentState.pendingInvitees.isEmpty() + // For now we remove this option if in invite to existing room flow (and not create DM) + && currentState.existingRoomId == null) { + actionItem { + id(R.drawable.ic_qr_code_add) + title(stringProvider.getString(R.string.qr_code)) + actionIconRes(R.drawable.ic_qr_code_add) + clickAction(View.OnClickListener { + callback?.onUseQRCode() + }) + } + } + } + + when (currentState.knownUsers) { + is Uninitialized -> renderEmptyState() + is Loading -> renderLoading() + is Fail -> renderFailure(currentState.knownUsers.error) + is Success -> buildKnownUsers(currentState, currentState.getSelectedMatrixId()) + } + + when (val asyncUsers = currentState.directoryUsers) { + is Uninitialized -> { + } + is Loading -> renderLoading() + is Fail -> renderFailure(asyncUsers.error) + is Success -> buildDirectoryUsers( + asyncUsers(), + currentState.getSelectedMatrixId(), + currentState.searchTerm, + // to avoid showing twice same user in known and suggestions + currentState.knownUsers.invoke()?.map { it.userId } ?: emptyList() + ) + } + } + + private fun buildKnownUsers(currentState: UserListViewState, selectedUsers: List) { + currentState.knownUsers()?.let { userList -> + userListHeaderItem { + id("known_header") + header(stringProvider.getString(R.string.direct_room_user_list_known_title)) + } + + if (userList.isEmpty()) { + renderEmptyState() + return + } + userList.forEach { item -> + val isSelected = selectedUsers.contains(item.userId) + userDirectoryUserItem { + id(item.userId) + selected(isSelected) + matrixItem(item.toMatrixItem()) + avatarRenderer(avatarRenderer) + clickListener { _ -> + callback?.onItemClick(item) + } + } + } + } + } + + private fun buildDirectoryUsers(directoryUsers: List, selectedUsers: List, searchTerms: String, ignoreIds: List) { + val toDisplay = directoryUsers.filter { !ignoreIds.contains(it.userId) } + if (toDisplay.isEmpty() && searchTerms.isBlank()) { + return + } + userListHeaderItem { + id("suggestions") + header(stringProvider.getString(R.string.direct_room_user_list_suggestions_title)) + } + if (toDisplay.isEmpty()) { + renderEmptyState() + } else { + toDisplay.forEach { user -> + if (user.userId != session.myUserId) { + val isSelected = selectedUsers.contains(user.userId) + userDirectoryUserItem { + id(user.userId) + selected(isSelected) + matrixItem(user.toMatrixItem()) + avatarRenderer(avatarRenderer) + clickListener { _ -> + callback?.onItemClick(user) + } + } + } + } + } + } + + private fun renderLoading() { + loadingItem { + id("loading") + } + } + + private fun renderEmptyState() { + noResultItem { + id("noResult") + text(stringProvider.getString(R.string.no_result_placeholder)) + } + } + + private fun renderFailure(failure: Throwable) { + errorWithRetryItem { + id("error") + text(errorFormatter.toHumanReadable(failure)) + } + } + + interface Callback { + fun onInviteFriendClick() + fun onContactBookClick() + fun onUseQRCode() + fun onItemClick(user: User) + fun onMatrixIdClick(matrixId: String) + fun onThreePidClick(threePid: ThreePid) + } +} diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragment.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt similarity index 57% rename from vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragment.kt rename to vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt index ec684e8eea..4af16772b8 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragment.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt @@ -36,53 +36,64 @@ import im.vector.app.core.extensions.hideKeyboard import im.vector.app.core.extensions.setupAsSearch import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.DimensionConverter +import im.vector.app.core.utils.startSharePlainTextIntent import im.vector.app.features.homeserver.HomeServerCapabilitiesViewModel -import kotlinx.android.synthetic.main.fragment_known_users.* +import kotlinx.android.synthetic.main.fragment_user_list.* +import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.user.model.User import javax.inject.Inject -class KnownUsersFragment @Inject constructor( - val userDirectoryViewModelFactory: UserDirectoryViewModel.Factory, - private val knownUsersController: KnownUsersController, +class UserListFragment @Inject constructor( + private val userListController: UserListController, private val dimensionConverter: DimensionConverter, val homeServerCapabilitiesViewModelFactory: HomeServerCapabilitiesViewModel.Factory -) : VectorBaseFragment(), KnownUsersController.Callback { +) : VectorBaseFragment(), UserListController.Callback { - private val args: KnownUsersFragmentArgs by args() + private val args: UserListFragmentArgs by args() + private val viewModel: UserListViewModel by activityViewModel() + private val homeServerCapabilitiesViewModel: HomeServerCapabilitiesViewModel by fragmentViewModel() + private lateinit var sharedActionViewModel: UserListSharedActionViewModel - override fun getLayoutResId() = R.layout.fragment_known_users + override fun getLayoutResId() = R.layout.fragment_user_list override fun getMenuRes() = args.menuResId - private val viewModel: UserDirectoryViewModel by activityViewModel() - private val homeServerCapabilitiesViewModel: HomeServerCapabilitiesViewModel by fragmentViewModel() - - private lateinit var sharedActionViewModel: UserDirectorySharedActionViewModel - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - sharedActionViewModel = activityViewModelProvider.get(UserDirectorySharedActionViewModel::class.java) + sharedActionViewModel = activityViewModelProvider.get(UserListSharedActionViewModel::class.java) + userListTitle.text = args.title + vectorBaseActivity.setSupportActionBar(userListToolbar) - knownUsersTitle.text = args.title - vectorBaseActivity.setSupportActionBar(knownUsersToolbar) setupRecyclerView() - setupFilterView() - setupAddByMatrixIdView() - setupAddFromPhoneBookView() + setupSearchView() setupCloseView() homeServerCapabilitiesViewModel.subscribe { - knownUsersE2EbyDefaultDisabled.isVisible = !it.isE2EByDefault + userListE2EbyDefaultDisabled.isVisible = !it.isE2EByDefault } - viewModel.selectSubscribe(this, UserDirectoryViewState::pendingInvitees) { + viewModel.selectSubscribe(this, UserListViewState::pendingInvitees) { renderSelectedUsers(it) } + + viewModel.observeViewEvents { + when (it) { + is UserListViewEvents.OpenShareMatrixToLing -> { + val text = getString(R.string.invite_friends_text, it.link) + startSharePlainTextIntent( + fragment = this, + activityResultLauncher = null, + chooserTitle = getString(R.string.invite_friends), + text = text, + extraTitle = getString(R.string.invite_friends_rich_title) + ) + } + } + } } override fun onDestroyView() { - knownUsersController.callback = null - knownUsersRecyclerView.cleanup() + recyclerView.cleanup() super.onDestroyView() } @@ -91,69 +102,52 @@ class KnownUsersFragment @Inject constructor( val showMenuItem = it.pendingInvitees.isNotEmpty() menu.forEach { menuItem -> menuItem.isVisible = showMenuItem - if (args.isCreatingRoom) { - menuItem.setTitle(if (it.existingDmRoomId != null) R.string.action_open else R.string.create_room_action_create) - } } } super.onPrepareOptionsMenu(menu) } override fun onOptionsItemSelected(item: MenuItem): Boolean = withState(viewModel) { - sharedActionViewModel.post(UserDirectorySharedAction.OnMenuItemSelected( - item.itemId, - it.pendingInvitees, - it.existingDmRoomId - )) + sharedActionViewModel.post(UserListSharedAction.OnMenuItemSelected(item.itemId, it.pendingInvitees)) return@withState true } - private fun setupAddByMatrixIdView() { - addByMatrixId.debouncedClicks { - sharedActionViewModel.post(UserDirectorySharedAction.OpenUsersDirectory) - } - } - - private fun setupAddFromPhoneBookView() { - addFromPhoneBook.debouncedClicks { - // TODO handle Permission first - sharedActionViewModel.post(UserDirectorySharedAction.OpenPhoneBook) - } - } - private fun setupRecyclerView() { - knownUsersController.callback = this + userListController.callback = this // Don't activate animation as we might have way to much item animation when filtering - knownUsersRecyclerView.configureWith(knownUsersController, disableItemAnimation = true) + recyclerView.configureWith(userListController, disableItemAnimation = true) } - private fun setupFilterView() { - knownUsersFilter + private fun setupSearchView() { + withState(viewModel) { + userListSearch.hint = getString(R.string.user_directory_search_hint, it.myUserId) + } + userListSearch .textChanges() - .startWith(knownUsersFilter.text) + .startWith(userListSearch.text) .subscribe { text -> - val filterValue = text.trim() - val action = if (filterValue.isBlank()) { - UserDirectoryAction.ClearFilterKnownUsers + val searchValue = text.trim() + val action = if (searchValue.isBlank()) { + UserListAction.ClearSearchUsers } else { - UserDirectoryAction.FilterKnownUsers(filterValue.toString()) + UserListAction.SearchUsers(searchValue.toString()) } viewModel.handle(action) } .disposeOnDestroyView() - knownUsersFilter.setupAsSearch() - knownUsersFilter.requestFocus() + userListSearch.setupAsSearch() + userListSearch.requestFocus() } private fun setupCloseView() { - knownUsersClose.debouncedClicks { + userListClose.debouncedClicks { requireActivity().finish() } } override fun invalidate() = withState(viewModel) { - knownUsersController.setData(it) + userListController.setData(it) } private fun renderSelectedUsers(invitees: Set) { @@ -183,12 +177,35 @@ class KnownUsersFragment @Inject constructor( chip.isCloseIconVisible = true chipGroup.addView(chip) chip.setOnCloseIconClickListener { - viewModel.handle(UserDirectoryAction.RemovePendingInvitee(pendingInvitee)) + viewModel.handle(UserListAction.RemovePendingInvitee(pendingInvitee)) } } + override fun onInviteFriendClick() { + viewModel.handle(UserListAction.ComputeMatrixToLinkForSharing) + } + + override fun onContactBookClick() { + sharedActionViewModel.post(UserListSharedAction.OpenPhoneBook) + } + override fun onItemClick(user: User) { view?.hideKeyboard() - viewModel.handle(UserDirectoryAction.SelectPendingInvitee(PendingInvitee.UserPendingInvitee(user))) + viewModel.handle(UserListAction.SelectPendingInvitee(PendingInvitee.UserPendingInvitee(user))) + } + + override fun onMatrixIdClick(matrixId: String) { + view?.hideKeyboard() + viewModel.handle(UserListAction.SelectPendingInvitee(PendingInvitee.UserPendingInvitee(User(matrixId)))) + } + + override fun onThreePidClick(threePid: ThreePid) { + view?.hideKeyboard() + viewModel.handle(UserListAction.SelectPendingInvitee(PendingInvitee.ThreePidPendingInvitee(threePid))) + } + + override fun onUseQRCode() { + view?.hideKeyboard() + sharedActionViewModel.post(UserListSharedAction.AddByQrCode) } } diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragmentArgs.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragmentArgs.kt similarity index 91% rename from vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragmentArgs.kt rename to vector/src/main/java/im/vector/app/features/userdirectory/UserListFragmentArgs.kt index c20aedb803..041f29a77a 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/KnownUsersFragmentArgs.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragmentArgs.kt @@ -20,9 +20,9 @@ import android.os.Parcelable import kotlinx.android.parcel.Parcelize @Parcelize -data class KnownUsersFragmentArgs( +data class UserListFragmentArgs( val title: String, val menuResId: Int, val excludedUserIds: Set? = null, - val isCreatingRoom: Boolean = false + val existingRoomId: String? = null ) : Parcelable diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListHeaderItem.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListHeaderItem.kt new file mode 100644 index 0000000000..82fa4a4d6f --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListHeaderItem.kt @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020 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.app.features.userdirectory + +import android.widget.TextView +import com.airbnb.epoxy.EpoxyAttribute +import com.airbnb.epoxy.EpoxyModelClass +import im.vector.app.R +import im.vector.app.core.epoxy.VectorEpoxyHolder +import im.vector.app.core.epoxy.VectorEpoxyModel + +@EpoxyModelClass(layout = R.layout.item_user_list_header) +abstract class UserListHeaderItem : VectorEpoxyModel() { + + @EpoxyAttribute var header: String = "" + + override fun bind(holder: Holder) { + super.bind(holder) + holder.headerTextView.text = header + } + + class Holder : VectorEpoxyHolder() { + val headerTextView by bind(R.id.userListHeaderView) + } +} diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectorySharedAction.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListSharedAction.kt similarity index 59% rename from vector/src/main/java/im/vector/app/features/userdirectory/UserDirectorySharedAction.kt rename to vector/src/main/java/im/vector/app/features/userdirectory/UserListSharedAction.kt index 14daa67f25..b2cdee3e63 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectorySharedAction.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListSharedAction.kt @@ -18,12 +18,10 @@ package im.vector.app.features.userdirectory import im.vector.app.core.platform.VectorSharedAction -sealed class UserDirectorySharedAction : VectorSharedAction { - object OpenUsersDirectory : UserDirectorySharedAction() - object OpenPhoneBook : UserDirectorySharedAction() - object Close : UserDirectorySharedAction() - object GoBack : UserDirectorySharedAction() - data class OnMenuItemSelected(val itemId: Int, - val invitees: Set, - val existingDmRoomId: String?) : UserDirectorySharedAction() +sealed class UserListSharedAction : VectorSharedAction { + object Close : UserListSharedAction() + object GoBack : UserListSharedAction() + data class OnMenuItemSelected(val itemId: Int, val invitees: Set) : UserListSharedAction() + object OpenPhoneBook : UserListSharedAction() + object AddByQrCode : UserListSharedAction() } diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectorySharedActionViewModel.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListSharedActionViewModel.kt similarity index 85% rename from vector/src/main/java/im/vector/app/features/userdirectory/UserDirectorySharedActionViewModel.kt rename to vector/src/main/java/im/vector/app/features/userdirectory/UserListSharedActionViewModel.kt index b63682e57a..05ebc73cff 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectorySharedActionViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListSharedActionViewModel.kt @@ -19,4 +19,4 @@ package im.vector.app.features.userdirectory import im.vector.app.core.platform.VectorSharedActionViewModel import javax.inject.Inject -class UserDirectorySharedActionViewModel @Inject constructor() : VectorSharedActionViewModel() +class UserListSharedActionViewModel @Inject constructor() : VectorSharedActionViewModel() diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewEvents.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewEvents.kt similarity index 85% rename from vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewEvents.kt rename to vector/src/main/java/im/vector/app/features/userdirectory/UserListViewEvents.kt index bfbdc657ef..95c6729fad 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewEvents.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewEvents.kt @@ -21,4 +21,6 @@ import im.vector.app.core.platform.VectorViewEvents /** * Transient events for invite users to room screen */ -sealed class UserDirectoryViewEvents : VectorViewEvents +sealed class UserListViewEvents : VectorViewEvents { + data class OpenShareMatrixToLing(val link: String) : UserListViewEvents() +} diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt new file mode 100644 index 0000000000..1011a3e28a --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2020 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.app.features.userdirectory + +import com.airbnb.mvrx.ActivityViewModelContext +import com.airbnb.mvrx.FragmentViewModelContext +import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.ViewModelContext +import com.jakewharton.rxrelay2.BehaviorRelay +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject +import im.vector.app.core.extensions.exhaustive +import im.vector.app.core.extensions.toggle +import im.vector.app.core.platform.VectorViewModel +import io.reactivex.Single +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import org.matrix.android.sdk.api.MatrixPatterns +import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.profile.ProfileService +import org.matrix.android.sdk.api.session.user.model.User +import org.matrix.android.sdk.api.util.toMatrixItem +import org.matrix.android.sdk.rx.rx +import java.util.concurrent.TimeUnit + +private typealias KnownUsersSearch = String +private typealias DirectoryUsersSearch = String + +class UserListViewModel @AssistedInject constructor(@Assisted initialState: UserListViewState, + @Assisted args: UserListFragmentArgs, + private val session: Session) + : VectorViewModel(initialState) { + + private val knownUsersSearch = BehaviorRelay.create() + private val directoryUsersSearch = BehaviorRelay.create() + + private var currentUserSearchDisposable: Disposable? = null + + @AssistedInject.Factory + interface Factory { + fun create(initialState: UserListViewState, args: UserListFragmentArgs): UserListViewModel + } + + companion object : MvRxViewModelFactory { + + private val USER_NOT_FOUND_MAP = emptyMap() + private val USER_NOT_FOUND = User("") + + override fun create(viewModelContext: ViewModelContext, state: UserListViewState): UserListViewModel? { + val factory = when (viewModelContext) { + is FragmentViewModelContext -> viewModelContext.fragment as? Factory + is ActivityViewModelContext -> viewModelContext.activity as? Factory + } + val args = viewModelContext.args() + return factory?.create(state, args) ?: error("You should let your activity/fragment implements Factory interface") + } + } + + init { + setState { + copy( + myUserId = session.myUserId, + existingRoomId = args.existingRoomId + ) + } + observeUsers() + } + + override fun handle(action: UserListAction) { + when (action) { + is UserListAction.SearchUsers -> handleSearchUsers(action.value) + is UserListAction.ClearSearchUsers -> handleClearSearchUsers() + is UserListAction.SelectPendingInvitee -> handleSelectUser(action) + is UserListAction.RemovePendingInvitee -> handleRemoveSelectedUser(action) + UserListAction.ComputeMatrixToLinkForSharing -> handleShareMyMatrixToLink() + }.exhaustive + } + + private fun handleSearchUsers(searchTerm: String) { + setState { + copy(searchTerm = searchTerm) + } + knownUsersSearch.accept(searchTerm) + directoryUsersSearch.accept(searchTerm) + } + + private fun handleShareMyMatrixToLink() { + session.permalinkService().createPermalink(session.myUserId)?.let { + _viewEvents.post(UserListViewEvents.OpenShareMatrixToLing(it)) + } + } + + private fun handleClearSearchUsers() { + knownUsersSearch.accept("") + directoryUsersSearch.accept("") + setState { + copy(searchTerm = "") + } + } + + private fun observeUsers() = withState { state -> + knownUsersSearch + .throttleLast(300, TimeUnit.MILLISECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .switchMap { + session.rx().livePagedUsers(it, state.excludedUserIds) + } + .execute { async -> + copy(knownUsers = async) + } + + currentUserSearchDisposable?.dispose() + directoryUsersSearch + .debounce(300, TimeUnit.MILLISECONDS) + .switchMapSingle { search -> + val stream = if (search.isBlank()) { + Single.just(emptyList()) + } else if (MatrixPatterns.isUserId(search)) { + // If it's a valid user id try to use Profile API + // because directory only returns users that are in public rooms or share a room with you, where as + // profile will work other federations + session.rx().searchUsersDirectory(search, 50, state.excludedUserIds ?: emptySet()) + .map { users -> + users.sortedBy { it.toMatrixItem().firstLetterOfDisplayName() } + } + .zipWith( + session.rx().getProfileInfo(search) + // ... not sure how to handle that properly (manage error case in map and return optional) + .onErrorReturn { USER_NOT_FOUND_MAP } + .map { json -> + if (json === USER_NOT_FOUND_MAP) { + USER_NOT_FOUND + } else { + User( + userId = search, + displayName = json[ProfileService.DISPLAY_NAME_KEY] as? String, + avatarUrl = json[ProfileService.AVATAR_URL_KEY] as? String + ) + } + }, + { t1, t2 -> + if (t2 == USER_NOT_FOUND) { + t1 + } + // profile result might also be in search results, in this case keep search result + else if (t1.indexOfFirst { it.userId == t2.userId } != -1) { + t1 + } else { + // put it first + listOf(t2) + t1 + } + } + ) + .doOnSubscribe { + currentUserSearchDisposable = it + } + .doOnDispose { + currentUserSearchDisposable = null + } + } else { + session.rx() + .searchUsersDirectory(search, 50, state.excludedUserIds ?: emptySet()) + .map { users -> + users.sortedBy { it.toMatrixItem().firstLetterOfDisplayName() } + } + .doOnSubscribe { + currentUserSearchDisposable = it + } + .doOnDispose { + currentUserSearchDisposable = null + } + } + stream.toAsync { + copy(directoryUsers = it) + } + } + .subscribe() + .disposeOnClear() + } + + private fun handleSelectUser(action: UserListAction.SelectPendingInvitee) = withState { state -> + val selectedUsers = state.pendingInvitees.toggle(action.pendingInvitee) + setState { copy(pendingInvitees = selectedUsers) } + } + + private fun handleRemoveSelectedUser(action: UserListAction.RemovePendingInvitee) = withState { state -> + val selectedUsers = state.pendingInvitees.minus(action.pendingInvitee) + setState { copy(pendingInvitees = selectedUsers) } + } +} diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewState.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewState.kt similarity index 78% rename from vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewState.kt rename to vector/src/main/java/im/vector/app/features/userdirectory/UserListViewState.kt index fe79a8ab37..f7cf421ca8 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserDirectoryViewState.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewState.kt @@ -17,30 +17,29 @@ package im.vector.app.features.userdirectory import androidx.paging.PagedList -import arrow.core.Option import com.airbnb.mvrx.Async import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.Uninitialized +import im.vector.app.core.contacts.MappedContact import org.matrix.android.sdk.api.session.user.model.User -data class UserDirectoryViewState( +data class UserListViewState( val excludedUserIds: Set? = null, val knownUsers: Async> = Uninitialized, val directoryUsers: Async> = Uninitialized, + val filteredMappedContacts: List = emptyList(), val pendingInvitees: Set = emptySet(), val createAndInviteState: Async = Uninitialized, - val directorySearchTerm: String = "", - val filterKnownUsersValue: Option = Option.empty(), - val existingDmRoomId: String? = null + val searchTerm: String = "", + val myUserId: String = "", + val existingRoomId: String? = null ) : MvRxState { - constructor(args: KnownUsersFragmentArgs) : this(excludedUserIds = args.excludedUserIds) - fun getSelectedMatrixId(): List { return pendingInvitees .mapNotNull { when (it) { - is PendingInvitee.UserPendingInvitee -> it.user.userId + is PendingInvitee.UserPendingInvitee -> it.user.userId is PendingInvitee.ThreePidPendingInvitee -> null } } diff --git a/vector/src/main/res/drawable/ic_book.xml b/vector/src/main/res/drawable/ic_book.xml new file mode 100644 index 0000000000..3cd7357248 --- /dev/null +++ b/vector/src/main/res/drawable/ic_book.xml @@ -0,0 +1,21 @@ + + + + diff --git a/vector/src/main/res/drawable/ic_invite_people.xml b/vector/src/main/res/drawable/ic_invite_people.xml new file mode 100644 index 0000000000..3ec60095ff --- /dev/null +++ b/vector/src/main/res/drawable/ic_invite_people.xml @@ -0,0 +1,10 @@ + + + diff --git a/vector/src/main/res/drawable/ic_picture_icon.xml b/vector/src/main/res/drawable/ic_picture_icon.xml new file mode 100644 index 0000000000..c978a714ab --- /dev/null +++ b/vector/src/main/res/drawable/ic_picture_icon.xml @@ -0,0 +1,29 @@ + + + + + diff --git a/vector/src/main/res/drawable/ic_qr_code_add.xml b/vector/src/main/res/drawable/ic_qr_code_add.xml new file mode 100644 index 0000000000..32e41f6e57 --- /dev/null +++ b/vector/src/main/res/drawable/ic_qr_code_add.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + diff --git a/vector/src/main/res/layout/activity_simple.xml b/vector/src/main/res/layout/activity_simple.xml index 0eda46a67d..c6f2af8171 100644 --- a/vector/src/main/res/layout/activity_simple.xml +++ b/vector/src/main/res/layout/activity_simple.xml @@ -1,7 +1,7 @@ - @@ -10,4 +10,24 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> + + + + + + \ No newline at end of file diff --git a/vector/src/main/res/layout/fragment_home_drawer.xml b/vector/src/main/res/layout/fragment_home_drawer.xml index d34ea0b815..2f1d7cc4c4 100644 --- a/vector/src/main/res/layout/fragment_home_drawer.xml +++ b/vector/src/main/res/layout/fragment_home_drawer.xml @@ -31,10 +31,11 @@ @@ -43,13 +44,13 @@ android:id="@+id/homeDrawerUsernameView" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginTop="24dp" - android:layout_marginEnd="@dimen/layout_horizontal_margin" + android:layout_marginTop="16dp" + android:layout_marginEnd="8dp" android:maxLines="1" android:singleLine="true" android:textColor="?riotx_text_primary" android:textSize="15sp" - app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintEnd_toStartOf="@+id/homeDrawerQRCodeButton" app:layout_constraintStart_toStartOf="@+id/homeDrawerHeaderAvatarView" app:layout_constraintTop_toBottomOf="@+id/homeDrawerHeaderAvatarView" tools:text="@sample/matrix.json/data/displayName" /> @@ -58,18 +59,69 @@ android:id="@+id/homeDrawerUserIdView" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginEnd="@dimen/layout_horizontal_margin" - android:layout_marginBottom="17dp" + android:layout_marginEnd="8dp" android:maxLines="1" android:singleLine="true" android:textColor="?riotx_text_secondary" android:textSize="15sp" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintBottom_toTopOf="@+id/homeDrawerInviteFriendButton" + app:layout_constraintEnd_toStartOf="@+id/homeDrawerQRCodeButton" app:layout_constraintStart_toStartOf="@+id/homeDrawerHeaderAvatarView" app:layout_constraintTop_toBottomOf="@+id/homeDrawerUsernameView" tools:text="@sample/matrix.json/data/mxid" /> + + + + + + + + + + + + + + + + + + + + diff --git a/vector/src/main/res/layout/fragment_qr_code_scanner.xml b/vector/src/main/res/layout/fragment_qr_code_scanner.xml index 589b7c73d4..135a856f4a 100644 --- a/vector/src/main/res/layout/fragment_qr_code_scanner.xml +++ b/vector/src/main/res/layout/fragment_qr_code_scanner.xml @@ -15,4 +15,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vector/src/main/res/layout/fragment_qr_code_scanner_with_button.xml b/vector/src/main/res/layout/fragment_qr_code_scanner_with_button.xml new file mode 100644 index 0000000000..6a59138990 --- /dev/null +++ b/vector/src/main/res/layout/fragment_qr_code_scanner_with_button.xml @@ -0,0 +1,51 @@ + + + + + + + + + \ No newline at end of file diff --git a/vector/src/main/res/layout/fragment_room_list.xml b/vector/src/main/res/layout/fragment_room_list.xml index 855c45f7c5..72266cc21a 100644 --- a/vector/src/main/res/layout/fragment_room_list.xml +++ b/vector/src/main/res/layout/fragment_room_list.xml @@ -23,16 +23,20 @@ tools:showPaths="true" tools:visibility="visible" /> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vector/src/main/res/layout/fragment_known_users.xml b/vector/src/main/res/layout/fragment_user_list.xml similarity index 68% rename from vector/src/main/res/layout/fragment_known_users.xml rename to vector/src/main/res/layout/fragment_user_list.xml index cf2d4e8025..15884502ad 100644 --- a/vector/src/main/res/layout/fragment_known_users.xml +++ b/vector/src/main/res/layout/fragment_user_list.xml @@ -1,5 +1,5 @@ - @@ -67,7 +67,7 @@ android:layout_marginEnd="@dimen/layout_horizontal_margin" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/knownUsersToolbar" + app:layout_constraintTop_toBottomOf="@+id/userListToolbar" app:maxHeight="64dp"> + app:layout_constraintTop_toBottomOf="@+id/userListSearch" /> - - - - - - - - + \ No newline at end of file diff --git a/vector/src/main/res/layout/item_checkbox.xml b/vector/src/main/res/layout/item_checkbox.xml new file mode 100644 index 0000000000..c7427b46c8 --- /dev/null +++ b/vector/src/main/res/layout/item_checkbox.xml @@ -0,0 +1,13 @@ + + \ No newline at end of file diff --git a/vector/src/main/res/layout/item_contact_action.xml b/vector/src/main/res/layout/item_contact_action.xml new file mode 100644 index 0000000000..daea0d5154 --- /dev/null +++ b/vector/src/main/res/layout/item_contact_action.xml @@ -0,0 +1,31 @@ + + + + + + + + \ No newline at end of file diff --git a/vector/src/main/res/layout/item_user_list_header.xml b/vector/src/main/res/layout/item_user_list_header.xml new file mode 100644 index 0000000000..26591b68ca --- /dev/null +++ b/vector/src/main/res/layout/item_user_list_header.xml @@ -0,0 +1,14 @@ + + + \ No newline at end of file diff --git a/vector/src/main/res/layout/motion_dms_fab_menu_merge.xml b/vector/src/main/res/layout/motion_dms_fab_menu_merge.xml deleted file mode 100644 index c0bcec6cb3..0000000000 --- a/vector/src/main/res/layout/motion_dms_fab_menu_merge.xml +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 1eb602e4c3..b6f2e15ab2 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -79,6 +79,7 @@ Pause Dismiss Reset + Start Chatting @@ -1754,6 +1755,7 @@ View the room directory Name or ID (#example:matrix.org) + Name or ID (like %s) Enable swipe to reply in timeline Add a dedicated tab for unread notifications on main screen. @@ -1762,10 +1764,15 @@ Add by matrix ID Add by QR code + QR code "Creating room…" "No result found, use Add by matrix ID to search on server." "Start typing to get results" "Filter by username or ID…" + Recent + Known Users + Contacts + Suggestions "Joining room…" @@ -2540,14 +2547,22 @@ INVITE Inviting users… Invite Users + Invite Friends + Hey, Talk to me on Element: %s + 🔐️ Join me on element Invitation sent to %1$s Invitations sent to %1$s and %2$s + "It's not a valid matrix QR code" Invitations sent to %1$s and one more Invitations sent to %1$s and %2$d more We could not invite users. Please check the users you want to invite and try again. + Scan + My code + This is your matrix.to code. If you share it with someone they can scan it with their element camera to add you as a contact + Current language Other available languages Loading available languages… @@ -2672,15 +2687,17 @@ Can\'t open a room where you are banned from. Can\'t find this room. Make sure it exists. + + Share by text + Cannot DM yourself! + Invalid QR code (Invalid URI)! + QR code not scanned! + The link was malformed The room is not yet created. Cancel the room creation? There are unsaved changes. Discard the changes? Discard changes - - Share by text - Cannot DM yourself! - Invalid QR code (Invalid URI)! - QR code not scanned! + Matrix Link diff --git a/vector/src/main/res/xml/motion_scene_dms_fab_menu.xml b/vector/src/main/res/xml/motion_scene_dms_fab_menu.xml deleted file mode 100644 index 8bb1c55df5..0000000000 --- a/vector/src/main/res/xml/motion_scene_dms_fab_menu.xml +++ /dev/null @@ -1,199 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From b888d13e62b0c4270dbb77938f3065c08f31f3eb Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 19 Nov 2020 11:12:23 +0100 Subject: [PATCH 43/66] Use orEmpty() --- .../crypto/verification/DefaultVerificationService.kt | 2 +- .../session/room/timeline/DefaultTimelineService.kt | 2 +- .../sdk/internal/session/sync/RoomTypingUsersHandler.kt | 2 +- .../internal/session/typing/DefaultTypingUsersTracker.kt | 2 +- .../android/sdk/internal/session/widgets/WidgetManager.kt | 2 +- .../app/features/roomdirectory/RoomDirectoryViewModel.kt | 6 +++--- .../vector/app/features/userdirectory/UserListController.kt | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationService.kt index 29ddd92213..a92f5c5bf1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationService.kt @@ -1204,7 +1204,7 @@ internal class DefaultVerificationService @Inject constructor( Timber.i("## Requesting verification to user: $otherUserId with device list $otherDevices") val targetDevices = otherDevices ?: cryptoStore.getUserDevices(otherUserId) - ?.values?.map { it.deviceId } ?: emptyList() + ?.values?.map { it.deviceId }.orEmpty() val requestsForUser = pendingRequests.getOrPut(otherUserId) { mutableListOf() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt index df2d238c05..783aa53ddf 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt @@ -103,7 +103,7 @@ internal class DefaultTimelineService @AssistedInject constructor(@Assisted priv .sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.ASCENDING) .findAll() ?.mapNotNull { timelineEventMapper.map(it).takeIf { it.root.isImageMessage() || it.root.isVideoMessage() } } - ?: emptyList() + .orEmpty() } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomTypingUsersHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomTypingUsersHandler.kt index 1655e551f1..f4f3e6ce43 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomTypingUsersHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomTypingUsersHandler.kt @@ -28,7 +28,7 @@ internal class RoomTypingUsersHandler @Inject constructor(@UserId private val us fun handle(realm: Realm, roomId: String, ephemeralResult: RoomSyncHandler.EphemeralResult?) { val roomMemberHelper = RoomMemberHelper(realm, roomId) - val typingIds = ephemeralResult?.typingUserIds?.filter { it != userId } ?: emptyList() + val typingIds = ephemeralResult?.typingUserIds?.filter { it != userId }.orEmpty() val senderInfo = typingIds.map { userId -> val roomMemberSummaryEntity = roomMemberHelper.getLastRoomMember(userId) SenderInfo( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/typing/DefaultTypingUsersTracker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/typing/DefaultTypingUsersTracker.kt index 2b7ff2624a..c5c3fc4b59 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/typing/DefaultTypingUsersTracker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/typing/DefaultTypingUsersTracker.kt @@ -37,6 +37,6 @@ internal class DefaultTypingUsersTracker @Inject constructor() : TypingUsersTrac } override fun getTypingUsers(roomId: String): List { - return typingUsers[roomId] ?: emptyList() + return typingUsers[roomId].orEmpty() } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetManager.kt index 22bdd2c6e4..329903f15b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetManager.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetManager.kt @@ -138,7 +138,7 @@ internal class WidgetManager @Inject constructor(private val integrationManager: ): LiveData> { val widgetsAccountData = accountDataDataSource.getLiveAccountDataEvent(UserAccountDataTypes.TYPE_WIDGETS) return Transformations.map(widgetsAccountData) { - it.getOrNull()?.mapToWidgets(widgetTypes, excludedTypes) ?: emptyList() + it.getOrNull()?.mapToWidgets(widgetTypes, excludedTypes).orEmpty() } } diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt index 42b17b4dad..c58e255bcc 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt @@ -204,9 +204,9 @@ class RoomDirectoryViewModel @AssistedInject constructor(@Assisted initialState: Timber.w("Try to join an already joining room. Should not happen") return@withState } - val viaServers = state.roomDirectoryData.homeServer?.let { - listOf(it) - } ?: emptyList() + val viaServers = state.roomDirectoryData.homeServer + ?.let { listOf(it) } + .orEmpty() session.joinRoom(action.roomId, viaServers = viaServers, callback = object : MatrixCallback { override fun onSuccess(data: Unit) { // We do not update the joiningRoomsIds here, because, the room is not joined yet regarding the sync data. diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListController.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListController.kt index 6cd76401fd..353505a35e 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListController.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListController.kt @@ -106,7 +106,7 @@ class UserListController @Inject constructor(private val session: Session, currentState.getSelectedMatrixId(), currentState.searchTerm, // to avoid showing twice same user in known and suggestions - currentState.knownUsers.invoke()?.map { it.userId } ?: emptyList() + currentState.knownUsers.invoke()?.map { it.userId }.orEmpty() ) } } From ae6de8fdf154831e2ae2d8ad1153a3405255d2a3 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 19 Nov 2020 15:14:14 +0100 Subject: [PATCH 44/66] Small cleanup --- .../debug/res/layout/activity_debug_menu.xml | 2 +- .../im/vector/app/core/epoxy/CheckBoxItem.kt | 1 - .../createdirect/CreateDirectRoomActivity.kt | 8 ++++---- .../features/matrixto/MatrixToBottomSheet.kt | 6 ++---- .../features/usercode/ScanUserCodeFragment.kt | 1 + .../features/usercode/ShowUserCodeFragment.kt | 1 - .../app/features/usercode/UserCodeActivity.kt | 20 +++++++++---------- .../usercode/UserCodeSharedViewModel.kt | 14 ++++++------- .../src/main/res/layout/activity_simple.xml | 9 +++------ ...rd.xml => bottom_sheet_matrix_to_card.xml} | 6 +----- .../main/res/layout/dialog_share_qr_code.xml | 2 +- .../main/res/layout/fragment_home_drawer.xml | 2 -- .../fragment_qr_code_scanner_with_button.xml | 1 + .../res/layout/fragment_user_code_show.xml | 5 ++--- vector/src/main/res/layout/item_checkbox.xml | 5 +++-- .../res/layout/item_verification_qr_code.xml | 2 +- 16 files changed, 37 insertions(+), 48 deletions(-) rename vector/src/main/res/layout/{fragment_matrix_to_card.xml => bottom_sheet_matrix_to_card.xml} (97%) diff --git a/vector/src/debug/res/layout/activity_debug_menu.xml b/vector/src/debug/res/layout/activity_debug_menu.xml index 458b44fd05..9a95085a07 100644 --- a/vector/src/debug/res/layout/activity_debug_menu.xml +++ b/vector/src/debug/res/layout/activity_debug_menu.xml @@ -72,7 +72,7 @@ android:id="@+id/debug_qr_code" android:layout_width="200dp" android:layout_height="200dp" - tools:src="@tools:sample/avatars" /> + tools:src="@drawable/ic_qr_code_add" /> diff --git a/vector/src/main/java/im/vector/app/core/epoxy/CheckBoxItem.kt b/vector/src/main/java/im/vector/app/core/epoxy/CheckBoxItem.kt index 4e53b293d3..2f32fafa9e 100644 --- a/vector/src/main/java/im/vector/app/core/epoxy/CheckBoxItem.kt +++ b/vector/src/main/java/im/vector/app/core/epoxy/CheckBoxItem.kt @@ -21,7 +21,6 @@ import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyModelClass import com.google.android.material.checkbox.MaterialCheckBox import im.vector.app.R -import kotlinx.android.synthetic.main.vector_preference_push_rule.view.* @EpoxyModelClass(layout = R.layout.item_checkbox) abstract class CheckBoxItem : VectorEpoxyModel() { diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt index 2e21d04d06..95351afec8 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt @@ -84,11 +84,11 @@ class CreateDirectRoomActivity : SimpleFragmentActivity(), UserListViewModel.Fac .observe() .subscribe { action -> when (action) { - UserListSharedAction.Close -> finish() - UserListSharedAction.GoBack -> onBackPressed() + UserListSharedAction.Close -> finish() + UserListSharedAction.GoBack -> onBackPressed() is UserListSharedAction.OnMenuItemSelected -> onMenuItemSelected(action) - UserListSharedAction.OpenPhoneBook -> openPhoneBook() - UserListSharedAction.AddByQrCode -> openAddByQrCode() + UserListSharedAction.OpenPhoneBook -> openPhoneBook() + UserListSharedAction.AddByQrCode -> openAddByQrCode() }.exhaustive } .disposeOnDestroy() diff --git a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt index 3f3706699f..91c09ef21a 100644 --- a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt @@ -23,7 +23,7 @@ import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.setTextOrHide import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment import im.vector.app.features.home.AvatarRenderer -import kotlinx.android.synthetic.main.fragment_matrix_to_card.* +import kotlinx.android.synthetic.main.bottom_sheet_matrix_to_card.* import org.matrix.android.sdk.api.util.MatrixItem import javax.inject.Inject @@ -41,7 +41,7 @@ class MatrixToBottomSheet(private val matrixItem: MatrixItem) : VectorBaseBottom private var interactionListener: InteractionListener? = null - override fun getLayoutResId() = R.layout.fragment_matrix_to_card + override fun getLayoutResId() = R.layout.bottom_sheet_matrix_to_card override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -56,8 +56,6 @@ class MatrixToBottomSheet(private val matrixItem: MatrixItem) : VectorBaseBottom } companion object { - const val ARGS = "MatrixToFragment.Args" - fun create(matrixItem: MatrixItem, listener: InteractionListener?): MatrixToBottomSheet { return MatrixToBottomSheet(matrixItem).apply { interactionListener = listener diff --git a/vector/src/main/java/im/vector/app/features/usercode/ScanUserCodeFragment.kt b/vector/src/main/java/im/vector/app/features/usercode/ScanUserCodeFragment.kt index 8b4820b06d..60354db9c6 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/ScanUserCodeFragment.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/ScanUserCodeFragment.kt @@ -102,6 +102,7 @@ class ScanUserCodeFragment @Inject constructor() override fun onPause() { super.onPause() + userCodeScannerView.setResultHandler(null) // Stop camera on pause userCodeScannerView.stopCamera() } diff --git a/vector/src/main/java/im/vector/app/features/usercode/ShowUserCodeFragment.kt b/vector/src/main/java/im/vector/app/features/usercode/ShowUserCodeFragment.kt index ab88f79bef..e812ca31bb 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/ShowUserCodeFragment.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/ShowUserCodeFragment.kt @@ -54,6 +54,5 @@ class ShowUserCodeFragment @Inject constructor( state.shareLink?.let { showUserCodeQRImage.setData(it) } showUserCodeCardNameText.setTextOrHide(state.matrixItem?.displayName) showUserCodeCardUserIdText.setTextOrHide(state.matrixItem?.id) - Unit } } diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt index 388dc220a8..0e7efa5b92 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt @@ -29,6 +29,7 @@ import com.airbnb.mvrx.viewModel import com.airbnb.mvrx.withState import im.vector.app.R import im.vector.app.core.di.ScreenComponent +import im.vector.app.core.extensions.commitTransaction import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.features.matrixto.MatrixToBottomSheet @@ -66,8 +67,8 @@ class UserCodeActivity sharedViewModel.selectSubscribe(this, UserCodeState::mode) { mode -> when (mode) { - UserCodeState.Mode.SHOW -> showFragment(ShowUserCodeFragment::class, Bundle.EMPTY) - UserCodeState.Mode.SCAN -> showFragment(ScanUserCodeFragment::class, Bundle.EMPTY) + UserCodeState.Mode.SHOW -> showFragment(ShowUserCodeFragment::class, Bundle.EMPTY) + UserCodeState.Mode.SCAN -> showFragment(ScanUserCodeFragment::class, Bundle.EMPTY) is UserCodeState.Mode.RESULT -> { showFragment(ShowUserCodeFragment::class, Bundle.EMPTY) MatrixToBottomSheet.create(mode.matrixItem, this).show(supportFragmentManager, "MatrixToBottomSheet") @@ -77,11 +78,11 @@ class UserCodeActivity sharedViewModel.observeViewEvents { when (it) { - is UserCodeShareViewEvents.InviteFriend -> TODO() - UserCodeShareViewEvents.Dismiss -> ActivityCompat.finishAfterTransition(this) + is UserCodeShareViewEvents.InviteFriend -> TODO() + UserCodeShareViewEvents.Dismiss -> ActivityCompat.finishAfterTransition(this) UserCodeShareViewEvents.ShowWaitingScreen -> simpleActivityWaitingView.isVisible = true UserCodeShareViewEvents.HideWaitingScreen -> simpleActivityWaitingView.isVisible = false - is UserCodeShareViewEvents.ToastMessage -> Toast.makeText(this, it.message, Toast.LENGTH_LONG).show() + is UserCodeShareViewEvents.ToastMessage -> Toast.makeText(this, it.message, Toast.LENGTH_LONG).show() is UserCodeShareViewEvents.NavigateToRoom -> navigator.openRoom(this, it.roomId) }.exhaustive } @@ -89,14 +90,13 @@ class UserCodeActivity private fun showFragment(fragmentClass: KClass, bundle: Bundle) { if (supportFragmentManager.findFragmentByTag(fragmentClass.simpleName) == null) { - supportFragmentManager.beginTransaction().let { - it.setCustomAnimations(R.anim.fade_in, R.anim.fade_out, R.anim.fade_in, R.anim.fade_out) - it.replace(R.id.simpleFragmentContainer, + supportFragmentManager.commitTransaction { + setCustomAnimations(R.anim.fade_in, R.anim.fade_out, R.anim.fade_in, R.anim.fade_out) + replace(R.id.simpleFragmentContainer, fragmentClass.java, bundle, fragmentClass.simpleName ) - it.commit() } } } @@ -110,7 +110,7 @@ class UserCodeActivity UserCodeState.Mode.SHOW -> super.onBackPressed() is UserCodeState.Mode.RESULT, UserCodeState.Mode.SCAN -> sharedViewModel.handle(UserCodeActions.SwitchMode(UserCodeState.Mode.SHOW)) - } + }.exhaustive } override fun create(initialState: UserCodeState, args: Args) = diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt index 17dd97cffa..1d1283c269 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt @@ -84,9 +84,9 @@ class UserCodeSharedViewModel @AssistedInject constructor( override fun handle(action: UserCodeActions) { when (action) { - UserCodeActions.DismissAction -> _viewEvents.post(UserCodeShareViewEvents.Dismiss) - is UserCodeActions.SwitchMode -> setState { copy(mode = action.mode) } - is UserCodeActions.DecodedQRCode -> handleQrCodeDecoded(action) + UserCodeActions.DismissAction -> _viewEvents.post(UserCodeShareViewEvents.Dismiss) + is UserCodeActions.SwitchMode -> setState { copy(mode = action.mode) } + is UserCodeActions.DecodedQRCode -> handleQrCodeDecoded(action) is UserCodeActions.StartChattingWithUser -> handleStartChatting(action) } } @@ -138,9 +138,9 @@ class UserCodeSharedViewModel @AssistedInject constructor( _viewEvents.post(UserCodeShareViewEvents.ShowWaitingScreen) viewModelScope.launch(Dispatchers.IO) { when (linkedId) { - is PermalinkData.RoomLink -> TODO() - is PermalinkData.UserLink -> { - var user = session.getUser(linkedId.userId) ?: awaitCallback> { + is PermalinkData.RoomLink -> TODO() + is PermalinkData.UserLink -> { + val user = session.getUser(linkedId.userId) ?: awaitCallback> { session.searchUsersDirectory(linkedId.userId, 10, emptySet(), it) }.firstOrNull { it.userId == linkedId.userId } // Create raw Uxid in case the user is not searchable @@ -152,7 +152,7 @@ class UserCodeSharedViewModel @AssistedInject constructor( ) } } - is PermalinkData.GroupLink -> TODO() + is PermalinkData.GroupLink -> TODO() is PermalinkData.FallbackLink -> TODO() } _viewEvents.post(UserCodeShareViewEvents.HideWaitingScreen) diff --git a/vector/src/main/res/layout/activity_simple.xml b/vector/src/main/res/layout/activity_simple.xml index c6f2af8171..d7382d173d 100644 --- a/vector/src/main/res/layout/activity_simple.xml +++ b/vector/src/main/res/layout/activity_simple.xml @@ -10,7 +10,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> - + android:layout_height="40dp" /> - + \ No newline at end of file diff --git a/vector/src/main/res/layout/fragment_matrix_to_card.xml b/vector/src/main/res/layout/bottom_sheet_matrix_to_card.xml similarity index 97% rename from vector/src/main/res/layout/fragment_matrix_to_card.xml rename to vector/src/main/res/layout/bottom_sheet_matrix_to_card.xml index 7356f105e0..b8c81ded3a 100644 --- a/vector/src/main/res/layout/fragment_matrix_to_card.xml +++ b/vector/src/main/res/layout/bottom_sheet_matrix_to_card.xml @@ -1,12 +1,10 @@ - - - + app:layout_constraintTop_toBottomOf="@id/matrixToCardUserIdText" /> diff --git a/vector/src/main/res/layout/dialog_share_qr_code.xml b/vector/src/main/res/layout/dialog_share_qr_code.xml index d209376edb..04613023a7 100644 --- a/vector/src/main/res/layout/dialog_share_qr_code.xml +++ b/vector/src/main/res/layout/dialog_share_qr_code.xml @@ -11,6 +11,6 @@ android:layout_height="300dp" android:layout_gravity="center_horizontal" android:contentDescription="@string/a11y_qr_code_for_verification" - tools:src="@color/riotx_header_panel_background_black" /> + tools:src="@drawable/ic_qr_code_add" /> diff --git a/vector/src/main/res/layout/fragment_home_drawer.xml b/vector/src/main/res/layout/fragment_home_drawer.xml index 2f1d7cc4c4..459f118ccd 100644 --- a/vector/src/main/res/layout/fragment_home_drawer.xml +++ b/vector/src/main/res/layout/fragment_home_drawer.xml @@ -93,7 +93,6 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="@id/homeDrawerUsernameView" /> - - + \ No newline at end of file diff --git a/vector/src/main/res/layout/fragment_user_code_show.xml b/vector/src/main/res/layout/fragment_user_code_show.xml index 7d96b80dbe..92c40b1eb2 100644 --- a/vector/src/main/res/layout/fragment_user_code_show.xml +++ b/vector/src/main/res/layout/fragment_user_code_show.xml @@ -1,5 +1,4 @@ - - + \ No newline at end of file diff --git a/vector/src/main/res/layout/item_checkbox.xml b/vector/src/main/res/layout/item_checkbox.xml index c7427b46c8..78dde9734b 100644 --- a/vector/src/main/res/layout/item_checkbox.xml +++ b/vector/src/main/res/layout/item_checkbox.xml @@ -1,13 +1,14 @@ \ No newline at end of file + app:layout_constraintTop_toBottomOf="@+id/phoneBookFilterContainer" + tools:text="@string/matrix_only_filter" /> \ No newline at end of file diff --git a/vector/src/main/res/layout/item_verification_qr_code.xml b/vector/src/main/res/layout/item_verification_qr_code.xml index b57470fdc1..413b94013a 100644 --- a/vector/src/main/res/layout/item_verification_qr_code.xml +++ b/vector/src/main/res/layout/item_verification_qr_code.xml @@ -11,6 +11,6 @@ android:layout_height="200dp" android:layout_gravity="center_horizontal" android:contentDescription="@string/a11y_qr_code_for_verification" - tools:src="@color/riotx_header_panel_background_black" /> + tools:src="@drawable/ic_qr_code_add" /> From baef9f5aa7ac4af415b9f82438a9ec777f6c8193 Mon Sep 17 00:00:00 2001 From: Valere Date: Fri, 20 Nov 2020 10:04:41 +0100 Subject: [PATCH 45/66] Fix permission handling + share my code by text --- .../app/core/platform/VectorBaseActivity.kt | 10 +++++ .../vector/app/core/utils/PermissionsTools.kt | 18 +++++++++ .../createdirect/CreateDirectRoomActivity.kt | 7 ++-- .../features/usercode/ScanUserCodeFragment.kt | 16 +++++++- .../features/usercode/ShowUserCodeFragment.kt | 31 +++++++++++++- .../app/features/usercode/UserCodeActions.kt | 2 + .../app/features/usercode/UserCodeActivity.kt | 17 ++++---- .../usercode/UserCodeShareViewEvents.kt | 3 +- .../usercode/UserCodeSharedViewModel.kt | 27 ++++++++----- vector/src/main/res/layout/activity.xml | 40 +++++++++++-------- .../res/layout/fragment_user_code_show.xml | 13 ++++++ vector/src/main/res/values/strings.xml | 2 + vector/src/main/res/values/style_snackbar.xml | 4 +- 13 files changed, 148 insertions(+), 42 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt index 79021902c4..f58f0b87ae 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt @@ -587,6 +587,16 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector { } } + fun showSnackbar(message: String, @StringRes withActionTitle: Int?, action: (() -> Unit)?) { + coordinatorLayout?.let { + Snackbar.make(it, message, Snackbar.LENGTH_LONG).apply { + withActionTitle?.let { + setAction(withActionTitle, { action?.invoke() }) + } + }.show() + } + } + /* ========================================================================================== * User Consent * ========================================================================================== */ diff --git a/vector/src/main/java/im/vector/app/core/utils/PermissionsTools.kt b/vector/src/main/java/im/vector/app/core/utils/PermissionsTools.kt index 44fc6afa4e..f3ac8d9c47 100644 --- a/vector/src/main/java/im/vector/app/core/utils/PermissionsTools.kt +++ b/vector/src/main/java/im/vector/app/core/utils/PermissionsTools.kt @@ -19,8 +19,11 @@ package im.vector.app.core.utils import android.Manifest import android.app.Activity import android.content.Context +import android.content.Intent import android.content.pm.PackageManager +import android.net.Uri import android.os.Build +import android.provider.Settings import android.widget.Toast import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts @@ -30,6 +33,8 @@ import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import im.vector.app.R +import im.vector.app.core.platform.VectorBaseActivity +import org.matrix.android.sdk.api.extensions.tryOrNull import timber.log.Timber // Android M permission request code management @@ -284,6 +289,19 @@ private fun checkPermissions(permissionsToBeGrantedBitMap: Int, return isPermissionGranted } +fun VectorBaseActivity.onPermissionDeniedSnackbar(@StringRes rationaleMessage: Int) { + showSnackbar(getString(rationaleMessage), R.string.settings) { + tryOrNull { + startActivity( + Intent().apply { + action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + data = Uri.fromParts("package", this@onPermissionDeniedSnackbar.packageName, null) + }) + } + } +} + /** * Helper method used in [.checkPermissions] to populate the list of the * permissions to be granted (permissionsListToBeGrantedOut) and the list of the permissions already denied (permissionAlreadyDeniedListOut). diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt index 95351afec8..b4c278116b 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt @@ -22,7 +22,6 @@ import android.content.Context import android.content.Intent import android.os.Bundle import android.view.View -import android.widget.Toast import androidx.appcompat.app.AlertDialog import com.airbnb.mvrx.Async import com.airbnb.mvrx.Fail @@ -43,6 +42,7 @@ import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_READ_CONTACTS import im.vector.app.core.utils.allGranted import im.vector.app.core.utils.checkPermissions +import im.vector.app.core.utils.onPermissionDeniedSnackbar import im.vector.app.features.contactsbook.ContactsBookFragment import im.vector.app.features.contactsbook.ContactsBookViewModel import im.vector.app.features.userdirectory.UserListFragment @@ -132,9 +132,10 @@ class CreateDirectRoomActivity : SimpleFragmentActivity(), UserListViewModel.Fac addFragment(R.id.container, CreateDirectRoomByQrCodeFragment::class.java) } } else { - Toast.makeText(baseContext, R.string.missing_permissions_error, Toast.LENGTH_SHORT).show() if (requestCode == PERMISSION_REQUEST_CODE_LAUNCH_CAMERA) { - finish() + onPermissionDeniedSnackbar(R.string.permissions_denied_qr_code) + } else if (requestCode == PERMISSION_REQUEST_CODE_READ_CONTACTS) { + onPermissionDeniedSnackbar(R.string.permissions_denied_add_contact) } } } diff --git a/vector/src/main/java/im/vector/app/features/usercode/ScanUserCodeFragment.kt b/vector/src/main/java/im/vector/app/features/usercode/ScanUserCodeFragment.kt index 60354db9c6..782d7e1c04 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/ScanUserCodeFragment.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/ScanUserCodeFragment.kt @@ -16,10 +16,13 @@ package im.vector.app.features.usercode +import android.Manifest import android.app.Activity +import android.content.pm.PackageManager import android.os.Bundle import android.view.View import android.widget.Toast +import androidx.core.content.ContextCompat import com.airbnb.mvrx.activityViewModel import com.google.zxing.Result import com.google.zxing.ResultMetadataType @@ -60,6 +63,9 @@ class ScanUserCodeFragment @Inject constructor() private val openCameraActivityResultLauncher = registerForPermissionsResult { allGranted -> if (allGranted) { startCamera() + } else { + // For now just go back + sharedViewModel.handle(UserCodeActions.SwitchMode(UserCodeState.Mode.SHOW)) } } @@ -90,12 +96,18 @@ class ScanUserCodeFragment @Inject constructor() } } + override fun onStart() { + super.onStart() + if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), openCameraActivityResultLauncher)) { + startCamera() + } + } + override fun onResume() { super.onResume() // Register ourselves as a handler for scan results. userCodeScannerView.setResultHandler(this) - // Start camera on resume - if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), openCameraActivityResultLauncher)) { + if (PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA)) { startCamera() } } diff --git a/vector/src/main/java/im/vector/app/features/usercode/ShowUserCodeFragment.kt b/vector/src/main/java/im/vector/app/features/usercode/ShowUserCodeFragment.kt index e812ca31bb..532557af84 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/ShowUserCodeFragment.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/ShowUserCodeFragment.kt @@ -23,6 +23,10 @@ import com.airbnb.mvrx.withState import im.vector.app.R import im.vector.app.core.extensions.setTextOrHide import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO +import im.vector.app.core.utils.checkPermissions +import im.vector.app.core.utils.registerForPermissionsResult +import im.vector.app.core.utils.startSharePlainTextIntent import im.vector.app.features.home.AvatarRenderer import kotlinx.android.synthetic.main.fragment_user_code_show.* import javax.inject.Inject @@ -35,13 +39,38 @@ class ShowUserCodeFragment @Inject constructor( val sharedViewModel: UserCodeSharedViewModel by activityViewModel() + private val openCameraActivityResultLauncher = registerForPermissionsResult { allGranted -> + if (allGranted) { + doOpenQRCodeScanner() + } else { + sharedViewModel.handle(UserCodeActions.CameraPermissionNotGranted) + } + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) showUserCodeClose.debouncedClicks { sharedViewModel.handle(UserCodeActions.DismissAction) } showUserCodeScanButton.debouncedClicks { - doOpenQRCodeScanner() + if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), openCameraActivityResultLauncher)) { + doOpenQRCodeScanner() + } + } + shareByText.debouncedClicks { + sharedViewModel.handle(UserCodeActions.ShareByText) + } + + sharedViewModel.observeViewEvents { + if (it is UserCodeShareViewEvents.SharePlainText) { + startSharePlainTextIntent( + fragment = this, + activityResultLauncher = null, + chooserTitle = it.title, + text = it.text, + extraTitle = it.richPlainText + ) + } } } diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeActions.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActions.kt index 0611e0f8c3..3411fe3d7f 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeActions.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActions.kt @@ -24,4 +24,6 @@ sealed class UserCodeActions : VectorViewModelAction { data class SwitchMode(val mode: UserCodeState.Mode) : UserCodeActions() data class DecodedQRCode(val code: String) : UserCodeActions() data class StartChattingWithUser(val matrixItem: MatrixItem) : UserCodeActions() + object CameraPermissionNotGranted : UserCodeActions() + object ShareByText : UserCodeActions() } diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt index 0e7efa5b92..149caaba8f 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt @@ -32,6 +32,7 @@ import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.commitTransaction import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.core.utils.onPermissionDeniedSnackbar import im.vector.app.features.matrixto.MatrixToBottomSheet import kotlinx.android.parcel.Parcelize import kotlinx.android.synthetic.main.activity_simple.* @@ -78,13 +79,15 @@ class UserCodeActivity sharedViewModel.observeViewEvents { when (it) { - is UserCodeShareViewEvents.InviteFriend -> TODO() - UserCodeShareViewEvents.Dismiss -> ActivityCompat.finishAfterTransition(this) - UserCodeShareViewEvents.ShowWaitingScreen -> simpleActivityWaitingView.isVisible = true - UserCodeShareViewEvents.HideWaitingScreen -> simpleActivityWaitingView.isVisible = false - is UserCodeShareViewEvents.ToastMessage -> Toast.makeText(this, it.message, Toast.LENGTH_LONG).show() - is UserCodeShareViewEvents.NavigateToRoom -> navigator.openRoom(this, it.roomId) - }.exhaustive + UserCodeShareViewEvents.Dismiss -> ActivityCompat.finishAfterTransition(this) + UserCodeShareViewEvents.ShowWaitingScreen -> simpleActivityWaitingView.isVisible = true + UserCodeShareViewEvents.HideWaitingScreen -> simpleActivityWaitingView.isVisible = false + is UserCodeShareViewEvents.ToastMessage -> Toast.makeText(this, it.message, Toast.LENGTH_LONG).show() + is UserCodeShareViewEvents.NavigateToRoom -> navigator.openRoom(this, it.roomId) + UserCodeShareViewEvents.CameraPermissionNotGranted -> onPermissionDeniedSnackbar(R.string.permissions_denied_qr_code) + else -> { + } + } } } diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeShareViewEvents.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeShareViewEvents.kt index 26fcffadd2..67a1ab8a6c 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeShareViewEvents.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeShareViewEvents.kt @@ -19,10 +19,11 @@ package im.vector.app.features.usercode import im.vector.app.core.platform.VectorViewEvents sealed class UserCodeShareViewEvents : VectorViewEvents { - data class InviteFriend(val permalink: String) : UserCodeShareViewEvents() object Dismiss : UserCodeShareViewEvents() object ShowWaitingScreen : UserCodeShareViewEvents() object HideWaitingScreen : UserCodeShareViewEvents() data class ToastMessage(val message: String) : UserCodeShareViewEvents() data class NavigateToRoom(val roomId: String) : UserCodeShareViewEvents() + object CameraPermissionNotGranted : UserCodeShareViewEvents() + data class SharePlainText(val text: String, val title: String, val richPlainText: String) : UserCodeShareViewEvents() } diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt index 1d1283c269..b456f24972 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt @@ -71,12 +71,6 @@ class UserCodeSharedViewModel @AssistedInject constructor( } } - private fun handleInviteFriend() { - session.permalinkService().createPermalink(initialState.userId)?.let { permalink -> - _viewEvents.post(UserCodeShareViewEvents.InviteFriend(permalink)) - } - } - @AssistedInject.Factory interface Factory { fun create(initialState: UserCodeState, args: UserCodeActivity.Args): UserCodeSharedViewModel @@ -84,10 +78,23 @@ class UserCodeSharedViewModel @AssistedInject constructor( override fun handle(action: UserCodeActions) { when (action) { - UserCodeActions.DismissAction -> _viewEvents.post(UserCodeShareViewEvents.Dismiss) - is UserCodeActions.SwitchMode -> setState { copy(mode = action.mode) } - is UserCodeActions.DecodedQRCode -> handleQrCodeDecoded(action) - is UserCodeActions.StartChattingWithUser -> handleStartChatting(action) + UserCodeActions.DismissAction -> _viewEvents.post(UserCodeShareViewEvents.Dismiss) + is UserCodeActions.SwitchMode -> setState { copy(mode = action.mode) } + is UserCodeActions.DecodedQRCode -> handleQrCodeDecoded(action) + is UserCodeActions.StartChattingWithUser -> handleStartChatting(action) + UserCodeActions.CameraPermissionNotGranted -> _viewEvents.post(UserCodeShareViewEvents.CameraPermissionNotGranted) + UserCodeActions.ShareByText -> handleShareByText() + } + } + + private fun handleShareByText() { + session.permalinkService().createPermalink(session.myUserId)?.let { permalink -> + val text = stringProvider.getString(R.string.invite_friends_text, permalink) + _viewEvents.post(UserCodeShareViewEvents.SharePlainText( + text, + stringProvider.getString(R.string.invite_friends), + stringProvider.getString(R.string.invite_friends_rich_title) + )) } } diff --git a/vector/src/main/res/layout/activity.xml b/vector/src/main/res/layout/activity.xml index b5203cd589..9e56d9e605 100644 --- a/vector/src/main/res/layout/activity.xml +++ b/vector/src/main/res/layout/activity.xml @@ -1,26 +1,32 @@ - - + android:layout_height="match_parent"> - + - + - + + + + \ No newline at end of file diff --git a/vector/src/main/res/layout/fragment_user_code_show.xml b/vector/src/main/res/layout/fragment_user_code_show.xml index 92c40b1eb2..ca65c64f19 100644 --- a/vector/src/main/res/layout/fragment_user_code_show.xml +++ b/vector/src/main/res/layout/fragment_user_code_show.xml @@ -49,6 +49,19 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toEndOf="@+id/showUserCodeClose" + app:layout_constraintEnd_toStartOf="@id/shareByText" + app:layout_constraintTop_toTopOf="parent" /> + + diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index b6f2e15ab2..d32dd86a19 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -425,6 +425,8 @@ Element can check your address book to find other Matrix users based on their email and phone numbers.\n\nDo you agree to share your address book for this purpose? Sorry. Action not performed, due to missing permissions + To scan a QR code, allow Camera permission to take a picture + To check your address book, allow Contact permission. Saved diff --git a/vector/src/main/res/values/style_snackbar.xml b/vector/src/main/res/values/style_snackbar.xml index 7e0dbc0e0b..5f1412e0b4 100644 --- a/vector/src/main/res/values/style_snackbar.xml +++ b/vector/src/main/res/values/style_snackbar.xml @@ -5,7 +5,9 @@ @color/notification_accent_color - - From 77863e2e88a40de5fe650afe3e16cddd606c036e Mon Sep 17 00:00:00 2001 From: Valere Date: Fri, 20 Nov 2020 14:49:24 +0100 Subject: [PATCH 50/66] copy tweaks --- vector/src/main/res/values/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 53ab08bffd..f82e7f6fe7 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -2549,8 +2549,8 @@ INVITE Inviting users… Invite Users - Invite Friends - Hey, Talk to me on Element: %s + Invite friends + Hey, talk to me on Element: %s 🔐️ Join me on element Invitation sent to %1$s Invitations sent to %1$s and %2$s From 7583b0a3588af4b6e5d1393960ccd43037559ed4 Mon Sep 17 00:00:00 2001 From: Valere Date: Fri, 20 Nov 2020 15:17:35 +0100 Subject: [PATCH 51/66] Fix rebase --- .../im/vector/app/features/userdirectory/UserListFragment.kt | 4 ++-- vector/src/main/res/layout/fragment_user_list.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt index 4af16772b8..0aad6dbe51 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt @@ -93,7 +93,7 @@ class UserListFragment @Inject constructor( } override fun onDestroyView() { - recyclerView.cleanup() + userListRecyclerView.cleanup() super.onDestroyView() } @@ -115,7 +115,7 @@ class UserListFragment @Inject constructor( private fun setupRecyclerView() { userListController.callback = this // Don't activate animation as we might have way to much item animation when filtering - recyclerView.configureWith(userListController, disableItemAnimation = true) + userListRecyclerView.configureWith(userListController, disableItemAnimation = true) } private fun setupSearchView() { diff --git a/vector/src/main/res/layout/fragment_user_list.xml b/vector/src/main/res/layout/fragment_user_list.xml index a5210ed99a..b2bb9a909c 100644 --- a/vector/src/main/res/layout/fragment_user_list.xml +++ b/vector/src/main/res/layout/fragment_user_list.xml @@ -122,7 +122,7 @@ tools:visibility="visible" /> Date: Fri, 20 Nov 2020 15:46:21 +0100 Subject: [PATCH 52/66] Fix string --- .../im/vector/app/features/userdirectory/UserListFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt index 0aad6dbe51..4568878446 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt @@ -120,7 +120,7 @@ class UserListFragment @Inject constructor( private fun setupSearchView() { withState(viewModel) { - userListSearch.hint = getString(R.string.user_directory_search_hint, it.myUserId) + userListSearch.hint = getString(R.string.user_directory_search_hint) } userListSearch .textChanges() From d9757cc6600989886b38b9b21980c65b89d0dad1 Mon Sep 17 00:00:00 2001 From: Valere Date: Fri, 20 Nov 2020 16:23:04 +0100 Subject: [PATCH 53/66] Fix lint --- vector/src/main/res/layout/item_contact_action.xml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/vector/src/main/res/layout/item_contact_action.xml b/vector/src/main/res/layout/item_contact_action.xml index 6c5fa38f4c..7a9a751257 100644 --- a/vector/src/main/res/layout/item_contact_action.xml +++ b/vector/src/main/res/layout/item_contact_action.xml @@ -1,5 +1,6 @@ Date: Fri, 20 Nov 2020 08:01:45 +0000 Subject: [PATCH 54/66] Translated using Weblate (French) Currently translated at 100.0% (1933 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/fr/ --- vector/src/main/res/values-fr/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/res/values-fr/strings.xml b/vector/src/main/res/values-fr/strings.xml index 26b09f1f2c..d6258d45bd 100644 --- a/vector/src/main/res/values-fr/strings.xml +++ b/vector/src/main/res/values-fr/strings.xml @@ -2089,7 +2089,7 @@ Quitter Actions d\'administrateur Les messages ici ne sont pas chiffrés de bout en bout. - Réagis avec : %s + A réagi avec : %s Sondage Si vous ne connaissez pas votre mot de passe, faites précédent et réinitialisez-le. Veuillez utiliser le format international (le numéro de téléphone doit commencer avec « + ») From 62b703ca88d3b60963012ae2dc4a03568a391459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20L=C3=B8vbr=C3=B8tte=20Olsen?= Date: Tue, 24 Nov 2020 07:08:01 +0000 Subject: [PATCH 55/66] =?UTF-8?q?Added=20translation=20using=20Weblate=20(?= =?UTF-8?q?Norwegian=20Bokm=C3=A5l)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastlane/metadata/android/de/changelogs/40100100.txt | 1 + fastlane/metadata/android/fa/changelogs/40100100.txt | 1 + fastlane/metadata/android/pt_BR/changelogs/40100100.txt | 1 + fastlane/metadata/android/sv/changelogs/40100100.txt | 1 + 4 files changed, 4 insertions(+) create mode 100644 fastlane/metadata/android/de/changelogs/40100100.txt create mode 100644 fastlane/metadata/android/fa/changelogs/40100100.txt create mode 100644 fastlane/metadata/android/pt_BR/changelogs/40100100.txt create mode 100644 fastlane/metadata/android/sv/changelogs/40100100.txt diff --git a/fastlane/metadata/android/de/changelogs/40100100.txt b/fastlane/metadata/android/de/changelogs/40100100.txt new file mode 100644 index 0000000000..70b786d12e --- /dev/null +++ b/fastlane/metadata/android/de/changelogs/40100100.txt @@ -0,0 +1 @@ +// TODO diff --git a/fastlane/metadata/android/fa/changelogs/40100100.txt b/fastlane/metadata/android/fa/changelogs/40100100.txt new file mode 100644 index 0000000000..6123bfc7fc --- /dev/null +++ b/fastlane/metadata/android/fa/changelogs/40100100.txt @@ -0,0 +1 @@ +// برای انجام diff --git a/fastlane/metadata/android/pt_BR/changelogs/40100100.txt b/fastlane/metadata/android/pt_BR/changelogs/40100100.txt new file mode 100644 index 0000000000..02cfd45a87 --- /dev/null +++ b/fastlane/metadata/android/pt_BR/changelogs/40100100.txt @@ -0,0 +1 @@ +// A FAZER diff --git a/fastlane/metadata/android/sv/changelogs/40100100.txt b/fastlane/metadata/android/sv/changelogs/40100100.txt new file mode 100644 index 0000000000..6da756aca9 --- /dev/null +++ b/fastlane/metadata/android/sv/changelogs/40100100.txt @@ -0,0 +1 @@ +// ATT GÖRA From 0e908ad8829317c46b42f2bd58618ae1699705c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20L=C3=B8vbr=C3=B8tte=20Olsen?= Date: Tue, 24 Nov 2020 08:22:53 +0000 Subject: [PATCH 56/66] =?UTF-8?q?Translated=20using=20Weblate=20(Norwegian?= =?UTF-8?q?=20Bokm=C3=A5l)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 43.1% (834 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/nb_NO/ --- vector/src/main/res/values-nb-rNO/strings.xml | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/vector/src/main/res/values-nb-rNO/strings.xml b/vector/src/main/res/values-nb-rNO/strings.xml index 42731a17c6..00b8c19bc4 100644 --- a/vector/src/main/res/values-nb-rNO/strings.xml +++ b/vector/src/main/res/values-nb-rNO/strings.xml @@ -590,7 +590,7 @@ Romkatalog Ingen offentlige rom tilgjengelig - 1 bruker + %d bruker %d brukere Send kjæsjlogg @@ -883,4 +883,29 @@ Du har ikke tillatelse til å starte en samtale i dette rommet Du har ikke tillatelse til å starte en konferansesamtale Tilbakestill + Ugyldig brukernavn/passord + Denne enheten bruker en utdatert TLS sikkerhetsprotokoll som er sårbar for angrep, for din egen sikkerhet får du ikke kople til serveren + Klarte ikke registrere bruker + Klarte ikke registrere bruker: Nettverksfeil + Klarte ikke logge inn + Klarte ikke logge inn: Nettverksfeil + Vennligst les og aksepter reglene for denne hjemmetjeneren: + Passordet ditt har blitt tilbakestilt. +\n +\nAlle øktene dine har blitt logget ut og får ikke lenger push-notifikasjoner. For å skru på notifikasjoner igjen, logg inn på enhetene på nytt. + Klarte ikke verifisere e-postadressen: Pass på at du har klikket på lenken i e-posten + En e-post har blitt sendt til %s. Etter du har fulgt lenken i den kan du klikke nedenfor. + Du må skrive et nytt passord. + Du må skrive inn e-postadressen som er knyttet til din konto. + For å tilbakestille passordet, skriv inn e-postadressen som er knyttet til kontoen din: + Denne hjemmetjeneren vil vite om du er en robot + Registrering med e-post og telefonummer samtidig fungerer ikke enda. Bare telefonummeret kommer til å bli registrert. +\n +\nDu kan legge e-postadressen din til i instillinger. + Bruk egendefinerte tjenerinstillinger (avansert) + Klarte ikke å starte en sanntidskopling. +\nVennligst be hjemmetjeneradministratoren din om å sette opp en TURN server så samtaler blir mer stabile. + Vennligst be administratoren for hjemmetjeneren din (%1$s) til å sette opp en TURN tjener for at telefonsamtaler skal fungere ordentlig. +\n +\nAlternativt kan du prøve å bruke den offentlige tjeneren på %2$s, men dette vil ikke være like stabilt, og det vil dele IP-adressen din med den serveren. Du kan styre dette i instillinger. \ No newline at end of file From d2398a7abbde7b01eac5634b611305f05a171d80 Mon Sep 17 00:00:00 2001 From: notramo Date: Tue, 24 Nov 2020 18:38:27 +0000 Subject: [PATCH 57/66] Translated using Weblate (Hungarian) Currently translated at 83.1% (158 of 190 strings) Translation: Element Android/Element Android Sdk Translate-URL: https://translate.element.io/projects/element-android/element-sdk/hu/ --- .../src/main/res/values-hu/strings.xml | 44 +++++++++++++++++-- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/matrix-sdk-android/src/main/res/values-hu/strings.xml b/matrix-sdk-android/src/main/res/values-hu/strings.xml index 4aade76c55..49238ee8ff 100644 --- a/matrix-sdk-android/src/main/res/values-hu/strings.xml +++ b/matrix-sdk-android/src/main/res/values-hu/strings.xml @@ -22,10 +22,10 @@ %s hanghívást indított. %s fogadta a hívást. %s befejezte a hívást. - %1$s láthatóvá tette a jövőbeli előzményeket %2$s számára - az összes szobatag, onnantól, hogy meg lettek hívva. - az összes szobatag, onnantól, hogy csatlakoztak. - az összes szobatag. + %1$s láthatóvá tette a jövőbeli előzményeket %2$s + a szoba összes tagja számára, a meghívásuk időpontjától kezdve. + a szoba összes tagja számára, a csatlakozásuk időpontjától kezdve. + az összes szobatag számára. bárki. ismeretlen (%s). %1$s bekapcsolta a végpontok közötti titkosítást (%2$s) @@ -139,4 +139,40 @@ Létrehoztad a szobát Matricát küldtél. Képet küldtél. + Saját + Saját (%1$d) + Alapértelmezett + Moderátor + Admin + Ön megváltoztatta a %1$s kisalkalmazást + %1$s megváltoztatta a %2$s kisalkalmazást + Ön eltávolította a %1$s kisalkalmazást + %1$s eltávolította a %2$s kisalkalmazást + Ön hozzáadott egy %1$s kisalkalmazást + %1$s hozzáadott egy %2$s kisalkalmazást + Ön elfogadta a meghívót ehhez: %1$s + Ön visszavonta %1$s felhasználó meghívóját + %1$s visszavonta %2$s felhasználó meghívóját + Ön visszavonta %1$s felhasználó meghívóját + Ön meghívta %1$s felhasználót + %1$s meghívta %2$s felhasználót + Ön meghívót küldött %1$s felhasználónak, hogy csatlakozzon a szobához + Ön frissítette a saját profilját %1$s + Ön eltávolította a szoba képét + %1$s eltávolította a szoba képét + Ön eltávolította a szoba témáját + Ön eltávolította a szoba nevét + Ön videókonferencia kezdeményezését kérte + Ön frissítette ezt a szobát. + %s frissítette a szobát. + Ön frissítette ezt a szobát. + Ön bekapcsolta a végpontok közötti titkosítást (%1$s) + Ön elérhetővé tette a jövőbeni üzeneteket %1$s + Ön elérhetővé tette a jövőbeni üzeneteket %1$s + %1$s elérhetővé tette a jövőbeni üzeneteket %2$s + Ön megváltoztatta a szoba nevét erre: %1$s + Ön eltávolította a saját megjelenített nevét (%1$s volt) + Ön megváltoztatta a saját megjelenítési nevét erről: %1$s, erre: %2$s + Ön beállította a saját megjelenítési nevét erre: %1$s + Az ön meghívása \ No newline at end of file From a8b5a5227f9c00424021f7ecfda9a65b73cbf70c Mon Sep 17 00:00:00 2001 From: Valere Date: Wed, 25 Nov 2020 15:47:27 +0100 Subject: [PATCH 58/66] Code review update --- .../createdirect/CreateDirectRoomActivity.kt | 4 ++-- .../features/invite/InviteUsersToRoomActivity.kt | 4 ++-- .../app/features/usercode/UserCodeActivity.kt | 4 ++-- .../features/usercode/UserCodeSharedViewModel.kt | 13 ++++--------- .../vector/app/features/usercode/UserCodeState.kt | 4 ++++ .../app/features/userdirectory/UserListViewModel.kt | 7 +++---- .../app/features/userdirectory/UserListViewState.kt | 4 ++++ 7 files changed, 21 insertions(+), 19 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt index b4c278116b..6fafe0b977 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt @@ -71,8 +71,8 @@ class CreateDirectRoomActivity : SimpleFragmentActivity(), UserListViewModel.Fac injector.inject(this) } - override fun create(initialState: UserListViewState, args: UserListFragmentArgs): UserListViewModel { - return userListViewModelFactory.create(initialState, args) + override fun create(initialState: UserListViewState): UserListViewModel { + return userListViewModelFactory.create(initialState) } override fun onCreate(savedInstanceState: Bundle?) { diff --git a/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt b/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt index 513fbb5d83..65f547a662 100644 --- a/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt +++ b/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt @@ -68,8 +68,8 @@ class InviteUsersToRoomActivity : SimpleFragmentActivity(), UserListViewModel.Fa injector.inject(this) } - override fun create(initialState: UserListViewState, args: UserListFragmentArgs): UserListViewModel { - return userListViewModelFactory.create(initialState, args) + override fun create(initialState: UserListViewState): UserListViewModel { + return userListViewModelFactory.create(initialState) } override fun onCreate(savedInstanceState: Bundle?) { diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt index 149caaba8f..ffef98d544 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt @@ -116,8 +116,8 @@ class UserCodeActivity }.exhaustive } - override fun create(initialState: UserCodeState, args: Args) = - viewModelFactory.create(initialState, args) + override fun create(initialState: UserCodeState) = + viewModelFactory.create(initialState) companion object { fun newIntent(context: Context, userId: String): Intent { diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt index b456f24972..aa1f882e78 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt @@ -41,7 +41,6 @@ import org.matrix.android.sdk.internal.util.awaitCallback class UserCodeSharedViewModel @AssistedInject constructor( @Assisted val initialState: UserCodeState, - @Assisted val args: UserCodeActivity.Args, private val session: Session, private val stringProvider: StringProvider, private val rawService: RawService) : VectorViewModel(initialState) { @@ -53,27 +52,23 @@ class UserCodeSharedViewModel @AssistedInject constructor( is FragmentViewModelContext -> viewModelContext.fragment as? Factory is ActivityViewModelContext -> viewModelContext.activity as? Factory } - return factory?.create(state, args) ?: error("You should let your activity/fragment implements Factory interface") - } - - override fun initialState(viewModelContext: ViewModelContext): UserCodeState? { - return UserCodeState(viewModelContext.args().userId) + return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface") } } init { - val user = session.getUser(args.userId) + val user = session.getUser(initialState.userId) setState { copy( matrixItem = user?.toMatrixItem(), - shareLink = session.permalinkService().createPermalink(args.userId) + shareLink = session.permalinkService().createPermalink(initialState.userId) ) } } @AssistedInject.Factory interface Factory { - fun create(initialState: UserCodeState, args: UserCodeActivity.Args): UserCodeSharedViewModel + fun create(initialState: UserCodeState): UserCodeSharedViewModel } override fun handle(action: UserCodeActions) { diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeState.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeState.kt index 3be882af3d..fdcfa2cb5e 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeState.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeState.kt @@ -30,4 +30,8 @@ data class UserCodeState( object SCAN : Mode() data class RESULT(val matrixItem: MatrixItem) : Mode() } + + constructor(args: UserCodeActivity.Args) : this( + userId = args.userId + ) } diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt index b1d9e26afa..85701c25a1 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt @@ -43,7 +43,6 @@ private typealias KnownUsersSearch = String private typealias DirectoryUsersSearch = String class UserListViewModel @AssistedInject constructor(@Assisted initialState: UserListViewState, - @Assisted args: UserListFragmentArgs, private val session: Session) : VectorViewModel(initialState) { @@ -54,7 +53,7 @@ class UserListViewModel @AssistedInject constructor(@Assisted initialState: User @AssistedInject.Factory interface Factory { - fun create(initialState: UserListViewState, args: UserListFragmentArgs): UserListViewModel + fun create(initialState: UserListViewState): UserListViewModel } companion object : MvRxViewModelFactory { @@ -65,7 +64,7 @@ class UserListViewModel @AssistedInject constructor(@Assisted initialState: User is ActivityViewModelContext -> viewModelContext.activity as? Factory } val args = viewModelContext.args() - return factory?.create(state, args) ?: error("You should let your activity/fragment implements Factory interface") + return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface") } } @@ -73,7 +72,7 @@ class UserListViewModel @AssistedInject constructor(@Assisted initialState: User setState { copy( myUserId = session.myUserId, - existingRoomId = args.existingRoomId + existingRoomId = initialState.existingRoomId ) } observeUsers() diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewState.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewState.kt index f7cf421ca8..69135f912d 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewState.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewState.kt @@ -35,6 +35,10 @@ data class UserListViewState( val existingRoomId: String? = null ) : MvRxState { + constructor(args: UserListFragmentArgs) : this( + existingRoomId = args.existingRoomId + ) + fun getSelectedMatrixId(): List { return pendingInvitees .mapNotNull { From bcd86977d2ff2ab6e52993fd96875dc7e9e477bf Mon Sep 17 00:00:00 2001 From: Valere Date: Wed, 25 Nov 2020 17:17:48 +0100 Subject: [PATCH 59/66] Fix test + lint --- .../java/im/vector/app/ui/UiAllScreensSanityTest.kt | 5 ++++- .../vector/app/features/usercode/UserCodeSharedViewModel.kt | 1 - .../vector/app/features/userdirectory/UserListViewModel.kt | 1 - 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt b/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt index 1c05a5d529..6b30700116 100644 --- a/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt +++ b/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt @@ -310,7 +310,10 @@ class UiAllScreensSanityTest { clickOn(R.id.createChatRoomButton) withIdlingResource(activityIdlingResource(CreateDirectRoomActivity::class.java)) { - assertDisplayed(R.id.addByMatrixId) + onView(withId(R.id.userListRecyclerView)) + .perform(waitForView(withText(R.string.qr_code))) + onView(withId(R.id.userListRecyclerView)) + .perform(waitForView(withText(R.string.invite_friends))) } closeSoftKeyboard() diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt index aa1f882e78..abef15a1ba 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt @@ -47,7 +47,6 @@ class UserCodeSharedViewModel @AssistedInject constructor( companion object : MvRxViewModelFactory { override fun create(viewModelContext: ViewModelContext, state: UserCodeState): UserCodeSharedViewModel? { - val args = viewModelContext.args() val factory = when (viewModelContext) { is FragmentViewModelContext -> viewModelContext.fragment as? Factory is ActivityViewModelContext -> viewModelContext.activity as? Factory diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt index 85701c25a1..f8eabbaed0 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt @@ -63,7 +63,6 @@ class UserListViewModel @AssistedInject constructor(@Assisted initialState: User is FragmentViewModelContext -> viewModelContext.fragment as? Factory is ActivityViewModelContext -> viewModelContext.activity as? Factory } - val args = viewModelContext.args() return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface") } } From 804afc9a1d59a4dbf76a3fa03f52f303484ecad2 Mon Sep 17 00:00:00 2001 From: Valere Date: Wed, 25 Nov 2020 15:19:49 +0100 Subject: [PATCH 60/66] Fix issues with matrix.to deep linking --- vector/src/main/AndroidManifest.xml | 6 +- .../vector/app/features/home/HomeActivity.kt | 61 +++++- .../app/features/matrixto/MatrixToAction.kt | 24 +++ .../features/matrixto/MatrixToBottomSheet.kt | 118 +++++++++-- .../matrixto/MatrixToBottomSheetState.kt | 27 +++ .../matrixto/MatrixToBottomSheetViewModel.kt | 192 ++++++++++++++++++ .../features/matrixto/MatrixToViewEvents.kt | 24 +++ .../permalink/PermalinkHandlerActivity.kt | 31 +-- .../app/features/usercode/UserCodeActivity.kt | 7 +- .../usercode/UserCodeSharedViewModel.kt | 45 ++-- .../layout/bottom_sheet_matrix_to_card.xml | 34 +++- 11 files changed, 511 insertions(+), 58 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/matrixto/MatrixToAction.kt create mode 100644 vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetState.kt create mode 100644 vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt create mode 100644 vector/src/main/java/im/vector/app/features/matrixto/MatrixToViewEvents.kt diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml index 7d2ca11813..e9bd03cb4b 100644 --- a/vector/src/main/AndroidManifest.xml +++ b/vector/src/main/AndroidManifest.xml @@ -81,7 +81,8 @@ android:resource="@xml/shortcuts" /> - + - + - diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index 32a4af1b1b..e3e942fce9 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -38,8 +38,12 @@ import im.vector.app.core.extensions.replaceFragment import im.vector.app.core.platform.ToolbarConfigurable import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.pushers.PushersManager +import im.vector.app.core.utils.toast import im.vector.app.features.disclaimer.showDisclaimerDialog +import im.vector.app.features.matrixto.MatrixToBottomSheet import im.vector.app.features.notifications.NotificationDrawerManager +import im.vector.app.features.permalink.NavigationInterceptor +import im.vector.app.features.permalink.PermalinkHandler import im.vector.app.features.popup.DefaultVectorAlert import im.vector.app.features.popup.PopupAlertManager import im.vector.app.features.popup.VerificationVectorAlert @@ -50,10 +54,12 @@ import im.vector.app.features.themes.ThemeUtils import im.vector.app.features.workers.signout.ServerBackupStatusViewModel import im.vector.app.features.workers.signout.ServerBackupStatusViewState import im.vector.app.push.fcm.FcmHelper +import io.reactivex.android.schedulers.AndroidSchedulers import kotlinx.android.parcel.Parcelize import kotlinx.android.synthetic.main.activity_home.* import kotlinx.android.synthetic.main.merge_overlay_waiting_view.* import org.matrix.android.sdk.api.session.InitialSyncProgressService +import org.matrix.android.sdk.api.session.permalinks.PermalinkService import org.matrix.android.sdk.api.util.MatrixItem import timber.log.Timber import javax.inject.Inject @@ -64,7 +70,8 @@ data class HomeActivityArgs( val accountCreation: Boolean ) : Parcelable -class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDetectorSharedViewModel.Factory, ServerBackupStatusViewModel.Factory { +class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDetectorSharedViewModel.Factory, ServerBackupStatusViewModel.Factory, + NavigationInterceptor { private lateinit var sharedActionViewModel: HomeSharedActionViewModel @@ -82,6 +89,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet @Inject lateinit var popupAlertManager: PopupAlertManager @Inject lateinit var shortcutsHandler: ShortcutsHandler @Inject lateinit var unknownDeviceViewModelFactory: UnknownDeviceDetectorSharedViewModel.Factory + @Inject lateinit var permalinkHandler: PermalinkHandler private val drawerListener = object : DrawerLayout.SimpleDrawerListener() { override fun onDrawerStateChanged(newState: Int) { @@ -117,9 +125,9 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet .observe() .subscribe { sharedAction -> when (sharedAction) { - is HomeActivitySharedAction.OpenDrawer -> drawerLayout.openDrawer(GravityCompat.START) + is HomeActivitySharedAction.OpenDrawer -> drawerLayout.openDrawer(GravityCompat.START) is HomeActivitySharedAction.CloseDrawer -> drawerLayout.closeDrawer(GravityCompat.START) - is HomeActivitySharedAction.OpenGroup -> { + is HomeActivitySharedAction.OpenGroup -> { drawerLayout.closeDrawer(GravityCompat.START) replaceFragment(R.id.homeDetailFragmentContainer, HomeDetailFragment::class.java, allowStateLoss = true) } @@ -136,20 +144,42 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet homeActivityViewModel.observeViewEvents { when (it) { is HomeActivityViewEvents.AskPasswordToInitCrossSigning -> handleAskPasswordToInitCrossSigning(it) - is HomeActivityViewEvents.OnNewSession -> handleOnNewSession(it) - HomeActivityViewEvents.PromptToEnableSessionPush -> handlePromptToEnablePush() - is HomeActivityViewEvents.OnCrossSignedInvalidated -> handleCrossSigningInvalidated(it) + is HomeActivityViewEvents.OnNewSession -> handleOnNewSession(it) + HomeActivityViewEvents.PromptToEnableSessionPush -> handlePromptToEnablePush() + is HomeActivityViewEvents.OnCrossSignedInvalidated -> handleCrossSigningInvalidated(it) }.exhaustive } homeActivityViewModel.subscribe(this) { renderState(it) } shortcutsHandler.observeRoomsAndBuildShortcuts() .disposeOnDestroy() + + if (isFirstCreation()) { + handleIntent(intent) + } + } + + private fun handleIntent(intent: Intent?) { + intent?.dataString?.let { deepLink -> + if (!deepLink.startsWith(PermalinkService.MATRIX_TO_URL_BASE)) return@let + + permalinkHandler.launch(this, deepLink, + navigationInterceptor = this, + buildTask = true) + // .delay(500, TimeUnit.MILLISECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { isHandled -> + if (!isHandled) { + toast(R.string.permalink_malformed) + } + } + .disposeOnDestroy() + } } private fun renderState(state: HomeActivityViewState) { when (val status = state.initialSyncProgressServiceStatus) { - is InitialSyncProgressService.Status.Idle -> { + is InitialSyncProgressService.Status.Idle -> { waiting_view.isVisible = false } is InitialSyncProgressService.Status.Progressing -> { @@ -270,6 +300,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet if (intent?.getParcelableExtra(MvRx.KEY_ARG)?.clearNotification == true) { notificationDrawerManager.clearAllEvents() } + handleIntent(intent) } override fun onDestroy() { @@ -313,11 +344,11 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet bugReporter.openBugReportScreen(this, false) return true } - R.id.menu_home_filter -> { + R.id.menu_home_filter -> { navigator.openRoomsFiltering(this) return true } - R.id.menu_home_setting -> { + R.id.menu_home_setting -> { navigator.openSettings(this) return true } @@ -334,6 +365,18 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet } } + override fun navToMemberProfile(userId: String): Boolean { + val listener = object : MatrixToBottomSheet.InteractionListener { + override fun navigateToRoom(roomId: String) { + navigator.openRoom(this@HomeActivity, roomId) + } + } + // TODO check if there is already one?? + MatrixToBottomSheet.withUserId(userId, listener) + .show(supportFragmentManager, "HA#MatrixToBottomSheet") + return true + } + companion object { fun newIntent(context: Context, clearNotification: Boolean = false, accountCreation: Boolean = false): Intent { val args = HomeActivityArgs( diff --git a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToAction.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToAction.kt new file mode 100644 index 0000000000..e1c6800494 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToAction.kt @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2020 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.app.features.matrixto + +import im.vector.app.core.platform.VectorViewModelAction +import org.matrix.android.sdk.api.util.MatrixItem + +sealed class MatrixToAction : VectorViewModelAction { + data class StartChattingWithUser(val matrixItem: MatrixItem) : MatrixToAction() +} diff --git a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt index 91c09ef21a..41020ea404 100644 --- a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt @@ -17,23 +17,38 @@ package im.vector.app.features.matrixto import android.os.Bundle +import android.os.Parcelable import android.view.View +import androidx.core.view.isInvisible +import androidx.core.view.isVisible +import com.airbnb.mvrx.Fail +import com.airbnb.mvrx.Loading +import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Success +import com.airbnb.mvrx.Uninitialized +import com.airbnb.mvrx.fragmentViewModel +import com.airbnb.mvrx.withState import im.vector.app.R import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.setTextOrHide import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment import im.vector.app.features.home.AvatarRenderer +import kotlinx.android.parcel.Parcelize import kotlinx.android.synthetic.main.bottom_sheet_matrix_to_card.* -import org.matrix.android.sdk.api.util.MatrixItem import javax.inject.Inject -class MatrixToBottomSheet(private val matrixItem: MatrixItem) : VectorBaseBottomSheetDialogFragment() { +class MatrixToBottomSheet : VectorBaseBottomSheetDialogFragment() { + + @Parcelize + data class MatrixToArgs( + val matrixToLink: String?, + val userId: String? + ) : Parcelable @Inject lateinit var avatarRenderer: AvatarRenderer - interface InteractionListener { - fun didTapStartMessage(matrixItem: MatrixItem) - } + @Inject + lateinit var matrixToBottomSheetViewModelFactory: MatrixToBottomSheetViewModel.Factory override fun injectWith(injector: ScreenComponent) { injector.inject(this) @@ -43,21 +58,100 @@ class MatrixToBottomSheet(private val matrixItem: MatrixItem) : VectorBaseBottom override fun getLayoutResId() = R.layout.bottom_sheet_matrix_to_card + private val viewModel by fragmentViewModel(MatrixToBottomSheetViewModel::class) + + interface InteractionListener { + fun navigateToRoom(roomId: String) + } + + override fun invalidate() = withState(viewModel) { state -> + super.invalidate() + when (val item = state.matrixItem) { + Uninitialized -> { + matrixToCardContentLoading.isVisible = false + matrixToCardUserContentVisibility.isVisible = false + } + is Loading -> { + matrixToCardContentLoading.isVisible = true + matrixToCardUserContentVisibility.isVisible = false + } + is Success -> { + matrixToCardContentLoading.isVisible = false + matrixToCardUserContentVisibility.isVisible = true + matrixToCardNameText.setTextOrHide(item.invoke().displayName) + matrixToCardUserIdText.setTextOrHide(item.invoke().id) + avatarRenderer.render(item.invoke(), matrixToCardAvatar) + } + is Fail -> { + // TODO display some error copy? + dismiss() + } + } + + when (state.startChattingState) { + Uninitialized -> { + matrixToCardButtonLoading.isVisible = false + matrixToCardSendMessageButton.isVisible = false + } + is Success -> { + matrixToCardButtonLoading.isVisible = false + matrixToCardSendMessageButton.isVisible = true + } + is Fail -> { + matrixToCardButtonLoading.isVisible = false + matrixToCardSendMessageButton.isVisible = true + // TODO display some error copy? + dismiss() + } + is Loading -> { + matrixToCardButtonLoading.isVisible = true + matrixToCardSendMessageButton.isInvisible = true + } + } + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) matrixToCardSendMessageButton.debouncedClicks { - interactionListener?.didTapStartMessage(matrixItem) - dismiss() + withState(viewModel) { + it.matrixItem.invoke()?.let { item -> + viewModel.handle(MatrixToAction.StartChattingWithUser(item)) + } + } } - matrixToCardNameText.setTextOrHide(matrixItem.displayName) - matrixToCardUserIdText.setTextOrHide(matrixItem.id) - avatarRenderer.render(matrixItem, matrixToCardAvatar) + viewModel.observeViewEvents { + when (it) { + is MatrixToViewEvents.NavigateToRoom -> { + interactionListener?.navigateToRoom(it.roomId) + dismiss() + } + MatrixToViewEvents.Dismiss -> dismiss() + } + } } companion object { - fun create(matrixItem: MatrixItem, listener: InteractionListener?): MatrixToBottomSheet { - return MatrixToBottomSheet(matrixItem).apply { + fun withLink(matrixToLink: String, listener: InteractionListener?): MatrixToBottomSheet { + return MatrixToBottomSheet().apply { + arguments = Bundle().apply { + putParcelable(MvRx.KEY_ARG, MatrixToBottomSheet.MatrixToArgs( + matrixToLink = matrixToLink, + userId = null + )) + } + interactionListener = listener + } + } + + fun withUserId(userId: String, listener: InteractionListener?): MatrixToBottomSheet { + return MatrixToBottomSheet().apply { + arguments = Bundle().apply { + putParcelable(MvRx.KEY_ARG, MatrixToBottomSheet.MatrixToArgs( + matrixToLink = null, + userId = userId + )) + } interactionListener = listener } } diff --git a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetState.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetState.kt new file mode 100644 index 0000000000..0080b28c66 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetState.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020 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.app.features.matrixto + +import com.airbnb.mvrx.Async +import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.Uninitialized +import org.matrix.android.sdk.api.util.MatrixItem + +data class MatrixToBottomSheetState( + val matrixItem: Async = Uninitialized, + val startChattingState: Async = Uninitialized +) : MvRxState diff --git a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt new file mode 100644 index 0000000000..06cae3218b --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2020 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.app.features.matrixto + +import androidx.lifecycle.viewModelScope +import com.airbnb.mvrx.Fail +import com.airbnb.mvrx.FragmentViewModelContext +import com.airbnb.mvrx.Loading +import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.Success +import com.airbnb.mvrx.Uninitialized +import com.airbnb.mvrx.ViewModelContext +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject +import im.vector.app.R +import im.vector.app.core.extensions.exhaustive +import im.vector.app.core.platform.VectorViewModel +import im.vector.app.core.resources.StringProvider +import im.vector.app.features.raw.wellknown.getElementWellknown +import im.vector.app.features.raw.wellknown.isE2EByDefault +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.extensions.tryOrNull +import org.matrix.android.sdk.api.raw.RawService +import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.permalinks.PermalinkData +import org.matrix.android.sdk.api.session.permalinks.PermalinkParser +import org.matrix.android.sdk.api.session.profile.ProfileService +import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams +import org.matrix.android.sdk.api.session.user.model.User +import org.matrix.android.sdk.api.util.JsonDict +import org.matrix.android.sdk.api.util.toMatrixItem +import org.matrix.android.sdk.internal.util.awaitCallback + +class MatrixToBottomSheetViewModel @AssistedInject constructor( + @Assisted initialState: MatrixToBottomSheetState, + @Assisted val args: MatrixToBottomSheet.MatrixToArgs, + private val session: Session, + private val stringProvider: StringProvider, + private val rawService: RawService) : VectorViewModel(initialState) { + + @AssistedInject.Factory + interface Factory { + fun create(initialState: MatrixToBottomSheetState, + args: MatrixToBottomSheet.MatrixToArgs): MatrixToBottomSheetViewModel + } + + init { + setState { + copy(matrixItem = Loading()) + } + viewModelScope.launch(Dispatchers.IO) { + resolveLink() + } + } + + private suspend fun resolveLink() { + when { + args.matrixToLink != null -> { + val linkedId = PermalinkParser.parse(args.matrixToLink) + if (linkedId is PermalinkData.FallbackLink) { + setState { + copy( + matrixItem = Fail(IllegalArgumentException(stringProvider.getString(R.string.permalink_malformed))), + startChattingState = Uninitialized + ) + } + return + } + + when (linkedId) { + is PermalinkData.UserLink -> { + val user = resolveUser(linkedId.userId) + setState { + copy( + matrixItem = Success(user.toMatrixItem()), + startChattingState = Success(Unit) + ) + } + } + is PermalinkData.RoomLink -> TODO() + is PermalinkData.GroupLink -> { + // not yet supported + } + is PermalinkData.FallbackLink -> { + } + } + } + args.userId != null -> { + val user = resolveUser(args.userId) + + setState { + copy( + matrixItem = Success(user.toMatrixItem()), + startChattingState = Success(Unit) + ) + } + } + else -> { + setState { + copy( + matrixItem = Fail(IllegalArgumentException(stringProvider.getString(R.string.unexpected_error))), + startChattingState = Uninitialized + ) + } + } + } + } + + private suspend fun resolveUser(userId: String): User { + return (session.getUser(userId) + ?: tryOrNull { + awaitCallback { + session.getProfile(userId, it) + } + }?.let { + User(userId, it[ProfileService.DISPLAY_NAME_KEY] as? String, it[ProfileService.AVATAR_URL_KEY] as? String) + } + // Create raw Uxid in case the user is not searchable + ?: User(userId, null, null)) + } + + companion object : MvRxViewModelFactory { + override fun create(viewModelContext: ViewModelContext, state: MatrixToBottomSheetState): MatrixToBottomSheetViewModel? { + val fragment: MatrixToBottomSheet = (viewModelContext as FragmentViewModelContext).fragment() + val args: MatrixToBottomSheet.MatrixToArgs = viewModelContext.args() + + return fragment.matrixToBottomSheetViewModelFactory.create(state, args) + } + } + + override fun handle(action: MatrixToAction) { + when (action) { + is MatrixToAction.StartChattingWithUser -> handleStartChatting(action) + }.exhaustive + } + + private fun handleStartChatting(action: MatrixToAction.StartChattingWithUser) { + val mxId = action.matrixItem.id + val existing = session.getExistingDirectRoomWithUser(mxId) + if (existing != null) { + // navigate to this room + _viewEvents.post(MatrixToViewEvents.NavigateToRoom(existing)) + } else { + setState { + copy(startChattingState = Loading()) + } + // we should create the room then navigate + viewModelScope.launch(Dispatchers.IO) { + val adminE2EByDefault = rawService.getElementWellknown(session.myUserId) + ?.isE2EByDefault() + ?: true + + val roomParams = CreateRoomParams() + .apply { + invitedUserIds.add(mxId) + setDirectMessage() + enableEncryptionIfInvitedUsersSupportIt = adminE2EByDefault + } + + val roomId = + try { + awaitCallback { session.createRoom(roomParams, it) }.also { + setState { + copy(startChattingState = Success(Unit)) + } + } + } catch (failure: Throwable) { + setState { + copy(startChattingState = Fail(Exception(stringProvider.getString(R.string.invite_users_to_room_failure)))) + } + return@launch + } + _viewEvents.post(MatrixToViewEvents.NavigateToRoom(roomId)) + } + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToViewEvents.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToViewEvents.kt new file mode 100644 index 0000000000..f9491fd361 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToViewEvents.kt @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2020 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.app.features.matrixto + +import im.vector.app.core.platform.VectorViewEvents + +sealed class MatrixToViewEvents : VectorViewEvents { + data class NavigateToRoom(val roomId: String) : MatrixToViewEvents() + object Dismiss : MatrixToViewEvents() +} diff --git a/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandlerActivity.kt b/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandlerActivity.kt index e005dd06c5..e8064aaec5 100644 --- a/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandlerActivity.kt +++ b/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandlerActivity.kt @@ -23,11 +23,9 @@ import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.replaceFragment import im.vector.app.core.platform.VectorBaseActivity -import im.vector.app.core.utils.toast +import im.vector.app.features.home.HomeActivity import im.vector.app.features.home.LoadingFragment import im.vector.app.features.login.LoginActivity -import io.reactivex.android.schedulers.AndroidSchedulers -import java.util.concurrent.TimeUnit import javax.inject.Inject class PermalinkHandlerActivity : VectorBaseActivity() { @@ -45,23 +43,28 @@ class PermalinkHandlerActivity : VectorBaseActivity() { if (isFirstCreation()) { replaceFragment(R.id.simpleFragmentContainer, LoadingFragment::class.java) } + handleIntent() + } + + private fun handleIntent() { // If we are not logged in, open login screen. // In the future, we might want to relaunch the process after login. if (!sessionHolder.hasActiveSession()) { startLoginActivity() return } - val uri = intent.dataString - permalinkHandler.launch(this, uri, buildTask = true) - .delay(500, TimeUnit.MILLISECONDS) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { isHandled -> - if (!isHandled) { - toast(R.string.permalink_malformed) - } - finish() - } - .disposeOnDestroy() + // We forward intent to HomeActivity (singleTask) to avoid the dueling app problem + // https://stackoverflow.com/questions/25884954/deep-linking-and-multiple-app-instances + intent.setClass(this, HomeActivity::class.java) + intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP + startActivity(intent) + + finish() + } + + override fun onNewIntent(intent: Intent?) { + super.onNewIntent(intent) + handleIntent() } private fun startLoginActivity() { diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt index ffef98d544..d6279470ae 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt @@ -36,7 +36,6 @@ import im.vector.app.core.utils.onPermissionDeniedSnackbar import im.vector.app.features.matrixto.MatrixToBottomSheet import kotlinx.android.parcel.Parcelize import kotlinx.android.synthetic.main.activity_simple.* -import org.matrix.android.sdk.api.util.MatrixItem import javax.inject.Inject import kotlin.reflect.KClass @@ -72,7 +71,7 @@ class UserCodeActivity UserCodeState.Mode.SCAN -> showFragment(ScanUserCodeFragment::class, Bundle.EMPTY) is UserCodeState.Mode.RESULT -> { showFragment(ShowUserCodeFragment::class, Bundle.EMPTY) - MatrixToBottomSheet.create(mode.matrixItem, this).show(supportFragmentManager, "MatrixToBottomSheet") + MatrixToBottomSheet.withUserId(mode.matrixItem.id, this).show(supportFragmentManager, "MatrixToBottomSheet") } } } @@ -104,8 +103,8 @@ class UserCodeActivity } } - override fun didTapStartMessage(matrixItem: MatrixItem) { - sharedViewModel.handle(UserCodeActions.StartChattingWithUser(matrixItem)) + override fun navigateToRoom(roomId: String) { + navigator.openRoom(this, roomId) } override fun onBackPressed() = withState(sharedViewModel) { diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt index abef15a1ba..93b198f9d7 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt @@ -30,12 +30,15 @@ import im.vector.app.features.raw.wellknown.getElementWellknown import im.vector.app.features.raw.wellknown.isE2EByDefault import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.raw.RawService import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.permalinks.PermalinkData import org.matrix.android.sdk.api.session.permalinks.PermalinkParser +import org.matrix.android.sdk.api.session.profile.ProfileService import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams import org.matrix.android.sdk.api.session.user.model.User +import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.api.util.toMatrixItem import org.matrix.android.sdk.internal.util.awaitCallback @@ -72,12 +75,12 @@ class UserCodeSharedViewModel @AssistedInject constructor( override fun handle(action: UserCodeActions) { when (action) { - UserCodeActions.DismissAction -> _viewEvents.post(UserCodeShareViewEvents.Dismiss) - is UserCodeActions.SwitchMode -> setState { copy(mode = action.mode) } - is UserCodeActions.DecodedQRCode -> handleQrCodeDecoded(action) - is UserCodeActions.StartChattingWithUser -> handleStartChatting(action) + UserCodeActions.DismissAction -> _viewEvents.post(UserCodeShareViewEvents.Dismiss) + is UserCodeActions.SwitchMode -> setState { copy(mode = action.mode) } + is UserCodeActions.DecodedQRCode -> handleQrCodeDecoded(action) + is UserCodeActions.StartChattingWithUser -> handleStartChatting(action) UserCodeActions.CameraPermissionNotGranted -> _viewEvents.post(UserCodeShareViewEvents.CameraPermissionNotGranted) - UserCodeActions.ShareByText -> handleShareByText() + UserCodeActions.ShareByText -> handleShareByText() } } @@ -139,13 +142,21 @@ class UserCodeSharedViewModel @AssistedInject constructor( _viewEvents.post(UserCodeShareViewEvents.ShowWaitingScreen) viewModelScope.launch(Dispatchers.IO) { when (linkedId) { - is PermalinkData.RoomLink -> TODO() - is PermalinkData.UserLink -> { - val user = session.getUser(linkedId.userId) ?: awaitCallback> { - session.searchUsersDirectory(linkedId.userId, 10, emptySet(), it) - }.firstOrNull { it.userId == linkedId.userId } - // Create raw Uxid in case the user is not searchable - ?: User(linkedId.userId, null, null) + is PermalinkData.RoomLink -> { + // not yet supported + _viewEvents.post(UserCodeShareViewEvents.ToastMessage(stringProvider.getString(R.string.not_implemented))) + } + is PermalinkData.UserLink -> { + val user = session.getUser(linkedId.userId) + ?: tryOrNull { + awaitCallback { + session.getProfile(linkedId.userId, it) + } + }?.let { + User(linkedId.userId, it[ProfileService.DISPLAY_NAME_KEY] as? String, it[ProfileService.AVATAR_URL_KEY] as? String) + } + // Create raw Uxid in case the user is not searchable + ?: User(linkedId.userId, null, null) setState { copy( @@ -153,8 +164,14 @@ class UserCodeSharedViewModel @AssistedInject constructor( ) } } - is PermalinkData.GroupLink -> TODO() - is PermalinkData.FallbackLink -> TODO() + is PermalinkData.GroupLink -> { + // not yet supported + _viewEvents.post(UserCodeShareViewEvents.ToastMessage(stringProvider.getString(R.string.not_implemented))) + } + is PermalinkData.FallbackLink -> { + // not yet supported + _viewEvents.post(UserCodeShareViewEvents.ToastMessage(stringProvider.getString(R.string.not_implemented))) + } } _viewEvents.post(UserCodeShareViewEvents.HideWaitingScreen) } diff --git a/vector/src/main/res/layout/bottom_sheet_matrix_to_card.xml b/vector/src/main/res/layout/bottom_sheet_matrix_to_card.xml index b8c81ded3a..d051bd7c98 100644 --- a/vector/src/main/res/layout/bottom_sheet_matrix_to_card.xml +++ b/vector/src/main/res/layout/bottom_sheet_matrix_to_card.xml @@ -3,13 +3,24 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" - android:layout_height="wrap_content"> + android:layout_height="wrap_content" + android:minHeight="200dp"> + + + + + + From 8e6e6736a37f3ec8d180b111493d40129ec3ffc5 Mon Sep 17 00:00:00 2001 From: Valere Date: Wed, 25 Nov 2020 17:57:18 +0100 Subject: [PATCH 61/66] Code review --- .../sdk/api/session/user/UserService.kt | 5 +++ .../session/user/DefaultUserService.kt | 31 ++++++++++++++ .../matrixto/MatrixToBottomSheetState.kt | 10 ++++- .../matrixto/MatrixToBottomSheetViewModel.kt | 40 ++++++++----------- .../usercode/UserCodeSharedViewModel.kt | 17 +++----- 5 files changed, 68 insertions(+), 35 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/user/UserService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/user/UserService.kt index 2cfc4b731f..ab85f979bf 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/user/UserService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/user/UserService.kt @@ -35,6 +35,11 @@ interface UserService { */ fun getUser(userId: String): User? + /** + * Try to resolve user from known users, or using profile api + */ + fun resolveUser(userId: String, callback: MatrixCallback) + /** * Search list of users on server directory. * @param search the searched term diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/DefaultUserService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/DefaultUserService.kt index d2eb7a14ef..1740956915 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/DefaultUserService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/DefaultUserService.kt @@ -19,10 +19,13 @@ package org.matrix.android.sdk.internal.session.user import androidx.lifecycle.LiveData import androidx.paging.PagedList import org.matrix.android.sdk.api.MatrixCallback +import org.matrix.android.sdk.api.session.profile.ProfileService import org.matrix.android.sdk.api.session.user.UserService import org.matrix.android.sdk.api.session.user.model.User import org.matrix.android.sdk.api.util.Cancelable +import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.api.util.Optional +import org.matrix.android.sdk.internal.session.profile.GetProfileInfoTask import org.matrix.android.sdk.internal.session.user.accountdata.UpdateIgnoredUserIdsTask import org.matrix.android.sdk.internal.session.user.model.SearchUserTask import org.matrix.android.sdk.internal.task.TaskExecutor @@ -32,12 +35,40 @@ import javax.inject.Inject internal class DefaultUserService @Inject constructor(private val userDataSource: UserDataSource, private val searchUserTask: SearchUserTask, private val updateIgnoredUserIdsTask: UpdateIgnoredUserIdsTask, + private val getProfileInfoTask: GetProfileInfoTask, private val taskExecutor: TaskExecutor) : UserService { override fun getUser(userId: String): User? { return userDataSource.getUser(userId) } + override fun resolveUser(userId: String, callback: MatrixCallback) { + val known = getUser(userId) + if (known != null) { + callback.onSuccess(known) + } else { + val params = GetProfileInfoTask.Params(userId) + getProfileInfoTask + .configureWith(params) { + this.callback = object : MatrixCallback { + override fun onSuccess(data: JsonDict) { + callback.onSuccess( + User( + userId, + data[ProfileService.DISPLAY_NAME_KEY] as? String, + data[ProfileService.AVATAR_URL_KEY] as? String) + ) + } + + override fun onFailure(failure: Throwable) { + callback.onFailure(failure) + } + } + } + .executeBy(taskExecutor) + } + } + override fun getUserLive(userId: String): LiveData> { return userDataSource.getUserLive(userId) } diff --git a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetState.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetState.kt index 0080b28c66..9ec2071a94 100644 --- a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetState.kt +++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetState.kt @@ -22,6 +22,14 @@ import com.airbnb.mvrx.Uninitialized import org.matrix.android.sdk.api.util.MatrixItem data class MatrixToBottomSheetState( + val userId: String? = null, + val deepLink: String? = null, val matrixItem: Async = Uninitialized, val startChattingState: Async = Uninitialized -) : MvRxState +) : MvRxState { + + constructor(args: MatrixToBottomSheet.MatrixToArgs) : this( + userId = args.userId, + deepLink = args.matrixToLink + ) +} diff --git a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt index 06cae3218b..5f06bc6edd 100644 --- a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt @@ -39,24 +39,20 @@ import org.matrix.android.sdk.api.raw.RawService import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.permalinks.PermalinkData import org.matrix.android.sdk.api.session.permalinks.PermalinkParser -import org.matrix.android.sdk.api.session.profile.ProfileService import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams import org.matrix.android.sdk.api.session.user.model.User -import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.api.util.toMatrixItem import org.matrix.android.sdk.internal.util.awaitCallback class MatrixToBottomSheetViewModel @AssistedInject constructor( @Assisted initialState: MatrixToBottomSheetState, - @Assisted val args: MatrixToBottomSheet.MatrixToArgs, private val session: Session, private val stringProvider: StringProvider, private val rawService: RawService) : VectorViewModel(initialState) { @AssistedInject.Factory interface Factory { - fun create(initialState: MatrixToBottomSheetState, - args: MatrixToBottomSheet.MatrixToArgs): MatrixToBottomSheetViewModel + fun create(initialState: MatrixToBottomSheetState): MatrixToBottomSheetViewModel } init { @@ -64,14 +60,14 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor( copy(matrixItem = Loading()) } viewModelScope.launch(Dispatchers.IO) { - resolveLink() + resolveLink(initialState) } } - private suspend fun resolveLink() { + private suspend fun resolveLink(initialState: MatrixToBottomSheetState) { when { - args.matrixToLink != null -> { - val linkedId = PermalinkParser.parse(args.matrixToLink) + initialState.deepLink != null -> { + val linkedId = PermalinkParser.parse(initialState.deepLink) if (linkedId is PermalinkData.FallbackLink) { setState { copy( @@ -92,7 +88,9 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor( ) } } - is PermalinkData.RoomLink -> TODO() + is PermalinkData.RoomLink -> { + // not yet supported + } is PermalinkData.GroupLink -> { // not yet supported } @@ -100,8 +98,8 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor( } } } - args.userId != null -> { - val user = resolveUser(args.userId) + initialState.userId != null -> { + val user = resolveUser(initialState.userId) setState { copy( @@ -110,7 +108,7 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor( ) } } - else -> { + else -> { setState { copy( matrixItem = Fail(IllegalArgumentException(stringProvider.getString(R.string.unexpected_error))), @@ -122,24 +120,20 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor( } private suspend fun resolveUser(userId: String): User { - return (session.getUser(userId) - ?: tryOrNull { - awaitCallback { - session.getProfile(userId, it) + return tryOrNull { + awaitCallback { + session.resolveUser(userId, it) } - }?.let { - User(userId, it[ProfileService.DISPLAY_NAME_KEY] as? String, it[ProfileService.AVATAR_URL_KEY] as? String) } - // Create raw Uxid in case the user is not searchable - ?: User(userId, null, null)) + // Create raw user in case the user is not searchable + ?: User(userId, null, null) } companion object : MvRxViewModelFactory { override fun create(viewModelContext: ViewModelContext, state: MatrixToBottomSheetState): MatrixToBottomSheetViewModel? { val fragment: MatrixToBottomSheet = (viewModelContext as FragmentViewModelContext).fragment() - val args: MatrixToBottomSheet.MatrixToArgs = viewModelContext.args() - return fragment.matrixToBottomSheetViewModelFactory.create(state, args) + return fragment.matrixToBottomSheetViewModelFactory.create(state) } } diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt index 93b198f9d7..98acab147e 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt @@ -35,10 +35,8 @@ import org.matrix.android.sdk.api.raw.RawService import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.permalinks.PermalinkData import org.matrix.android.sdk.api.session.permalinks.PermalinkParser -import org.matrix.android.sdk.api.session.profile.ProfileService import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams import org.matrix.android.sdk.api.session.user.model.User -import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.api.util.toMatrixItem import org.matrix.android.sdk.internal.util.awaitCallback @@ -147,15 +145,12 @@ class UserCodeSharedViewModel @AssistedInject constructor( _viewEvents.post(UserCodeShareViewEvents.ToastMessage(stringProvider.getString(R.string.not_implemented))) } is PermalinkData.UserLink -> { - val user = session.getUser(linkedId.userId) - ?: tryOrNull { - awaitCallback { - session.getProfile(linkedId.userId, it) - } - }?.let { - User(linkedId.userId, it[ProfileService.DISPLAY_NAME_KEY] as? String, it[ProfileService.AVATAR_URL_KEY] as? String) - } - // Create raw Uxid in case the user is not searchable + val user = tryOrNull { + awaitCallback { + session.resolveUser(linkedId.userId, it) + } + } + // Create raw Uxid in case the user is not searchable ?: User(linkedId.userId, null, null) setState { From 4f5632b9163648aefd5edee7186e997d465856bc Mon Sep 17 00:00:00 2001 From: Valere Date: Wed, 25 Nov 2020 18:02:01 +0100 Subject: [PATCH 62/66] code review --- .../vector/app/features/home/HomeActivity.kt | 12 +++---- .../matrixto/MatrixToBottomSheetViewModel.kt | 35 +++++++++---------- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index e3e942fce9..d0d10beb31 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -125,9 +125,9 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet .observe() .subscribe { sharedAction -> when (sharedAction) { - is HomeActivitySharedAction.OpenDrawer -> drawerLayout.openDrawer(GravityCompat.START) + is HomeActivitySharedAction.OpenDrawer -> drawerLayout.openDrawer(GravityCompat.START) is HomeActivitySharedAction.CloseDrawer -> drawerLayout.closeDrawer(GravityCompat.START) - is HomeActivitySharedAction.OpenGroup -> { + is HomeActivitySharedAction.OpenGroup -> { drawerLayout.closeDrawer(GravityCompat.START) replaceFragment(R.id.homeDetailFragmentContainer, HomeDetailFragment::class.java, allowStateLoss = true) } @@ -144,9 +144,9 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet homeActivityViewModel.observeViewEvents { when (it) { is HomeActivityViewEvents.AskPasswordToInitCrossSigning -> handleAskPasswordToInitCrossSigning(it) - is HomeActivityViewEvents.OnNewSession -> handleOnNewSession(it) - HomeActivityViewEvents.PromptToEnableSessionPush -> handlePromptToEnablePush() - is HomeActivityViewEvents.OnCrossSignedInvalidated -> handleCrossSigningInvalidated(it) + is HomeActivityViewEvents.OnNewSession -> handleOnNewSession(it) + HomeActivityViewEvents.PromptToEnableSessionPush -> handlePromptToEnablePush() + is HomeActivityViewEvents.OnCrossSignedInvalidated -> handleCrossSigningInvalidated(it) }.exhaustive } homeActivityViewModel.subscribe(this) { renderState(it) } @@ -179,7 +179,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet private fun renderState(state: HomeActivityViewState) { when (val status = state.initialSyncProgressServiceStatus) { - is InitialSyncProgressService.Status.Idle -> { + is InitialSyncProgressService.Status.Idle -> { waiting_view.isVisible = false } is InitialSyncProgressService.Status.Progressing -> { diff --git a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt index 5f06bc6edd..79af3684b9 100644 --- a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt @@ -121,11 +121,11 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor( private suspend fun resolveUser(userId: String): User { return tryOrNull { - awaitCallback { - session.resolveUser(userId, it) - } - } - // Create raw user in case the user is not searchable + awaitCallback { + session.resolveUser(userId, it) + } + } + // Create raw user in case the user is not searchable ?: User(userId, null, null) } @@ -166,19 +166,18 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor( enableEncryptionIfInvitedUsersSupportIt = adminE2EByDefault } - val roomId = - try { - awaitCallback { session.createRoom(roomParams, it) }.also { - setState { - copy(startChattingState = Success(Unit)) - } - } - } catch (failure: Throwable) { - setState { - copy(startChattingState = Fail(Exception(stringProvider.getString(R.string.invite_users_to_room_failure)))) - } - return@launch - } + val roomId = try { + awaitCallback { session.createRoom(roomParams, it) } + } catch (failure: Throwable) { + setState { + copy(startChattingState = Fail(Exception(stringProvider.getString(R.string.invite_users_to_room_failure)))) + } + return@launch + } + setState { + // we can hide this button has we will navigate out + copy(startChattingState = Uninitialized) + } _viewEvents.post(MatrixToViewEvents.NavigateToRoom(roomId)) } } From 15d93c8aeb6e8ac10ab07bac4ec294c8a8fd8c62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20L=C3=B8vbr=C3=B8tte=20Olsen?= Date: Wed, 25 Nov 2020 11:27:35 +0000 Subject: [PATCH 63/66] =?UTF-8?q?Translated=20using=20Weblate=20(Norwegian?= =?UTF-8?q?=20Bokm=C3=A5l)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 43.3% (837 of 1933 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/nb_NO/ --- vector/src/main/res/values-nb-rNO/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vector/src/main/res/values-nb-rNO/strings.xml b/vector/src/main/res/values-nb-rNO/strings.xml index 00b8c19bc4..c6275dd936 100644 --- a/vector/src/main/res/values-nb-rNO/strings.xml +++ b/vector/src/main/res/values-nb-rNO/strings.xml @@ -908,4 +908,9 @@ Vennligst be administratoren for hjemmetjeneren din (%1$s) til å sette opp en TURN tjener for at telefonsamtaler skal fungere ordentlig. \n \nAlternativt kan du prøve å bruke den offentlige tjeneren på %2$s, men dette vil ikke være like stabilt, og det vil dele IP-adressen din med den serveren. Du kan styre dette i instillinger. + e-postlenken har ikke blitt trykket på enda + Dette brukernavnet er allerede brukt + Inneholdt ikke gyldig JSON + Ugyldig JSON + Biletten din ble ikke gjenkjent \ No newline at end of file From fbc3f47eebedf05a0c4094e65eccaadd3eb6e9ab Mon Sep 17 00:00:00 2001 From: Valere Date: Thu, 26 Nov 2020 14:17:47 +0100 Subject: [PATCH 64/66] Fix / update profile when no rooms --- CHANGES.md | 1 + .../session/profile/DefaultProfileService.kt | 12 +++++++----- .../sdk/internal/session/user/UserStore.kt | 19 +++++++++++++++++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 9e823db140..04050e70c4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -23,6 +23,7 @@ Bugfix 🐛: - Try to fix cropped image in timeline (#2126) - Registration: annoying error message scares every new user when they add an email (#2391) - Fix jitsi integration for those with non-vanilla dialler frameworks + - Update profile has no effect if user is in zero rooms Translations 🗣: - diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt index 8d09277295..5265e4f17d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt @@ -31,6 +31,7 @@ import org.matrix.android.sdk.internal.database.model.PendingThreePidEntity import org.matrix.android.sdk.internal.database.model.UserThreePidEntity import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.session.content.FileUploader +import org.matrix.android.sdk.internal.session.user.UserStore import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.task.configureWith import org.matrix.android.sdk.internal.task.launchToCallback @@ -49,6 +50,7 @@ internal class DefaultProfileService @Inject constructor(private val taskExecuto private val finalizeAddingThreePidTask: FinalizeAddingThreePidTask, private val deleteThreePidTask: DeleteThreePidTask, private val pendingThreePidMapper: PendingThreePidMapper, + private val userStore: UserStore, private val fileUploader: FileUploader) : ProfileService { override fun getDisplayName(userId: String, matrixCallback: MatrixCallback>): Cancelable { @@ -70,17 +72,17 @@ internal class DefaultProfileService @Inject constructor(private val taskExecuto } override fun setDisplayName(userId: String, newDisplayName: String, matrixCallback: MatrixCallback): Cancelable { - return setDisplayNameTask - .configureWith(SetDisplayNameTask.Params(userId = userId, newDisplayName = newDisplayName)) { - callback = matrixCallback - } - .executeBy(taskExecutor) + return taskExecutor.executorScope.launchToCallback(coroutineDispatchers.io, matrixCallback) { + setDisplayNameTask.execute(SetDisplayNameTask.Params(userId = userId, newDisplayName = newDisplayName)) + userStore.updateDisplayName(userId, newDisplayName) + } } override fun updateAvatar(userId: String, newAvatarUri: Uri, fileName: String, matrixCallback: MatrixCallback): Cancelable { return taskExecutor.executorScope.launchToCallback(coroutineDispatchers.main, matrixCallback) { val response = fileUploader.uploadFromUri(newAvatarUri, fileName, "image/jpeg") setAvatarUrlTask.execute(SetAvatarUrlTask.Params(userId = userId, newAvatarUrl = response.contentUri)) + userStore.updateAvatar(userId, response.contentUri) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/UserStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/UserStore.kt index 5c8cbd08b1..c030872dad 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/UserStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/UserStore.kt @@ -18,12 +18,15 @@ package org.matrix.android.sdk.internal.session.user import com.zhuinden.monarchy.Monarchy import org.matrix.android.sdk.internal.database.model.UserEntity +import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.util.awaitTransaction import javax.inject.Inject internal interface UserStore { suspend fun createOrUpdate(userId: String, displayName: String? = null, avatarUrl: String? = null) + suspend fun updateAvatar(userId: String, avatarUrl: String? = null) + suspend fun updateDisplayName(userId: String, displayName: String? = null) } internal class RealmUserStore @Inject constructor(@SessionDatabase private val monarchy: Monarchy) : UserStore { @@ -34,4 +37,20 @@ internal class RealmUserStore @Inject constructor(@SessionDatabase private val m it.insertOrUpdate(userEntity) } } + + override suspend fun updateAvatar(userId: String, avatarUrl: String?) { + monarchy.awaitTransaction { realm -> + UserEntity.where(realm, userId).findFirst()?.let { + it.avatarUrl = avatarUrl ?: "" + } + } + } + + override suspend fun updateDisplayName(userId: String, displayName: String?) { + monarchy.awaitTransaction { realm -> + UserEntity.where(realm, userId).findFirst()?.let { + it.displayName = displayName ?: "" + } + } + } } From 835a36986da73ea41db70bc95f900ad3c9b4d7e8 Mon Sep 17 00:00:00 2001 From: Valere Date: Thu, 26 Nov 2020 17:39:00 +0100 Subject: [PATCH 65/66] Refactoring following review --- .../vector/app/features/home/HomeActivity.kt | 5 +- .../home/room/detail/RoomDetailFragment.kt | 2 +- .../features/matrixto/MatrixToBottomSheet.kt | 18 +----- .../matrixto/MatrixToBottomSheetState.kt | 4 +- .../matrixto/MatrixToBottomSheetViewModel.kt | 63 +++++++------------ .../features/permalink/PermalinkHandler.kt | 7 ++- .../app/features/usercode/UserCodeActivity.kt | 2 +- .../usercode/UserCodeSharedViewModel.kt | 2 +- .../app/features/usercode/UserCodeState.kt | 2 +- 9 files changed, 36 insertions(+), 69 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index d0d10beb31..7dde0edf32 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -18,6 +18,7 @@ package im.vector.app.features.home import android.content.Context import android.content.Intent +import android.net.Uri import android.os.Bundle import android.os.Parcelable import android.view.MenuItem @@ -365,14 +366,14 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet } } - override fun navToMemberProfile(userId: String): Boolean { + override fun navToMemberProfile(userId: String, deepLink: Uri): Boolean { val listener = object : MatrixToBottomSheet.InteractionListener { override fun navigateToRoom(roomId: String) { navigator.openRoom(this@HomeActivity, roomId) } } // TODO check if there is already one?? - MatrixToBottomSheet.withUserId(userId, listener) + MatrixToBottomSheet.withLink(deepLink.toString(), listener) .show(supportFragmentManager, "HA#MatrixToBottomSheet") return true } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt index e289234e7a..3f5e476a5e 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt @@ -1460,7 +1460,7 @@ class RoomDetailFragment @Inject constructor( return false } - override fun navToMemberProfile(userId: String): Boolean { + override fun navToMemberProfile(userId: String, deepLink: Uri): Boolean { openRoomMemberProfile(userId) return true } diff --git a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt index 41020ea404..69f30bb470 100644 --- a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt @@ -41,8 +41,7 @@ class MatrixToBottomSheet : VectorBaseBottomSheetDialogFragment() { @Parcelize data class MatrixToArgs( - val matrixToLink: String?, - val userId: String? + val matrixToLink: String ) : Parcelable @Inject lateinit var avatarRenderer: AvatarRenderer @@ -136,20 +135,7 @@ class MatrixToBottomSheet : VectorBaseBottomSheetDialogFragment() { return MatrixToBottomSheet().apply { arguments = Bundle().apply { putParcelable(MvRx.KEY_ARG, MatrixToBottomSheet.MatrixToArgs( - matrixToLink = matrixToLink, - userId = null - )) - } - interactionListener = listener - } - } - - fun withUserId(userId: String, listener: InteractionListener?): MatrixToBottomSheet { - return MatrixToBottomSheet().apply { - arguments = Bundle().apply { - putParcelable(MvRx.KEY_ARG, MatrixToBottomSheet.MatrixToArgs( - matrixToLink = null, - userId = userId + matrixToLink = matrixToLink )) } interactionListener = listener diff --git a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetState.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetState.kt index 9ec2071a94..9b1ce9fea8 100644 --- a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetState.kt +++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetState.kt @@ -22,14 +22,12 @@ import com.airbnb.mvrx.Uninitialized import org.matrix.android.sdk.api.util.MatrixItem data class MatrixToBottomSheetState( - val userId: String? = null, - val deepLink: String? = null, + val deepLink: String, val matrixItem: Async = Uninitialized, val startChattingState: Async = Uninitialized ) : MvRxState { constructor(args: MatrixToBottomSheet.MatrixToArgs) : this( - userId = args.userId, deepLink = args.matrixToLink ) } diff --git a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt index 79af3684b9..6e8a530c9a 100644 --- a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt @@ -65,42 +65,20 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor( } private suspend fun resolveLink(initialState: MatrixToBottomSheetState) { - when { - initialState.deepLink != null -> { - val linkedId = PermalinkParser.parse(initialState.deepLink) - if (linkedId is PermalinkData.FallbackLink) { - setState { - copy( - matrixItem = Fail(IllegalArgumentException(stringProvider.getString(R.string.permalink_malformed))), - startChattingState = Uninitialized - ) - } - return - } - - when (linkedId) { - is PermalinkData.UserLink -> { - val user = resolveUser(linkedId.userId) - setState { - copy( - matrixItem = Success(user.toMatrixItem()), - startChattingState = Success(Unit) - ) - } - } - is PermalinkData.RoomLink -> { - // not yet supported - } - is PermalinkData.GroupLink -> { - // not yet supported - } - is PermalinkData.FallbackLink -> { - } - } + val permalinkData = PermalinkParser.parse(initialState.deepLink) + if (permalinkData is PermalinkData.FallbackLink) { + setState { + copy( + matrixItem = Fail(IllegalArgumentException(stringProvider.getString(R.string.permalink_malformed))), + startChattingState = Uninitialized + ) } - initialState.userId != null -> { - val user = resolveUser(initialState.userId) + return + } + when (permalinkData) { + is PermalinkData.UserLink -> { + val user = resolveUser(permalinkData.userId) setState { copy( matrixItem = Success(user.toMatrixItem()), @@ -108,13 +86,16 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor( ) } } - else -> { - setState { - copy( - matrixItem = Fail(IllegalArgumentException(stringProvider.getString(R.string.unexpected_error))), - startChattingState = Uninitialized - ) - } + is PermalinkData.RoomLink -> { + // not yet supported + _viewEvents.post(MatrixToViewEvents.Dismiss) + } + is PermalinkData.GroupLink -> { + // not yet supported + _viewEvents.post(MatrixToViewEvents.Dismiss) + } + is PermalinkData.FallbackLink -> { + _viewEvents.post(MatrixToViewEvents.Dismiss) } } } diff --git a/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt b/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt index 11c55f6a73..f1149d8990 100644 --- a/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt +++ b/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt @@ -63,13 +63,14 @@ class PermalinkHandler @Inject constructor(private val activeSessionHolder: Acti .subscribeOn(Schedulers.computation()) .observeOn(AndroidSchedulers.mainThread()) .flatMap { permalinkData -> - handlePermalink(permalinkData, context, navigationInterceptor, buildTask) + handlePermalink(permalinkData, deepLink, context, navigationInterceptor, buildTask) } .onErrorReturnItem(false) } private fun handlePermalink( permalinkData: PermalinkData, + rawLink: Uri, context: Context, navigationInterceptor: NavigationInterceptor?, buildTask: Boolean @@ -96,7 +97,7 @@ class PermalinkHandler @Inject constructor(private val activeSessionHolder: Acti Single.just(true) } is PermalinkData.UserLink -> { - if (navigationInterceptor?.navToMemberProfile(permalinkData.userId) != true) { + if (navigationInterceptor?.navToMemberProfile(permalinkData.userId, rawLink) != true) { navigator.openRoomMemberProfile(userId = permalinkData.userId, roomId = null, context = context, buildTask = buildTask) } Single.just(true) @@ -175,7 +176,7 @@ interface NavigationInterceptor { /** * Return true if the navigation has been intercepted */ - fun navToMemberProfile(userId: String): Boolean { + fun navToMemberProfile(userId: String, deepLink: Uri): Boolean { return false } } diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt index d6279470ae..547e2d939f 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt @@ -71,7 +71,7 @@ class UserCodeActivity UserCodeState.Mode.SCAN -> showFragment(ScanUserCodeFragment::class, Bundle.EMPTY) is UserCodeState.Mode.RESULT -> { showFragment(ShowUserCodeFragment::class, Bundle.EMPTY) - MatrixToBottomSheet.withUserId(mode.matrixItem.id, this).show(supportFragmentManager, "MatrixToBottomSheet") + MatrixToBottomSheet.withLink(mode.rawLink, this).show(supportFragmentManager, "MatrixToBottomSheet") } } } diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt index 98acab147e..45b6f0ee65 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt @@ -155,7 +155,7 @@ class UserCodeSharedViewModel @AssistedInject constructor( setState { copy( - mode = UserCodeState.Mode.RESULT(user.toMatrixItem()) + mode = UserCodeState.Mode.RESULT(user.toMatrixItem(), action.code) ) } } diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeState.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeState.kt index fdcfa2cb5e..c26da7c0a4 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeState.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeState.kt @@ -28,7 +28,7 @@ data class UserCodeState( sealed class Mode { object SHOW : Mode() object SCAN : Mode() - data class RESULT(val matrixItem: MatrixItem) : Mode() + data class RESULT(val matrixItem: MatrixItem, val rawLink: String) : Mode() } constructor(args: UserCodeActivity.Args) : this( From 708cdad38b4a8f4ade899c4011352cd3c5a11549 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 27 Nov 2020 10:24:07 +0100 Subject: [PATCH 66/66] Update changelog --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 2e0d764579..761d8a4634 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -27,6 +27,7 @@ Bugfix 🐛: - Registration: annoying error message scares every new user when they add an email (#2391) - Fix jitsi integration for those with non-vanilla dialler frameworks - Update profile has no effect if user is in zero rooms + - Fix issues with matrix.to deep linking (#2349) Translations 🗣: -