From fc7bb448bdf2d5c11768936c2b5c960897f8d62c Mon Sep 17 00:00:00 2001 From: Szimszon Date: Wed, 5 Dec 2018 20:17:36 +0000 Subject: [PATCH 0001/1528] Translated using Weblate (Hungarian) Currently translated at 100.0% (1387 of 1387 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/hu/ --- src/i18n/strings/hu.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json index 6b69512d7b..23c5a25e5d 100644 --- a/src/i18n/strings/hu.json +++ b/src/i18n/strings/hu.json @@ -1410,5 +1410,9 @@ "Common names and surnames are easy to guess": "Elterjedt neveket könnyű kitalálni", "Great! This passphrase looks strong enough.": "Szuper! Ez a jelmondat elég erősnek látszik.", "As a safety net, you can use it to restore your encrypted message history.": "Használhatod egy biztonsági hálóként a titkosított üzenetek visszaállításához.", - "Failed to load group members": "A közösség tagságokat nem sikerült betölteni" + "Failed to load group members": "A közösség tagságokat nem sikerült betölteni", + "Failed to invite users to the room:": "Felhasználókat nem sikerült meghívni a szobába:", + "You do not have permission to invite people to this room.": "Nincs jogosultságod embereket meghívni ebbe a szobába.", + "User %(user_id)s does not exist": "%(user_id)s felhasználó nem létezik", + "Unknown server error": "Ismeretlen szerver hiba" } From b33a0b1952fe83537e76082d6f75e820bc2e2e7c Mon Sep 17 00:00:00 2001 From: Besnik Bleta Date: Wed, 5 Dec 2018 19:11:43 +0000 Subject: [PATCH 0002/1528] Translated using Weblate (Albanian) Currently translated at 99.3% (1378 of 1387 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/sq/ --- src/i18n/strings/sq.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/sq.json b/src/i18n/strings/sq.json index 5671184e0a..53f2241b07 100644 --- a/src/i18n/strings/sq.json +++ b/src/i18n/strings/sq.json @@ -1381,5 +1381,9 @@ "Common names and surnames are easy to guess": "Emra dhe mbiemra të rëndomtë janë të kollajtë për t’u hamendësuar", "Great! This passphrase looks strong enough.": "Bukur! Ky frazëkalim duket goxha i fuqishëm.", "Failed to load group members": "S'u arrit të ngarkoheshin anëtarë grupi", - "As a safety net, you can use it to restore your encrypted message history.": "Si një rrjet sigurie, mund ta përdorni për të rikthyer historikun e mesazheve tuaj të fshehtëzuar." + "As a safety net, you can use it to restore your encrypted message history.": "Si një rrjet sigurie, mund ta përdorni për të rikthyer historikun e mesazheve tuaj të fshehtëzuar.", + "Failed to invite users to the room:": "S’u arrit të ftohen përdorues te dhoma:", + "You do not have permission to invite people to this room.": "S’keni leje të ftoni njerëz në këtë dhomë.", + "User %(user_id)s does not exist": "Përdoruesi %(user_id)s nuk ekziston", + "Unknown server error": "Gabim i panjohur shërbyesi" } From 21ebe2746b6f05104d7d032f8895f1a99f6029ea Mon Sep 17 00:00:00 2001 From: Karol Kosek Date: Wed, 5 Dec 2018 20:52:36 +0000 Subject: [PATCH 0003/1528] Translated using Weblate (Polish) Currently translated at 90.2% (1252 of 1387 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/pl/ --- src/i18n/strings/pl.json | 43 +++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/src/i18n/strings/pl.json b/src/i18n/strings/pl.json index 705442e7bf..a4eb6f3e7e 100644 --- a/src/i18n/strings/pl.json +++ b/src/i18n/strings/pl.json @@ -1140,11 +1140,11 @@ "This room is not showing flair for any communities": "Ten pokój nie wyświetla wyróżników dla żadnych społeczności", "Flair will appear if enabled in room settings": "Wyróżnik pojawi się, jeśli został włączony w ustawieniach pokoju", "Flair will not appear": "Wyróżnik nie wyświetli się", - "%(severalUsers)sjoined %(count)s times|one": "%(severalUsers)sdołączył", + "%(severalUsers)sjoined %(count)s times|one": "%(severalUsers)sdołączyło", "%(count)s Resend all or cancel all now. You can also select individual messages to resend or cancel.|one": "Wyślij ponownie wiadomość lub anuluj wiadomość.", - "was invited %(count)s times|other": "został zaproszony %(count)s razy", - "was invited %(count)s times|one": "został zaproszony", - "was banned %(count)s times|one": "został zablokowany", + "was invited %(count)s times|other": "został(a) zaproszony(-a) %(count)s razy", + "was invited %(count)s times|one": "został(a) zaproszony(-a)", + "was banned %(count)s times|one": "został(a) zablokowany(-a)", "was kicked %(count)s times|one": "został wyrzucony", "Whether or not you're using the Richtext mode of the Rich Text Editor": "Niezależnie od tego, czy używasz trybu Richtext edytora tekstu w formacie RTF", "Call in Progress": "Łączenie w toku", @@ -1233,5 +1233,38 @@ "Sequences like abc or 6543 are easy to guess": "Sekwencje takie jak abc lub 6543 są łatwe do odgadnięcia", "A word by itself is easy to guess": "Samo słowo jest łatwe do odgadnięcia", "Names and surnames by themselves are easy to guess": "Imiona i nazwiska same w sobie są łatwe do odgadnięcia", - "Common names and surnames are easy to guess": "Popularne imiona i nazwiska są łatwe do odgadnięcia" + "Common names and surnames are easy to guess": "Popularne imiona i nazwiska są łatwe do odgadnięcia", + "You do not have permission to invite people to this room.": "Nie masz uprawnień do zapraszania ludzi do tego pokoju.", + "User %(user_id)s does not exist": "Użytkownik %(user_id)s nie istnieje", + "Unknown server error": "Nieznany bład serwera", + "%(oneUser)sleft %(count)s times|one": "%(oneUser)swyszedł(-ła)", + "%(oneUser)sjoined and left %(count)s times|other": "%(oneUser)sdołączył(a) i wyszedł(-ła) %(count)s razy", + "%(oneUser)sjoined and left %(count)s times|one": "%(oneUser)sdołączył(a) i wyszedł(-ła)", + "%(severalUsers)sleft %(count)s times|other": "%(severalUsers)swyszło %(count)s razy", + "%(oneUser)sleft %(count)s times|other": "%(oneUser)sopuścił(a) %(count)s razy", + "%(severalUsers)sjoined and left %(count)s times|one": "%(severalUsers)sdołączyło i wyszli(-ły)", + "%(severalUsers)sjoined and left %(count)s times|other": "%(severalUsers)sdołączyło i wyszli(-ły) %(count)s razy", + "were invited %(count)s times|other": "zostali(-ły) zaproszeni(-one) %(count)s razy", + "were banned %(count)s times|one": "zostali(-ły) zablokowani(-e)", + "were banned %(count)s times|other": "zostali(-ły) zablokowani(-e) %(count)s razy", + "was banned %(count)s times|other": "został(a) zablokowany(-a) %(count)s razy", + "%(oneUser)schanged their avatar %(count)s times|other": "%(oneUser)szmienił(a) swój awatar %(count)s razy", + "%(oneUser)schanged their avatar %(count)s times|one": "%(oneUser)szmienił(a) swój awatar", + "%(items)s and %(count)s others|other": "%(items)s i %(count)s innych", + "%(items)s and %(count)s others|one": "%(items)s i jeden inny", + "%(severalUsers)schanged their avatar %(count)s times|one": "%(severalUsers)szmieniło swój awatar", + "%(severalUsers)schanged their avatar %(count)s times|other": "%(severalUsers)szmieniło swój awatar %(count)s razy", + "%(oneUser)schanged their name %(count)s times|one": "%(oneUser)szmienił(a) swoją nazwę", + "%(oneUser)schanged their name %(count)s times|other": "%(oneUser)szmienił(a) swoją nazwę %(count)s razy", + "Failed to invite users to the room:": "Nie udało się zaprosić użytkowników do pokoju:", + "No backup is present": "Brak kopii zapasowej", + "Start a new backup": "Rozpocznij nową kopię zapasową", + "The following files cannot be uploaded:": "Następujące pliki nie mogą zostać wysłane:", + "Add some now": "Dodaj teraz kilka", + "Please review and accept all of the homeserver's policies": "Przeczytaj i zaakceptuj wszystkie zasady dotyczące serwera domowego", + "Failed to remove widget": "Nie udało się usunąć widżetu", + "%(severalUsers)sleft and rejoined %(count)s times|other": "%(severalUsers)swyszło i dołączyło ponownie %(count)s razy", + "%(severalUsers)sleft and rejoined %(count)s times|one": "%(severalUsers)swyszło i dołączyło ponownie", + "%(oneUser)sleft and rejoined %(count)s times|other": "%(oneUser)swyszedł(-ła) i dołączył(a) ponownie %(count)s razy", + "%(oneUser)sleft and rejoined %(count)s times|one": "%(oneUser)swyszedł(-ła) i dołączył(a) ponownie" } From 62aae2aa02f87803956efbf4658137a9366d7431 Mon Sep 17 00:00:00 2001 From: Szimszon Date: Wed, 5 Dec 2018 20:17:47 +0000 Subject: [PATCH 0004/1528] Translated using Weblate (Hungarian) Currently translated at 100.0% (1388 of 1388 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/hu/ --- src/i18n/strings/hu.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json index 23c5a25e5d..c92419bee4 100644 --- a/src/i18n/strings/hu.json +++ b/src/i18n/strings/hu.json @@ -1414,5 +1414,6 @@ "Failed to invite users to the room:": "Felhasználókat nem sikerült meghívni a szobába:", "You do not have permission to invite people to this room.": "Nincs jogosultságod embereket meghívni ebbe a szobába.", "User %(user_id)s does not exist": "%(user_id)s felhasználó nem létezik", - "Unknown server error": "Ismeretlen szerver hiba" + "Unknown server error": "Ismeretlen szerver hiba", + "There was an error joining the room": "A szobába való belépésnél hiba történt" } From 4f645134021ee0a27e8c275c9e043a6ba86bc8a3 Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Thu, 6 Dec 2018 05:32:56 +0000 Subject: [PATCH 0005/1528] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (1388 of 1388 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/zh_Hant/ --- src/i18n/strings/zh_Hant.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/zh_Hant.json b/src/i18n/strings/zh_Hant.json index 712911064f..9485ea4f78 100644 --- a/src/i18n/strings/zh_Hant.json +++ b/src/i18n/strings/zh_Hant.json @@ -1407,5 +1407,11 @@ "Names and surnames by themselves are easy to guess": "姓名與姓氏本身很容易猜測", "Common names and surnames are easy to guess": "常見的名字與姓氏易於猜測", "Great! This passphrase looks strong enough.": "很好!這個密碼看起來夠強了。", - "As a safety net, you can use it to restore your encrypted message history.": "做為安全網,您可以使用它來復原您已加密的訊息歷史。" + "As a safety net, you can use it to restore your encrypted message history.": "做為安全網,您可以使用它來復原您已加密的訊息歷史。", + "Failed to invite users to the room:": "邀請使用者到聊天室失敗:", + "There was an error joining the room": "加入聊天室時發生錯誤", + "You do not have permission to invite people to this room.": "您沒有權限邀請夥伴到此聊天室。", + "User %(user_id)s does not exist": "使用者 %(user_id)s 不存在", + "Unknown server error": "未知的伺服器錯誤", + "Failed to load group members": "載入群組成員失敗" } From 8e029ea048f37bddf6b7c6f4e3eddb2e6b923899 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20C?= Date: Thu, 6 Dec 2018 09:16:17 +0000 Subject: [PATCH 0006/1528] Translated using Weblate (French) Currently translated at 100.0% (1388 of 1388 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/fr/ --- src/i18n/strings/fr.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json index a6e2942e38..49d9a5ac21 100644 --- a/src/i18n/strings/fr.json +++ b/src/i18n/strings/fr.json @@ -1410,5 +1410,10 @@ "Use a longer keyboard pattern with more turns": "Utilisez un schéma plus long et avec plus de variations", "Great! This passphrase looks strong enough.": "Super ! Cette phrase de passe a l'air assez forte.", "As a safety net, you can use it to restore your encrypted message history.": "En cas de problème, vous pouvez l'utiliser pour récupérer l'historique de vos messages chiffrés.", - "Failed to load group members": "Échec du chargement des membres du groupe" + "Failed to load group members": "Échec du chargement des membres du groupe", + "Failed to invite users to the room:": "Échec de l'invitation d'utilisateurs dans le salon :", + "There was an error joining the room": "Une erreur est survenue en rejoignant le salon", + "You do not have permission to invite people to this room.": "Vous n'avez pas la permission d'envoyer des invitations dans ce salon.", + "User %(user_id)s does not exist": "L'utilisateur %(user_id)s n'existe pas", + "Unknown server error": "Erreur de serveur inconnue" } From 5c59da8732eab7314168fc6c3ebec88bcb06ab10 Mon Sep 17 00:00:00 2001 From: Angelo Martinovic Date: Thu, 6 Dec 2018 09:18:31 +0000 Subject: [PATCH 0007/1528] Added translation using Weblate (Croatian) --- src/i18n/strings/hr.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/i18n/strings/hr.json diff --git a/src/i18n/strings/hr.json b/src/i18n/strings/hr.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/src/i18n/strings/hr.json @@ -0,0 +1 @@ +{} From b1728b641519fcdc0ec54c79da09a727cea0fd69 Mon Sep 17 00:00:00 2001 From: random Date: Thu, 6 Dec 2018 11:52:45 +0000 Subject: [PATCH 0008/1528] Translated using Weblate (Italian) Currently translated at 100.0% (1388 of 1388 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/it/ --- src/i18n/strings/it.json | 117 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 116 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/it.json b/src/i18n/strings/it.json index e367e8196f..727dc10c9e 100644 --- a/src/i18n/strings/it.json +++ b/src/i18n/strings/it.json @@ -1297,5 +1297,120 @@ "Add some now": "Aggiungine ora", "You are an administrator of this community. You will not be able to rejoin without an invite from another administrator.": "Sei un amministratore di questa comunità. Non potrai rientrare senza un invito da parte di un altro amministratore.", "Open Devtools": "Apri Devtools", - "Show developer tools": "Mostra strumenti sviluppatore" + "Show developer tools": "Mostra strumenti sviluppatore", + "Unable to load! Check your network connectivity and try again.": "Impossibile caricare! Controlla la tua connessione di rete e riprova.", + "Failed to invite users to the room:": "Impossibile invitare gli utenti nella stanza:", + "There was an error joining the room": "Si è verificato un errore entrando nella stanza", + "Use a few words, avoid common phrases": "Usa poche parole, evita frasi comuni", + "No need for symbols, digits, or uppercase letters": "Non sono necessari simboli, numeri o maiuscole", + "Use a longer keyboard pattern with more turns": "Usa una tastiera più lunga con più variazioni", + "Avoid repeated words and characters": "Evita ripetizioni di parole e caratteri", + "Avoid sequences": "Evita sequenze", + "Avoid recent years": "Evita anni recenti", + "Avoid years that are associated with you": "Evita anni che sono associati a te", + "Avoid dates and years that are associated with you": "Evita date e anni che sono associati a te", + "Capitalization doesn't help very much": "Le maiuscole non aiutano molto", + "All-uppercase is almost as easy to guess as all-lowercase": "Tutte maiuscole è altrettanto facile da indovinare come tutte minuscole", + "Reversed words aren't much harder to guess": "Le parole invertite non sono molto più difficili da indovinare", + "Predictable substitutions like '@' instead of 'a' don't help very much": "Sostituzioni prevedibili come '@' al posto di 'a' non aiutano molto", + "Add another word or two. Uncommon words are better.": "Aggiungi ancora una o due parole. Meglio parole non comuni.", + "Repeats like \"aaa\" are easy to guess": "Ripetizioni come \"aaa\" sono facili da indovinare", + "Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Ripetizioni come \"abcabcabc\" sono solo leggermente più difficili da indovinare di \"abc\"", + "Sequences like abc or 6543 are easy to guess": "Sequenze come abc o 6543 sono facili da indovinare", + "Recent years are easy to guess": "Gli anni recenti sono facili da indovinare", + "Dates are often easy to guess": "Le date sono spesso facili da indovinare", + "This is a top-10 common password": "Queste sono le 10 password più comuni", + "This is a top-100 common password": "Queste sono le 100 password più comuni", + "This is a very common password": "Questa è una password molto comune", + "This is similar to a commonly used password": "Questa è simile a una password usata comunemente", + "A word by itself is easy to guess": "Una parola di per sé è facile da indovinare", + "Names and surnames by themselves are easy to guess": "Nomi e cognomi di per sé sono facili da indovinare", + "Common names and surnames are easy to guess": "Nomi e cognomi comuni sono facili da indovinare", + "You do not have permission to invite people to this room.": "Non hai l'autorizzazione di invitare persone in questa stanza.", + "User %(user_id)s does not exist": "L'utente %(user_id)s non esiste", + "Unknown server error": "Errore sconosciuto del server", + "Backup of encryption keys to server": "Backup delle chiavi di cifratura nel server", + "Delete Backup": "Elimina backup", + "Delete your backed up encryption keys from the server? You will no longer be able to use your recovery key to read encrypted message history": "Eliminare il backup delle tue chiavi di cifratura dal server? Non potrai più usare la chiave di ripristino per leggere la cronologia dei messaggi cifrati", + "Delete backup": "Elimina backup", + "Unable to load key backup status": "Impossibile caricare lo stato del backup delle chiavi", + "This device is uploading keys to this backup": "Questo dispositivo sta inviando le chiavi a questo backup", + "This device is not uploading keys to this backup": "Questo dispositivo non sta inviando le chiavi a questo backup", + "Backup has a valid signature from this device": "Il backup ha una firma valida da questo dispositivo", + "Backup has a valid signature from verified device x": "Il backup ha una firma valida dal dispositivo verificato x", + "Backup has a valid signature from unverified device ": "Il backup ha una firma valida dal dispositivo non verificato ", + "Backup has an invalid signature from verified device ": "Il backup ha una firma non valida dal dispositivo verificato ", + "Backup has an invalid signature from unverified device ": "Il backup ha una firma non valida dal dispositivo non verificato ", + "Backup is not signed by any of your devices": "Il backup non è firmato da alcun tuo dispositivo", + "Backup version: ": "Versione backup: ", + "Algorithm: ": "Algoritmo: ", + "Restore backup": "Ripristina backup", + "No backup is present": "Nessun backup presente", + "Start a new backup": "Avvia un nuovo backup", + "The following files cannot be uploaded:": "I seguenti file non possono essere inviati:", + "Please review and accept all of the homeserver's policies": "Si prega di rivedere e accettare tutte le politiche dell'homeserver", + "To avoid losing your chat history, you must export your room keys before logging out. You will need to go back to the newer version of Riot to do this": "Per evitare di perdere la cronologia della chat, devi esportare le tue chiavi della stanza prima di uscire. Dovrai tornare alla versione più recente di Riot per farlo", + "You've previously used a newer version of Riot on %(host)s. To use this version again with end to end encryption, you will need to sign out and back in again. ": "Hai usato in precedenza una versione più recente di Riot su %(host)s. Per usare di nuovo questa versione con cifratura end-to-end, dovrai disconnettere e riaccedere. ", + "Incompatible Database": "Database non compatibile", + "Continue With Encryption Disabled": "Continua con la cifratura disattivata", + "Unable to load backup status": "Impossibile caricare lo stato del backup", + "Unable to restore backup": "Impossibile ripristinare il backup", + "No backup found!": "Nessun backup trovato!", + "Backup Restored": "Backup ripristinato", + "Failed to decrypt %(failedCount)s sessions!": "Decifrazione di %(failedCount)s sessioni fallita!", + "Restored %(sessionCount)s session keys": "Ripristinate le chiavi di %(sessionCount)s sessioni", + "Enter Recovery Passphrase": "Inserisci la password di recupero", + "Access your secure message history and set up secure messaging by entering your recovery passphrase.": "Accedi alla cronologia sicura dei messaggi e imposta la messaggistica sicura inserendo la tua password di recupero.", + "Next": "Prossimo", + "If you've forgotten your recovery passphrase you can use your recovery key or set up new recovery options": "Se hai dimenticato la password di recupero puoi usare la tua chiave di recupero o impostare nuove opzioni di recupero", + "Enter Recovery Key": "Inserisci la chiave di recupero", + "This looks like a valid recovery key!": "Sembra essere una chiave di recupero valida!", + "Not a valid recovery key": "Non è una chiave di recupero valida", + "Access your secure message history and set up secure messaging by entering your recovery key.": "Accedi alla cronologia sicura dei messaggi e imposta la messaggistica sicura inserendo la tua chiave di recupero.", + "If you've forgotten your recovery passphrase you can ": "Se hai dimenticato la password di recupero puoi ", + "Failed to load group members": "Caricamento membri del gruppo fallito", + "You are currently using Riot anonymously as a guest.": "Attualmente stai usando Riot in modo anonimo come ospite.", + "If you would like to create a Matrix account you can register now.": "Se vuoi creare un account Matrix puoi registrarti adesso.", + "File is too big. Maximum file size is %(fileSize)s": "File troppo grande. La dimensione massima è %(fileSize)s", + "Key Backup": "Backup chiave", + "Failed to perform homeserver discovery": "Ricerca dell'homeserver fallita", + "Invalid homeserver discovery response": "Risposta della ricerca homeserver non valida", + "Cannot find homeserver": "Impossibile trovare l'homeserver", + "Sign in with single sign-on": "Accedi con single sign-on", + "Great! This passphrase looks strong enough.": "Ottimo! Questa password sembra abbastanza forte.", + "Secure your encrypted message history with a Recovery Passphrase.": "Proteggi la cronologia dei messaggi cifrati con una password di recupero.", + "You'll need it if you log out or lose access to this device.": "Ti servirà se ti disconnetti o perdi l'accesso a questo dispositivo.", + "Enter a passphrase...": "Inserisci una password...", + "If you don't want encrypted message history to be availble on other devices, .": "Se non vuoi che la cronologia dei messaggi cifrati sia disponibile su altri dispositivi, .", + "Or, if you don't want to create a Recovery Passphrase, skip this step and .": "Oppure, se non vuoi creare una password di recupero, salta questo passo e .", + "That matches!": "Corrisponde!", + "That doesn't match.": "Non corrisponde.", + "Go back to set it again.": "Torna per reimpostare.", + "Type in your Recovery Passphrase to confirm you remember it. If it helps, add it to your password manager or store it somewhere safe.": "Digita la tua password di recupero per confermare che la ricordi. Se aiuta, aggiungila al tuo gestore di password o conservarla in un luogo sicuro.", + "Repeat your passphrase...": "Ripeti la password...", + "As a safety net, you can use it to restore your encrypted message history if you forget your Recovery Passphrase.": "Come rete di sicurezza, puoi usarla per ripristinare la cronologia dei messaggi cifrati se dimentichi la password di recupero.", + "As a safety net, you can use it to restore your encrypted message history.": "Come rete di sicurezza, puoi usarla per ripristinare la cronologia dei messaggi cifrati.", + "Make a copy of this Recovery Key and keep it safe.": "Fai una copia di questa password di recupero e tienila al sicuro.", + "Your Recovery Key": "La tua chiave di recupero", + "Copy to clipboard": "Copia negli appunti", + "Download": "Scarica", + "I've made a copy": "Ho fatto una copia", + "Your Recovery Key has been copied to your clipboard, paste it to:": "La tua chiave di recupero è stata copiata negli appunti, incollala in:", + "Your Recovery Key is in your Downloads folder.": "La tua chiave di recupero è nella cartella Download.", + "Print it and store it somewhere safe": "Stampala e conservala in un luogo sicuro", + "Save it on a USB key or backup drive": "Salvala in una chiave USB o disco di backup", + "Copy it to your personal cloud storage": "Copiala nel tuo archivio cloud personale", + "Got it": "Capito", + "Backup created": "Backup creato", + "Your encryption keys are now being backed up to your Homeserver.": "Le chiavi di cifratura vengono ora salvate sul tuo homeserver.", + "Without setting up Secure Message Recovery, you won't be able to restore your encrypted message history if you log out or use another device.": "Senza impostare un ripristino sicuro dei messaggi, non potrai ripristinare la cronologia dei messaggi cifrati se ti disconnetti o utilizzi un altro dispositivo.", + "Set up Secure Message Recovery": "Imposta ripristino sicuro dei messaggi", + "Create a Recovery Passphrase": "Crea una password di recupero", + "Confirm Recovery Passphrase": "Conferma la password di recupero", + "Recovery Key": "Chiave di recupero", + "Keep it safe": "Tienila al sicuro", + "Backing up...": "Backup...", + "Create Key Backup": "Crea backup chiave", + "Unable to create key backup": "Impossibile creare backup della chiave", + "Retry": "Riprova" } From 3f04f8116f34e0fb2bbad40a85e9afa5d3fcf09f Mon Sep 17 00:00:00 2001 From: Osoitz Date: Thu, 6 Dec 2018 14:49:06 +0000 Subject: [PATCH 0009/1528] Translated using Weblate (Basque) Currently translated at 100.0% (1388 of 1388 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/eu/ --- src/i18n/strings/eu.json | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/eu.json b/src/i18n/strings/eu.json index ce5778b749..5127e40e47 100644 --- a/src/i18n/strings/eu.json +++ b/src/i18n/strings/eu.json @@ -1378,5 +1378,40 @@ "Sign in with single sign-on": "Hai saioa urrats batean", "Failed to perform homeserver discovery": "Huts egin du hasiera-zerbitzarien bilaketak", "Invalid homeserver discovery response": "Baliogabeko hasiera-zerbitzarien bilaketaren erantzuna", - "Cannot find homeserver": "Ezin izan da hasiera-zerbitzaria aurkitu" + "Cannot find homeserver": "Ezin izan da hasiera-zerbitzaria aurkitu", + "Failed to invite users to the room:": "Huts egin du erabiltzaileak gelara elkartzean:", + "There was an error joining the room": "Errore bat gertatu da gelara elkartzean", + "Use a few words, avoid common phrases": "Erabili hitz gutxi batzuk, ekidin ohiko esaldiak", + "No need for symbols, digits, or uppercase letters": "Ez dira sinboloak, zenbakiak edo letra larriak behar", + "Use a longer keyboard pattern with more turns": "Erabili teklatu-eredu luzeago bat aldaketa gehiagorekin", + "Avoid repeated words and characters": "Ekidin errepikatutako hitzak eta karaktereak", + "Avoid sequences": "Ekidin sekuentziak", + "Avoid recent years": "Ekidin azkenaldiko urteak", + "Avoid years that are associated with you": "Ekidin zurekin zerikusia duten urteak", + "Avoid dates and years that are associated with you": "Ekidin zurekin zerikusia duten datak eta urteak", + "Capitalization doesn't help very much": "Letra larriek eta xeheak ez dute askorik laguntzen", + "All-uppercase is almost as easy to guess as all-lowercase": "Dena letra larriz dena letra xehez bezain erraza da asmatzeko", + "Reversed words aren't much harder to guess": "Alderantzikatutako hitzak ez dira asmatzeko asmoz zailagoak", + "Predictable substitutions like '@' instead of 'a' don't help very much": "Aurreikusi daitezkeen ordezkatzeak, esaterako '@' erabiltzea 'a' adierazteko, ez dute askorik laguntzen", + "Add another word or two. Uncommon words are better.": "Gehitu hitz bat edo bi gehiago. Ezohiko hitzak hobeak dira.", + "Repeats like \"aaa\" are easy to guess": "'aaa' bezalako errepikapenak erraz asmatu daitezke", + "Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "\"abcabcabc\" bezalako errepikapenak ia \"abc\" bezain errazak dira asmatzeko", + "Sequences like abc or 6543 are easy to guess": "abc edo 6543 bezalako sekuentziak errazak dira asmatzeko", + "Recent years are easy to guess": "Azkenaldiko urteak errazak dira asmatzeko", + "Dates are often easy to guess": "Datak maiz errazak dira asmatzeko", + "This is a top-10 common password": "Pasahitz hau 10 erabilienen artean dago", + "This is a top-100 common password": "Pasahitz hau 100 erabilienen artean dago", + "This is a very common password": "Pasahitz hau oso ohikoa da", + "This is similar to a commonly used password": "Pasahitz hau maiz erabilitako beste baten oso antzekoa da", + "A word by itself is easy to guess": "Hitz bat berez asmatzeko oso erreza da", + "Names and surnames by themselves are easy to guess": "Izen eta abizenak berez asmatzeko errazak dira", + "Common names and surnames are easy to guess": "Ohiko izenak eta abizenak asmatzeko errazak dira", + "You do not have permission to invite people to this room.": "Ez duzu jendea gela honetara gonbidatzeko baimenik.", + "User %(user_id)s does not exist": "Ez dago %(user_id)s erabiltzailerik", + "Unknown server error": "Zerbitzari errore ezezaguna", + "The following files cannot be uploaded:": "Honako fitxategi hauek ezin dira igo:", + "Failed to load group members": "Huts egin du taldeko kideak kargatzean", + "File is too big. Maximum file size is %(fileSize)s": "Fitxategia handiegia da. Gehieneko tamaina %(fileSize)s da", + "Great! This passphrase looks strong enough.": "Ongi! Pasaesaldi hau nahiko gogorra ematen du.", + "As a safety net, you can use it to restore your encrypted message history.": "Badaezpada, zure zifratutako mezuen historiala berreskuratzeko erabili dezakezu." } From e52eb52db9ec0b3d4fd1f6214c0b71216cdef406 Mon Sep 17 00:00:00 2001 From: Akarshan Biswas Date: Thu, 6 Dec 2018 15:33:29 +0000 Subject: [PATCH 0010/1528] Translated using Weblate (Hindi) Currently translated at 27.2% (378 of 1388 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/hi/ --- src/i18n/strings/hi.json | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/i18n/strings/hi.json b/src/i18n/strings/hi.json index 4c944f9925..5542e96b39 100644 --- a/src/i18n/strings/hi.json +++ b/src/i18n/strings/hi.json @@ -13,7 +13,7 @@ "Whether or not you're logged in (we don't record your user name)": "चाहे आप लॉग इन हों या ना हों( हम आपका खाता नाम दर्ज नहीं करते )", "Your language of choice": "आपकी चयन की भाषा", "Which officially provided instance you are using, if any": "क्या आप कोई अधिकृत संस्करण इस्तेमाल कर रहे हैं? अगर हां, तो कौन सा", - "Your homeserver's URL": "आपके होमसर्वर का यू. आर. एल.", + "Your homeserver's URL": "आपके होमसर्वर का यूआरएल", "Every page you use in the app": "हर पृष्ठ जिसका आप इस एप में इस्तेमाल करते हैं", "Your User Agent": "आपका उपभोक्ता प्रतिनिधि", "Custom Server Options": "कस्टम सर्वर विकल्प", @@ -354,5 +354,27 @@ "Unable to fetch notification target list": "अधिसूचना लक्ष्य सूची लाने में असमर्थ", "Notification targets": "अधिसूचना के लक्ष्य", "Advanced notification settings": "उन्नत अधिसूचना सेटिंग्स", - "There are advanced notifications which are not shown here": "उन्नत सूचनाएं हैं जो यहां दिखाई नहीं दी गई हैं" + "There are advanced notifications which are not shown here": "उन्नत सूचनाएं हैं जो यहां दिखाई नहीं दी गई हैं", + "Failed to invite users to the room:": "रूम में उपयोगकर्ताओं को आमंत्रित करने में विफल:", + "There was an error joining the room": "रूम में शामिल होने में एक त्रुटि हुई", + "Use a few words, avoid common phrases": "कम शब्दों का प्रयोग करें, सामान्य वाक्यांशों से बचें", + "No need for symbols, digits, or uppercase letters": "प्रतीकों, अंक, या अपरकेस अक्षरों की कोई ज़रूरत नहीं है", + "Use a longer keyboard pattern with more turns": "अधिक मोड़ के साथ एक लंबा कीबोर्ड पैटर्न का प्रयोग करें", + "Avoid repeated words and characters": "दोहराए गए शब्दों और अक्षरो से बचें", + "Avoid sequences": "अनुक्रम से बचें", + "Avoid recent years": "हाल के वर्षों से बचें", + "Avoid years that are associated with you": "आपके साथ जुड़े वर्षों से बचें", + "Avoid dates and years that are associated with you": "आपके साथ जुड़े तिथियों और वर्षों से बचें", + "Capitalization doesn't help very much": "कैपिटलाइजेशन यहाँ ज्यादा मददगार नहीं हैं", + "All-uppercase is almost as easy to guess as all-lowercase": "सभी अपरकेस सभी लोअरकेस के तरह अनुमान लगाने में आसान हैं", + "Reversed words aren't much harder to guess": "उल्टा शब्द अनुमान लगाने के लिए बहुत कठिन नहीं हैं", + "Predictable substitutions like '@' instead of 'a' don't help very much": "'a' के बजाय '@' जैसी अनुमानित प्रतिस्थापन बहुत मदद नहीं करते हैं", + "Add another word or two. Uncommon words are better.": "एक या एक से ज्यादा शब्द जोड़ें। असामान्य शब्द बेहतर हैं।", + "Repeats like \"aaa\" are easy to guess": "\"Aaa\" जैसे आवृत्ति अनुमान लगाना आसान है", + "Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "\"Abcabcabc\" जैसे आवृत्ति \"abc\" से अनुमान लगाने के लिए थोड़ा कठिन है", + "Sequences like abc or 6543 are easy to guess": "abc या 6543 जैसे अनुक्रम अनुमान लगाना आसान है", + "Recent years are easy to guess": "हाल के वर्षों का अनुमान लगाना आसान है", + "Dates are often easy to guess": "तिथियां अक्सर अनुमान लगाने में आसान होती हैं", + "This is a top-10 common password": "यह एक शीर्ष 10 सामान्य पासवर्ड में से एक है", + "This is a top-100 common password": "यह एक शीर्ष १०० सामान्य पासवर्ड में से एक है" } From 50461c93065a3e457fe962f7310e929c23339678 Mon Sep 17 00:00:00 2001 From: Akarshan Biswas Date: Thu, 6 Dec 2018 15:34:51 +0000 Subject: [PATCH 0011/1528] Translated using Weblate (Hindi) Currently translated at 27.3% (380 of 1388 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/hi/ Use native number system instead --- src/i18n/strings/hi.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/i18n/strings/hi.json b/src/i18n/strings/hi.json index 5542e96b39..1cf6ae0f78 100644 --- a/src/i18n/strings/hi.json +++ b/src/i18n/strings/hi.json @@ -375,6 +375,8 @@ "Sequences like abc or 6543 are easy to guess": "abc या 6543 जैसे अनुक्रम अनुमान लगाना आसान है", "Recent years are easy to guess": "हाल के वर्षों का अनुमान लगाना आसान है", "Dates are often easy to guess": "तिथियां अक्सर अनुमान लगाने में आसान होती हैं", - "This is a top-10 common password": "यह एक शीर्ष 10 सामान्य पासवर्ड में से एक है", - "This is a top-100 common password": "यह एक शीर्ष १०० सामान्य पासवर्ड में से एक है" + "This is a top-10 common password": "यह एक शीर्ष १० सामान्य पासवर्ड में से एक है", + "This is a top-100 common password": "यह एक शीर्ष १०० सामान्य पासवर्ड में से एक है", + "This is a very common password": "यह एक बहुत ही आम पासवर्ड है", + "This is similar to a commonly used password": "यह आमतौर पर इस्तेमाल किए गए पासवर्ड के समान है" } From dbb0a34456efe61734fd698d135e101cc680a595 Mon Sep 17 00:00:00 2001 From: Krombel Date: Thu, 6 Dec 2018 15:54:52 +0000 Subject: [PATCH 0012/1528] Translated using Weblate (German) Currently translated at 97.9% (1359 of 1388 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/de/ --- src/i18n/strings/de_DE.json | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/de_DE.json b/src/i18n/strings/de_DE.json index 0e12104a7d..ab744d855b 100644 --- a/src/i18n/strings/de_DE.json +++ b/src/i18n/strings/de_DE.json @@ -1355,5 +1355,34 @@ "This looks like a valid recovery key!": "Dies sieht nach einem validen Wiederherstellungsschlüssel aus", "Not a valid recovery key": "Kein valider Wiederherstellungsschlüssel", "Key Backup": "Schlüsselsicherung", - "Cannot find homeserver": "Konnte Heimserver nicht finden" + "Cannot find homeserver": "Konnte Heimserver nicht finden", + "There was an error joining the room": "Es gab einen Fehler beim Raum-Beitreten", + "Use a few words, avoid common phrases": "Benutze einige Worte, vermeide gängige Phrasen", + "No need for symbols, digits, or uppercase letters": "Kein Bedarf an Symbolen, Zahlen oder Großbuchstaben", + "Avoid repeated words and characters": "Vermeide wiederholte Worte und Zeichen", + "Avoid sequences": "Vermeide Sätze", + "Avoid recent years": "Vermeide nahe Jahre", + "Avoid years that are associated with you": "Vermeide Jahre, die mit dir zusammenhängen", + "Avoid dates and years that are associated with you": "Vermeide Daten und Jahre, die mit dir in Verbindung stehen", + "Capitalization doesn't help very much": "Großschreibung hilft nicht viel", + "All-uppercase is almost as easy to guess as all-lowercase": "Alles groß zu geschrieben ist fast genauso schnell zu raten, wie alles klein zu schreiben", + "Reversed words aren't much harder to guess": "Umgedrehte Worte sind nicht schwerer zu erraten", + "Predictable substitutions like '@' instead of 'a' don't help very much": "Vorhersagbare Ersetzungen wie '@' anstelle von 'a' helfen nicht viel", + "Add another word or two. Uncommon words are better.": "Füge ein weiteres wort hinzu - oder mehr. Ungewöhnliche Worte sind besser.", + "Repeats like \"aaa\" are easy to guess": "Wiederholungen wie \"aaa\" sind einfach zu erraten", + "Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Wiederholungen wie \"abcabcabc\" sind nur leicht schwerer zu raten als \"abc\"", + "Sequences like abc or 6543 are easy to guess": "Sequenzen wie \"abc\" oder \"6543\" sind leicht zu raten", + "Recent years are easy to guess": "Kürzlich vergangene Jahre sind einfach zu raten", + "Dates are often easy to guess": "Daten sind oft einfach zu erraten", + "This is a top-10 common password": "Dies ist unter den Top 10 der üblichen Passwörter", + "This is a top-100 common password": "Dies ist unter den Top 100 der üblichen Passwörter", + "This is a very common password": "Dies ist ein recht bekanntes Passwort", + "This is similar to a commonly used password": "Dies ist ähnlich zu einem oft genutzten Passwort", + "A word by itself is easy to guess": "Ein Wort alleine ist einfach zu erraten", + "Names and surnames by themselves are easy to guess": "Namen und Familiennamen alleine sind einfach zu erraten", + "Common names and surnames are easy to guess": "Häufige Namen und Familiennamen sind einfach zu erraten", + "You do not have permission to invite people to this room.": "Du hast keine Berechtigung um Personen in diesen Raum einzuladen.", + "User %(user_id)s does not exist": "Benutzer %(user_id)s existiert nicht", + "Unknown server error": "Unbekannter Server-Fehler", + "Failed to invite users to the room:": "Konnte Benutzer nicht in den Raum einladen:" } From c0f888f43c47862fa581b1538a2302e845323544 Mon Sep 17 00:00:00 2001 From: Karol Kosek Date: Wed, 5 Dec 2018 21:01:43 +0000 Subject: [PATCH 0013/1528] Translated using Weblate (Polish) Currently translated at 90.9% (1262 of 1387 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/pl/ --- src/i18n/strings/pl.json | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/pl.json b/src/i18n/strings/pl.json index a4eb6f3e7e..e22c00bb0b 100644 --- a/src/i18n/strings/pl.json +++ b/src/i18n/strings/pl.json @@ -1266,5 +1266,15 @@ "%(severalUsers)sleft and rejoined %(count)s times|other": "%(severalUsers)swyszło i dołączyło ponownie %(count)s razy", "%(severalUsers)sleft and rejoined %(count)s times|one": "%(severalUsers)swyszło i dołączyło ponownie", "%(oneUser)sleft and rejoined %(count)s times|other": "%(oneUser)swyszedł(-ła) i dołączył(a) ponownie %(count)s razy", - "%(oneUser)sleft and rejoined %(count)s times|one": "%(oneUser)swyszedł(-ła) i dołączył(a) ponownie" + "%(oneUser)sleft and rejoined %(count)s times|one": "%(oneUser)swyszedł(-ła) i dołączył(a) ponownie", + "%(oneUser)srejected their invitation %(count)s times|other": "%(oneUser)sodrzucił(a) ich zaproszenie %(count)s razy", + "%(oneUser)srejected their invitation %(count)s times|one": "%(oneUser)sodrzucił(a) ich zaproszenie", + "%(severalUsers)srejected their invitations %(count)s times|one": "%(severalUsers)sodrzuciło ich zaproszenia", + "%(oneUser)shad their invitation withdrawn %(count)s times|other": "%(oneUser)swycofał(a) zaproszenie %(count)s razy", + "%(oneUser)shad their invitation withdrawn %(count)s times|one": "%(oneUser)swycofał(a) zaproszenie", + "%(severalUsers)shad their invitations withdrawn %(count)s times|other": "%(severalUsers)swycofało zaproszenie %(count)s razy", + "%(severalUsers)shad their invitations withdrawn %(count)s times|one": "%(severalUsers)swycofało zaproszenie", + "%(severalUsers)schanged their name %(count)s times|other": "%(severalUsers)szmieniło ich nazwę %(count)s razy", + "%(severalUsers)schanged their name %(count)s times|one": "%(severalUsers)szmieniło ich nazwę", + "Continue With Encryption Disabled": "Kontynuuj Z Wyłączonym Szyfrowaniem" } From 8e2233dc6cbb913dc56af8618dc6b431330c4036 Mon Sep 17 00:00:00 2001 From: Slavi Pantaleev Date: Fri, 7 Dec 2018 04:06:38 +0000 Subject: [PATCH 0014/1528] Translated using Weblate (Bulgarian) Currently translated at 92.1% (1279 of 1388 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/bg/ --- src/i18n/strings/bg.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/bg.json b/src/i18n/strings/bg.json index 246d53c8d2..3fc4560cba 100644 --- a/src/i18n/strings/bg.json +++ b/src/i18n/strings/bg.json @@ -1299,5 +1299,9 @@ "Open Devtools": "Отвори инструментите за разработчици", "Show developer tools": "Покажи инструментите за разработчици", "If you would like to create a Matrix account you can register now.": "Ако искате да създадете Matrix акаунт, може да се регистрирате тук.", - "You are currently using Riot anonymously as a guest.": "В момента използвате Riot анонимно, като гост." + "You are currently using Riot anonymously as a guest.": "В момента използвате Riot анонимно, като гост.", + "Unable to load! Check your network connectivity and try again.": "Неуспешно зареждане! Проверете мрежовите настройки и опитайте пак.", + "Failed to invite users to the room:": "Неуспешно поканване на потребители в стаята:", + "There was an error joining the room": "Възникна грешка при влизане в стаята", + "Use a few words, avoid common phrases": "Използвайте няколко думи, избягвайте общи фрази" } From 007ee0fa197b767217fe87b39e3ef5ac1fa2a066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20C?= Date: Sat, 8 Dec 2018 10:03:01 +0000 Subject: [PATCH 0015/1528] Translated using Weblate (French) Currently translated at 100.0% (1395 of 1395 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/fr/ --- src/i18n/strings/fr.json | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json index 49d9a5ac21..0b35a53aef 100644 --- a/src/i18n/strings/fr.json +++ b/src/i18n/strings/fr.json @@ -1415,5 +1415,13 @@ "There was an error joining the room": "Une erreur est survenue en rejoignant le salon", "You do not have permission to invite people to this room.": "Vous n'avez pas la permission d'envoyer des invitations dans ce salon.", "User %(user_id)s does not exist": "L'utilisateur %(user_id)s n'existe pas", - "Unknown server error": "Erreur de serveur inconnue" + "Unknown server error": "Erreur de serveur inconnue", + "Show a reminder to enable Secure Message Recovery in encrypted rooms": "Afficher un rappel pour activer la récupération de messages sécurisée dans les salons chiffrés", + "Secure Message Recovery": "Récupération de messages sécurisée", + "If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.": "Si vous vous déconnectez ou si vous utilisez un autre appareil, vous perdrez l'historique de vos messages chiffrés. Pour éviter cela, configurez la récupération de messages sécurisée.", + "Don't ask again": "Ne plus me demander", + "Set up": "Configurer", + "If you don't want encrypted message history to be available on other devices, .": "Si vous ne souhaitez pas que l'historique de vos messages chiffrés soit disponible sur d'autres appareils, .", + "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Si vous ne configurez pas la récupération de messages sécurisée, vous perdrez l'historique de vos messages sécurisés quand vous vous déconnectez.", + "If you don't want to set this up now, you can later in Settings.": "Si vous ne voulez pas le configurer maintenant, vous pouvez le faire plus tard dans les paramètres." } From a5e79415d7d47687e1950b9801403737a0078fff Mon Sep 17 00:00:00 2001 From: Szimszon Date: Sat, 8 Dec 2018 13:39:57 +0000 Subject: [PATCH 0016/1528] Translated using Weblate (Hungarian) Currently translated at 100.0% (1395 of 1395 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/hu/ --- src/i18n/strings/hu.json | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json index c92419bee4..c54f8ffe27 100644 --- a/src/i18n/strings/hu.json +++ b/src/i18n/strings/hu.json @@ -1415,5 +1415,13 @@ "You do not have permission to invite people to this room.": "Nincs jogosultságod embereket meghívni ebbe a szobába.", "User %(user_id)s does not exist": "%(user_id)s felhasználó nem létezik", "Unknown server error": "Ismeretlen szerver hiba", - "There was an error joining the room": "A szobába való belépésnél hiba történt" + "There was an error joining the room": "A szobába való belépésnél hiba történt", + "Show a reminder to enable Secure Message Recovery in encrypted rooms": "Mutass emlékeztetőt a Biztonságos Üzenet Visszaállítás bekapcsolásához a titkosított szobákban", + "Secure Message Recovery": "Biztonságos Üzenet Visszaállítás", + "If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.": "A titkosított üzeneteidhez nem férsz hozzá ha kijelentkezel vagy másik eszközt használsz. A Biztonságos Üzenet Visszaállítás beállításával ezt elkerülheted.", + "Don't ask again": "Ne kérdezd többet", + "Set up": "Beállítás", + "If you don't want encrypted message history to be available on other devices, .": "Ha más eszközön nem szeretnél hozzáférni a titkosított üzeneteidhez akkor .", + "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "A Biztonságos Üzenet Visszaállítás beállítása nélkül kijelentkezés után elveszted a hozzáférést a titkosított üzeneteidhez.", + "If you don't want to set this up now, you can later in Settings.": "Ha most nem akarod beállítani, később a Beállításoknál megteheted." } From ec0c3f3cd18eb7b050a9b2a8b68abef40cf1db3c Mon Sep 17 00:00:00 2001 From: Besnik Bleta Date: Fri, 7 Dec 2018 20:46:57 +0000 Subject: [PATCH 0017/1528] Translated using Weblate (Albanian) Currently translated at 99.3% (1386 of 1395 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/sq/ --- src/i18n/strings/sq.json | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/sq.json b/src/i18n/strings/sq.json index 53f2241b07..d6356caa4e 100644 --- a/src/i18n/strings/sq.json +++ b/src/i18n/strings/sq.json @@ -1385,5 +1385,14 @@ "Failed to invite users to the room:": "S’u arrit të ftohen përdorues te dhoma:", "You do not have permission to invite people to this room.": "S’keni leje të ftoni njerëz në këtë dhomë.", "User %(user_id)s does not exist": "Përdoruesi %(user_id)s nuk ekziston", - "Unknown server error": "Gabim i panjohur shërbyesi" + "Unknown server error": "Gabim i panjohur shërbyesi", + "There was an error joining the room": "Pati një gabim ardhjeje në dhomë", + "Show a reminder to enable Secure Message Recovery in encrypted rooms": "Shfaq një kujtues për aktivizim Rimarrje Mesazhesh të Parrezik në dhoma të fshehtëzuara", + "Secure Message Recovery": "Rimarrje Mesazhesh të Parrezik", + "If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.": "Nëse dilni nga llogaria apo përdorni një pajisje tjetër, do të humbni historikun e mesazheve të parrezik. Që ta parandaloni këtë, rregulloni Rimarrje Mesazhesh të Parrezik.", + "Don't ask again": "Mos pyet sërish", + "Set up": "Rregulloje", + "If you don't want encrypted message history to be available on other devices, .": "Nëse s’doni që historiku i mesazheve të fshehtëzuar të gjendet në pajisje të tjera, .", + "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Po s’rregulluat Rimarrje Mesazhesh të Parrezik, do të humbni historikun e mesazheve të parrezik, kur të dilni nga llogaria.", + "If you don't want to set this up now, you can later in Settings.": "Nëse s’doni ta rregulloni tani këtë, mund ta bëni më vonë që nga Rregullimet." } From 4a5f0a5b71f764634d84c30d0f165e895a4aa407 Mon Sep 17 00:00:00 2001 From: Slavi Pantaleev Date: Fri, 7 Dec 2018 22:45:07 +0000 Subject: [PATCH 0018/1528] Translated using Weblate (Bulgarian) Currently translated at 91.9% (1283 of 1395 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/bg/ --- src/i18n/strings/bg.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/bg.json b/src/i18n/strings/bg.json index 3fc4560cba..a8134448fb 100644 --- a/src/i18n/strings/bg.json +++ b/src/i18n/strings/bg.json @@ -1303,5 +1303,9 @@ "Unable to load! Check your network connectivity and try again.": "Неуспешно зареждане! Проверете мрежовите настройки и опитайте пак.", "Failed to invite users to the room:": "Неуспешно поканване на потребители в стаята:", "There was an error joining the room": "Възникна грешка при влизане в стаята", - "Use a few words, avoid common phrases": "Използвайте няколко думи, избягвайте общи фрази" + "Use a few words, avoid common phrases": "Използвайте няколко думи, избягвайте общи фрази", + "You do not have permission to invite people to this room.": "Нямате привилегии да каните хора в тази стая.", + "User %(user_id)s does not exist": "Потребител %(user_id)s не съществува", + "Unknown server error": "Непозната сървърна грешка", + "No need for symbols, digits, or uppercase letters": "Няма нужда от символи, цифри и главни букви" } From 3d00af9cd054b3c6770399e6d3cb84737655ca90 Mon Sep 17 00:00:00 2001 From: Osoitz Date: Sun, 9 Dec 2018 12:40:41 +0000 Subject: [PATCH 0019/1528] Translated using Weblate (Basque) Currently translated at 99.4% (1387 of 1395 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/eu/ --- src/i18n/strings/eu.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/i18n/strings/eu.json b/src/i18n/strings/eu.json index 5127e40e47..1915cbc1ca 100644 --- a/src/i18n/strings/eu.json +++ b/src/i18n/strings/eu.json @@ -892,11 +892,11 @@ "%(oneUser)sjoined %(count)s times|other": "%(oneUser)s%(count)s aldiz elkartu da", "%(oneUser)sjoined %(count)s times|one": "%(oneUser)s elkartu da", "%(severalUsers)sleft %(count)s times|other": "%(severalUsers)s%(count)s aldiz atera dira", - "%(severalUsers)sleft %(count)s times|one": "%(severalUsers)s atera da", + "%(severalUsers)sleft %(count)s times|one": "%(severalUsers)s atera dira", "%(oneUser)sleft %(count)s times|other": "%(oneUser)s%(count)s aldiz atera da", "%(oneUser)sleft %(count)s times|one": "%(oneUser)s atera da", "%(severalUsers)sjoined and left %(count)s times|other": "%(severalUsers)s elkartu eta atera dira %(count)s aldiz", - "%(severalUsers)sjoined and left %(count)s times|one": "%(severalUsers)s elkartu eta atera da", + "%(severalUsers)sjoined and left %(count)s times|one": "%(severalUsers)s elkartu eta atera dira", "%(oneUser)sjoined and left %(count)s times|other": "%(oneUser)s elkartu eta atera da %(count)s aldiz", "%(oneUser)sjoined and left %(count)s times|one": "%(oneUser)s elkartu eta atera da", "%(severalUsers)sleft and rejoined %(count)s times|other": "%(severalUsers)s atera eta berriz elkartu dira %(count)s aldiz", From ee581b3b011d35da9b1bf420b5ecd0baa68c8272 Mon Sep 17 00:00:00 2001 From: Slavi Pantaleev Date: Mon, 10 Dec 2018 04:03:44 +0000 Subject: [PATCH 0020/1528] Translated using Weblate (Bulgarian) Currently translated at 93.6% (1307 of 1395 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/bg/ --- src/i18n/strings/bg.json | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/bg.json b/src/i18n/strings/bg.json index a8134448fb..0cc724624c 100644 --- a/src/i18n/strings/bg.json +++ b/src/i18n/strings/bg.json @@ -1307,5 +1307,29 @@ "You do not have permission to invite people to this room.": "Нямате привилегии да каните хора в тази стая.", "User %(user_id)s does not exist": "Потребител %(user_id)s не съществува", "Unknown server error": "Непозната сървърна грешка", - "No need for symbols, digits, or uppercase letters": "Няма нужда от символи, цифри и главни букви" + "No need for symbols, digits, or uppercase letters": "Няма нужда от символи, цифри и главни букви", + "Avoid repeated words and characters": "Избягвайте повтарящи се думи и символи", + "Avoid sequences": "Избягвайте последователности", + "Avoid recent years": "Избягвайте скорошни години", + "Avoid years that are associated with you": "Избягвайте години свързани с вас", + "Avoid dates and years that are associated with you": "Избягвайте дати и години свързани с вас", + "Capitalization doesn't help very much": "Главни букви не помагат много", + "All-uppercase is almost as easy to guess as all-lowercase": "Само главни букви е почти толкова лесно за познаване колкото само малки", + "Reversed words aren't much harder to guess": "Разбъркани думи не са много по-трудни за познаване", + "Predictable substitutions like '@' instead of 'a' don't help very much": "Предвидими замествания (като '@' вместо 'a') не помагат много", + "Add another word or two. Uncommon words are better.": "Добавете една или няколко други думи. Рядко срещаните думи са по-добри.", + "Repeats like \"aaa\" are easy to guess": "Повторения като \"aaa\" са лесни за познаване", + "Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Повторения като \"abcabcabc\" са само малко по-трудни за познаване от \"abc\"", + "Sequences like abc or 6543 are easy to guess": "Последователности като abc и 6543 са лесни за познаване", + "Recent years are easy to guess": "Близките години са лесни за познаване", + "Dates are often easy to guess": "Датите често са лесни за познаване", + "This is a top-10 common password": "Тази парола е в топ 10 на често срещаните пароли", + "This is a top-100 common password": "Тази парола е в топ 100 на често срещаните пароли", + "This is a very common password": "Тази парола е много често срещана", + "This is similar to a commonly used password": "Тази парола е подобна на често срещана такава", + "A word by itself is easy to guess": "Единични думи се отгатват лесно", + "Names and surnames by themselves are easy to guess": "Имена и фамилии сами по себе си са лесни за отгатване", + "Common names and surnames are easy to guess": "Често срещани имена и фамилии са лесни за отгатване", + "Use a longer keyboard pattern with more turns": "Използвайте по-дълга клавиатурна последователност с повече разклонения", + "Backup of encryption keys to server": "Резервно копие на ключовете за шифроване на сървъра" } From c6093bcd9b159f9970321acd71b935974cbf9ee4 Mon Sep 17 00:00:00 2001 From: Karol Kosek Date: Sun, 9 Dec 2018 16:40:44 +0000 Subject: [PATCH 0021/1528] Translated using Weblate (Polish) Currently translated at 90.6% (1265 of 1395 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/pl/ --- src/i18n/strings/pl.json | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/i18n/strings/pl.json b/src/i18n/strings/pl.json index e22c00bb0b..791d88ba3d 100644 --- a/src/i18n/strings/pl.json +++ b/src/i18n/strings/pl.json @@ -195,7 +195,7 @@ "Displays action": "Wyświetlane akcje", "Do you want to load widget from URL:": "Czy chcesz załadować widżet z adresu:", "Don't send typing notifications": "Nie wysyłaj powiadomienia o pisaniu", - "Download %(text)s": "Pobrano %(text)s", + "Download %(text)s": "Pobierz %(text)s", "Drop File Here": "Upuść plik tutaj", "Drop here to tag %(section)s": "Upuść tutaj by oznaczyć %(section)s", "Ed25519 fingerprint": "Odcisk Ed25519", @@ -1276,5 +1276,8 @@ "%(severalUsers)shad their invitations withdrawn %(count)s times|one": "%(severalUsers)swycofało zaproszenie", "%(severalUsers)schanged their name %(count)s times|other": "%(severalUsers)szmieniło ich nazwę %(count)s razy", "%(severalUsers)schanged their name %(count)s times|one": "%(severalUsers)szmieniło ich nazwę", - "Continue With Encryption Disabled": "Kontynuuj Z Wyłączonym Szyfrowaniem" + "Continue With Encryption Disabled": "Kontynuuj Z Wyłączonym Szyfrowaniem", + "Capitalization doesn't help very much": "Kapitalizacja nie pomaga bardzo", + "This is a top-10 common password": "To jest 10 najpopularniejszych haseł", + "This is a top-100 common password": "To jest 100 najpopularniejszych haseł" } From f6d2fefe619e87362594d3550518ae381c2ab2f3 Mon Sep 17 00:00:00 2001 From: random Date: Tue, 11 Dec 2018 10:36:26 +0000 Subject: [PATCH 0022/1528] Translated using Weblate (Italian) Currently translated at 100.0% (1395 of 1395 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/it/ --- src/i18n/strings/it.json | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/it.json b/src/i18n/strings/it.json index 727dc10c9e..c7c0fe7ca2 100644 --- a/src/i18n/strings/it.json +++ b/src/i18n/strings/it.json @@ -1412,5 +1412,13 @@ "Backing up...": "Backup...", "Create Key Backup": "Crea backup chiave", "Unable to create key backup": "Impossibile creare backup della chiave", - "Retry": "Riprova" + "Retry": "Riprova", + "Show a reminder to enable Secure Message Recovery in encrypted rooms": "Mostra un promemoria per attivare il ripristino sicuro dei messaggi nelle stanze cifrate", + "Secure Message Recovery": "Ripristino sicuro dei messaggi", + "If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.": "Se ti disconnetti o usi un altro dispositivo, perderai la cronologia sicura dei messaggi. Per evitare che accada, imposta il ripristino sicuro dei messaggi.", + "Don't ask again": "Non chiedere più", + "Set up": "Imposta", + "If you don't want encrypted message history to be available on other devices, .": "Se non vuoi che la cronologia dei messaggi cifrati sia disponibile su altri dispositivi, .", + "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Se non imposti il ripristino sicuro dei messaggi, perderai la cronologia sicura dei messaggi quando ti disconnetti.", + "If you don't want to set this up now, you can later in Settings.": "Se non vuoi impostarlo ora, è possibile farlo in seguito nelle impostazioni." } From d6dd2005db466fe8ccaf69774af4d1e76b981d56 Mon Sep 17 00:00:00 2001 From: Osoitz Date: Tue, 11 Dec 2018 15:25:15 +0000 Subject: [PATCH 0023/1528] Translated using Weblate (Basque) Currently translated at 100.0% (1395 of 1395 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/eu/ --- src/i18n/strings/eu.json | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/eu.json b/src/i18n/strings/eu.json index 1915cbc1ca..9218a2a814 100644 --- a/src/i18n/strings/eu.json +++ b/src/i18n/strings/eu.json @@ -1413,5 +1413,13 @@ "Failed to load group members": "Huts egin du taldeko kideak kargatzean", "File is too big. Maximum file size is %(fileSize)s": "Fitxategia handiegia da. Gehieneko tamaina %(fileSize)s da", "Great! This passphrase looks strong enough.": "Ongi! Pasaesaldi hau nahiko gogorra ematen du.", - "As a safety net, you can use it to restore your encrypted message history.": "Badaezpada, zure zifratutako mezuen historiala berreskuratzeko erabili dezakezu." + "As a safety net, you can use it to restore your encrypted message history.": "Badaezpada, zure zifratutako mezuen historiala berreskuratzeko erabili dezakezu.", + "Show a reminder to enable Secure Message Recovery in encrypted rooms": "Erakutsi zifratutako geletan mezuen berreskuratze segurua gaitzeko origarri bat", + "Secure Message Recovery": "Mezuen berreskuratze segurua", + "If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.": "Saioa amaitzen baduzu edo beste gailu bat erabiltzen baduzu, zure mezu seguruen historiala galduko duzu. Hau gertatu ez dadin, ezarri mezuen berreskuratze segurua.", + "Don't ask again": "Ez galdetu berriro", + "Set up": "Ezarri", + "If you don't want encrypted message history to be available on other devices, .": "Zifratutako mezuen historiala beste gailuetan eskuragarri egotea ez baduzu nahi, .", + "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Mezuen berreskuratze segurua ezartzen ez baduzu, mezu seguruen historiala galduko duzu saioa amaitzean.", + "If you don't want to set this up now, you can later in Settings.": "Ez baduzu hau orain ezarri nahi, gero ere egin dezakezu ezarpenetan." } From 18386ef75a2d0d84334da654c9a84e37c557f941 Mon Sep 17 00:00:00 2001 From: csybr Date: Mon, 10 Dec 2018 21:24:56 +0000 Subject: [PATCH 0024/1528] Translated using Weblate (Norwegian Nynorsk) Currently translated at 87.0% (1215 of 1395 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/nn/ --- src/i18n/strings/nn.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/i18n/strings/nn.json b/src/i18n/strings/nn.json index c00189aa47..fa4d5f60c6 100644 --- a/src/i18n/strings/nn.json +++ b/src/i18n/strings/nn.json @@ -1141,7 +1141,7 @@ "Export E2E room keys": "Hent E2E-romnyklar ut", "You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "Det kan henda at du stilte dei inn på ein annan klient enn Riot. Du kan ikkje stilla på dei i Riot men dei gjeld framleis", "Key share requests are sent to your other devices automatically. If you rejected or dismissed the key share request on your other devices, click here to request the keys for this session again.": "Nykeldelingsførespurnader vert sende til dei andre einingane dine av seg sjølv. Viss du sa nei til eller avviste førespurnadene på dei andre einingane, klikk her for å beda om nyklane for denne øykta på nytt.", - "Jump to read receipt": "Hopp til lest-lappen", + "Jump to read receipt": "Hopp til lesen-lappen", "Filter room members": "Filtrer rommedlemer", "inline-code": "kode-i-tekst", "block-quote": "blokk-sitat", @@ -1210,7 +1210,7 @@ "Failed to set direct chat tag": "Fekk ikkje til å setja direktesamtale-merke", "Failed to remove tag %(tagName)s from room": "Fekk ikkje til å fjerna merket %(tagName)s frå rommet", "Failed to add tag %(tagName)s to room": "Fekk ikkje til å leggja merket %(tagName)s til i rommet", - "Hide read receipts": "Gøym lest-lappar", + "Hide read receipts": "Gøym lesen-lappar", "For security, logging out will delete any end-to-end encryption keys from this browser. If you want to be able to decrypt your conversation history from future Riot sessions, please export your room keys for safe-keeping.": "Av sikkerheitsmessige grunnar vil det å logga ut sletta alle ende-til-ende-krypteringsnyklar frå nettlesaren. Viss du vil kunna dekryptera samtalehistoria di på framtidige Riot-øykter, ver venleg og hent ut romnyklande dine og tak vare på dei.", "This process allows you to export the keys for messages you have received in encrypted rooms to a local file. You will then be able to import the file into another Matrix client in the future, so that client will also be able to decrypt these messages.": "Dette tillèt deg å henta nyklane for meldingar du har sendt i krypterte rom ut til ei lokal fil. Då kan du henta fila inn til ein annan Matrix-klient i framtida, slik at den klienten òg kan dekryptera meldingane.", "The exported file will allow anyone who can read it to decrypt any encrypted messages that you can see, so you should be careful to keep it secure. To help with this, you should enter a passphrase below, which will be used to encrypt the exported data. It will only be possible to import the data by using the same passphrase.": "Å henta filen ut tillèt kven som helst som kan lesa ho å dekryptera alle krypterte meldingar du kan sjå, so du bør passa på å halda ho trygg. For å hjelpa til med dette bør du skriva ei passetning inn i feltet under, som vil brukast til å kryptere den uthenta dataen. Det vil berre vera mogeleg å henta dataen inn med den same passetninga.", From 4074a3c14c27519831043dbc1bc608a8e5e036ed Mon Sep 17 00:00:00 2001 From: Karol Kosek Date: Mon, 10 Dec 2018 23:17:51 +0000 Subject: [PATCH 0025/1528] Translated using Weblate (Polish) Currently translated at 91.3% (1275 of 1395 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/pl/ --- src/i18n/strings/pl.json | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/pl.json b/src/i18n/strings/pl.json index 791d88ba3d..cf97027da8 100644 --- a/src/i18n/strings/pl.json +++ b/src/i18n/strings/pl.json @@ -1279,5 +1279,15 @@ "Continue With Encryption Disabled": "Kontynuuj Z Wyłączonym Szyfrowaniem", "Capitalization doesn't help very much": "Kapitalizacja nie pomaga bardzo", "This is a top-10 common password": "To jest 10 najpopularniejszych haseł", - "This is a top-100 common password": "To jest 100 najpopularniejszych haseł" + "This is a top-100 common password": "To jest 100 najpopularniejszych haseł", + "You are currently using Riot anonymously as a guest.": "Używasz obecnie Riot anonimowo jako gość.", + "If you would like to create a Matrix account you can register now.": "Jeśli chcesz utworzyć konto Matrix, możesz zarejestrować się teraz.", + "Enter Recovery Key": "Wprowadź Klucz Odzyskiwania", + "This looks like a valid recovery key!": "To wygląda na prawidłowy klucz odzyskiwania!", + "Not a valid recovery key": "Nieprawidłowy klucz odzyskiwania", + "If you don't want to set this up now, you can later in Settings.": "Jeśli nie chcesz tego teraz ustawiać, możesz to zrobić później w Ustawieniach.", + "Retry": "Ponów", + "Create Key Backup": "Stwórz kopię zapasową klucza", + "Recovery Key": "Przywróć Klucz", + "Backup created": "Stworzono kopię zapasową" } From 3a9418b6df51328eba23c8d8f116eb91cbd7a77e Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Wed, 12 Dec 2018 03:06:17 +0000 Subject: [PATCH 0026/1528] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (1397 of 1397 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/zh_Hant/ --- src/i18n/strings/zh_Hant.json | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/zh_Hant.json b/src/i18n/strings/zh_Hant.json index 9485ea4f78..0a94a8062f 100644 --- a/src/i18n/strings/zh_Hant.json +++ b/src/i18n/strings/zh_Hant.json @@ -1413,5 +1413,16 @@ "You do not have permission to invite people to this room.": "您沒有權限邀請夥伴到此聊天室。", "User %(user_id)s does not exist": "使用者 %(user_id)s 不存在", "Unknown server error": "未知的伺服器錯誤", - "Failed to load group members": "載入群組成員失敗" + "Failed to load group members": "載入群組成員失敗", + "Show a reminder to enable Secure Message Recovery in encrypted rooms": "顯示在已加密的聊天室中啟用安全訊息復原的提醒", + "Messages containing @room": "包含 @room 的訊息", + "Encrypted messages in one-to-one chats": "在一對一的聊天中的加密訊息", + "Encrypted messages in group chats": "在群組聊天中的已加密訊息", + "Secure Message Recovery": "安全訊息復原", + "If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.": "如果您登出或使用其他裝置,您將會遺失您的安全訊息歷史。要避免發生這種事,請設定安全訊息復原。", + "Don't ask again": "不要再次詢問", + "Set up": "設定", + "If you don't want encrypted message history to be available on other devices, .": "如果您不想要在其他裝置上也可以看到已加密的訊息歷史,可以。", + "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "在沒有設定安全訊息復原的情況下,您將會在登出時遺失您的安全訊息歷史。", + "If you don't want to set this up now, you can later in Settings.": "如果您不想立刻進行設定,您稍後可以在設定中進行。" } From 175dad32579fb65eb2d216030c2ba987683e6924 Mon Sep 17 00:00:00 2001 From: Szimszon Date: Wed, 12 Dec 2018 07:36:15 +0000 Subject: [PATCH 0027/1528] Translated using Weblate (Hungarian) Currently translated at 100.0% (1397 of 1397 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/hu/ --- src/i18n/strings/hu.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json index c54f8ffe27..3c9657da1b 100644 --- a/src/i18n/strings/hu.json +++ b/src/i18n/strings/hu.json @@ -1423,5 +1423,8 @@ "Set up": "Beállítás", "If you don't want encrypted message history to be available on other devices, .": "Ha más eszközön nem szeretnél hozzáférni a titkosított üzeneteidhez akkor .", "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "A Biztonságos Üzenet Visszaállítás beállítása nélkül kijelentkezés után elveszted a hozzáférést a titkosított üzeneteidhez.", - "If you don't want to set this up now, you can later in Settings.": "Ha most nem akarod beállítani, később a Beállításoknál megteheted." + "If you don't want to set this up now, you can later in Settings.": "Ha most nem akarod beállítani, később a Beállításoknál megteheted.", + "Messages containing @room": "Az üzenetek „@room”-ot tartalmaznak", + "Encrypted messages in one-to-one chats": "Titkosított üzenetek közvetlen csevegésekben", + "Encrypted messages in group chats": "Titkosított üzenetek a csoportos beszélgetésekben" } From b15ab07264de0e8b4bebf1b9d7bb268f3c1362f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20C?= Date: Wed, 12 Dec 2018 08:02:57 +0000 Subject: [PATCH 0028/1528] Translated using Weblate (French) Currently translated at 100.0% (1397 of 1397 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/fr/ --- src/i18n/strings/fr.json | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json index 0b35a53aef..b194f23ff8 100644 --- a/src/i18n/strings/fr.json +++ b/src/i18n/strings/fr.json @@ -1070,7 +1070,7 @@ "Monday": "Lundi", "All messages (noisy)": "Tous les messages (fort)", "Enable them now": "Les activer maintenant", - "Messages containing my user name": "Message contenant mon nom d'utilisateur", + "Messages containing my user name": "Messages contenant mon nom d'utilisateur", "Toolbox": "Boîte à outils", "Collecting logs": "Récupération des journaux", "more": "plus", @@ -1423,5 +1423,8 @@ "Set up": "Configurer", "If you don't want encrypted message history to be available on other devices, .": "Si vous ne souhaitez pas que l'historique de vos messages chiffrés soit disponible sur d'autres appareils, .", "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Si vous ne configurez pas la récupération de messages sécurisée, vous perdrez l'historique de vos messages sécurisés quand vous vous déconnectez.", - "If you don't want to set this up now, you can later in Settings.": "Si vous ne voulez pas le configurer maintenant, vous pouvez le faire plus tard dans les paramètres." + "If you don't want to set this up now, you can later in Settings.": "Si vous ne voulez pas le configurer maintenant, vous pouvez le faire plus tard dans les paramètres.", + "Messages containing @room": "Messages contenant @room", + "Encrypted messages in one-to-one chats": "Messages chiffrés dans les discussions directes", + "Encrypted messages in group chats": "Messages chiffrés dans les discussions de groupe" } From 1283653bc91f8ea4cde0b4956666f1cc7e990f35 Mon Sep 17 00:00:00 2001 From: Besnik Bleta Date: Wed, 12 Dec 2018 15:04:55 +0000 Subject: [PATCH 0029/1528] Translated using Weblate (Albanian) Currently translated at 99.3% (1388 of 1397 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/sq/ --- src/i18n/strings/sq.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/sq.json b/src/i18n/strings/sq.json index d6356caa4e..468f26278b 100644 --- a/src/i18n/strings/sq.json +++ b/src/i18n/strings/sq.json @@ -1394,5 +1394,8 @@ "Set up": "Rregulloje", "If you don't want encrypted message history to be available on other devices, .": "Nëse s’doni që historiku i mesazheve të fshehtëzuar të gjendet në pajisje të tjera, .", "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Po s’rregulluat Rimarrje Mesazhesh të Parrezik, do të humbni historikun e mesazheve të parrezik, kur të dilni nga llogaria.", - "If you don't want to set this up now, you can later in Settings.": "Nëse s’doni ta rregulloni tani këtë, mund ta bëni më vonë që nga Rregullimet." + "If you don't want to set this up now, you can later in Settings.": "Nëse s’doni ta rregulloni tani këtë, mund ta bëni më vonë që nga Rregullimet.", + "Messages containing @room": "Mesazhe që përmbajnë @room", + "Encrypted messages in one-to-one chats": "Mesazhe të fshehtëzuar në fjalosje tek-për-tek", + "Encrypted messages in group chats": "Mesazhe të fshehtëzuar në fjalosje në grup" } From 17347534d1d7b4954de0356d0c143c4b15f507a1 Mon Sep 17 00:00:00 2001 From: Tirifto Date: Wed, 12 Dec 2018 14:09:01 +0000 Subject: [PATCH 0030/1528] Translated using Weblate (Esperanto) Currently translated at 82.7% (1156 of 1397 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/eo/ --- src/i18n/strings/eo.json | 46 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/eo.json b/src/i18n/strings/eo.json index aad2c0de8e..776c0dde7b 100644 --- a/src/i18n/strings/eo.json +++ b/src/i18n/strings/eo.json @@ -1124,5 +1124,49 @@ "%(senderName)s removed the main address for this room.": "%(senderName)s forigis la ĉefan adreson de la ĉambro.", "Please contact your service administrator to continue using the service.": "Bonvolu kontakti administranton de la servo por daŭre uzadi la servon.", "Pin unread rooms to the top of the room list": "Fiksi nelegitajn ĉambrojn supre de la listo", - "Pin rooms I'm mentioned in to the top of the room list": "Fiksi ĉambrojn kun mencioj de mia nomo supre de la listo" + "Pin rooms I'm mentioned in to the top of the room list": "Fiksi ĉambrojn kun mencioj de mia nomo supre de la listo", + "A call is currently being placed!": "Alia voko nun dumas!", + "Unable to load! Check your network connectivity and try again.": "Ne eblas enlegi! Kontrolu vian retan konekton kaj reprovu.", + "Failed to invite users to the room:": "Malsukcesis inviti uzantojn al la ĉambro:", + "Opens the Developer Tools dialog": "Maflermas evoluigistan interagujon", + "This homeserver has hit its Monthly Active User limit.": "Tiu ĉi hejmservilo atingis sian monatan limon de aktivaj uzantoj.", + "This homeserver has exceeded one of its resource limits.": "Tiu ĉi hejmservilo superis je unu el siaj risurcaj limoj.", + "Unable to connect to Homeserver. Retrying...": "Ne povas konektiĝi al hejmservilo. Reprovanta…", + "You do not have permission to invite people to this room.": "Vi ne havas permeson inviti homojn al la ĉambro.", + "User %(user_id)s does not exist": "Uzanto %(user_id)s ne ekzistas", + "Unknown server error": "Nekonata servila eraro", + "Use a few words, avoid common phrases": "Uzu malmultajn vortojn, kaj evitu oftajn frazojn", + "Avoid repeated words and characters": "Evitu ripetadon de vortoj kaj signoj", + "Avoid sequences": "Evitu sinsekvojn", + "Avoid recent years": "Evitu freŝdatajn jarojn", + "Avoid years that are associated with you": "Evitu jarojn, kiuj ligiĝas al vi", + "Avoid dates and years that are associated with you": "Evitu datojn kaj jarojn, kiuj ligiĝas al vi", + "Capitalization doesn't help very much": "Majusklado ne helpas multe", + "All-uppercase is almost as easy to guess as all-lowercase": "Plena majusklado estas preskaŭ same facile konjektebla kiel plena minusklado", + "Reversed words aren't much harder to guess": "Renversitaj vortoj ne estas multe pli malfacile konjekteblaj", + "Predictable substitutions like '@' instead of 'a' don't help very much": "Facile diveneblaj anstataŭigoj, kiel ‹@› anstataŭ ‹a›, ne helpas multe", + "Add another word or two. Uncommon words are better.": "Aldonu alian vorton aŭ du. Maloftaj vortoj pli bonas.", + "Repeats like \"aaa\" are easy to guess": "Ripetoj kiel «aaa» estas facile diveneblaj", + "Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Ripetoj kiel «abcabcabc» estas apenaŭ pli bonaj ol nur «abc»", + "Sequences like abc or 6543 are easy to guess": "Sinsekvoj kiel «abc» aŭ «6543» estas facile diveneblaj", + "Recent years are easy to guess": "Freŝdataj jaroj estas facile diveneblaj", + "Dates are often easy to guess": "Datoj estas ofte facile diveneblaj", + "This is a top-10 common password": "Ĉi tiu pasvorto estas inter la 10 plej oftaj", + "This is a top-100 common password": "Ĉi tiu pasvorto estas inter la 100 plej oftaj", + "This is a very common password": "Ĉi tiu pasvorto estas tre ofta", + "This is similar to a commonly used password": "Ĉi tiu pasvorto similas iun tre oftan", + "A word by itself is easy to guess": "Memstara vorto estas facile divenebla", + "Names and surnames by themselves are easy to guess": "Ankaŭ nomoj familiaj kaj individiuaj estas memstare facile diveneblaj", + "Common names and surnames are easy to guess": "Oftaj nomoj familiaj kaj individuaj estas facile diveneblaj", + "There was an error joining the room": "Okazis eraro dum aliĝo al la ĉambro", + "Sorry, your homeserver is too old to participate in this room.": "Pardonu, via hejmservilo estas tro malnova por partoprenado en la ĉambro.", + "Please contact your homeserver administrator.": "Bonvolu kontakti la administranton de via hejmservilo.", + "Increase performance by only loading room members on first view": "Plibonigu efikecon per nur unuafoja enlego de ĉambranoj", + "Backup of encryption keys to server": "Savkopio de ĉifroŝlosiloj al servilo", + "Show a reminder to enable Secure Message Recovery in encrypted rooms": "Montri memorigilon por ŝalti Sekuran Ricevon de Mesaĝoj en ĉifrataj ĉambroj", + "Show developer tools": "Montri evolugistajn ilojn", + "Messages containing @room": "Mesaĝoj enhavantaj @room", + "Encrypted messages in one-to-one chats": "Ĉifritaj mesaĝoj en duopaj babiloj", + "Encrypted messages in group chats": "Ĉifritaj mesaĝoj en grupaj babiloj", + "Delete Backup": "Forigi savkopion" } From 7009a20950f60827c4fca49dfb85f2a49866bb42 Mon Sep 17 00:00:00 2001 From: Szimszon Date: Wed, 12 Dec 2018 07:36:41 +0000 Subject: [PATCH 0031/1528] Translated using Weblate (Hungarian) Currently translated at 100.0% (1398 of 1398 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/hu/ --- src/i18n/strings/hu.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json index 3c9657da1b..6531e3b5a0 100644 --- a/src/i18n/strings/hu.json +++ b/src/i18n/strings/hu.json @@ -1426,5 +1426,6 @@ "If you don't want to set this up now, you can later in Settings.": "Ha most nem akarod beállítani, később a Beállításoknál megteheted.", "Messages containing @room": "Az üzenetek „@room”-ot tartalmaznak", "Encrypted messages in one-to-one chats": "Titkosított üzenetek közvetlen csevegésekben", - "Encrypted messages in group chats": "Titkosított üzenetek a csoportos beszélgetésekben" + "Encrypted messages in group chats": "Titkosított üzenetek a csoportos beszélgetésekben", + "That doesn't look like a valid email address": "Ez nem úgy néz ki, mint egy érvényes e-mail cím" } From f8655af2f08bc02d9e934e1c87090c405235f0f9 Mon Sep 17 00:00:00 2001 From: Osoitz Date: Wed, 12 Dec 2018 20:09:49 +0000 Subject: [PATCH 0032/1528] Translated using Weblate (Basque) Currently translated at 100.0% (1398 of 1398 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/eu/ --- src/i18n/strings/eu.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/eu.json b/src/i18n/strings/eu.json index 9218a2a814..2fc08d0fcd 100644 --- a/src/i18n/strings/eu.json +++ b/src/i18n/strings/eu.json @@ -1421,5 +1421,9 @@ "Set up": "Ezarri", "If you don't want encrypted message history to be available on other devices, .": "Zifratutako mezuen historiala beste gailuetan eskuragarri egotea ez baduzu nahi, .", "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Mezuen berreskuratze segurua ezartzen ez baduzu, mezu seguruen historiala galduko duzu saioa amaitzean.", - "If you don't want to set this up now, you can later in Settings.": "Ez baduzu hau orain ezarri nahi, gero ere egin dezakezu ezarpenetan." + "If you don't want to set this up now, you can later in Settings.": "Ez baduzu hau orain ezarri nahi, gero ere egin dezakezu ezarpenetan.", + "Messages containing @room": "@room duten mezuak", + "Encrypted messages in one-to-one chats": "Zifratutako mezuak bi pertsonen arteko txatetan", + "Encrypted messages in group chats": "Zifratutako mezuak talde-txatetan", + "That doesn't look like a valid email address": "Horrek ez du baliozko e-mail baten itxurarik" } From a5cf239bd06850aa6d4de6db50a6c51938300d98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20C?= Date: Wed, 12 Dec 2018 08:03:28 +0000 Subject: [PATCH 0033/1528] Translated using Weblate (French) Currently translated at 100.0% (1398 of 1398 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/fr/ --- src/i18n/strings/fr.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json index b194f23ff8..cd99326b4f 100644 --- a/src/i18n/strings/fr.json +++ b/src/i18n/strings/fr.json @@ -1426,5 +1426,6 @@ "If you don't want to set this up now, you can later in Settings.": "Si vous ne voulez pas le configurer maintenant, vous pouvez le faire plus tard dans les paramètres.", "Messages containing @room": "Messages contenant @room", "Encrypted messages in one-to-one chats": "Messages chiffrés dans les discussions directes", - "Encrypted messages in group chats": "Messages chiffrés dans les discussions de groupe" + "Encrypted messages in group chats": "Messages chiffrés dans les discussions de groupe", + "That doesn't look like a valid email address": "Cela ne ressemble pas à une adresse e-mail valide" } From dd8ef820d9d9a0713d9dead412a3d8fed3c2fd44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20C?= Date: Thu, 13 Dec 2018 09:06:29 +0000 Subject: [PATCH 0034/1528] Translated using Weblate (French) Currently translated at 100.0% (1398 of 1398 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/fr/ --- src/i18n/strings/fr.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json index cd99326b4f..0164913651 100644 --- a/src/i18n/strings/fr.json +++ b/src/i18n/strings/fr.json @@ -1303,7 +1303,7 @@ "Pin rooms I'm mentioned in to the top of the room list": "Épingler les salons où l'on me mentionne en haut de la liste des salons", "If you would like to create a Matrix account you can register now.": "Si vous souhaitez créer un compte Matrix, vous pouvez vous inscrire maintenant.", "You are currently using Riot anonymously as a guest.": "Vous utilisez Riot de façon anonyme en tant qu'invité.", - "Please review and accept all of the homeserver's policies": "Veuillez lire et accepter toutes les polices du serveur d'accueil", + "Please review and accept all of the homeserver's policies": "Veuillez lire et accepter toutes les politiques du serveur d'accueil", "To avoid losing your chat history, you must export your room keys before logging out. You will need to go back to the newer version of Riot to do this": "Pour éviter de perdre l'historique de vos discussions, vous devez exporter vos clés avant de vous déconnecter. Vous devez revenir à une version plus récente de Riot pour pouvoir le faire", "You've previously used a newer version of Riot on %(host)s. To use this version again with end to end encryption, you will need to sign out and back in again. ": "Vous avez utilisé une version plus récente de Riot sur %(host)s. Pour utiliser à nouveau cette version avec le chiffrement de bout à bout, vous devez vous déconnecter et vous reconnecter. ", "Incompatible Database": "Base de données incompatible", From e61f7bca8e23179646fed255e77f56662678bdb4 Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Fri, 14 Dec 2018 01:34:37 +0000 Subject: [PATCH 0035/1528] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (1404 of 1404 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/zh_Hant/ --- src/i18n/strings/zh_Hant.json | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/zh_Hant.json b/src/i18n/strings/zh_Hant.json index 0a94a8062f..07b4f892ca 100644 --- a/src/i18n/strings/zh_Hant.json +++ b/src/i18n/strings/zh_Hant.json @@ -1424,5 +1424,13 @@ "Set up": "設定", "If you don't want encrypted message history to be available on other devices, .": "如果您不想要在其他裝置上也可以看到已加密的訊息歷史,可以。", "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "在沒有設定安全訊息復原的情況下,您將會在登出時遺失您的安全訊息歷史。", - "If you don't want to set this up now, you can later in Settings.": "如果您不想立刻進行設定,您稍後可以在設定中進行。" + "If you don't want to set this up now, you can later in Settings.": "如果您不想立刻進行設定,您稍後可以在設定中進行。", + "That doesn't look like a valid email address": "看起來不像有效的電子郵件地址", + "Invalid configuration: Cannot supply a default homeserver URL and a default server name": "無效的設定:無法提供預設的家伺服器 URL 與預設的伺服器名稱", + "Unknown error discovering homeserver": "探索家伺服器時發生未知的錯誤", + "%(count)s Notifications|other": "%(count)s 個通知", + "%(count)s Notifications|one": "%(count)s 個通知", + "Invalid identity server discovery response": "無效的身份伺服器探索回應", + "General failure": "一般錯誤", + "Unknown failure discovering homeserver": "探索家伺服器時發生未知的失敗" } From d958a4fc1f276557d05c6ca339c381e87f2e0535 Mon Sep 17 00:00:00 2001 From: Szimszon Date: Fri, 14 Dec 2018 07:13:43 +0000 Subject: [PATCH 0036/1528] Translated using Weblate (Hungarian) Currently translated at 100.0% (1405 of 1405 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/hu/ --- src/i18n/strings/hu.json | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json index 6531e3b5a0..25e3c7ca84 100644 --- a/src/i18n/strings/hu.json +++ b/src/i18n/strings/hu.json @@ -1427,5 +1427,14 @@ "Messages containing @room": "Az üzenetek „@room”-ot tartalmaznak", "Encrypted messages in one-to-one chats": "Titkosított üzenetek közvetlen csevegésekben", "Encrypted messages in group chats": "Titkosított üzenetek a csoportos beszélgetésekben", - "That doesn't look like a valid email address": "Ez nem úgy néz ki, mint egy érvényes e-mail cím" + "That doesn't look like a valid email address": "Ez nem úgy néz ki, mint egy érvényes e-mail cím", + "Only use lower case letters, numbers and '=_-./'": "Csak kisbetűket, számokat és „=_-./” jelet használj", + "Checking...": "Ellenőrzés...", + "Invalid configuration: Cannot supply a default homeserver URL and a default server name": "Hibás konfiguráció: Az alapértelmezett Matrix szerver URL és az alapértelmezett szerver név nem tamogatott", + "Unknown error discovering homeserver": "A mátrix szerver felderítésénél ismeretlen hiba történt", + "%(count)s Notifications|other": "%(count)s értesítés", + "%(count)s Notifications|one": "%(count)s értesítés", + "Invalid identity server discovery response": "Azonosító szerver felderítésére érkezett válasz érvénytelen", + "General failure": "Általános hiba", + "Unknown failure discovering homeserver": "Mátrix szerver felderítésénél ismeretlen hiba történt" } From ef1ad6f4b6278f9454f6d1efec3f87dec11c27aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20C?= Date: Fri, 14 Dec 2018 08:23:56 +0000 Subject: [PATCH 0037/1528] Translated using Weblate (French) Currently translated at 100.0% (1405 of 1405 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/fr/ --- src/i18n/strings/fr.json | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json index 0164913651..0c78bb1da8 100644 --- a/src/i18n/strings/fr.json +++ b/src/i18n/strings/fr.json @@ -1427,5 +1427,14 @@ "Messages containing @room": "Messages contenant @room", "Encrypted messages in one-to-one chats": "Messages chiffrés dans les discussions directes", "Encrypted messages in group chats": "Messages chiffrés dans les discussions de groupe", - "That doesn't look like a valid email address": "Cela ne ressemble pas à une adresse e-mail valide" + "That doesn't look like a valid email address": "Cela ne ressemble pas à une adresse e-mail valide", + "Only use lower case letters, numbers and '=_-./'": "Utiliser uniquement des lettres minuscules, des chiffres et les symboles =_-./", + "Checking...": "Vérification…", + "Invalid configuration: Cannot supply a default homeserver URL and a default server name": "Configuration non valide : Impossible de fournir une URL de serveur d'accueil par défaut et un nom de serveur par défaut", + "Unknown error discovering homeserver": "Erreur inconnue lors de la découverte du serveur d'accueil", + "%(count)s Notifications|other": "%(count)s notifications", + "%(count)s Notifications|one": "%(count)s notification", + "Invalid identity server discovery response": "Réponse non valide lors de la découverte du serveur d'identité", + "General failure": "Échec général", + "Unknown failure discovering homeserver": "Échec inconnu lors de la découverte du serveur d'accueil" } From 379906cad8850ccc5265a29483cb75ab554399e2 Mon Sep 17 00:00:00 2001 From: random Date: Fri, 14 Dec 2018 11:11:48 +0000 Subject: [PATCH 0038/1528] Translated using Weblate (Italian) Currently translated at 100.0% (1405 of 1405 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/it/ --- src/i18n/strings/it.json | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/it.json b/src/i18n/strings/it.json index c7c0fe7ca2..0d910bba91 100644 --- a/src/i18n/strings/it.json +++ b/src/i18n/strings/it.json @@ -1420,5 +1420,18 @@ "Set up": "Imposta", "If you don't want encrypted message history to be available on other devices, .": "Se non vuoi che la cronologia dei messaggi cifrati sia disponibile su altri dispositivi, .", "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Se non imposti il ripristino sicuro dei messaggi, perderai la cronologia sicura dei messaggi quando ti disconnetti.", - "If you don't want to set this up now, you can later in Settings.": "Se non vuoi impostarlo ora, è possibile farlo in seguito nelle impostazioni." + "If you don't want to set this up now, you can later in Settings.": "Se non vuoi impostarlo ora, è possibile farlo in seguito nelle impostazioni.", + "Messages containing @room": "Messaggi contenenti @room", + "Encrypted messages in one-to-one chats": "Messaggi cifrati in chat uno-ad-uno", + "Encrypted messages in group chats": "Messaggi cifrati in chat di gruppo", + "That doesn't look like a valid email address": "Non sembra essere un indirizzo email valido", + "Only use lower case letters, numbers and '=_-./'": "Usa solo lettere minuscole, numeri e '=_-./'", + "Checking...": "Controllo...", + "Invalid configuration: Cannot supply a default homeserver URL and a default server name": "Configurazione non valida: impossibile fornire un URL di homeserver e un nome server predefiniti", + "Unknown error discovering homeserver": "Errore sconosciuto cercando gli homeserver", + "%(count)s Notifications|other": "%(count)s notifiche", + "%(count)s Notifications|one": "%(count)s notifica", + "Invalid identity server discovery response": "Risposta non valida cercando server di identità", + "General failure": "Guasto generale", + "Unknown failure discovering homeserver": "Errore sconosciuto cercando homeserver" } From d9f566cd136ff34761ec3cc58f376cad01ec221e Mon Sep 17 00:00:00 2001 From: Slavi Pantaleev Date: Mon, 17 Dec 2018 01:20:51 +0000 Subject: [PATCH 0039/1528] Translated using Weblate (Bulgarian) Currently translated at 100.0% (1405 of 1405 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/bg/ --- src/i18n/strings/bg.json | 102 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/bg.json b/src/i18n/strings/bg.json index 0cc724624c..57e369627c 100644 --- a/src/i18n/strings/bg.json +++ b/src/i18n/strings/bg.json @@ -1331,5 +1331,105 @@ "Names and surnames by themselves are easy to guess": "Имена и фамилии сами по себе си са лесни за отгатване", "Common names and surnames are easy to guess": "Често срещани имена и фамилии са лесни за отгатване", "Use a longer keyboard pattern with more turns": "Използвайте по-дълга клавиатурна последователност с повече разклонения", - "Backup of encryption keys to server": "Резервно копие на ключовете за шифроване на сървъра" + "Backup of encryption keys to server": "Резервно копие на ключовете за шифроване на сървъра", + "Show a reminder to enable Secure Message Recovery in encrypted rooms": "Покажи напомняне за включване на Защитено Възстановяване на Съобщения в шифровани стаи", + "Messages containing @room": "Съобщения съдържащи @room", + "Encrypted messages in one-to-one chats": "Шифровани съобщения в 1-на-1 чатове", + "Encrypted messages in group chats": "Шифровани съобщения в групови чатове", + "Delete Backup": "Изтрий резервното копие", + "Delete your backed up encryption keys from the server? You will no longer be able to use your recovery key to read encrypted message history": "Изтриване на резервното копие на ключовете за шифроване от сървъра? Вече няма да може да използвате възстановителния ключ за да разчитате шифрованите съобщения", + "Delete backup": "Изтрий резервното копие", + "Unable to load key backup status": "Неуспешно зареждане на състоянието на резервното копие на ключа", + "This device is uploading keys to this backup": "Това устройство качва ключовете си в това резервно копие", + "This device is not uploading keys to this backup": "Това устройство не качва ключовете си в това резервно копие", + "Backup has a valid signature from this device": "Резервното копие има валиден подпис за това устройство", + "Backup has a valid signature from verified device x": "Резервното копие има валиден подпис от потвърдено устройство x", + "Backup has a valid signature from unverified device ": "Резервното копие има валиден подпис от непотвърдено устройство ", + "Backup has an invalid signature from verified device ": "Резервното копие има невалиден подпис от потвърдено устройство ", + "Backup has an invalid signature from unverified device ": "Резервното копие има невалиден подпис от непотвърдено устройство ", + "Backup is not signed by any of your devices": "Резервното копие не е подписано от нито едно Ваше устройство", + "Backup version: ": "Версия на резервното копие: ", + "Algorithm: ": "Алгоритъм: ", + "Restore backup": "Възстанови резервно копие", + "No backup is present": "Няма налично резервно копие", + "Start a new backup": "Направи ново резервно копие", + "The following files cannot be uploaded:": "Следните файлове не могат да бъдат качени:", + "Secure Message Recovery": "Защитено Възстановяване на Съобщения", + "If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.": "Ако излезете от профила си или използвате друго устройство, ще загубите защитената история на съобщенията. За да предотвратите това, настройте Защитено Възстановяване на Съобщения.", + "Don't ask again": "Не питай пак", + "Set up": "Настрой", + "Please review and accept all of the homeserver's policies": "Моля прегледайте и приемете всички политики на сървъра", + "Failed to load group members": "Неуспешно зареждане на членовете на групата", + "That doesn't look like a valid email address": "Това не изглежда като валиден имейл адрес", + "To avoid losing your chat history, you must export your room keys before logging out. You will need to go back to the newer version of Riot to do this": "За да избегнете загубата на чат история, трябва да експортирате ключовете на стаята преди да излезете от профила си. Ще трябва да се върнете към по-новата версия на Riot за да направите това", + "You've previously used a newer version of Riot on %(host)s. To use this version again with end to end encryption, you will need to sign out and back in again. ": "Преди време сте използвали по-нова версия на Riot на %(host)s. За да използвате тази версия отново с шифроване от край до край, ще е необходимо да излезете от профила си и да влезете отново. ", + "Incompatible Database": "Несъвместима база данни", + "Continue With Encryption Disabled": "Продължи с изключено шифроване", + "Only use lower case letters, numbers and '=_-./'": "Използвайте само малки букви, цифри и '=_-./'", + "Checking...": "Проверяване...", + "Unable to load backup status": "Неуспешно зареждане на състоянието на резервното копие", + "Unable to restore backup": "Неуспешно възстановяване на резервно копие", + "No backup found!": "Не е открито резервно копие!", + "Backup Restored": "Резервното копие е възстановено", + "Failed to decrypt %(failedCount)s sessions!": "Неуспешно разшифроване на %(failedCount)s сесии!", + "Restored %(sessionCount)s session keys": "Възстановени бяха %(sessionCount)s сесийни ключа", + "Enter Recovery Passphrase": "Въведете парола за възстановяване", + "Access your secure message history and set up secure messaging by entering your recovery passphrase.": "Получете достъп до защитената история на съобщенията и настройте защитен чат, чрез въвеждане на паролата за възстановяване.", + "Next": "Напред", + "If you've forgotten your recovery passphrase you can use your recovery key or set up new recovery options": "Ако сте забравили паролата за възстановяване, можете да използвате ключа за възстановяване или да настройте други варианти за възстановяване", + "Enter Recovery Key": "Въведете ключ за възстановяване", + "This looks like a valid recovery key!": "Това изглежда като валиден ключ за възстановяване!", + "Not a valid recovery key": "Не е валиден ключ за възстановяване", + "Access your secure message history and set up secure messaging by entering your recovery key.": "Получете достъп до защитената история на съобщенията и настройте защитен чат, чрез въвеждане на ключа за възстановяване.", + "If you've forgotten your recovery passphrase you can ": "Ако сте забравили паролата за възстановяване, може да ", + "Invalid configuration: Cannot supply a default homeserver URL and a default server name": "Невалидна конфигурация: не може да бъдат намерени име и URL адрес по подразбиране на сървъра", + "Unknown error discovering homeserver": "Непозната грешка при откриването на конфигурацията за сървъра", + "%(count)s Notifications|other": "%(count)s известия", + "%(count)s Notifications|one": "%(count)s известие", + "File is too big. Maximum file size is %(fileSize)s": "Файлът е прекалено голям. Максималният размер е %(fileSize)s", + "Key Backup": "Резервно копие на ключа", + "Invalid homeserver discovery response": "Невалиден отговор по време на откриването на конфигурацията за сървъра", + "Invalid identity server discovery response": "Невалиден отговор по време на откриването на конфигурацията за сървъра за самоличност", + "General failure": "Обща грешка", + "Failed to perform homeserver discovery": "Неуспешно откриване на конфигурацията за сървъра", + "Unknown failure discovering homeserver": "Непозната грешка при откриването на конфигурацията за сървъра", + "Sign in with single sign-on": "Влезте посредством single-sign-on", + "Great! This passphrase looks strong enough.": "Чудесно! Паролата изглежда сигурна.", + "Secure your encrypted message history with a Recovery Passphrase.": "Защитете историята на шифрованите съобщения с парола за възстановяване.", + "You'll need it if you log out or lose access to this device.": "Ще е необходимо, ако излезете от профила си или загубите достъп до това устройство.", + "Enter a passphrase...": "Въведете парола...", + "If you don't want encrypted message history to be available on other devices, .": "Ако не искате шифрованата история на съобщенията да бъде достъпна на други устройства, .", + "Or, if you don't want to create a Recovery Passphrase, skip this step and .": "Ако пък не искате да създавате парола за възстановяване, пропуснете тази стъпка и .", + "That matches!": "Това съвпада!", + "That doesn't match.": "Това не съвпада.", + "Go back to set it again.": "Върнете се и го настройте пак.", + "Type in your Recovery Passphrase to confirm you remember it. If it helps, add it to your password manager or store it somewhere safe.": "Въведете паролата за възстановяване за да потвърдите, че я помните. Ако ще помогне, запазете я в паролите на браузъра си или на друго сигурно място.", + "Repeat your passphrase...": "Повторете паролата...", + "As a safety net, you can use it to restore your encrypted message history if you forget your Recovery Passphrase.": "Като предпазна мярка, можете да го използвате за възстановяване на шифрованата история на съобщенията, в случай че сте забравили паролата за възстановяване.", + "As a safety net, you can use it to restore your encrypted message history.": "Като предпазна мярка, можете да го използвате за възстановяване на шифрованата история на съобщенията.", + "Make a copy of this Recovery Key and keep it safe.": "Направете копие на ключа за възстановяване и го пазете на сигурно място.", + "Your Recovery Key": "Вашия ключ за възстановяване", + "Copy to clipboard": "Копирай в клипборд", + "Download": "Свали", + "I've made a copy": "Направих копие", + "Your Recovery Key has been copied to your clipboard, paste it to:": "Ключа Ви за възстановяване беше копиран в клипборда, поставете го в:", + "Your Recovery Key is in your Downloads folder.": "Ключът Ви за възстановяване е в папка Изтеглени.", + "Print it and store it somewhere safe": "Принтирайте гои го съхранявайте на безопасно място", + "Save it on a USB key or backup drive": "Запазете го на USB или резервен диск", + "Copy it to your personal cloud storage": "Копирайте го в персонално облачно пространство", + "Got it": "Разбрах", + "Backup created": "Резервното копие бе създадено", + "Your encryption keys are now being backed up to your Homeserver.": "Прави се резервно копие на ключовете Ви за шифроване върху сървъра.", + "Without setting up Secure Message Recovery, you won't be able to restore your encrypted message history if you log out or use another device.": "Без настроено Защитено Възстановяване на Съобщения, няма да може да възстановите шифрованата история на съобщенията, в случай че излезете от профила си или използвате друго устройство.", + "Set up Secure Message Recovery": "Настрой Защитено Възстановяване на Съобщения", + "Create a Recovery Passphrase": "Създай парола за възстановяване", + "Confirm Recovery Passphrase": "Потвърди парола за възстановяване", + "Recovery Key": "Ключ за възстановяване", + "Keep it safe": "Пазете го в безопасност", + "Backing up...": "Създаване на резервно копие...", + "Create Key Backup": "Създай резервно копие на ключа", + "Unable to create key backup": "Неуспешно създаване на резервно копие на ключа", + "Retry": "Опитай пак", + "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Без настроено Защитено Възстановяване на Съобщения, ще загубите защитената история на съобщенията когато излезете от профила си.", + "If you don't want to set this up now, you can later in Settings.": "Ако не искате да настройвате това сега, може и по-късно от Настройки." } From 71a4adf47ddf2a12b76cb63fcad184464c3f1376 Mon Sep 17 00:00:00 2001 From: Besnik Bleta Date: Fri, 14 Dec 2018 07:36:39 +0000 Subject: [PATCH 0040/1528] Translated using Weblate (Albanian) Currently translated at 99.2% (1395 of 1405 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/sq/ --- src/i18n/strings/sq.json | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/sq.json b/src/i18n/strings/sq.json index 468f26278b..788534cfb3 100644 --- a/src/i18n/strings/sq.json +++ b/src/i18n/strings/sq.json @@ -1397,5 +1397,14 @@ "If you don't want to set this up now, you can later in Settings.": "Nëse s’doni ta rregulloni tani këtë, mund ta bëni më vonë që nga Rregullimet.", "Messages containing @room": "Mesazhe që përmbajnë @room", "Encrypted messages in one-to-one chats": "Mesazhe të fshehtëzuar në fjalosje tek-për-tek", - "Encrypted messages in group chats": "Mesazhe të fshehtëzuar në fjalosje në grup" + "Encrypted messages in group chats": "Mesazhe të fshehtëzuar në fjalosje në grup", + "That doesn't look like a valid email address": "Kjo s’duket si adresë email e vlefshme", + "Only use lower case letters, numbers and '=_-./'": "Përdorni vetëm shkronja të vogla, numra dhe '=_-./'", + "Checking...": "Po kontrollohet…", + "Invalid configuration: Cannot supply a default homeserver URL and a default server name": "Formësim i pavlefshëm: S’mund të jepen një URL parazgjedhje për shërbyesin Home dhe një emër parazgjedhje shërbyesi", + "Unknown error discovering homeserver": "Gabim i panjohur gjatë zbulimit të shërbyesit Home", + "%(count)s Notifications|other": "%(count)s Njoftime", + "%(count)s Notifications|one": "%(count)s Njoftim", + "Invalid identity server discovery response": "Përgjigje e pavlefshme zbulimi identiteti shërbyesi", + "Unknown failure discovering homeserver": "Dështim i panjohur gjatë zbulimi shërbyesi Home" } From c34d14436e38c8e853f5d79db4d8cf30eba4dd29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20C?= Date: Fri, 14 Dec 2018 08:26:28 +0000 Subject: [PATCH 0041/1528] Translated using Weblate (French) Currently translated at 100.0% (1405 of 1405 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/fr/ --- src/i18n/strings/fr.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json index 0c78bb1da8..0e91a15eca 100644 --- a/src/i18n/strings/fr.json +++ b/src/i18n/strings/fr.json @@ -1435,6 +1435,6 @@ "%(count)s Notifications|other": "%(count)s notifications", "%(count)s Notifications|one": "%(count)s notification", "Invalid identity server discovery response": "Réponse non valide lors de la découverte du serveur d'identité", - "General failure": "Échec général", - "Unknown failure discovering homeserver": "Échec inconnu lors de la découverte du serveur d'accueil" + "General failure": "Erreur générale", + "Unknown failure discovering homeserver": "Erreur inconnue lors de la découverte du serveur d'accueil" } From e0b03872a0d2578812c6e1f11dcbc5eb5d87bb32 Mon Sep 17 00:00:00 2001 From: Karol Kosek Date: Sat, 15 Dec 2018 17:02:02 +0000 Subject: [PATCH 0042/1528] Translated using Weblate (Polish) Currently translated at 92.7% (1303 of 1405 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/pl/ --- src/i18n/strings/pl.json | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/pl.json b/src/i18n/strings/pl.json index cf97027da8..c472b84f8b 100644 --- a/src/i18n/strings/pl.json +++ b/src/i18n/strings/pl.json @@ -1289,5 +1289,34 @@ "Retry": "Ponów", "Create Key Backup": "Stwórz kopię zapasową klucza", "Recovery Key": "Przywróć Klucz", - "Backup created": "Stworzono kopię zapasową" + "Backup created": "Stworzono kopię zapasową", + "Unable to create key backup": "Nie można utworzyć kopii zapasowej klucza", + "Backing up...": "Tworzenie kopii zapasowych…", + "Create a Recovery Passphrase": "Utwórz hasło odzyskiwania", + "Confirm Recovery Passphrase": "Potwierdź hasło odzyskiwania", + "Download": "Pobierz", + "Copy to clipboard": "Skopiuj do schowka", + "Your Recovery Key": "Twój Klucz Odzyskiwania", + "Enter a passphrase...": "Wprowadź hasło…", + "Key Backup": "Kopia Zapasowa Klucza", + "File is too big. Maximum file size is %(fileSize)s": "Plik jest zbyt duży. Maksymalny rozmiar pliku to %(fileSize)s", + "%(count)s Notifications|other": "%(count)s Powiadomień", + "%(count)s Notifications|one": "%(count)s Powiadomienie", + "Next": "Następny", + "Backup Restored": "Przywrócono Kopię Zapasową", + "No backup found!": "Nie znaleziono kopii zapasowej!", + "Checking...": "Sprawdzanie…", + "Create a new room with the same name, description and avatar": "Utwórz nowy pokój o tej samej nazwie, opisie i awatarze", + "That doesn't look like a valid email address": "To nie wygląda na poprawny adres e-mail", + "was kicked %(count)s times|other": "został(a) wyrzucony(-a) %(count)s razy", + "were kicked %(count)s times|one": "zostali wyrzuceni", + "were kicked %(count)s times|other": "zostali wyrzuceni %(count)s razy", + "was unbanned %(count)s times|one": "został(a) odbanowany(-a)", + "were unbanned %(count)s times|one": "zostali odbanowani", + "was unbanned %(count)s times|other": "został(a) odbanowany(-a) %(count)s razy", + "were unbanned %(count)s times|other": "zostali odbanowani %(count)s razy", + "Please review and accept the policies of this homeserver:": "Przeczytaj i zaakceptuj zasady tego serwera domowego:", + "Upgrade room to version %(ver)s": "Zaktualizuj pokój do wersji %(ver)s", + "Don't ask again": "Nie pytaj ponownie", + "Messages containing @room": "Wiadomości zawierające @room" } From 98afb9399fa3987f41250472381100e4e290cd47 Mon Sep 17 00:00:00 2001 From: Szimszon Date: Tue, 18 Dec 2018 10:34:27 +0000 Subject: [PATCH 0043/1528] Translated using Weblate (Hungarian) Currently translated at 100.0% (1411 of 1411 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/hu/ --- src/i18n/strings/hu.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json index 25e3c7ca84..0ac5bb5fdf 100644 --- a/src/i18n/strings/hu.json +++ b/src/i18n/strings/hu.json @@ -1436,5 +1436,12 @@ "%(count)s Notifications|one": "%(count)s értesítés", "Invalid identity server discovery response": "Azonosító szerver felderítésére érkezett válasz érvénytelen", "General failure": "Általános hiba", - "Unknown failure discovering homeserver": "Mátrix szerver felderítésénél ismeretlen hiba történt" + "Unknown failure discovering homeserver": "Mátrix szerver felderítésénél ismeretlen hiba történt", + "Backup has a valid signature from verified device ": "A mentésnek ellenőrzött eszköztől származó érvényes aláírása van", + "New Recovery Method": "Új Visszaállítási Eljárás", + "A new recovery passphrase and key for Secure Messages has been detected.": "Biztonságos Üzenetekhez való új visszaállítási jelmondatot és kulcsot találtunk.", + "Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "A Biztonságos Üzenetek ezen az eszközön való beállításával az új visszaállítási eljárással lesznek újra titkosítva a régi üzenetek.", + "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Ha nem te állítottad be a visszaállítási eljárást akkor lehet, hogy egy támadó próbálja elérni a fiókodat. Változtasd meg a fiókod jelszavát és állítsd be az új visszaállítási eljárást a Beállításokban amint lehet.", + "Set up Secure Messages": "Biztonságos Üzenetek beállítása", + "Go to Settings": "Irány a Beállítások" } From 618ed725c8efa736815bdec5f7fd6163266613f8 Mon Sep 17 00:00:00 2001 From: Besnik Bleta Date: Tue, 18 Dec 2018 15:31:55 +0000 Subject: [PATCH 0044/1528] Translated using Weblate (Albanian) Currently translated at 99.2% (1401 of 1411 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/sq/ --- src/i18n/strings/sq.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/sq.json b/src/i18n/strings/sq.json index 788534cfb3..da8dc054b2 100644 --- a/src/i18n/strings/sq.json +++ b/src/i18n/strings/sq.json @@ -1406,5 +1406,12 @@ "%(count)s Notifications|other": "%(count)s Njoftime", "%(count)s Notifications|one": "%(count)s Njoftim", "Invalid identity server discovery response": "Përgjigje e pavlefshme zbulimi identiteti shërbyesi", - "Unknown failure discovering homeserver": "Dështim i panjohur gjatë zbulimi shërbyesi Home" + "Unknown failure discovering homeserver": "Dështim i panjohur gjatë zbulimi shërbyesi Home", + "Backup has a valid signature from verified device ": "Kopjeruajtja ka një nënshkrim të vlefshëm prej pajisjes së verifikuar ", + "New Recovery Method": "Metodë e Re Rimarrjesh", + "A new recovery passphrase and key for Secure Messages has been detected.": "Janë pikasur një frazëkalim dhe kyç i ri rimarrjesh për Mesazhe të Sigurt.", + "Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "Rregullimi i Mesazheve të Sigurt në këtë pajisje do të rifshehtëzojë historikun e mesazheve në këtë pajisje me metodën e re të rimarrjeve.", + "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Nëse metodën e re të rimarrjeve s’e keni caktuar ju, dikush mund të jetë duke u rrekur të hyjë në llogarinë tuaj. Ndryshoni menjëherë fjalëkalimin e llogarisë tuaj, te Rregullimet, dhe caktoni një metodë të re rimarrjesh.", + "Set up Secure Messages": "Rregulloni Mesazhi të Sigurt", + "Go to Settings": "Kalo te Rregullimet" } From 8c36e725c45f468a2bed7f64fe91e8423d9470c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20C?= Date: Wed, 19 Dec 2018 09:16:40 +0000 Subject: [PATCH 0045/1528] Translated using Weblate (French) Currently translated at 100.0% (1411 of 1411 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/fr/ --- src/i18n/strings/fr.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json index 0e91a15eca..98ad96b3ca 100644 --- a/src/i18n/strings/fr.json +++ b/src/i18n/strings/fr.json @@ -1436,5 +1436,12 @@ "%(count)s Notifications|one": "%(count)s notification", "Invalid identity server discovery response": "Réponse non valide lors de la découverte du serveur d'identité", "General failure": "Erreur générale", - "Unknown failure discovering homeserver": "Erreur inconnue lors de la découverte du serveur d'accueil" + "Unknown failure discovering homeserver": "Erreur inconnue lors de la découverte du serveur d'accueil", + "Backup has a valid signature from verified device ": "La sauvegarde a une signature valide depuis un appareil vérifié", + "New Recovery Method": "Nouvelle méthode de récupération", + "A new recovery passphrase and key for Secure Messages has been detected.": "Une nouvelle phrase de passe et une nouvelle clé de récupération pour les messages sécurisés ont été détectées.", + "Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "La configuration des messages sécurisés sur cet appareil va rechiffrer l'historique des messages de cet appareil avec la nouvelle méthode de récupération.", + "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Si vous n'avez pas activé de nouvelle méthode de récupération, un attaquant essaye peut-être d'accéder à votre compte. Changez immédiatement le mot de passe de votre compte et configurez une nouvelle méthode de récupération dans les paramètres.", + "Set up Secure Messages": "Configurer les messages sécurisés", + "Go to Settings": "Aller aux paramètres" } From 73e20ebf9f6546a1fb3550e5ef01b65680ba94cd Mon Sep 17 00:00:00 2001 From: Akarshan Biswas Date: Wed, 19 Dec 2018 08:08:02 +0000 Subject: [PATCH 0046/1528] Translated using Weblate (Hindi) Currently translated at 36.8% (520 of 1411 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/hi/ --- src/i18n/strings/hi.json | 143 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 142 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/hi.json b/src/i18n/strings/hi.json index 1cf6ae0f78..3e3c1ca2e8 100644 --- a/src/i18n/strings/hi.json +++ b/src/i18n/strings/hi.json @@ -378,5 +378,146 @@ "This is a top-10 common password": "यह एक शीर्ष १० सामान्य पासवर्ड में से एक है", "This is a top-100 common password": "यह एक शीर्ष १०० सामान्य पासवर्ड में से एक है", "This is a very common password": "यह एक बहुत ही आम पासवर्ड है", - "This is similar to a commonly used password": "यह आमतौर पर इस्तेमाल किए गए पासवर्ड के समान है" + "This is similar to a commonly used password": "यह आमतौर पर इस्तेमाल किए गए पासवर्ड के समान है", + "You do not have permission to invite people to this room.": "आपको इस कमरे में लोगों को आमंत्रित करने की अनुमति नहीं है।", + "User %(user_id)s does not exist": "उपयोगकर्ता %(user_id)s मौजूद नहीं है", + "Unknown server error": "अज्ञात सर्वर त्रुटि", + "A word by itself is easy to guess": "सिर्फ एक शब्द अनुमान लगाना आसान है", + "Names and surnames by themselves are easy to guess": "खुद के नाम और उपनाम अनुमान लगाना आसान है", + "Common names and surnames are easy to guess": "सामान्य नाम और उपनाम अनुमान लगाना आसान है", + "Show a reminder to enable Secure Message Recovery in encrypted rooms": "एन्क्रिप्टेड रूम में सुरक्षित संदेश रिकवरी सक्षम करने के लिए एक अनुस्मारक दिखाएं", + "Messages containing @room": "@Room युक्त संदेश", + "Encrypted messages in one-to-one chats": "एक एक के साथ चैट में एन्क्रिप्टेड संदेश", + "Encrypted messages in group chats": "समूह चैट में एन्क्रिप्टेड संदेश", + "Backup has a valid signature from verified device ": "बैकअप के पास सत्यापित डिवाइस से वैध हस्ताक्षर है", + "You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "हो सकता है कि आपने उन्हें रायट के अलावा किसी अन्य ग्राहक में कॉन्फ़िगर किया हो। आप उन्हें रायट में ट्यून नहीं कर सकते लेकिन वे अभी भी आवेदन करते हैं", + "Enable desktop notifications": "डेस्कटॉप अधिसूचनाएं सक्षम करें", + "Show message in desktop notification": "डेस्कटॉप अधिसूचना में संदेश दिखाएं", + "Enable audible notifications in web client": "वेब क्लाइंट में श्रव्य अधिसूचनाएं सक्षम करें", + "Off": "बंद", + "On": "चालू", + "Noisy": "शोरगुल", + "Cannot add any more widgets": "विजेट और जोड़ नहीं सकते हैं", + "The maximum permitted number of widgets have already been added to this room.": "इस रूम में विजेट की अधिकतम अनुमत संख्या पहले से ही जोड़ दी गई है।", + "Add a widget": "विजेट जोड़ें", + "Drop File Here": "यहां फ़ाइल ड्रॉप करें", + "Drop file here to upload": "अपलोड करने के लिए यहां फ़ाइल ड्रॉप करें", + " (unsupported)": " (असमर्थित)", + "Join as voice or video.": "आवाज या वीडियो के रूप में शामिल हों।", + "Ongoing conference call%(supportedText)s.": "चल रहे सम्मेलन कॉल %(supportedText)s।", + "This event could not be displayed": "यह घटना प्रदर्शित नहीं की जा सकी", + "%(senderName)s sent an image": "%(senderName)s ने एक छवि भेजी", + "%(senderName)s sent a video": "%(senderName)s ने एक वीडियो भेजा", + "%(senderName)s uploaded a file": "%(senderName)s ने एक फाइल अपलोड की", + "Options": "विकल्प", + "Your key share request has been sent - please check your other devices for key share requests.": "आपका कुंजी शेयर अनुरोध भेजा गया है - कृपया कुंजी शेयर अनुरोधों के लिए अपने अन्य डिवाइस देखें।", + "Key share requests are sent to your other devices automatically. If you rejected or dismissed the key share request on your other devices, click here to request the keys for this session again.": "कुंजी शेयर अनुरोध स्वचालित रूप से अपने अन्य उपकरणों के लिए भेजा जाता है। आप को अस्वीकार कर दिया या अपने अन्य उपकरणों पर कुंजी शेयर अनुरोध को खारिज कर दिया है, तो फिर इस सत्र के लिए कुंजी का अनुरोध करने के लिए यहां क्लिक करें।", + "If your other devices do not have the key for this message you will not be able to decrypt them.": "यदि आपके अन्य उपकरणों में इस संदेश की कुंजी नहीं है तो आप उन्हें डिक्रिप्ट करने में सक्षम नहीं होंगे।", + "Key request sent.": "कुंजी अनुरोध भेजा गया।", + "Re-request encryption keys from your other devices.": "अपने अन्य उपकरणों से एन्क्रिप्शन कुंजी का पुन: अनुरोध करें ।", + "Undecryptable": "डिक्रिप्ट करना संभव नहीं", + "Encrypting": "एन्क्रिप्ट किया जा रहा", + "Encrypted, not sent": "एन्क्रिप्ट हो चूका, भेजा नहीं गया", + "Encrypted by a verified device": "एक सत्यापित डिवाइस द्वारा एन्क्रिप्ट किया गया", + "Encrypted by an unverified device": "एक असत्यापित डिवाइस द्वारा एन्क्रिप्ट किया गया", + "Unencrypted message": "बिना एन्क्रिप्ट वाला संदेश", + "Please select the destination room for this message": "कृपया इस संदेश के लिए गंतव्य रूम का चयन करें", + "Blacklisted": "काली सूची में डाला गया", + "Verified": "सत्यापित", + "Unverified": "असत्यापित", + "device id: ": "डिवाइस आईडी: ", + "Disinvite": "आमंत्रित नहीं करना", + "Kick": "किक", + "Disinvite this user?": "इस उपयोगकर्ता को आमंत्रित नहीं करें?", + "Kick this user?": "इस उपयोगकर्ता को किक करें?", + "Failed to kick": "किक करने में विफल", + "Unban": "अप्रतिबंधित करें", + "Ban": "प्रतिबंध", + "Unban this user?": "इस उपयोगकर्ता को अप्रतिबंधित करें?", + "Ban this user?": "इस उपयोगकर्ता को प्रतिबंधित करें?", + "Failed to ban user": "उपयोगकर्ता को प्रतिबंधित करने में विफल", + "Demote yourself?": "खुद को अवनत करें?", + "You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges.": "आप इस बदलाव को पूर्ववत नहीं कर पाएंगे क्योंकि आप स्वयं को अवनत कर रहे हैं, अगर आप रूम में आखिरी विशेषाधिकार प्राप्त उपयोगकर्ता हैं तो विशेषाधिकार हासिल करना असंभव होगा।", + "Demote": "अवनत", + "Failed to mute user": "उपयोगकर्ता को म्यूट करने में विफल", + "Failed to toggle moderator status": "मॉडरेटर स्थिति टॉगल करने में विफल", + "Failed to change power level": "पावर स्तर बदलने में विफल", + "You will not be able to undo this change as you are promoting the user to have the same power level as yourself.": "आप इस परिवर्तन को पूर्ववत नहीं कर पाएंगे क्योंकि आप उपयोगकर्ता को अपने आप से समान शक्ति स्तर रखने के लिए प्रोत्साहित कर रहे हैं।", + "Are you sure?": "क्या आपको यकीन है?", + "No devices with registered encryption keys": "पंजीकृत एन्क्रिप्शन कुंजी के साथ कोई डिवाइस नहीं", + "Devices": "उपकरण", + "Unignore": "अनदेखा न करें", + "Ignore": "अनदेखा करें", + "Jump to read receipt": "पढ़ी हुई रसीद में कूदें", + "Mention": "उल्लेख", + "Invite": "आमंत्रण", + "Share Link to User": "उपयोगकर्ता को लिंक साझा करें", + "User Options": "उपयोगकर्ता विकल्प", + "Direct chats": "प्रत्यक्ष चैट", + "Unmute": "अनम्यूट", + "Mute": "म्यूट", + "Revoke Moderator": "मॉडरेटर को रद्द करें", + "Make Moderator": "मॉडरेटर बनायें", + "Admin Tools": "व्यवस्थापक उपकरण", + "Level:": "स्तर:", + "Close": "बंद", + "and %(count)s others...|other": "और %(count)s अन्य ...", + "and %(count)s others...|one": "और एक अन्य...", + "Invited": "आमंत्रित", + "Filter room members": "रूम के सदस्यों को फ़िल्टर करें", + "%(userName)s (power %(powerLevelNumber)s)": "%(userName)s (शक्ति %(powerLevelNumber)s)", + "bold": "बोल्ड", + "italic": "तिरछा", + "deleted": "हटाए गए", + "underlined": "रेखांकित", + "inline-code": "इनलाइन कोड", + "block-quote": "ब्लॉक उद्धरण", + "bulleted-list": "बुलेटेड सूची", + "numbered-list": "गिने-सूची", + "Attachment": "आसक्ति", + "At this time it is not possible to reply with a file so this will be sent without being a reply.": "इस समय फ़ाइल के साथ जवाब देना संभव नहीं है, इसलिए इसे उत्तर दिए बिना भेजा जाएगा।", + "Are you sure you want to upload the following files?": "क्या आप वाकई निम्नलिखित फाइलें अपलोड करना चाहते हैं?", + "The following files cannot be uploaded:": "निम्नलिखित फाइलें अपलोड नहीं की जा सकती हैं:", + "Upload Files": "फाइल अपलोड करें", + "Encrypted room": "एन्क्रिप्टेड रूम", + "Unencrypted room": "अनएन्क्रिप्टेड रूम", + "Hangup": "फोन रख देना", + "Voice call": "आवाज कॉल", + "Video call": "वीडियो कॉल", + "Upload file": "फाइल अपलोड करें", + "Show Text Formatting Toolbar": "टेक्स्ट स्वरूपण टूलबार दिखाएं", + "Send an encrypted reply…": "एक एन्क्रिप्टेड उत्तर भेजें …", + "Send a reply (unencrypted)…": "एक उत्तर भेजें (अनएन्क्रिप्टेड) …", + "Send an encrypted message…": "एक एन्क्रिप्टेड संदेश भेजें …", + "Send a message (unencrypted)…": "एक संदेश भेजें (अनएन्क्रिप्टेड) …", + "This room has been replaced and is no longer active.": "इस रूम को बदल दिया गया है और अब सक्रिय नहीं है।", + "The conversation continues here.": "वार्तालाप यहां जारी है।", + "You do not have permission to post to this room": "आपको इस रूम में पोस्ट करने की अनुमति नहीं है", + "Turn Markdown on": "मार्कडाउन चालू करें", + "Turn Markdown off": "मार्कडाउन बंद करें", + "Hide Text Formatting Toolbar": "टेक्स्ट स्वरूपण टूलबार छुपाएं", + "Server error": "सर्वर त्रुटि", + "Server unavailable, overloaded, or something else went wrong.": "सर्वर अनुपलब्ध, अधिभारित, या कुछ और गलत हो गया।", + "Command error": "कमांड त्रुटि", + "Unable to reply": "उत्तर देने में असमर्थ", + "At this time it is not possible to reply with an emote.": "इस समय एक भावना के साथ जवाब देना संभव नहीं है।", + "Markdown is disabled": "मार्कडाउन अक्षम है", + "Markdown is enabled": "मार्कडाउन सक्षम है", + "No pinned messages.": "कोई पिन संदेश नहीं।", + "Loading...": "लोड हो रहा है...", + "Pinned Messages": "पिन किए गए संदेश", + "Unpin Message": "संदेश अनपिन करें", + "Jump to message": "संदेश पर कूदें", + "%(duration)ss": "%(duration)s सेकंड", + "%(duration)sm": "%(duration)s मिनट", + "%(duration)sh": "%(duration)s घंटा", + "%(duration)sd": "%(duration)s दिन", + "Online for %(duration)s": "%(duration)s के लिए ऑनलाइन", + "Idle for %(duration)s": "%(duration)s के लिए निष्क्रिय", + "Offline for %(duration)s": "%(duration)s के लिए ऑफ़लाइन", + "Unknown for %(duration)s": "%(duration)s के लिए अज्ञात", + "Online": "ऑनलाइन", + "Idle": "निष्क्रिय", + "Offline": "ऑफलाइन", + "Unknown": "अज्ञात" } From b9793af90c7d05625248398ebb929113f5da7dc4 Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Wed, 19 Dec 2018 13:40:49 +0000 Subject: [PATCH 0047/1528] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (1411 of 1411 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/zh_Hant/ --- src/i18n/strings/zh_Hant.json | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/zh_Hant.json b/src/i18n/strings/zh_Hant.json index 07b4f892ca..defd2c6b95 100644 --- a/src/i18n/strings/zh_Hant.json +++ b/src/i18n/strings/zh_Hant.json @@ -1432,5 +1432,14 @@ "%(count)s Notifications|one": "%(count)s 個通知", "Invalid identity server discovery response": "無效的身份伺服器探索回應", "General failure": "一般錯誤", - "Unknown failure discovering homeserver": "探索家伺服器時發生未知的失敗" + "Unknown failure discovering homeserver": "探索家伺服器時發生未知的失敗", + "Backup has a valid signature from verified device ": "備份有從驗證過的裝置而來的有效簽章", + "Only use lower case letters, numbers and '=_-./'": "僅使用小寫字母,數字與 '=_-./'", + "Checking...": "正在檢查……", + "New Recovery Method": "新復原方法", + "A new recovery passphrase and key for Secure Messages has been detected.": "偵測到安全訊息的新復原密碼與金鑰。", + "Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "在此裝置上設定安全訊息將會以新的復原方法重新加密此裝置的訊息歷史。", + "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "如果您沒有設定新的復原方法,攻擊者可能會嘗試存取您的帳號。在設定中立刻變更您的密碼並設定新的復原方法。", + "Set up Secure Messages": "設定安全訊息", + "Go to Settings": "到設定" } From ce7485854e74b0bb77054c373c64cc7ae2fa2d80 Mon Sep 17 00:00:00 2001 From: Szimszon Date: Wed, 19 Dec 2018 18:27:11 +0000 Subject: [PATCH 0048/1528] Translated using Weblate (Hungarian) Currently translated at 100.0% (1417 of 1417 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/hu/ --- src/i18n/strings/hu.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json index 0ac5bb5fdf..2f307b77e5 100644 --- a/src/i18n/strings/hu.json +++ b/src/i18n/strings/hu.json @@ -1443,5 +1443,11 @@ "Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "A Biztonságos Üzenetek ezen az eszközön való beállításával az új visszaállítási eljárással lesznek újra titkosítva a régi üzenetek.", "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Ha nem te állítottad be a visszaállítási eljárást akkor lehet, hogy egy támadó próbálja elérni a fiókodat. Változtasd meg a fiókod jelszavát és állítsd be az új visszaállítási eljárást a Beállításokban amint lehet.", "Set up Secure Messages": "Biztonságos Üzenetek beállítása", - "Go to Settings": "Irány a Beállítások" + "Go to Settings": "Irány a Beállítások", + "Straight rows of keys are easy to guess": "A billentyű sorokat könnyű kitalálni", + "Short keyboard patterns are easy to guess": "Rövid billentyűzet sormintát könnyű kitalálni", + "Custom user status messages": "Egyedi felhasználói állapot üzenet", + "Set a new status...": "Új állapot beállítása...", + "Clear status": "Állapot törlése", + "Unable to load commit detail: %(msg)s": "Sikertelen betöltés részletek: \n%(msg)s" } From d558ea1dbf8af83fffc488b75d7d973031f54f06 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 19 Dec 2018 23:51:19 +0100 Subject: [PATCH 0049/1528] WIP --- src/resizer/distributors.js | 19 ++----- src/resizer/item.js | 78 ++++++++++++++++++++++++++ src/resizer/resizer.js | 38 +++++++------ src/resizer/room.js | 109 +++++++++++++++++++++++++++--------- src/resizer/sizer.js | 24 +------- 5 files changed, 189 insertions(+), 79 deletions(-) create mode 100644 src/resizer/item.js diff --git a/src/resizer/distributors.js b/src/resizer/distributors.js index caf677a18f..cb876bf98c 100644 --- a/src/resizer/distributors.js +++ b/src/resizer/distributors.js @@ -27,20 +27,13 @@ the offset from the container edge of where the mouse cursor is. */ class FixedDistributor { - constructor(sizer, item, id, config) { - this.sizer = sizer; + constructor(item) { this.item = item; - this.id = id; - this.beforeOffset = sizer.getItemOffset(this.item); - this.onResized = config && config.onResized; + this.beforeOffset = item.offset(); } - resize(itemSize) { - this.sizer.setItemSize(this.item, itemSize); - if (this.onResized) { - this.onResized(itemSize, this.id, this.item); - } - return itemSize; + resize(size) { + this.item.setSize(size); } resizeFromContainerOffset(offset) { @@ -50,8 +43,8 @@ class FixedDistributor { class CollapseDistributor extends FixedDistributor { - constructor(sizer, item, id, config) { - super(sizer, item, id, config); + constructor(item, sizer, _container, config) { + super(item); this.toggleSize = config && config.toggleSize; this.onCollapsed = config && config.onCollapsed; this.isCollapsed = false; diff --git a/src/resizer/item.js b/src/resizer/item.js new file mode 100644 index 0000000000..ad508150a5 --- /dev/null +++ b/src/resizer/item.js @@ -0,0 +1,78 @@ +/* +Copyright 2018 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +export default class ResizeItem { + constructor(domNode, id, reverse, resizer, sizer) { + this.domNode = domNode; + this.id = id; + this.reverse = reverse; + this.resizer = resizer; + this.sizer = sizer; + } + + static fromResizeHandle(handle, resizer, sizer) { + const id = handle.getAttribute("data-id"); + const reverse = resizer.isReverseResizeHandle(handle); + const domNode = reverse ? handle.nextElementSibling : handle.previousElementSibling; + return new ResizeItem(domNode, id, reverse, resizer, sizer); + } + + _advance(forwards) { + // opposite direction from fromResizeHandle to get back to handle + let handle = this.reverse ? + this.domNode.previousElementSibling : + this.domNode.nextElementSibling; + const moveNext = forwards !== this.reverse; // xor + // iterate at least once to avoid infinite loop + do { + if (moveNext) { + handle = handle.nextElementSibling; + } else { + handle = handle.previousElementSibling; + } + } while(handle && !this.resizer.isResizeHandle(handle)); + if (handle) { + const nextHandle = ResizeItem.fromResizeHandle(handle, this.resizer, this.sizer); + nextHandle.reverse = this.reverse; + return nextHandle; + } + } + + next() { + return this._advance(true); + } + + previous() { + return this._advance(false); + } + + size() { + return this.sizer.getItemSize(this.domNode); + } + + offset() { + return this.sizer.getItemOffset(this.domNode); + } + + setSize(size) { + this.sizer.setItemSize(this.domNode, size); + console.log("resizing", this.domNode, "to", size, this.size()); + const callback = this.resizer.distributorCtor.onResized; + if (callback) { + callback(size, this.id, this.domNode); + } + } +} diff --git a/src/resizer/resizer.js b/src/resizer/resizer.js index 0e113b3664..8bdbc6cffe 100644 --- a/src/resizer/resizer.js +++ b/src/resizer/resizer.js @@ -15,6 +15,7 @@ limitations under the License. */ import {Sizer} from "./sizer"; +import ResizeItem from "./item"; /* classNames: @@ -28,7 +29,10 @@ classNames: resizing: string */ + export class Resizer { + // TODO move vertical/horizontal to config option/container class + // as it doesn't make sense to mix them within one container/Resizer constructor(container, distributorCtor, distributorCfg, sizerCtor = Sizer) { this.container = container; this.distributorCtor = distributorCtor; @@ -79,7 +83,11 @@ export class Resizer { } } - _isResizeHandle(el) { + isReverseResizeHandle(el) { + return el && el.classList.contains(this.classNames.reverse); + } + + isResizeHandle(el) { return el && el.classList.contains(this.classNames.handle); } @@ -119,35 +127,29 @@ export class Resizer { _createSizerAndDistributor(resizeHandle) { const vertical = resizeHandle.classList.contains(this.classNames.vertical); - const reverse = resizeHandle.classList.contains(this.classNames.reverse); - + const reverse = this.isReverseResizeHandle(resizeHandle); // eslint-disable-next-line new-cap const sizer = new this.sizerCtor(this.container, vertical, reverse); - - const items = this._getResizableItems(); - const prevItem = resizeHandle.previousElementSibling; - // if reverse, resize the item after the handle instead of before, so + 1 - const itemIndex = items.indexOf(prevItem) + (reverse ? 1 : 0); - const item = items[itemIndex]; - const id = resizeHandle.getAttribute("data-id"); + const item = ResizeItem.fromResizeHandle(resizeHandle, this, sizer); // eslint-disable-next-line new-cap const distributor = new this.distributorCtor( - sizer, item, id, this.distributorCfg, - items, this.container); + item, + sizer, + this.container, + this.distributorCfg + ); return {sizer, distributor}; } - _getResizableItems() { - return Array.from(this.container.children).filter(el => { - return !this._isResizeHandle(el) && ( - this._isResizeHandle(el.previousElementSibling) || - this._isResizeHandle(el.nextElementSibling)); + _getResizableItems(reverse) { + return this._getResizeHandles().map((handle) => { + return ResizeItem.fromResizeHandle(handle); }); } _getResizeHandles() { return Array.from(this.container.children).filter(el => { - return this._isResizeHandle(el); + return this.isResizeHandle(el); }); } } diff --git a/src/resizer/room.js b/src/resizer/room.js index def12d49eb..fda09940b1 100644 --- a/src/resizer/room.js +++ b/src/resizer/room.js @@ -15,42 +15,99 @@ limitations under the License. */ import {Sizer} from "./sizer"; -import {FixedDistributor} from "./distributors"; class RoomSizer extends Sizer { setItemSize(item, size) { - const isString = typeof size === "string"; - const cl = item.classList; - if (isString) { - if (size === "resized-all") { - cl.add("resized-all"); - cl.remove("resized-sized"); - item.style.maxHeight = null; - } - } else { - cl.add("resized-sized"); - cl.remove("resized-all"); - item.style.maxHeight = `${Math.round(size)}px`; - } + item.style.maxHeight = `${Math.round(size)}px`; } } -class RoomDistributor extends FixedDistributor { - resize(itemSize) { - const scrollItem = this.item.querySelector(".mx_RoomSubList_scroll"); - if (!scrollItem) { - return; //FIXME: happens when starting the page on a community url, taking the safe way out for now - } - const fixedHeight = this.item.offsetHeight - scrollItem.offsetHeight; - if (itemSize > (fixedHeight + scrollItem.scrollHeight)) { - super.resize("resized-all"); +/* +class RoomSubList extends ResizeItem { + collapsed() { + + } + + scrollSizes() { + return {offsetHeight, scrollHeight}; + } + + id() { + + } +} +*/ + +const MIN_SIZE = 70; +// would be good to have a way in here to know if the item can be resized +// - collapsed items can't be resized (.mx_RoomSubList_hidden) +// - items at MIN_SIZE can't be resized smaller +// - items at maxContentHeight can't be resized larger + +// if you shrink the predecesor, and start dragging down again afterwards, which item has to grow? + +class RoomDistributor { + constructor(item) { + this.item = item; + } + + _handleSize() { + return 1; + } + + // returns the remainder of size it didn't consume for this item + _sizeItem(item, size) { + // if collapsed, do nothing and subtract own height + if (item.domNode.classList.contains("mx_RoomSubList_hidden")) { + return; + } else if (size < MIN_SIZE) { + item.setSize(MIN_SIZE); } else { - super.resize(itemSize); + const scrollItem = item.domNode.querySelector(".mx_RoomSubList_scroll"); + const headerHeight = item.size() - scrollItem.offsetHeight; + const maxContentHeight = headerHeight + scrollItem.scrollHeight; + // avoid flexbox growing larger than the content height + if (size > maxContentHeight) { + item.setSize(maxContentHeight); + } else { + item.setSize(size); + } } } - resizeFromContainerOffset(offset) { - return this.resize(offset - this.sizer.getItemOffset(this.item)); + resize(size) { + if (size < 0) { + console.log("NEGATIVE SIZE RESIZE RESIZE RESIZE!!!", size); + } + let item = this.item; + // move to item that is at position of cursor + // this would happen if the cursor goes beyond the min-height + while (item && size < 0) { + item = item.previous(); + if (item) { + size = item.size() - size - this._handleSize(); + } + } + // change size of item and previous items from here + while(item && size > 0) { + const itemSize = item.size(); + this._sizeItem(item, size); + const delta = item.size() - itemSize; + const remainder = size - delta; + // pass remainder to previous item + if (remainder !== 0) { + item = item.previous(); + if (item) { + size = item.size() - remainder - this._handleSize(); + } + } else { + item = null; + } + } + } + + resizeFromContainerOffset(containerOffset) { + this.resize(containerOffset - this.item.offset()); } } diff --git a/src/resizer/sizer.js b/src/resizer/sizer.js index 303214854b..1cb212e20a 100644 --- a/src/resizer/sizer.js +++ b/src/resizer/sizer.js @@ -18,31 +18,13 @@ limitations under the License. implements DOM/CSS operations for resizing. The sizer determines what CSS mechanism is used for sizing items, like flexbox, ... */ -class Sizer { +export class Sizer { constructor(container, vertical, reverse) { this.container = container; this.reverse = reverse; this.vertical = vertical; } - getItemPercentage(item) { - /* - const flexGrow = window.getComputedStyle(item).flexGrow; - if (flexGrow === "") { - return null; - } - return parseInt(flexGrow) / 1000; - */ - const style = window.getComputedStyle(item); - const sizeStr = this.vertical ? style.height : style.width; - const size = parseInt(sizeStr, 10); - return size / this.getTotalSize(); - } - - setItemPercentage(item, percent) { - item.style.flexGrow = Math.round(percent * 1000); - } - /** @param {Element} item the dom element being resized @return {number} how far the edge of the item is from the edge of the container @@ -97,11 +79,9 @@ class Sizer { } } -class FlexSizer extends Sizer { +export class FlexSizer extends Sizer { setItemSize(item, size) { item.style.flexGrow = `0`; item.style.flexBasis = `${Math.round(size)}px`; } } - -module.exports = {Sizer, FlexSizer}; From 8a45dea26198628123c101e7fdd9087c7b2aacaa Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Thu, 20 Dec 2018 03:41:52 +0000 Subject: [PATCH 0050/1528] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (1417 of 1417 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/zh_Hant/ --- src/i18n/strings/zh_Hant.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/zh_Hant.json b/src/i18n/strings/zh_Hant.json index defd2c6b95..91fad25ee1 100644 --- a/src/i18n/strings/zh_Hant.json +++ b/src/i18n/strings/zh_Hant.json @@ -1441,5 +1441,11 @@ "Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "在此裝置上設定安全訊息將會以新的復原方法重新加密此裝置的訊息歷史。", "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "如果您沒有設定新的復原方法,攻擊者可能會嘗試存取您的帳號。在設定中立刻變更您的密碼並設定新的復原方法。", "Set up Secure Messages": "設定安全訊息", - "Go to Settings": "到設定" + "Go to Settings": "到設定", + "Straight rows of keys are easy to guess": "直排按鍵很容易猜到", + "Short keyboard patterns are easy to guess": "短鍵盤重覆很容易猜到", + "Custom user status messages": "自訂使用者狀態訊息", + "Unable to load commit detail: %(msg)s": "無法載入遞交的詳細資訊:", + "Set a new status...": "設定新狀態……", + "Clear status": "清除狀態" } From 5c1072e569c2b2a8c67885f208d833545d05e88f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20C?= Date: Thu, 20 Dec 2018 08:55:06 +0000 Subject: [PATCH 0051/1528] Translated using Weblate (French) Currently translated at 100.0% (1417 of 1417 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/fr/ --- src/i18n/strings/fr.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json index 98ad96b3ca..62e58dbd46 100644 --- a/src/i18n/strings/fr.json +++ b/src/i18n/strings/fr.json @@ -1443,5 +1443,11 @@ "Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "La configuration des messages sécurisés sur cet appareil va rechiffrer l'historique des messages de cet appareil avec la nouvelle méthode de récupération.", "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Si vous n'avez pas activé de nouvelle méthode de récupération, un attaquant essaye peut-être d'accéder à votre compte. Changez immédiatement le mot de passe de votre compte et configurez une nouvelle méthode de récupération dans les paramètres.", "Set up Secure Messages": "Configurer les messages sécurisés", - "Go to Settings": "Aller aux paramètres" + "Go to Settings": "Aller aux paramètres", + "Straight rows of keys are easy to guess": "Les suites de touches sont faciles à deviner", + "Short keyboard patterns are easy to guess": "Les répétitions de motif court sur un clavier sont faciles à deviner", + "Custom user status messages": "Messages de statut de l'utilisateur personnalisés", + "Unable to load commit detail: %(msg)s": "Impossible de charger les détails de l'envoi : %(msg)s", + "Set a new status...": "Configurer un nouveau statut…", + "Clear status": "Effacer le statut" } From 0ea8eec304c0c62fc3fe5a090fd67f05ca3b54c2 Mon Sep 17 00:00:00 2001 From: Slavi Pantaleev Date: Fri, 21 Dec 2018 11:42:50 +0000 Subject: [PATCH 0052/1528] Translated using Weblate (Bulgarian) Currently translated at 100.0% (1417 of 1417 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/bg/ --- src/i18n/strings/bg.json | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/bg.json b/src/i18n/strings/bg.json index 57e369627c..1064fc8b91 100644 --- a/src/i18n/strings/bg.json +++ b/src/i18n/strings/bg.json @@ -1431,5 +1431,18 @@ "Unable to create key backup": "Неуспешно създаване на резервно копие на ключа", "Retry": "Опитай пак", "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Без настроено Защитено Възстановяване на Съобщения, ще загубите защитената история на съобщенията когато излезете от профила си.", - "If you don't want to set this up now, you can later in Settings.": "Ако не искате да настройвате това сега, може и по-късно от Настройки." + "If you don't want to set this up now, you can later in Settings.": "Ако не искате да настройвате това сега, може и по-късно от Настройки.", + "Straight rows of keys are easy to guess": "Клавиши от прави редици са лесни за отгатване", + "Short keyboard patterns are easy to guess": "Къси клавиатурни последователности са лесни за отгатване", + "Custom user status messages": "Собствено статус съобщение", + "Backup has a valid signature from verified device ": "Резервното копие има валиден подпис от потвърдено устройство ", + "Unable to load commit detail: %(msg)s": "Неуспешно зареждане на информация за commit: %(msg)s", + "Set a new status...": "Задаване на нов статус...", + "Clear status": "Изчисти статуса", + "New Recovery Method": "Нов метод за възстановяване", + "A new recovery passphrase and key for Secure Messages has been detected.": "Беше открита нова парола за възстановяване за Защитени Съобщения.", + "Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "Настройката на Защитени Съобщения на това устройство ще зашифрова наново историята на съобщенията му посредством новия метод за възстановяване.", + "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Ако не сте настройвали новия метод за възстановяване, вероятно някой се опитва да проникне в акаунта Ви. Веднага променете паролата на акаунта си и настройте нов метод за възстановяване от Настройки.", + "Set up Secure Messages": "Настрой Защитени Съобщения", + "Go to Settings": "Отиди в Настройки" } From cb7ba63494d7a0e356a9016fc1f2aa5f1d9ed6b6 Mon Sep 17 00:00:00 2001 From: random Date: Fri, 21 Dec 2018 14:13:56 +0000 Subject: [PATCH 0053/1528] Translated using Weblate (Italian) Currently translated at 100.0% (1417 of 1417 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/it/ --- src/i18n/strings/it.json | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/it.json b/src/i18n/strings/it.json index 0d910bba91..9b3fe8fad4 100644 --- a/src/i18n/strings/it.json +++ b/src/i18n/strings/it.json @@ -1433,5 +1433,18 @@ "%(count)s Notifications|one": "%(count)s notifica", "Invalid identity server discovery response": "Risposta non valida cercando server di identità", "General failure": "Guasto generale", - "Unknown failure discovering homeserver": "Errore sconosciuto cercando homeserver" + "Unknown failure discovering homeserver": "Errore sconosciuto cercando homeserver", + "Straight rows of keys are easy to guess": "Sequenze di tasti in riga sono facili da indovinare", + "Short keyboard patterns are easy to guess": "Sequenze di tasti brevi sono facili da indovinare", + "Custom user status messages": "Messaggi di stato utente personalizzati", + "Backup has a valid signature from verified device ": "Il backup ha una firma valida dal dispositivo verificato ", + "Unable to load commit detail: %(msg)s": "Caricamento dettagli del commit fallito: %(msg)s", + "Set a new status...": "Imposta un nuovo stato...", + "Clear status": "Elimina stato", + "New Recovery Method": "Nuovo metodo di recupero", + "A new recovery passphrase and key for Secure Messages has been detected.": "Sono state rilevate una nuova password e chiave di recupero per messaggi sicuri.", + "Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "Impostare i messaggi sicuri su questo dispositivo cripterà di nuovo la cronologia dei messaggi con il nuovo metodo di recupero.", + "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Se non hai impostato il nuovo metodo di recupero, un aggressore potrebbe tentare di accedere al tuo account. Cambia la password del tuo account e imposta immediatamente un nuovo metodo di recupero nelle impostazioni.", + "Set up Secure Messages": "Imposta i messaggi sicuri", + "Go to Settings": "Vai alle impostazioni" } From 095f43c896a34e41e8f4af8494997ce7357dcd34 Mon Sep 17 00:00:00 2001 From: Besnik Bleta Date: Wed, 19 Dec 2018 19:01:04 +0000 Subject: [PATCH 0054/1528] Translated using Weblate (Albanian) Currently translated at 99.2% (1407 of 1417 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/sq/ --- src/i18n/strings/sq.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/sq.json b/src/i18n/strings/sq.json index da8dc054b2..b5ff119659 100644 --- a/src/i18n/strings/sq.json +++ b/src/i18n/strings/sq.json @@ -1413,5 +1413,11 @@ "Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "Rregullimi i Mesazheve të Sigurt në këtë pajisje do të rifshehtëzojë historikun e mesazheve në këtë pajisje me metodën e re të rimarrjeve.", "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Nëse metodën e re të rimarrjeve s’e keni caktuar ju, dikush mund të jetë duke u rrekur të hyjë në llogarinë tuaj. Ndryshoni menjëherë fjalëkalimin e llogarisë tuaj, te Rregullimet, dhe caktoni një metodë të re rimarrjesh.", "Set up Secure Messages": "Rregulloni Mesazhi të Sigurt", - "Go to Settings": "Kalo te Rregullimet" + "Go to Settings": "Kalo te Rregullimet", + "Straight rows of keys are easy to guess": "Rreshta uniformë tastesh janë lehtësisht të hamendësueshëm", + "Short keyboard patterns are easy to guess": "Kombinime të shkurtra tastiere janë lehtësisht të hamendësueshme", + "Custom user status messages": "Mesazhe vetjakë për gjendje përdoruesi", + "Unable to load commit detail: %(msg)s": "S’arrihet të ngarkohen hollësi depozitimi: %(msg)s", + "Set a new status...": "Caktoni një gjendje të re…", + "Clear status": "Pastroji gjendjen" } From 09dc0f2a3a7a203abd5e2ad85ea669930fe27296 Mon Sep 17 00:00:00 2001 From: Karol Kosek Date: Mon, 24 Dec 2018 09:31:14 +0000 Subject: [PATCH 0055/1528] Translated using Weblate (Polish) Currently translated at 92.0% (1304 of 1417 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/pl/ --- src/i18n/strings/pl.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/pl.json b/src/i18n/strings/pl.json index c472b84f8b..dc377a3514 100644 --- a/src/i18n/strings/pl.json +++ b/src/i18n/strings/pl.json @@ -1318,5 +1318,6 @@ "Please review and accept the policies of this homeserver:": "Przeczytaj i zaakceptuj zasady tego serwera domowego:", "Upgrade room to version %(ver)s": "Zaktualizuj pokój do wersji %(ver)s", "Don't ask again": "Nie pytaj ponownie", - "Messages containing @room": "Wiadomości zawierające @room" + "Messages containing @room": "Wiadomości zawierające @room", + "This is similar to a commonly used password": "Jest to podobne do powszechnie stosowanego hasła" } From d4aab3dc8184b49b966b7eec9bb0f08cb118b982 Mon Sep 17 00:00:00 2001 From: Osoitz Date: Wed, 26 Dec 2018 10:19:44 +0000 Subject: [PATCH 0056/1528] Translated using Weblate (Basque) Currently translated at 99.5% (1410 of 1417 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/eu/ --- src/i18n/strings/eu.json | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/eu.json b/src/i18n/strings/eu.json index 2fc08d0fcd..1bf9fbb415 100644 --- a/src/i18n/strings/eu.json +++ b/src/i18n/strings/eu.json @@ -1425,5 +1425,20 @@ "Messages containing @room": "@room duten mezuak", "Encrypted messages in one-to-one chats": "Zifratutako mezuak bi pertsonen arteko txatetan", "Encrypted messages in group chats": "Zifratutako mezuak talde-txatetan", - "That doesn't look like a valid email address": "Horrek ez du baliozko e-mail baten itxurarik" + "That doesn't look like a valid email address": "Horrek ez du baliozko e-mail baten itxurarik", + "Straight rows of keys are easy to guess": "Teklatuko errenkadak asmatzeko errazak dira", + "Short keyboard patterns are easy to guess": "Teklatuko eredu laburrak asmatzeko errazak dira", + "Custom user status messages": "Erabiltzailearen egoera mezu pertsonalizatuak", + "Only use lower case letters, numbers and '=_-./'": "Erabili soilik letra xeheak, zenbakiak eta '=_-./'", + "Checking...": "Egiaztatzen...", + "Set a new status...": "Ezarri egoera berri bat...", + "Clear status": "Garbitu egoera", + "Invalid configuration: Cannot supply a default homeserver URL and a default server name": "Konfigurazio baliogabea: Ezin da lehenetsitako hasiera-zerbitzari bat eta lehenetsitako zerbitzari izen bat zerbitzatu", + "Unknown error discovering homeserver": "Errore ezezaguna hasiera-zerbitzaria bilatzean", + "%(count)s Notifications|other": "%(count)s jakinarazpen", + "%(count)s Notifications|one": "Jakinarazpen %(count)s", + "General failure": "Hutsegite orokorra", + "New Recovery Method": "Berreskuratze metodo berria", + "Set up Secure Messages": "Ezarri mezu seguruak", + "Go to Settings": "Joan ezarpenetara" } From 2340798fcf4bd3d5a301276276ff3003ba55e29d Mon Sep 17 00:00:00 2001 From: Szimszon Date: Tue, 25 Dec 2018 20:47:01 +0000 Subject: [PATCH 0057/1528] Translated using Weblate (Hungarian) Currently translated at 100.0% (1417 of 1417 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/hu/ --- src/i18n/strings/hu.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json index 2f307b77e5..229dd4fc66 100644 --- a/src/i18n/strings/hu.json +++ b/src/i18n/strings/hu.json @@ -228,7 +228,7 @@ "Joins room with given alias": "A megadott becenévvel belépett a szobába", "Jump to first unread message.": "Ugrás az első olvasatlan üzenetre.", "%(senderName)s kicked %(targetName)s.": "%(senderName)s kizárta: %(targetName)s.", - "Kick": "Kirúg", + "Kick": "Elküld", "Kicks user with given id": "Az adott azonosítójú felhasználó kirúgása", "Labs": "Labor", "Last seen": "Utoljára láttuk", From fbded080507cc7ac81b757c5177382906a5bcfba Mon Sep 17 00:00:00 2001 From: Karol Kosek Date: Tue, 25 Dec 2018 10:20:22 +0000 Subject: [PATCH 0058/1528] Translated using Weblate (Polish) Currently translated at 92.0% (1304 of 1417 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/pl/ --- src/i18n/strings/pl.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/i18n/strings/pl.json b/src/i18n/strings/pl.json index dc377a3514..bfab119be8 100644 --- a/src/i18n/strings/pl.json +++ b/src/i18n/strings/pl.json @@ -335,7 +335,7 @@ "AM": "AM", "PM": "PM", "NOT verified": "NIEzweryfikowany", - "NOTE: Apps are not end-to-end encrypted": "UWAGA: Aplikacje nie są szyfrowane metodą użytkownik-użytkownik", + "NOTE: Apps are not end-to-end encrypted": "UWAGA: Aplikacje nie są szyfrowane metodą end-to-end", "No devices with registered encryption keys": "Brak urządzeń z zarejestrowanymi kluczami szyfrującymi", "No display name": "Brak nazwy ekranowej", "No more results": "Nie ma więcej wyników", @@ -451,7 +451,7 @@ "To reset your password, enter the email address linked to your account": "Aby zresetować swoje hasło, wpisz adres e-mail powiązany z twoim kontem", "Turn Markdown off": "Wyłącz Markdown", "Turn Markdown on": "Włącz Markdown", - "%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).": "%(senderName)s włączył szyfrowanie użytkownik-użytkownik (algorithm %(algorithm)s).", + "%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).": "%(senderName)s włączył(a) szyfrowanie end-to-end (algorytm %(algorithm)s).", "Unable to add email address": "Nie można dodać adresu e-mail", "Unable to create widget.": "Nie można utworzyć widżetu.", "Unable to remove contact information": "Nie można usunąć informacji kontaktowych", From 3f6bd1f94b6858cc1748c6ba617666eee709d6d2 Mon Sep 17 00:00:00 2001 From: Osoitz Date: Sun, 30 Dec 2018 12:02:40 +0000 Subject: [PATCH 0059/1528] Translated using Weblate (Basque) Currently translated at 100.0% (1417 of 1417 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/eu/ --- src/i18n/strings/eu.json | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/i18n/strings/eu.json b/src/i18n/strings/eu.json index 1bf9fbb415..9feceec6f4 100644 --- a/src/i18n/strings/eu.json +++ b/src/i18n/strings/eu.json @@ -1309,7 +1309,7 @@ "Unable to load key backup status": "Ezin izan da babes-kopiaren egoera kargatu", "This device is uploading keys to this backup": "Gailu honek gakoak babes-kopia honetara igotzen ditu", "This device is not uploading keys to this backup": "Gailu honek ez ditu gakoak igotzen babes-kopia honetara", - "Backup has a valid signature from this device": "Babes-kopiak gailu honen baliozko sinadura du", + "Backup has a valid signature from this device": "Babes-kopiak gailu honen baliozko sinadura bat du", "Backup has a valid signature from verified device x": "Babes-kopiak egiaztatutako x gailuaren baliozko sinadura du", "Backup has a valid signature from unverified device ": "Babes-kopiak egiaztatu gabeko gailu baten baliozko sinadura du", "Backup has an invalid signature from verified device ": "Babes-kopiak egiaztatutako gailuaren balio gabeko sinadura du", @@ -1440,5 +1440,12 @@ "General failure": "Hutsegite orokorra", "New Recovery Method": "Berreskuratze metodo berria", "Set up Secure Messages": "Ezarri mezu seguruak", - "Go to Settings": "Joan ezarpenetara" + "Go to Settings": "Joan ezarpenetara", + "Unknown failure discovering homeserver": "Hutsegite ezezaguna hasiera-zerbitzaria bilatzean", + "Backup has a valid signature from verified device ": "Babes-kopiak egiaztatutako gailu baten baliozko sinadura bat du", + "Unable to load commit detail: %(msg)s": "Ezin izan dira xehetasunak kargatu: %(msg)s", + "Invalid identity server discovery response": "Baliogabeko erantzuna identitate zerbitzariaren bilaketan", + "A new recovery passphrase and key for Secure Messages has been detected.": "Mezu seguruentzako berreskuratze pasa-esaldi eta gako berri bat antzeman dira.", + "Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "Mezu seguruak gailu honetan ezartzeak, gailu honen mezuen historiala birzifratuko du berreskuratze metodo berriarekin.", + "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Ez baduzu berreskuratze sistema berria ezarri, erasotzaile bat zure kontua atzitzen saiatzen egon daiteke. Aldatu zure kontuaren pasahitza eta ezarri berreskuratze metodo berria berehala ezarpenetan." } From 1d5b3df5f1d53ee5be584cf823a17f980fcc4e42 Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Wed, 2 Jan 2019 13:18:23 +0000 Subject: [PATCH 0060/1528] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (1417 of 1417 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/zh_Hant/ --- src/i18n/strings/zh_Hant.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/zh_Hant.json b/src/i18n/strings/zh_Hant.json index 91fad25ee1..23963c3cfa 100644 --- a/src/i18n/strings/zh_Hant.json +++ b/src/i18n/strings/zh_Hant.json @@ -1445,7 +1445,7 @@ "Straight rows of keys are easy to guess": "直排按鍵很容易猜到", "Short keyboard patterns are easy to guess": "短鍵盤重覆很容易猜到", "Custom user status messages": "自訂使用者狀態訊息", - "Unable to load commit detail: %(msg)s": "無法載入遞交的詳細資訊:", + "Unable to load commit detail: %(msg)s": "無法載入遞交的詳細資訊:%(msg)s", "Set a new status...": "設定新狀態……", "Clear status": "清除狀態" } From 8e9fcbefff4929de1df3daec7c26f342a15a071a Mon Sep 17 00:00:00 2001 From: Silvano Date: Sat, 29 Dec 2018 15:21:01 +0000 Subject: [PATCH 0061/1528] Translated using Weblate (Italian) Currently translated at 100.0% (1417 of 1417 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/it/ --- src/i18n/strings/it.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/i18n/strings/it.json b/src/i18n/strings/it.json index 9b3fe8fad4..73c85d89b3 100644 --- a/src/i18n/strings/it.json +++ b/src/i18n/strings/it.json @@ -81,8 +81,8 @@ "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s": "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s", "Register": "Registrati", "Rooms": "Stanze", - "The remote side failed to pick up": "Il destinatario non ha risposto", - "Unable to capture screen": "Impossibile acquisire lo schermo", + "The remote side failed to pick up": "Dall'altro lato non è giunta risposta", + "Unable to capture screen": "Impossibile catturare la schermata", "Call": "Chiama", "Answer": "Rispondi", "Invite to Community": "Invita alla community", @@ -101,13 +101,13 @@ "Your identity server's URL": "L'URL del tuo server identità", "Analytics": "Statistiche", "The information being sent to us to help make Riot.im better includes:": "Le informazioni inviate per aiutarci a migliorare Riot.im includono:", - "Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": "Se questa pagina include informazioni identificabili, come una stanza, utente o ID di gruppo, questi dati sono rimossi prima che vengano inviati al server.", + "Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": "Se questa pagina include informazioni identificabili, come una stanza, un utente o un ID di un gruppo, tali dati saranno rimossi prima di essere inviati al server.", "Call Failed": "Chiamata fallita", "There are unknown devices in this room: if you proceed without verifying them, it will be possible for someone to eavesdrop on your call.": "Ci sono dispositivi sconosciuti in questa stanza: se procedi senza verificarli, qualcuno avrà la possibilità di intercettare la tua chiamata.", - "Review Devices": "Revisiona i dispositivi", + "Review Devices": "Controlla i dispositivi", "Call Anyway": "Chiama comunque", "Answer Anyway": "Rispondi comunque", - "Call Timeout": "Scadenza chiamata", + "Call Timeout": "Tempo di attesa della chiamata", "Existing Call": "Chiamata esistente", "You are already in a call.": "Partecipi già ad una chiamata.", "Conference calling is in development and may not be reliable.": "Le chiamate di gruppo sono in sviluppo e potrebbero essere inaffidabili.", @@ -599,7 +599,7 @@ "Communities": "Comunità", "Home": "Inizio", "Integrations Error": "Errore di integrazioni", - "Could not connect to the integration server": "Impossibile connettere al server di integrazione", + "Could not connect to the integration server": "Impossibile connettersi al server di integrazione", "Manage Integrations": "Gestisci integrazioni", "%(nameList)s %(transitionList)s": "%(nameList)s %(transitionList)s", "%(severalUsers)sjoined %(count)s times|other": "%(severalUsers)ssono entrati %(count)s volte", @@ -1196,11 +1196,11 @@ "No Audio Outputs detected": "Nessuna uscita audio rilevata", "Audio Output": "Uscita audio", "Try the app first": "Prova prima l'app", - "A conference call could not be started because the intgrations server is not available": "La chiamata di gruppo non può essere iniziata perchè il server di integrazione non è disponibile", + "A conference call could not be started because the intgrations server is not available": "La chiamata di gruppo non può essere avviata perché il server di integrazione non è disponibile", "Call in Progress": "Chiamata in corso", "A call is already in progress!": "Una chiamata è già in corso!", "Permission Required": "Permesso richiesto", - "You do not have permission to start a conference call in this room": "Non hai il permesso di iniziare una chiamata di gruppo in questa stanza", + "You do not have permission to start a conference call in this room": "Non hai il permesso di avviare una chiamata di gruppo in questa stanza", "Jitsi Conference Calling": "Chiamata di gruppo Jitsi", "Show empty room list headings": "Mostra le intestazioni dell'elenco delle stanze vuote", "This event could not be displayed": "Questo evento non può essere mostrato", @@ -1220,7 +1220,7 @@ "The phone number field must not be blank.": "Il campo telefono non deve essere vuoto.", "The password field must not be blank.": "Il campo passwordl non deve essere vuoto.", "You can't send any messages until you review and agree to our terms and conditions.": "Non è possibile inviare alcun messaggio fino a quando non si esaminano e si accettano i nostri termini e condizioni .", - "A call is currently being placed!": "Attualmente è in corso una chiamata!", + "A call is currently being placed!": "Attualmente c'è una chiamata in corso!", "System Alerts": "Avvisi di sistema", "This homeserver has hit its Monthly Active User limit. Please contact your service administrator to continue using the service.": "L'homeserver ha raggiunto il suo limite di utenti attivi mensili. Contatta l'amministratore del servizio per continuare ad usarlo.", "This homeserver has hit its Monthly Active User limit so some users will not be able to log in. Please contact your service administrator to get this limit increased.": "Questo homeserver ha raggiunto il suo limite di utenti attivi mensili, perciò alcuni utenti non potranno accedere. Contatta l'amministratore del servizio per fare aumentare questo limite.", From 451743c459c6df713b95b55b4732641b0e398e1e Mon Sep 17 00:00:00 2001 From: Besnik Bleta Date: Thu, 3 Jan 2019 10:48:02 +0000 Subject: [PATCH 0062/1528] Translated using Weblate (Albanian) Currently translated at 99.2% (1408 of 1418 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/sq/ --- src/i18n/strings/sq.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/sq.json b/src/i18n/strings/sq.json index b5ff119659..9535635b07 100644 --- a/src/i18n/strings/sq.json +++ b/src/i18n/strings/sq.json @@ -1419,5 +1419,6 @@ "Custom user status messages": "Mesazhe vetjakë për gjendje përdoruesi", "Unable to load commit detail: %(msg)s": "S’arrihet të ngarkohen hollësi depozitimi: %(msg)s", "Set a new status...": "Caktoni një gjendje të re…", - "Clear status": "Pastroji gjendjen" + "Clear status": "Pastroji gjendjen", + "To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "Që të shihni historik mesazhesh të sigurta dhe të garantoni se mund t’i shihni mesazhet e reja në pajisje të ardhshme, ujdisni Rimarrje Mesazhesh të Sigurt." } From ea7b7797a7c5668a736439135cd54fd98aabae53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20C?= Date: Thu, 3 Jan 2019 10:55:59 +0000 Subject: [PATCH 0063/1528] Translated using Weblate (French) Currently translated at 100.0% (1418 of 1418 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/fr/ --- src/i18n/strings/fr.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json index 62e58dbd46..3c162bfae6 100644 --- a/src/i18n/strings/fr.json +++ b/src/i18n/strings/fr.json @@ -298,7 +298,7 @@ "Tried to load a specific point in this room's timeline, but was unable to find it.": "Un instant donné de la chronologie n’a pu être chargé car il n’a pas pu être trouvé.", "Turn Markdown off": "Désactiver le formatage ’Markdown’", "Turn Markdown on": "Activer le formatage ’Markdown’", - "%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).": "%(senderName)s a activé le chiffrement de bout-en-bout (algorithme %(algorithm)s).", + "%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).": "%(senderName)s a activé le chiffrement de bout en bout (algorithme %(algorithm)s).", "Unable to add email address": "Impossible d'ajouter l'adresse e-mail", "Unable to remove contact information": "Impossible de supprimer les informations du contact", "Unable to verify email address.": "Impossible de vérifier l’adresse e-mail.", @@ -926,7 +926,7 @@ "Answer": "Répondre", "Send": "Envoyer", "Old cryptography data detected": "Anciennes données de chiffrement détectées", - "Data from an older version of Riot has been detected. This will have caused end-to-end cryptography to malfunction in the older version. End-to-end encrypted messages exchanged recently whilst using the older version may not be decryptable in this version. This may also cause messages exchanged with this version to fail. If you experience problems, log out and back in again. To retain message history, export and re-import your keys.": "Nous avons détecté des données d'une ancienne version de Riot. Le chiffrement de bout-en-bout n'aura pas fonctionné correctement sur l'ancienne version. Les messages chiffrés échangés récemment dans l'ancienne version ne sont peut-être pas déchiffrables dans cette version. Les échanges de message avec cette version peuvent aussi échouer. Si vous rencontrez des problèmes, déconnectez-vous puis reconnectez-vous. Pour conserver l'historique des messages, exportez puis réimportez vos clés de chiffrement.", + "Data from an older version of Riot has been detected. This will have caused end-to-end cryptography to malfunction in the older version. End-to-end encrypted messages exchanged recently whilst using the older version may not be decryptable in this version. This may also cause messages exchanged with this version to fail. If you experience problems, log out and back in again. To retain message history, export and re-import your keys.": "Nous avons détecté des données d'une ancienne version de Riot. Le chiffrement de bout en bout n'aura pas fonctionné correctement sur l'ancienne version. Les messages chiffrés échangés récemment dans l'ancienne version ne sont peut-être pas déchiffrables dans cette version. Les échanges de message avec cette version peuvent aussi échouer. Si vous rencontrez des problèmes, déconnectez-vous puis reconnectez-vous. Pour conserver l'historique des messages, exportez puis réimportez vos clés de chiffrement.", "Warning": "Attention", "You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges.": "Vous ne pourrez pas annuler cette modification car vous vous destituez. Si vous êtes le dernier utilisateur privilégié de ce salon, il sera impossible de récupérer les privilèges.", "%(count)s of your messages have not been sent.|one": "Votre message n'a pas été envoyé.", @@ -1305,7 +1305,7 @@ "You are currently using Riot anonymously as a guest.": "Vous utilisez Riot de façon anonyme en tant qu'invité.", "Please review and accept all of the homeserver's policies": "Veuillez lire et accepter toutes les politiques du serveur d'accueil", "To avoid losing your chat history, you must export your room keys before logging out. You will need to go back to the newer version of Riot to do this": "Pour éviter de perdre l'historique de vos discussions, vous devez exporter vos clés avant de vous déconnecter. Vous devez revenir à une version plus récente de Riot pour pouvoir le faire", - "You've previously used a newer version of Riot on %(host)s. To use this version again with end to end encryption, you will need to sign out and back in again. ": "Vous avez utilisé une version plus récente de Riot sur %(host)s. Pour utiliser à nouveau cette version avec le chiffrement de bout à bout, vous devez vous déconnecter et vous reconnecter. ", + "You've previously used a newer version of Riot on %(host)s. To use this version again with end to end encryption, you will need to sign out and back in again. ": "Vous avez utilisé une version plus récente de Riot sur %(host)s. Pour utiliser à nouveau cette version avec le chiffrement de bout en bout, vous devez vous déconnecter et vous reconnecter. ", "Incompatible Database": "Base de données incompatible", "Continue With Encryption Disabled": "Continuer avec le chiffrement désactivé", "Sign in with single sign-on": "Se connecter avec l'authentification unique", @@ -1449,5 +1449,6 @@ "Custom user status messages": "Messages de statut de l'utilisateur personnalisés", "Unable to load commit detail: %(msg)s": "Impossible de charger les détails de l'envoi : %(msg)s", "Set a new status...": "Configurer un nouveau statut…", - "Clear status": "Effacer le statut" + "Clear status": "Effacer le statut", + "To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "Pour voir votre historique de messages sécurisé et vous assurer que vous pouvez voir les nouveaux messages sur de futurs appareils, configurez la récupération de messages sécurisée." } From 255688546c3ec9509d06fb4d47b15a8b1ddc9a95 Mon Sep 17 00:00:00 2001 From: Szimszon Date: Tue, 25 Dec 2018 20:47:01 +0000 Subject: [PATCH 0064/1528] Translated using Weblate (Hungarian) Currently translated at 100.0% (1418 of 1418 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/hu/ --- src/i18n/strings/hu.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json index 229dd4fc66..01239599a9 100644 --- a/src/i18n/strings/hu.json +++ b/src/i18n/strings/hu.json @@ -1449,5 +1449,6 @@ "Custom user status messages": "Egyedi felhasználói állapot üzenet", "Set a new status...": "Új állapot beállítása...", "Clear status": "Állapot törlése", - "Unable to load commit detail: %(msg)s": "Sikertelen betöltés részletek: \n%(msg)s" + "Unable to load commit detail: %(msg)s": "Sikertelen betöltés részletek: \n%(msg)s", + "To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "Ahhoz, hogy a múltbeli titkosított üzeneteidet és az újakat a leendő eszközeiden láthasd, állítsd be a Biztonságos Üzenet Visszaállítást." } From b045fe7950e67ab9cd17c6d3fb383fb3a2620f50 Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Wed, 2 Jan 2019 13:18:23 +0000 Subject: [PATCH 0065/1528] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (1418 of 1418 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/zh_Hant/ --- src/i18n/strings/zh_Hant.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/zh_Hant.json b/src/i18n/strings/zh_Hant.json index 23963c3cfa..a474724c11 100644 --- a/src/i18n/strings/zh_Hant.json +++ b/src/i18n/strings/zh_Hant.json @@ -1447,5 +1447,6 @@ "Custom user status messages": "自訂使用者狀態訊息", "Unable to load commit detail: %(msg)s": "無法載入遞交的詳細資訊:%(msg)s", "Set a new status...": "設定新狀態……", - "Clear status": "清除狀態" + "Clear status": "清除狀態", + "To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "要檢視您的安全訊息歷史並確保可以在將來的裝置上檢視新訊息,請設定安全訊息復原。" } From aab7b541a19fc731621ce2f0cc862729183fe678 Mon Sep 17 00:00:00 2001 From: Osoitz Date: Sun, 30 Dec 2018 12:03:39 +0000 Subject: [PATCH 0066/1528] Translated using Weblate (Basque) Currently translated at 100.0% (1418 of 1418 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/eu/ --- src/i18n/strings/eu.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/eu.json b/src/i18n/strings/eu.json index 9feceec6f4..bee6ef4668 100644 --- a/src/i18n/strings/eu.json +++ b/src/i18n/strings/eu.json @@ -1447,5 +1447,6 @@ "Invalid identity server discovery response": "Baliogabeko erantzuna identitate zerbitzariaren bilaketan", "A new recovery passphrase and key for Secure Messages has been detected.": "Mezu seguruentzako berreskuratze pasa-esaldi eta gako berri bat antzeman dira.", "Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "Mezu seguruak gailu honetan ezartzeak, gailu honen mezuen historiala birzifratuko du berreskuratze metodo berriarekin.", - "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Ez baduzu berreskuratze sistema berria ezarri, erasotzaile bat zure kontua atzitzen saiatzen egon daiteke. Aldatu zure kontuaren pasahitza eta ezarri berreskuratze metodo berria berehala ezarpenetan." + "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Ez baduzu berreskuratze sistema berria ezarri, erasotzaile bat zure kontua atzitzen saiatzen egon daiteke. Aldatu zure kontuaren pasahitza eta ezarri berreskuratze metodo berria berehala ezarpenetan.", + "To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "Zure mezu seguruen historiala ikusteko eta etorkizunean erabiltzen dituzun gailuetan ere mezuak ikusi ahal izango dituzula ziurtatzeko, ezarri mezuen berreskuratze segurua." } From 8dbe87f09b55d69ddf5bf1b50bd1ef5ff39ea57d Mon Sep 17 00:00:00 2001 From: Paulo Miranda Date: Sun, 6 Jan 2019 01:02:54 +0000 Subject: [PATCH 0067/1528] Translated using Weblate (Portuguese (Brazil)) Currently translated at 90.2% (1280 of 1418 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/pt_BR/ --- src/i18n/strings/pt_BR.json | 194 ++++++++++++++++++++++++++++++++++-- 1 file changed, 186 insertions(+), 8 deletions(-) diff --git a/src/i18n/strings/pt_BR.json b/src/i18n/strings/pt_BR.json index 08ad8a4bd5..e3a977e9c6 100644 --- a/src/i18n/strings/pt_BR.json +++ b/src/i18n/strings/pt_BR.json @@ -767,8 +767,8 @@ "Addresses": "Endereços", "Invalid community ID": "ID de comunidade inválido", "'%(groupId)s' is not a valid community ID": "'%(groupId)s' não é um ID de comunidade válido", - "Flair": "Flair", - "Showing flair for these communities:": "Esta sala mostrará flairs para as seguintes comunidades:", + "Flair": "Insígnia", + "Showing flair for these communities:": "Esta sala mostrará insígnias para as seguintes comunidades:", "This room is not showing flair for any communities": "Esta sala não está mostrando fairs para nenhuma comunidade", "New community ID (e.g. +foo:%(localDomain)s)": "Novo ID de comunidade (p.ex: +foo:%(localDomain)s)", "URL previews are enabled by default for participants in this room.": "Pré-visualizações de links estão ativadas por padrão para participantes desta sala.", @@ -788,7 +788,7 @@ "Failed to withdraw invitation": "Não foi possível retirar o convite", "Failed to remove user from community": "Não foi possível remover esta pessoa da comunidade", "Filter community members": "Filtrar participantes da comunidade", - "Flair will appear if enabled in room settings": "Os flairs aparecerão se estiverem ativados nas configurações da sala", + "Flair will appear if enabled in room settings": "As insígnias aparecerão se estiverem ativados nas configurações da sala", "Flair will not appear": "Os flairs não aparecerão", "Are you sure you want to remove '%(roomName)s' from %(groupId)s?": "Tem certeza que quer remover a sala '%(roomName)s' do grupo %(groupId)s?", "Removing a room from the community will also remove it from the community page.": "Remover uma sala da comunidade também a removerá da página da comunidade.", @@ -800,7 +800,7 @@ "Only visible to community members": "Apenas visível para integrantes da comunidade", "Filter community rooms": "Filtrar salas da comunidade", "Something went wrong when trying to get your communities.": "Algo deu errado quando estava carregando suas comunidades.", - "Display your community flair in rooms configured to show it.": "Mostrar o flair de sua comunidade em salas configuradas para isso.", + "Display your community flair in rooms configured to show it.": "Mostrar a insígnia de sua comunidade em salas configuradas para isso.", "You're not currently a member of any communities.": "Atualmente você não é integrante de nenhuma comunidade.", "NOTE: Apps are not end-to-end encrypted": "Nota: os apps não são criptografados ponta-a-ponta", "Do you want to load widget from URL:": "Você quer carregar o widget da URL:", @@ -849,7 +849,7 @@ "were unbanned %(count)s times|one": "tiveram seu banimento desfeito", "was unbanned %(count)s times|other": "teve seu banimento desfeito %(count)s vezes", "was unbanned %(count)s times|one": "teve seu banimento desfeito", - "were kicked %(count)s times|other": "foram excluídas/os %(count)s vezes", + "were kicked %(count)s times|other": "foram chutados %(count)s vezes", "were kicked %(count)s times|one": "foram excluídas/os", "was kicked %(count)s times|other": "foi excluída/o %(count)s vezes", "was kicked %(count)s times|one": "foi excluída/o", @@ -968,7 +968,7 @@ "If your other devices do not have the key for this message you will not be able to decrypt them.": "Se seus outros dispositivos não têm a chave para esta mensagem, você não poderá decriptá-las.", "Key request sent.": "Requisição de chave enviada.", "Re-request encryption keys from your other devices.": "Requisitar novamente chaves de encriptação de seus outros dispositivos.", - "%(user)s is a %(userRole)s": "%(user)s é %(userRole)s", + "%(user)s is a %(userRole)s": "%(user)s é um %(userRole)s", "Fetching third party location failed": "Falha ao acessar localização de terceiros", "A new version of Riot is available.": "Uma nova versão do Riot está disponível.", "I understand the risks and wish to continue": "Entendo os riscos e desejo continuar", @@ -1062,7 +1062,7 @@ "Invite to this room": "Convidar para esta sala", "Please install Chrome or Firefox for the best experience.": "Por favor Instale Chrome Ou Firefox para uma melhor Experiencia.", "Failed to get public room list": "Falha ao acessar a lista pública de salas", - "Send logs": "Enviar relatórios de erro", + "Send logs": "Enviar registros", "All messages": "Todas as mensagens", "Call invitation": "Convite para chamada", "Downloading update...": "Baixando atualização...", @@ -1114,5 +1114,183 @@ "Collapse panel": "Colapsar o painel", "With your current browser, the look and feel of the application may be completely incorrect, and some or all features may not function. If you want to try it anyway you can continue, but you are on your own in terms of any issues you may encounter!": "Com o seu navegador atual, a aparência e sensação de uso da aplicação podem estar completamente incorretas, e algumas das funcionalidades poderão não funcionar. Se você quiser tentar de qualquer maneira, pode continuar, mas aí vai ter que se virar sozinho(a) com os problemas que porventura encontrar!", "Checking for an update...": "Verificando se há atualizações...", - "There are advanced notifications which are not shown here": "Existem opções avançadas que não são exibidas aqui" + "There are advanced notifications which are not shown here": "Existem opções avançadas que não são exibidas aqui", + "Every page you use in the app": "Toda a página que você usa no aplicativo", + "e.g. ": "ex. ", + "Your User Agent": "Seu Agente de Usuário", + "Your device resolution": "Sua resolução de dispositivo", + "A conference call could not be started because the intgrations server is not available": "Não foi possível iniciar uma chamada em conferência porque o servidor de integrações não está disponível", + "Call in Progress": "Chamada em andamento", + "A call is currently being placed!": "Uma chamada está sendo feita atualmente!", + "A call is already in progress!": "Uma chamada já está em andamento!", + "Permission Required": "Permissão Exigida", + "You do not have permission to start a conference call in this room": "Você não tem permissão para iniciar uma chamada de conferência nesta sala", + "Unable to load! Check your network connectivity and try again.": "Incapaz de carregar! Verifique sua conectividade de rede e tente novamente.", + "Registration Required": "Registro requerido", + "You need to register to do this. Would you like to register now?": "Você precisa se registrar para fazer isso. Você gostaria de se registrar agora?", + "Failed to invite users to the room:": "Não foi possível convidar usuários para a sala:", + "Missing roomId.": "RoomId ausente.", + "Opens the Developer Tools dialog": "Abre a caixa de diálogo Ferramentas do desenvolvedor", + "Forces the current outbound group session in an encrypted room to be discarded": "Força a atual sessão de grupo de saída em uma sala criptografada a ser descartada", + "%(senderName)s added %(count)s %(addedAddresses)s as addresses for this room.|other": "%(senderName)s adicionado %(addedAddresses)s como endereço para esta sala.", + "%(senderName)s added %(count)s %(addedAddresses)s as addresses for this room.|one": "%(senderName)s adicionado %(addedAddresses)s como um endereço para esta sala.", + "%(senderName)s removed %(count)s %(removedAddresses)s as addresses for this room.|other": "%(senderName)s removido %(removedAddresses)s como endereços para esta sala.", + "%(senderName)s removed %(count)s %(removedAddresses)s as addresses for this room.|one": "%(senderName)s removido %(removedAddresses)s como um endereço para esta sala.", + "e.g. %(exampleValue)s": "ex. %(exampleValue)s", + "%(senderName)s set the main address for this room to %(address)s.": "%(senderName)s definiu o endereço principal desta sala para %(address)s.", + "%(senderName)s removed the main address for this room.": "%(senderName)s removeu o endereço principal para esta sala.", + "This homeserver has hit its Monthly Active User limit.": "Este homeserver atingiu seu limite de usuário ativo mensal.", + "This homeserver has exceeded one of its resource limits.": "Este homeserver ultrapassou um dos seus limites de recursos.", + "Please contact your service administrator to continue using the service.": "Por favor, entre em contato com o seu administrador de serviços para continuar usando o serviço.", + "Unable to connect to Homeserver. Retrying...": "Não é possível conectar-se ao Homeserver. Tentando novamente ...", + "You do not have permission to invite people to this room.": "Você não tem permissão para convidar pessoas para esta sala.", + "User %(user_id)s does not exist": "Usuário %(user_id)s não existe", + "Unknown server error": "Erro de servidor desconhecido", + "Use a few words, avoid common phrases": "Use algumas palavras, evite frases comuns", + "No need for symbols, digits, or uppercase letters": "Não há necessidade de símbolos, dígitos ou letras maiúsculas", + "Avoid repeated words and characters": "Evite palavras e caracteres repetidos", + "Avoid sequences": "Evite sequências", + "Avoid recent years": "Evite anos recentes", + "Avoid years that are associated with you": "Evite anos associados a você", + "Avoid dates and years that are associated with you": "Evite datas e anos associados a você", + "Capitalization doesn't help very much": "A capitalização não ajuda muito", + "All-uppercase is almost as easy to guess as all-lowercase": "Todas as maiúsculas são quase tão fáceis de adivinhar quanto todas as minúsculas", + "Reversed words aren't much harder to guess": "Palavras invertidas não são muito mais difíceis de adivinhar", + "Predictable substitutions like '@' instead of 'a' don't help very much": "Substituições previsíveis como '@' em vez de 'a' não ajudam muito", + "Add another word or two. Uncommon words are better.": "Adicione outra palavra ou duas. Palavras incomuns são melhores.", + "Repeats like \"aaa\" are easy to guess": "Repetições como \"aaa\" são fáceis de adivinhar", + "Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Repetições como \"abcabcabc\" são apenas um pouco mais difíceis de adivinhar que \"abc\"", + "Sequences like abc or 6543 are easy to guess": "Sequências como abc ou 6543 são fáceis de adivinhar", + "Recent years are easy to guess": "Os últimos anos são fáceis de adivinhar", + "%(senderName)s added %(addedAddresses)s and removed %(removedAddresses)s as addresses for this room.": "%(senderName)s adicionou %(addedAddresses)s e removeu %(removedAddresses)s como endereços para esta sala.", + "Dates are often easy to guess": "As datas costumam ser fáceis de adivinhar", + "This is a top-10 common password": "Esta é uma das top-10 senhas mais comuns", + "This is a top-100 common password": "Esta é uma das top-100 senhas mais comuns", + "This is a very common password": "Isto é uma senha muito comum", + "This is similar to a commonly used password": "Isto é similar a uma senha muito comum", + "A word by itself is easy to guess": "Uma palavra por si só é fácil de adivinhar", + "Names and surnames by themselves are easy to guess": "Nomes e sobrenomes sozinhos são fáceis de adivinhar", + "Common names and surnames are easy to guess": "Nomes e sobrenomes comuns são fáceis de adivinhar", + "Straight rows of keys are easy to guess": "Linhas retas de teclas são fáceis de adivinhar", + "Short keyboard patterns are easy to guess": "Padrões de teclado curtos são fáceis de adivinhar", + "There was an error joining the room": "Houve um erro ao entrar na sala", + "Sorry, your homeserver is too old to participate in this room.": "Desculpe, seu homeserver é muito velho para participar desta sala.", + "Please contact your homeserver administrator.": "Por favor, entre em contato com o administrador do seu homeserver.", + "Custom user status messages": "Mensagens de status de usuário personalizadas", + "Increase performance by only loading room members on first view": "Aumentar o desempenho apenas carregando membros da sala na primeira exibição", + "Backup of encryption keys to server": "Backup de chaves de criptografia para o servidor", + "Always show encryption icons": "Mostrar sempre ícones de criptografia", + "Show a reminder to enable Secure Message Recovery in encrypted rooms": "Mostrar um lembrete para ativar o Secure Message Recovery em salas criptografadas", + "Send analytics data": "Enviar dados analíticos", + "Enable widget screenshots on supported widgets": "Ativar capturas de tela do widget em widgets suportados", + "Show empty room list headings": "Mostrar cabeçalhos de lista de salas vazias", + "Show developer tools": "Mostrar ferramentas de desenvolvedor", + "Messages containing @room": "Mensagens contendo @room", + "Encrypted messages in one-to-one chats": "Mensagens criptografadas em bate-papos individuais", + "Encrypted messages in group chats": "Mensagens criptografadas em bate-papos de grupo", + "Delete Backup": "Deletar Backup", + "Delete your backed up encryption keys from the server? You will no longer be able to use your recovery key to read encrypted message history": "Excluir suas chaves de criptografia de backup do servidor? Você não poderá mais usar sua chave de recuperação para ler o histórico de mensagens criptografadas", + "Delete backup": "Deletar backup", + "Unable to load key backup status": "Não é possível carregar o status da chave de backup", + "This device is uploading keys to this backup": "Este dispositivo está carregando chaves para este backup", + "This device is not uploading keys to this backup": "Este dispositivo não está enviando chaves para este backup", + "Backup has a valid signature from this device": "O backup tem uma assinatura válida deste dispositivo", + "Pin rooms I'm mentioned in to the top of the room list": "Salas fixadas em que eu fui mencionado no topo da lista de salas", + "Pin unread rooms to the top of the room list": "Salas marcadas não lidas no topo da lista de salas", + "Backup version: ": "Versão do Backup: ", + "Algorithm: ": "Algoritmo: ", + "Restore backup": "Restaurar backup", + "No backup is present": "Não há backup disponível", + "Start a new backup": "Iniciar um novo backup", + "This event could not be displayed": "O evento não pôde ser exibido", + "Encrypting": "Criptografando", + "Encrypted, not sent": "Criptografado, não enviado", + "Use a longer keyboard pattern with more turns": "Use um padrão de teclas em diferentes direções e sentido", + "Share Link to User": "Compartilhar Link com Usuário", + "underlined": "sublinhado", + "inline-code": "código inline", + "numbered-list": "lista ordenada", + "bulleted-list": "lista não-ordenada", + "At this time it is not possible to reply with a file so this will be sent without being a reply.": "No momento, não é possível responder com um arquivo, portanto, isso será enviado sem ser uma resposta.", + "The following files cannot be uploaded:": "Os seguintes arquivos não podem ser enviados:", + "This room has been replaced and is no longer active.": "Esta sala foi substituída e não está mais ativa.", + "The conversation continues here.": "A conversa continua aqui.", + "Unable to reply": "Não é possível responder", + "At this time it is not possible to reply with an emote.": "Neste momento não é possível responder com um emote.", + "Seen by %(displayName)s (%(userName)s) at %(dateTime)s": "Visto por %(displayName)s (%(userName)s) em %(dateTime)s", + "Share room": "Compartilhar sala", + "System Alerts": "Alertas do Sistema", + "Joining room...": "Entrando na sala...", + "To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "Para visualizar seu histórico de mensagens seguras e garantir a exibição de novas mensagens em dispositivos futuros, configure Recuperação Segura de Mensagens.", + "If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.": "Se você sair ou usar outro dispositivo, perderá seu histórico de mensagens seguras. Para evitar isso, configure a Recuperação Segura de Mensagens.", + "Secure Message Recovery": "Recuperação Segura de Mensagens", + "Don't ask again": "Não pergunte novamente", + "Set up": "Configurar", + "To notify everyone in the room, you must be a": "Para notificar todos na sala, você deve ser um", + "Muted Users": "Usuários silenciados", + "Upgrade room to version %(ver)s": "Atualiza a sala para a versão %(ver)s", + "Open Devtools": "Abrir as Ferramentas de Desenvolvimento", + "Internal room ID: ": "ID da sala interno: ", + "Room version number: ": "Número de versão da sala: ", + "There is a known vulnerability affecting this room.": "Existe uma vulnerabilidade conhecida que afeta esta sala.", + "This room version is vulnerable to malicious modification of room state.": "Esta versão da sala é vulnerável à modificação mal-intencionada do estado da sala.", + "Click here to upgrade to the latest room version and ensure room integrity is protected.": "Clique aqui para atualizar para a versão mais recente do quarto e garantir que a integridade da sala esteja protegida.", + "Only room administrators will see this warning": "Somente administradores de sala verão esse aviso", + "You don't currently have any stickerpacks enabled": "Atualmente, você não tem nenhum stickerpacks ativado", + "Demote": "Reduzir privilégio", + "Demote yourself?": "Reduzir seu próprio privilégio?", + "Backup has a valid signature from verified device ": "O backup tem uma assinatura válida do dispositivo verificado", + "Backup has a valid signature from unverified device ": "O backup tem uma assinatura válida do dispositivo não verificado", + "Backup is not signed by any of your devices": "O backup não está assinado por nenhum dos seus dispositivos", + "deleted": "excluído", + "Backup has an invalid signature from verified device ": "O backup tem uma assinatura inválida do dispositivo verificado ", + "Backup has an invalid signature from unverified device ": "O backup tem uma assinatura inválida do dispositivo não verificado ", + "block-quote": "bloco de citação", + "You have no historical rooms": "Você não tem salas históricas", + "Add some now": "Adicione alguns agora", + "Stickerpack": "Stickerpack", + "Hide Stickers": "Esconder Stickers", + "Show Stickers": "Mostrar Stickers", + "In encrypted rooms, like this one, URL previews are disabled by default to ensure that your homeserver (where the previews are generated) cannot gather information about links you see in this room.": "Em salas criptografadas, como esta, as visualizações de URL são desabilitadas por padrão para garantir que o seu homeserver (onde as visualizações são geradas) não possa coletar informações sobre os links que você vê nesta sala.", + "When someone puts a URL in their message, a URL preview can be shown to give more information about that link such as the title, description, and an image from the website.": "Quando alguém coloca um URL em sua mensagem, uma visualização de URL pode ser exibida para fornecer mais informações sobre esse link, como o título, a descrição e uma imagem do site.", + "This room is a continuation of another conversation.": "Esta sala é uma continuação de outra conversa.", + "Click here to see older messages.": "Clique aqui para ver as mensagens mais antigas.", + "Please review and accept all of the homeserver's policies": "Por favor, revise e aceite todas as políticas do homeserver", + "Please review and accept the policies of this homeserver:": "Por favor, revise e aceite as políticas deste homeserver:", + "Code": "Código", + "The email field must not be blank.": "O campo de email não pode estar em branco.", + "The user name field must not be blank.": "O campo de nome de usuário não deve ficar em branco.", + "The phone number field must not be blank.": "O campo do número de telefone não pode estar em branco.", + "The password field must not be blank.": "O campo da senha não pode ficar em branco.", + "Failed to load group members": "Falha ao carregar membros do grupo", + "Please help improve Riot.im by sending anonymous usage data. This will use a cookie (please see our Cookie Policy).": "Por favor, ajude a melhorar o Riot.im enviando dados de uso anônimo. Isso usará um cookie (consulte nossa Política de cookies ).", + "Please help improve Riot.im by sending anonymous usage data. This will use a cookie.": "Por favor, ajude a melhorar o Riot.im enviando dados de uso anônimo. Isto irá usar um cookie.", + "Yes, I want to help!": "Sim, quero ajudar!", + "Please contact your service administrator to get this limit increased.": "Por favor, entre em contato com o administrador do serviço para aumentar esse limite.", + "This homeserver has hit its Monthly Active User limit so some users will not be able to log in.": "Este homeserver atingiu seu limite de usuário ativo mensal, então alguns usuários não poderão efetuar login.", + "This homeserver has exceeded one of its resource limits so some users will not be able to log in.": "Este homeserver excedeu um dos seus limites de recursos, de modo que alguns usuários não poderão efetuar login.", + "Warning: This widget might use cookies.": "Aviso: Este widget pode usar cookies.", + "Failed to remove widget": "Falha ao remover o widget", + "An error ocurred whilst trying to remove the widget from the room": "Ocorreu um erro ao tentar remover o widget da sala", + "Reload widget": "Recarregar widget", + "Picture": "Figura", + "Unable to load event that was replied to, it either does not exist or you do not have permission to view it.": "Não é possível carregar o evento que foi respondido, ele não existe ou você não tem permissão para visualizá-lo.", + "That doesn't look like a valid email address": "Isso não parece ser um endereço de e-mail válido", + "Preparing to send logs": "Preparando para enviar registros", + "Logs sent": "Registros enviados", + "Failed to send logs: ": "Falha ao enviar registros: ", + "Submit debug logs": "Submeter registros de depuração", + "Debug logs contain application usage data including your username, the IDs or aliases of the rooms or groups you have visited and the usernames of other users. They do not contain messages.": "Os registros de depuração contêm dados de uso do aplicativo, incluindo seu nome de usuário, os IDs ou aliases das salas ou grupos que você visitou e os nomes de usuários de outros usuários. Eles não contêm mensagens.", + "Before submitting logs, you must create a GitHub issue to describe your problem.": "Antes de enviar os registros, você deve criar uma questão no GitHub para descrever seu problema.", + "What GitHub issue are these logs for?": "Para qual questão do GitHub são esses registros?", + "Notes:": "Notas:", + "Unable to load commit detail: %(msg)s": "Não é possível carregar os detalhes do commit: %(msg)s", + "To avoid losing your chat history, you must export your room keys before logging out. You will need to go back to the newer version of Riot to do this": "Para evitar perder seu histórico de bate-papo, você deve exportar as chaves do seu quarto antes de fazer logout. Você precisará voltar para a versão mais recente do Riot para fazer isso", + "You've previously used a newer version of Riot on %(host)s. To use this version again with end to end encryption, you will need to sign out and back in again. ": "Você já usou uma versão mais recente do Riot em %(host)s. Para usar essa versão novamente com criptografia de ponta a ponta, você precisará sair e voltar novamente. ", + "Incompatible Database": "Banco de dados incompatível", + "Continue With Encryption Disabled": "Continuar com criptografia desativada", + "This will make your account permanently unusable. You will not be able to log in, and no one will be able to re-register the same user ID. This will cause your account to leave all rooms it is participating in, and it will remove your account details from your identity server. This action is irreversible.": "Isso tornará sua conta permanentemente inutilizável. Você não poderá efetuar login e ninguém poderá registrar novamente o mesmo ID de usuário. Isso fará com que sua conta deixe todas as salas nas quais está participando e removerá os detalhes da sua conta do seu servidor de identidade. Esta ação é irreversível.", + "Deactivating your account does not by default cause us to forget messages you have sent. If you would like us to forget your messages, please tick the box below.": "Desativar sua conta não faz com que, por padrão, esqueçamos as mensagens que você enviou. Se você quiser que esqueçamos suas mensagens, marque a caixa abaixo.", + "Message visibility in Matrix is similar to email. Our forgetting your messages means that messages you have sent will not be shared with any new or unregistered users, but registered users who already have access to these messages will still have access to their copy.": "A visibilidade da mensagem no Matrix é semelhante ao e-mail. O fato de esquecermos suas mensagens significa que as mensagens que você enviou não serão compartilhadas com usuários novos ou não registrados, mas os usuários registrados que já têm acesso a essas mensagens ainda terão acesso a suas cópias.", + "Please forget all messages I have sent when my account is deactivated (Warning: this will cause future users to see an incomplete view of conversations)": "Por favor, esqueça todas as mensagens que enviei quando minha conta for desativada (Aviso: isso fará com que futuros usuários vejam uma visão incompleta das conversas)" } From 0de3e18f01e6a8f9aab466279619067e2b79ba03 Mon Sep 17 00:00:00 2001 From: Heitor Date: Sun, 6 Jan 2019 12:18:05 +0000 Subject: [PATCH 0068/1528] Translated using Weblate (Portuguese (Brazil)) Currently translated at 91.2% (1294 of 1418 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/pt_BR/ --- src/i18n/strings/pt_BR.json | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/pt_BR.json b/src/i18n/strings/pt_BR.json index e3a977e9c6..e8f7bb31ea 100644 --- a/src/i18n/strings/pt_BR.json +++ b/src/i18n/strings/pt_BR.json @@ -1292,5 +1292,19 @@ "This will make your account permanently unusable. You will not be able to log in, and no one will be able to re-register the same user ID. This will cause your account to leave all rooms it is participating in, and it will remove your account details from your identity server. This action is irreversible.": "Isso tornará sua conta permanentemente inutilizável. Você não poderá efetuar login e ninguém poderá registrar novamente o mesmo ID de usuário. Isso fará com que sua conta deixe todas as salas nas quais está participando e removerá os detalhes da sua conta do seu servidor de identidade. Esta ação é irreversível.", "Deactivating your account does not by default cause us to forget messages you have sent. If you would like us to forget your messages, please tick the box below.": "Desativar sua conta não faz com que, por padrão, esqueçamos as mensagens que você enviou. Se você quiser que esqueçamos suas mensagens, marque a caixa abaixo.", "Message visibility in Matrix is similar to email. Our forgetting your messages means that messages you have sent will not be shared with any new or unregistered users, but registered users who already have access to these messages will still have access to their copy.": "A visibilidade da mensagem no Matrix é semelhante ao e-mail. O fato de esquecermos suas mensagens significa que as mensagens que você enviou não serão compartilhadas com usuários novos ou não registrados, mas os usuários registrados que já têm acesso a essas mensagens ainda terão acesso a suas cópias.", - "Please forget all messages I have sent when my account is deactivated (Warning: this will cause future users to see an incomplete view of conversations)": "Por favor, esqueça todas as mensagens que enviei quando minha conta for desativada (Aviso: isso fará com que futuros usuários vejam uma visão incompleta das conversas)" + "Please forget all messages I have sent when my account is deactivated (Warning: this will cause future users to see an incomplete view of conversations)": "Por favor, esqueça todas as mensagens que enviei quando minha conta for desativada (Aviso: isso fará com que futuros usuários vejam uma visão incompleta das conversas)", + "To continue, please enter your password:": "Para continuar, por favor digite sua senha:", + "password": "senha", + "Incompatible local cache": "Cache local incompatível", + "Clear cache and resync": "Limpar cache e ressincronizar", + "Riot now uses 3-5x less memory, by only loading information about other users when needed. Please wait whilst we resynchronise with the server!": "Riot agora usa 3-5x menos memória, pois carrega informação sobre outros usuários apenas quando necessário. Por favor, aguarde enquanto ressincronizamos com o servidor!", + "Updating Riot": "Atualizando Riot", + "Failed to upgrade room": "Falha ao atualizar a sala", + "The room upgrade could not be completed": "A atualização da sala não pode ser completada", + "Upgrade this room to version %(version)s": "Atualize essa sala para versão %(version)s", + "Upgrade Room Version": "Atualize a Versão da Sala", + "Upgrading this room requires closing down the current instance of the room and creating a new room it its place. To give room members the best possible experience, we will:": "Atualização dessa sala requer fechar a instância atual e criar uma nova sala em seu lugar. Para dar aos usuários a melhor experiência possível, nós vamos:", + "Create a new room with the same name, description and avatar": "Criar uma nova sala com o mesmo nome, descrição e avatar", + "Stop users from speaking in the old version of the room, and post a message advising users to move to the new room": "Impedir usuários de conversar na versão antiga da sala e postar uma mensagem aconselhando os usuários a migrarem para a nova sala", + "Put a link back to the old room at the start of the new room so people can see old messages": "Colocar um link para a sala antiga no começo da sala nova de modo que as pessoas possam ver mensagens antigas" } From e538f381a5e42d987baf3f1d730cc7c243874461 Mon Sep 17 00:00:00 2001 From: Paulo Miranda Date: Tue, 8 Jan 2019 15:05:21 +0000 Subject: [PATCH 0069/1528] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (1418 of 1418 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/pt_BR/ --- src/i18n/strings/pt_BR.json | 130 +++++++++++++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 3 deletions(-) diff --git a/src/i18n/strings/pt_BR.json b/src/i18n/strings/pt_BR.json index e8f7bb31ea..010fc6a037 100644 --- a/src/i18n/strings/pt_BR.json +++ b/src/i18n/strings/pt_BR.json @@ -863,7 +863,7 @@ "%(oneUser)schanged their avatar %(count)s times|one": "%(oneUser)s alterou a sua imagem de perfil", "%(items)s and %(count)s others|other": "%(items)s e %(count)s outras", "%(items)s and %(count)s others|one": "%(items)s e uma outra", - "collapse": "colapsar", + "collapse": "recolher", "expand": "expandir", "Custom of %(powerLevel)s": "Personalizado de %(powerLevel)s", "In reply to ": "Em resposta a ", @@ -1111,7 +1111,7 @@ "Event Content": "Conteúdo do Evento", "Thank you!": "Obrigado!", "Quote": "Citar", - "Collapse panel": "Colapsar o painel", + "Collapse panel": "Recolher painel", "With your current browser, the look and feel of the application may be completely incorrect, and some or all features may not function. If you want to try it anyway you can continue, but you are on your own in terms of any issues you may encounter!": "Com o seu navegador atual, a aparência e sensação de uso da aplicação podem estar completamente incorretas, e algumas das funcionalidades poderão não funcionar. Se você quiser tentar de qualquer maneira, pode continuar, mas aí vai ter que se virar sozinho(a) com os problemas que porventura encontrar!", "Checking for an update...": "Verificando se há atualizações...", "There are advanced notifications which are not shown here": "Existem opções avançadas que não são exibidas aqui", @@ -1306,5 +1306,129 @@ "Upgrading this room requires closing down the current instance of the room and creating a new room it its place. To give room members the best possible experience, we will:": "Atualização dessa sala requer fechar a instância atual e criar uma nova sala em seu lugar. Para dar aos usuários a melhor experiência possível, nós vamos:", "Create a new room with the same name, description and avatar": "Criar uma nova sala com o mesmo nome, descrição e avatar", "Stop users from speaking in the old version of the room, and post a message advising users to move to the new room": "Impedir usuários de conversar na versão antiga da sala e postar uma mensagem aconselhando os usuários a migrarem para a nova sala", - "Put a link back to the old room at the start of the new room so people can see old messages": "Colocar um link para a sala antiga no começo da sala nova de modo que as pessoas possam ver mensagens antigas" + "Put a link back to the old room at the start of the new room so people can see old messages": "Colocar um link para a sala antiga no começo da sala nova de modo que as pessoas possam ver mensagens antigas", + "You've previously used Riot on %(host)s with lazy loading of members enabled. In this version lazy loading is disabled. As the local cache is not compatible between these two settings, Riot needs to resync your account.": "Você já usou o Riot em %(host)s com o carregamento Lazy de membros ativado. Nesta versão, o carregamento Lazy está desativado. Como o cache local não é compatível entre essas duas configurações, a Riot precisa ressincronizar sua conta.", + "If the other version of Riot is still open in another tab, please close it as using Riot on the same host with both lazy loading enabled and disabled simultaneously will cause issues.": "Se a outra versão do Riot ainda estiver aberta em outra aba, por favor, feche-a pois usar o Riot no mesmo host com o carregamento Lazy ativado e desativado simultaneamente causará problemas.", + "Update any local room aliases to point to the new room": "Atualize todos os aliases da sala local para apontar para a nova sala", + "Log out and remove encryption keys?": "Sair e remover chaves de criptografia?", + "Clear Storage and Sign Out": "Limpar armazenamento e sair", + "Refresh": "Atualizar", + "We encountered an error trying to restore your previous session.": "Encontramos um erro ao tentar restaurar sua sessão anterior.", + "Clearing your browser's storage may fix the problem, but will sign you out and cause any encrypted chat history to become unreadable.": "Limpar o armazenamento do seu navegador pode resolver o problema, mas você será deslogado e isso fará que qualquer histórico de bate-papo criptografado fique ilegível.", + "Only use lower case letters, numbers and '=_-./'": "Utilize apenas letras minúsculas, números e '=_-. /'", + "Checking...": "Checando...", + "Share Room": "Compartilhar Sala", + "Link to most recent message": "Link para a mensagem mais recente", + "Share User": "Compartilhar Usuário", + "Share Community": "Compartilhar Comunidade", + "Share Room Message": "Compartilhar Mensagem da Sala", + "Link to selected message": "Link para a mensagem selecionada", + "COPY": "COPIAR", + "Unable to load backup status": "Não é possível carregar o status do backup", + "Unable to restore backup": "Não é possível restaurar o backup", + "No backup found!": "Nenhum backup encontrado!", + "Backup Restored": "Backup restaurado", + "Access your secure message history and set up secure messaging by entering your recovery passphrase.": "Acesse seu histórico de mensagens seguras e configure mensagens seguras digitando sua frase secreta de recuperação.", + "Next": "Próximo", + "If you've forgotten your recovery passphrase you can use your recovery key or set up new recovery options": "Se você esqueceu sua frase secreata de recuperação, você pode usar sua chave de recuperação ou configurar novas opções de recuperação", + "Enter Recovery Key": "Digite a chave de recuperação", + "This looks like a valid recovery key!": "Isso parece uma chave de recuperação válida!", + "Not a valid recovery key": "Não é uma chave de recuperação válida", + "Access your secure message history and set up secure messaging by entering your recovery key.": "Acesse seu histórico seguro de mensagens e configure mensagens seguras inserindo sua chave de recuperação.", + "If you've forgotten your recovery passphrase you can ": "Se você esqueceu sua senha de recuperação, você pode .": "Se você não quiser que o histórico de mensagens criptografadas esteja disponível em outros dispositivos, .": "Ou, se você não quiser criar uma frase secreta de recuperação, pule esta etapa e + + + + + ); + }, +}); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index ef659bf566..816506f6c3 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -222,8 +222,10 @@ "Your browser does not support the required cryptography extensions": "Your browser does not support the required cryptography extensions", "Not a valid Riot keyfile": "Not a valid Riot keyfile", "Authentication check failed: incorrect password?": "Authentication check failed: incorrect password?", + "Unrecognised address": "Unrecognised address", "You do not have permission to invite people to this room.": "You do not have permission to invite people to this room.", "User %(user_id)s does not exist": "User %(user_id)s does not exist", + "User %(user_id)s may or may not exist": "User %(user_id)s may or may not exist", "Unknown server error": "Unknown server error", "Use a few words, avoid common phrases": "Use a few words, avoid common phrases", "No need for symbols, digits, or uppercase letters": "No need for symbols, digits, or uppercase letters", @@ -291,6 +293,7 @@ "Pin unread rooms to the top of the room list": "Pin unread rooms to the top of the room list", "Enable widget screenshots on supported widgets": "Enable widget screenshots on supported widgets", "Show empty room list headings": "Show empty room list headings", + "Always retry invites for unknown users": "Always retry invites for unknown users", "Show developer tools": "Show developer tools", "Collecting app version information": "Collecting app version information", "Collecting logs": "Collecting logs", @@ -965,6 +968,9 @@ "Clear cache and resync": "Clear cache and resync", "Riot now uses 3-5x less memory, by only loading information about other users when needed. Please wait whilst we resynchronise with the server!": "Riot now uses 3-5x less memory, by only loading information about other users when needed. Please wait whilst we resynchronise with the server!", "Updating Riot": "Updating Riot", + "Failed to invite the following users": "Failed to invite the following users", + "Try again and never warn me again": "Try again and never warn me again", + "Try again": "Try again", "Failed to upgrade room": "Failed to upgrade room", "The room upgrade could not be completed": "The room upgrade could not be completed", "Upgrade this room to version %(version)s": "Upgrade this room to version %(version)s", diff --git a/src/settings/Settings.js b/src/settings/Settings.js index 1cac8559d1..507bcf49b8 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -317,6 +317,11 @@ export const SETTINGS = { displayName: _td('Show empty room list headings'), default: true, }, + "alwaysRetryInvites": { + supportedLevels: LEVELS_ACCOUNT_SETTINGS, + displayName: _td('Always retry invites for unknown users'), + default: false, + }, "showDeveloperTools": { supportedLevels: LEVELS_ACCOUNT_SETTINGS, displayName: _td('Show developer tools'), diff --git a/src/utils/MultiInviter.js b/src/utils/MultiInviter.js index ad10f28edf..0d7a8837b8 100644 --- a/src/utils/MultiInviter.js +++ b/src/utils/MultiInviter.js @@ -15,11 +15,15 @@ See the License for the specific language governing permissions and limitations under the License. */ +import React from "react"; import MatrixClientPeg from '../MatrixClientPeg'; import {getAddressType} from '../UserAddress'; import GroupStore from '../stores/GroupStore'; import Promise from 'bluebird'; import {_t} from "../languageHandler"; +import sdk from "../index"; +import Modal from "../Modal"; +import SettingsStore from "../settings/SettingsStore"; /** * Invites multiple addresses to a room or group, handling rate limiting from the server @@ -41,7 +45,7 @@ export default class MultiInviter { this.addrs = []; this.busy = false; this.completionStates = {}; // State of each address (invited or error) - this.errorTexts = {}; // Textual error per address + this.errors = {}; // { address: {errorText, errcode} } this.deferred = null; } @@ -61,7 +65,10 @@ export default class MultiInviter { for (const addr of this.addrs) { if (getAddressType(addr) === null) { this.completionStates[addr] = 'error'; - this.errorTexts[addr] = 'Unrecognised address'; + this.errors[addr] = { + errcode: 'M_INVALID', + errorText: _t('Unrecognised address'), + }; } } this.deferred = Promise.defer(); @@ -85,18 +92,23 @@ export default class MultiInviter { } getErrorText(addr) { - return this.errorTexts[addr]; + return this.errors[addr] ? this.errors[addr].errorText : null; } - async _inviteToRoom(roomId, addr) { + async _inviteToRoom(roomId, addr, ignoreProfile) { const addrType = getAddressType(addr); if (addrType === 'email') { return MatrixClientPeg.get().inviteByEmail(roomId, addr); } else if (addrType === 'mx-user-id') { - const profile = await MatrixClientPeg.get().getProfileInfo(addr); - if (!profile) { - return Promise.reject({errcode: "M_NOT_FOUND", error: "User does not have a profile."}); + if (!ignoreProfile && !SettingsStore.getValue("alwaysRetryInvites", this.roomId)) { + const profile = await MatrixClientPeg.get().getProfileInfo(addr); + if (!profile) { + return Promise.reject({ + errcode: "M_NOT_FOUND", + error: "User does not have a profile or does not exist.", + }); + } } return MatrixClientPeg.get().invite(roomId, addr); @@ -105,19 +117,113 @@ export default class MultiInviter { } } + _doInvite(address, ignoreProfile) { + return new Promise((resolve, reject) => { + let doInvite; + if (this.groupId !== null) { + doInvite = GroupStore.inviteUserToGroup(this.groupId, address); + } else { + doInvite = this._inviteToRoom(this.roomId, address, ignoreProfile); + } - _inviteMore(nextIndex) { + doInvite.then(() => { + if (this._canceled) { + return; + } + + this.completionStates[address] = 'invited'; + delete this.errors[address]; + + resolve(); + }).catch((err) => { + if (this._canceled) { + return; + } + + let errorText; + let fatal = false; + if (err.errcode === 'M_FORBIDDEN') { + fatal = true; + errorText = _t('You do not have permission to invite people to this room.'); + } else if (err.errcode === 'M_LIMIT_EXCEEDED') { + // we're being throttled so wait a bit & try again + setTimeout(() => { + this._doInvite(address, ignoreProfile).then(resolve, reject); + }, 5000); + return; + } else if (['M_NOT_FOUND', 'M_USER_NOT_FOUND'].includes(err.errcode)) { + errorText = _t("User %(user_id)s does not exist", {user_id: address}); + } else if (err.errcode === 'M_PROFILE_UNKNOWN') { + errorText = _t("User %(user_id)s may or may not exist", {user_id: address}); + } else if (err.errcode === 'M_PROFILE_NOT_FOUND' && !ignoreProfile) { + // Invite without the profile check + console.warn(`User ${address} does not have a profile - trying invite again`); + this._doInvite(address, true).then(resolve, reject); + } else { + errorText = _t('Unknown server error'); + } + + this.completionStates[address] = 'error'; + this.errors[address] = {errorText, errcode: err.errcode}; + + this.busy = !fatal; + this.fatal = fatal; + + if (fatal) { + reject(); + } else { + resolve(); + } + }); + }); + } + + _inviteMore(nextIndex, ignoreProfile) { if (this._canceled) { return; } if (nextIndex === this.addrs.length) { this.busy = false; + if (Object.keys(this.errors).length > 0 && !this.groupId) { + // There were problems inviting some people - see if we can invite them + // without caring if they exist or not. + const reinviteErrors = ['M_NOT_FOUND', 'M_USER_NOT_FOUND', 'M_PROFILE_UNKNOWN', 'M_PROFILE_NOT_FOUND']; + const reinvitableUsers = Object.keys(this.errors).filter(a => reinviteErrors.includes(this.errors[a].errcode)); + + if (reinvitableUsers.length > 0) { + const retryInvites = () => { + const promises = reinvitableUsers.map(u => this._doInvite(u, true)); + Promise.all(promises).then(() => this.deferred.resolve(this.completionStates)); + }; + + if (SettingsStore.getValue("alwaysRetryInvites", this.roomId)) { + retryInvites(); + return; + } + + const RetryInvitesDialog = sdk.getComponent("dialogs.RetryInvitesDialog"); + console.log("Showing failed to invite dialog..."); + Modal.createTrackedDialog('Failed to invite the following users to the room', '', RetryInvitesDialog, { + failedInvites: this.errors, + onTryAgain: () => retryInvites(), + onGiveUp: () => { + // Fake all the completion states because we already warned the user + for (const addr of Object.keys(this.completionStates)) { + this.completionStates[addr] = 'invited'; + } + this.deferred.resolve(this.completionStates); + }, + }); + return; + } + } this.deferred.resolve(this.completionStates); return; } const addr = this.addrs[nextIndex]; + console.log(`Inviting ${addr}`); // don't try to invite it if it's an invalid address // (it will already be marked as an error though, @@ -134,48 +240,8 @@ export default class MultiInviter { return; } - let doInvite; - if (this.groupId !== null) { - doInvite = GroupStore.inviteUserToGroup(this.groupId, addr); - } else { - doInvite = this._inviteToRoom(this.roomId, addr); - } - - doInvite.then(() => { - if (this._canceled) { return; } - - this.completionStates[addr] = 'invited'; - - this._inviteMore(nextIndex + 1); - }).catch((err) => { - if (this._canceled) { return; } - - let errorText; - let fatal = false; - if (err.errcode === 'M_FORBIDDEN') { - fatal = true; - errorText = _t('You do not have permission to invite people to this room.'); - } else if (err.errcode === 'M_LIMIT_EXCEEDED') { - // we're being throttled so wait a bit & try again - setTimeout(() => { - this._inviteMore(nextIndex); - }, 5000); - return; - } else if(err.errcode === "M_NOT_FOUND") { - errorText = _t("User %(user_id)s does not exist", {user_id: addr}); - } else { - errorText = _t('Unknown server error'); - } - this.completionStates[addr] = 'error'; - this.errorTexts[addr] = errorText; - this.busy = !fatal; - this.fatal = fatal; - - if (!fatal) { - this._inviteMore(nextIndex + 1); - } else { - this.deferred.resolve(this.completionStates); - } - }); + this._doInvite(addr, ignoreProfile).then(() => { + this._inviteMore(nextIndex + 1, ignoreProfile); + }).catch(() => this.deferred.resolve(this.completionStates)); } } From c351ee3d30d2fe6ae3fa8a023fa783791ee98162 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 10 Jan 2019 21:54:07 -0700 Subject: [PATCH 0083/1528] Appease the linter --- src/components/views/dialogs/RetryInvitesDialog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/dialogs/RetryInvitesDialog.js b/src/components/views/dialogs/RetryInvitesDialog.js index 24647ae4a0..f27b0bc08b 100644 --- a/src/components/views/dialogs/RetryInvitesDialog.js +++ b/src/components/views/dialogs/RetryInvitesDialog.js @@ -49,7 +49,7 @@ export default React.createClass({ const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); const errorList = Object.keys(this.props.failedInvites) - .map(address =>

{address}: {this.props.failedInvites[address].errorText}

); + .map(address =>

{address}: {this.props.failedInvites[address].errorText}

); return ( Date: Fri, 11 Jan 2019 16:10:35 +0100 Subject: [PATCH 0084/1528] fix typo --- src/resizer/item.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/resizer/item.js b/src/resizer/item.js index 13932f9170..e0e1ff809c 100644 --- a/src/resizer/item.js +++ b/src/resizer/item.js @@ -69,7 +69,7 @@ export default class ResizeItem { setSize(size) { this.sizer.setItemSize(this.domNode, size); - const callback = this.resizer.distributorCtor.onResized; + const callback = this.resizer.distributorCfg.onResized; if (callback) { callback(size, this.id, this.domNode); } @@ -77,7 +77,7 @@ export default class ResizeItem { clearSize() { this.sizer.clearItemSize(this.domNode); - const callback = this.resizer.distributorCtor.onResized; + const callback = this.resizer.distributorCfg.onResized; if (callback) { callback(null, this.id, this.domNode); } From a413f358f70cc3692a793c8ef45027a1ed829e1d Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 11 Jan 2019 17:17:58 +0100 Subject: [PATCH 0085/1528] normalize sizes when starting drag operation --- res/css/structures/_RoomSubList.scss | 4 +- src/resizer/distributors.js | 4 ++ src/resizer/item.js | 19 +++++++++ src/resizer/resizer.js | 3 ++ src/resizer/room.js | 60 +++++++++++----------------- 5 files changed, 51 insertions(+), 39 deletions(-) diff --git a/res/css/structures/_RoomSubList.scss b/res/css/structures/_RoomSubList.scss index 8225e1208c..08e7eec6d7 100644 --- a/res/css/structures/_RoomSubList.scss +++ b/res/css/structures/_RoomSubList.scss @@ -33,13 +33,13 @@ limitations under the License. .mx_RoomSubList { min-height: 31px; - flex: 0 10000 content; + flex: 0 10000 auto; display: flex; flex-direction: column; } .mx_RoomSubList.resized-sized { - flex: 0 1 0; + flex: 0 1 auto; } .mx_RoomSubList_nonEmpty { diff --git a/src/resizer/distributors.js b/src/resizer/distributors.js index cb876bf98c..f19b864a09 100644 --- a/src/resizer/distributors.js +++ b/src/resizer/distributors.js @@ -39,6 +39,10 @@ class FixedDistributor { resizeFromContainerOffset(offset) { this.resize(offset - this.beforeOffset); } + + start() {} + + finish() {} } diff --git a/src/resizer/item.js b/src/resizer/item.js index e0e1ff809c..ac47e3aea6 100644 --- a/src/resizer/item.js +++ b/src/resizer/item.js @@ -82,4 +82,23 @@ export default class ResizeItem { callback(null, this.id, this.domNode); } } + + + first() { + const firstHandle = Array.from(this.domNode.parentElement.children).find(el => { + return this.resizer.isResizeHandle(el); + }); + if (firstHandle) { + return ResizeItem.fromResizeHandle(firstHandle, this.resizer, this.sizer); + } + } + + last() { + const lastHandle = Array.from(this.domNode.parentElement.children).reverse().find(el => { + return this.resizer.isResizeHandle(el); + }); + if (lastHandle) { + return ResizeItem.fromResizeHandle(lastHandle, this.resizer, this.sizer); + } + } } diff --git a/src/resizer/resizer.js b/src/resizer/resizer.js index 8bdbc6cffe..16440bcc48 100644 --- a/src/resizer/resizer.js +++ b/src/resizer/resizer.js @@ -107,6 +107,7 @@ export class Resizer { } const {sizer, distributor} = this._createSizerAndDistributor(resizeHandle); + distributor.start(); const onMouseMove = (event) => { const offset = sizer.offsetFromEvent(event); @@ -118,9 +119,11 @@ export class Resizer { if (this.classNames.resizing) { this.container.classList.remove(this.classNames.resizing); } + distributor.finish(); body.removeEventListener("mouseup", onMouseUp, false); body.removeEventListener("mousemove", onMouseMove, false); }; + // TODO: listen for mouseout on document here as well body.addEventListener("mouseup", onMouseUp, false); body.addEventListener("mousemove", onMouseMove, false); } diff --git a/src/resizer/room.js b/src/resizer/room.js index 59f47f31fc..6b2951a605 100644 --- a/src/resizer/room.js +++ b/src/resizer/room.js @@ -18,7 +18,7 @@ import {Sizer} from "./sizer"; class RoomSizer extends Sizer { setItemSize(item, size) { - item.style.flexBasis = `${Math.round(size)}px`; + item.style.maxHeight = `${Math.round(size)}px`; item.classList.add("resized-sized"); // const total = this.getTotalSize(); // const percent = size / total; @@ -27,7 +27,7 @@ class RoomSizer extends Sizer { } clearItemSize(item) { - item.style.flexBasis = null; + item.style.maxHeight = null; item.classList.remove("resized-sized"); } } @@ -87,44 +87,15 @@ class RoomDistributor { return item.domNode.classList.contains("resized-sized"); } - resize(size, interactive = false) { - // console.log("*** starting resize session with size", size); - - // grow/shrink items after first? - // const itemSize = this.item.size(); - // // - // if (size < itemSize) { - // let nextItem = this.item.next(); - // while (nextItem) - // } - - if (interactive) { - const nextItem = this.item.next(); - if (nextItem) { - // let item = nextItem; - // let hasUnsizedProceedingItem = false; - // while (item) { - // if (this._isSized(item)) { - // hasUnsizedProceedingItem = true; - // item = null; - // } else { - // item = item.next(); - // } - // } - // if (!hasUnsizedProceedingItem) { - nextItem.clearSize(); - // } - } - } - + resize(size) { + console.log("*** starting resize session with size", size); let item = this.item; while (item) { - // TODO: collapsed if (this._isCollapsed(item)) { item = item.previous(); } else if (size <= MIN_SIZE) { - // console.log(" - resizing", item.id, "to min size", MIN_SIZE); + console.log(" - resizing", item.id, "to min size", MIN_SIZE); item.setSize(MIN_SIZE); const remainder = MIN_SIZE - size; item = item.previous(); @@ -144,18 +115,33 @@ class RoomDistributor { } } else { - // console.log(" - resizing", item.id, "to size", size); + console.log(" - resizing", item.id, "to size", size); item.setSize(size); item = null; size = 0; } } } - // console.log("*** ending resize session"); + console.log("*** ending resize session"); } resizeFromContainerOffset(containerOffset) { - this.resize(containerOffset - this.item.offset(), true); + this.resize(containerOffset - this.item.offset()); + } + + start() { + console.log("RoomDistributor::start: setting all items to their actual size in pixels"); + let item = this.item.first(); + while(item) { + if (!this._isCollapsed(item)) { + item.setSize(item.size()); + } + item = item.next(); + } + } + + finish() { + } } From 136dd4a556ee7691ac8e64fb41821c10faa3361a Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 11 Jan 2019 18:20:34 +0100 Subject: [PATCH 0086/1528] stop resize operation when cursor leaves viewport as mouseup can't be detected outside of viewport --- src/resizer/resizer.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/resizer/resizer.js b/src/resizer/resizer.js index 16440bcc48..5d63073da9 100644 --- a/src/resizer/resizer.js +++ b/src/resizer/resizer.js @@ -115,16 +115,17 @@ export class Resizer { }; const body = document.body; - const onMouseUp = (event) => { + const finishResize = () => { if (this.classNames.resizing) { this.container.classList.remove(this.classNames.resizing); } distributor.finish(); - body.removeEventListener("mouseup", onMouseUp, false); + body.removeEventListener("mouseup", finishResize, false); + document.removeEventListener("mouseleave", finishResize, false); body.removeEventListener("mousemove", onMouseMove, false); }; - // TODO: listen for mouseout on document here as well - body.addEventListener("mouseup", onMouseUp, false); + body.addEventListener("mouseup", finishResize, false); + document.addEventListener("mouseleave", finishResize, false); body.addEventListener("mousemove", onMouseMove, false); } From a05c0f9214833e119f09a0f7742a156482dd88f0 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 11 Jan 2019 15:46:03 -0700 Subject: [PATCH 0087/1528] Rephrase everything to be "invite anyways" rather than "retry" Also handle profile errors better --- ...itesDialog.js => AskInviteAnywayDialog.js} | 33 ++++++------ src/i18n/strings/en_EN.json | 9 ++-- src/settings/Settings.js | 4 +- src/utils/MultiInviter.js | 52 +++++++++++-------- 4 files changed, 54 insertions(+), 44 deletions(-) rename src/components/views/dialogs/{RetryInvitesDialog.js => AskInviteAnywayDialog.js} (63%) diff --git a/src/components/views/dialogs/RetryInvitesDialog.js b/src/components/views/dialogs/AskInviteAnywayDialog.js similarity index 63% rename from src/components/views/dialogs/RetryInvitesDialog.js rename to src/components/views/dialogs/AskInviteAnywayDialog.js index f27b0bc08b..5c61c3a694 100644 --- a/src/components/views/dialogs/RetryInvitesDialog.js +++ b/src/components/views/dialogs/AskInviteAnywayDialog.js @@ -23,20 +23,20 @@ import SettingsStore from "../../../settings/SettingsStore"; export default React.createClass({ propTypes: { - failedInvites: PropTypes.object.isRequired, // { address: { errcode, errorText } } - onTryAgain: PropTypes.func.isRequired, + unknownProfileUsers: PropTypes.array.isRequired, // [ {userId, errorText}... ] + onInviteAnyways: PropTypes.func.isRequired, onGiveUp: PropTypes.func.isRequired, onFinished: PropTypes.func.isRequired, }, - _onTryAgainClicked: function() { - this.props.onTryAgain(); + _onInviteClicked: function() { + this.props.onInviteAnyways(); this.props.onFinished(true); }, - _onTryAgainNeverWarnClicked: function() { - SettingsStore.setValue("alwaysRetryInvites", null, SettingLevel.ACCOUNT, true); - this.props.onTryAgain(); + _onInviteNeverWarnClicked: function() { + SettingsStore.setValue("alwaysInviteUnknownUsers", null, SettingLevel.ACCOUNT, true); + this.props.onInviteAnyways(); this.props.onFinished(true); }, @@ -48,28 +48,31 @@ export default React.createClass({ render: function() { const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); - const errorList = Object.keys(this.props.failedInvites) - .map(address =>

{address}: {this.props.failedInvites[address].errorText}

); + const errorList = this.props.unknownProfileUsers + .map(address =>
  • {address.userId}: {address.errorText}
  • ); return (
    - { errorList } +

    {_t("The following users may not exist - would you like to invite them anyways?")}

    +
      + { errorList } +
    - -
    diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 816506f6c3..4f8674db2f 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -293,7 +293,7 @@ "Pin unread rooms to the top of the room list": "Pin unread rooms to the top of the room list", "Enable widget screenshots on supported widgets": "Enable widget screenshots on supported widgets", "Show empty room list headings": "Show empty room list headings", - "Always retry invites for unknown users": "Always retry invites for unknown users", + "Always invite users which may not exist": "Always invite users which may not exist", "Show developer tools": "Show developer tools", "Collecting app version information": "Collecting app version information", "Collecting logs": "Collecting logs", @@ -884,6 +884,10 @@ "That doesn't look like a valid email address": "That doesn't look like a valid email address", "You have entered an invalid address.": "You have entered an invalid address.", "Try using one of the following valid address types: %(validTypesList)s.": "Try using one of the following valid address types: %(validTypesList)s.", + "The following users may not exist": "The following users may not exist", + "The following users may not exist - would you like to invite them anyways?": "The following users may not exist - would you like to invite them anyways?", + "Invite anyways and never warn me again": "Invite anyways and never warn me again", + "Invite anyways": "Invite anyways", "Preparing to send logs": "Preparing to send logs", "Logs sent": "Logs sent", "Thank you!": "Thank you!", @@ -968,9 +972,6 @@ "Clear cache and resync": "Clear cache and resync", "Riot now uses 3-5x less memory, by only loading information about other users when needed. Please wait whilst we resynchronise with the server!": "Riot now uses 3-5x less memory, by only loading information about other users when needed. Please wait whilst we resynchronise with the server!", "Updating Riot": "Updating Riot", - "Failed to invite the following users": "Failed to invite the following users", - "Try again and never warn me again": "Try again and never warn me again", - "Try again": "Try again", "Failed to upgrade room": "Failed to upgrade room", "The room upgrade could not be completed": "The room upgrade could not be completed", "Upgrade this room to version %(version)s": "Upgrade this room to version %(version)s", diff --git a/src/settings/Settings.js b/src/settings/Settings.js index 507bcf49b8..a007f78c1f 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -317,9 +317,9 @@ export const SETTINGS = { displayName: _td('Show empty room list headings'), default: true, }, - "alwaysRetryInvites": { + "alwaysInviteUnknownUsers": { supportedLevels: LEVELS_ACCOUNT_SETTINGS, - displayName: _td('Always retry invites for unknown users'), + displayName: _td('Always invite users which may not exist'), default: false, }, "showDeveloperTools": { diff --git a/src/utils/MultiInviter.js b/src/utils/MultiInviter.js index 0d7a8837b8..b5f4f960a9 100644 --- a/src/utils/MultiInviter.js +++ b/src/utils/MultiInviter.js @@ -101,13 +101,18 @@ export default class MultiInviter { if (addrType === 'email') { return MatrixClientPeg.get().inviteByEmail(roomId, addr); } else if (addrType === 'mx-user-id') { - if (!ignoreProfile && !SettingsStore.getValue("alwaysRetryInvites", this.roomId)) { - const profile = await MatrixClientPeg.get().getProfileInfo(addr); - if (!profile) { - return Promise.reject({ - errcode: "M_NOT_FOUND", - error: "User does not have a profile or does not exist.", - }); + if (!ignoreProfile && !SettingsStore.getValue("alwaysInviteUnknownUsers", this.roomId)) { + try { + const profile = await MatrixClientPeg.get().getProfileInfo(addr); + if (!profile) { + // noinspection ExceptionCaughtLocallyJS + throw new Error("User has no profile"); + } + } catch (e) { + throw { + errcode: "RIOT.USER_NOT_FOUND", + error: "User does not have a profile or does not exist." + }; } } @@ -119,6 +124,8 @@ export default class MultiInviter { _doInvite(address, ignoreProfile) { return new Promise((resolve, reject) => { + console.log(`Inviting ${address}`); + let doInvite; if (this.groupId !== null) { doInvite = GroupStore.inviteUserToGroup(this.groupId, address); @@ -151,13 +158,13 @@ export default class MultiInviter { this._doInvite(address, ignoreProfile).then(resolve, reject); }, 5000); return; - } else if (['M_NOT_FOUND', 'M_USER_NOT_FOUND'].includes(err.errcode)) { + } else if (['M_NOT_FOUND', 'M_USER_NOT_FOUND', 'RIOT.USER_NOT_FOUND'].includes(err.errcode)) { errorText = _t("User %(user_id)s does not exist", {user_id: address}); - } else if (err.errcode === 'M_PROFILE_UNKNOWN') { + } else if (err.errcode === 'M_PROFILE_UNDISCLOSED') { errorText = _t("User %(user_id)s may or may not exist", {user_id: address}); } else if (err.errcode === 'M_PROFILE_NOT_FOUND' && !ignoreProfile) { // Invite without the profile check - console.warn(`User ${address} does not have a profile - trying invite again`); + console.warn(`User ${address} does not have a profile - inviting anyways automatically`); this._doInvite(address, true).then(resolve, reject); } else { errorText = _t('Unknown server error'); @@ -188,28 +195,28 @@ export default class MultiInviter { if (Object.keys(this.errors).length > 0 && !this.groupId) { // There were problems inviting some people - see if we can invite them // without caring if they exist or not. - const reinviteErrors = ['M_NOT_FOUND', 'M_USER_NOT_FOUND', 'M_PROFILE_UNKNOWN', 'M_PROFILE_NOT_FOUND']; - const reinvitableUsers = Object.keys(this.errors).filter(a => reinviteErrors.includes(this.errors[a].errcode)); + const unknownProfileErrors = ['M_NOT_FOUND', 'M_USER_NOT_FOUND', 'M_PROFILE_UNDISCLOSED', 'M_PROFILE_NOT_FOUND', 'RIOT.USER_NOT_FOUND']; + const unknownProfileUsers = Object.keys(this.errors).filter(a => unknownProfileErrors.includes(this.errors[a].errcode)); - if (reinvitableUsers.length > 0) { - const retryInvites = () => { - const promises = reinvitableUsers.map(u => this._doInvite(u, true)); + if (unknownProfileUsers.length > 0) { + const inviteUnknowns = () => { + const promises = unknownProfileUsers.map(u => this._doInvite(u, true)); Promise.all(promises).then(() => this.deferred.resolve(this.completionStates)); }; - if (SettingsStore.getValue("alwaysRetryInvites", this.roomId)) { - retryInvites(); + if (SettingsStore.getValue("alwaysInviteUnknownUsers", this.roomId)) { + inviteUnknowns(); return; } - const RetryInvitesDialog = sdk.getComponent("dialogs.RetryInvitesDialog"); + const AskInviteAnywayDialog = sdk.getComponent("dialogs.AskInviteAnywayDialog"); console.log("Showing failed to invite dialog..."); - Modal.createTrackedDialog('Failed to invite the following users to the room', '', RetryInvitesDialog, { - failedInvites: this.errors, - onTryAgain: () => retryInvites(), + Modal.createTrackedDialog('Failed to invite the following users to the room', '', AskInviteAnywayDialog, { + unknownProfileUsers: unknownProfileUsers.map(u => {return {userId: u, errorText: this.errors[u].errorText};}), + onInviteAnyways: () => inviteUnknowns(), onGiveUp: () => { // Fake all the completion states because we already warned the user - for (const addr of Object.keys(this.completionStates)) { + for (const addr of unknownProfileUsers) { this.completionStates[addr] = 'invited'; } this.deferred.resolve(this.completionStates); @@ -223,7 +230,6 @@ export default class MultiInviter { } const addr = this.addrs[nextIndex]; - console.log(`Inviting ${addr}`); // don't try to invite it if it's an invalid address // (it will already be marked as an error though, From 2edea5abfa503395cb3f55edaf2a471d36bfc797 Mon Sep 17 00:00:00 2001 From: Krombel Date: Sat, 12 Jan 2019 02:44:10 +0000 Subject: [PATCH 0088/1528] Translated using Weblate (German) Currently translated at 100.0% (1418 of 1418 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/de/ --- src/i18n/strings/de_DE.json | 65 ++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/de_DE.json b/src/i18n/strings/de_DE.json index ab744d855b..cb3ee96a49 100644 --- a/src/i18n/strings/de_DE.json +++ b/src/i18n/strings/de_DE.json @@ -1384,5 +1384,68 @@ "You do not have permission to invite people to this room.": "Du hast keine Berechtigung um Personen in diesen Raum einzuladen.", "User %(user_id)s does not exist": "Benutzer %(user_id)s existiert nicht", "Unknown server error": "Unbekannter Server-Fehler", - "Failed to invite users to the room:": "Konnte Benutzer nicht in den Raum einladen:" + "Failed to invite users to the room:": "Konnte Benutzer nicht in den Raum einladen:", + "Short keyboard patterns are easy to guess": "Kurze Tastaturmuster sind einfach zu erraten", + "Show a reminder to enable Secure Message Recovery in encrypted rooms": "Zeige eine Erinnerung um die Sichere Nachrichten-Wiederherstellung in verschlüsselten Räumen zu aktivieren", + "Messages containing @room": "Nachrichten die \"@room\" enthalten", + "Encrypted messages in one-to-one chats": "Verschlüsselte Nachrichten in 1:1 Chats", + "Encrypted messages in group chats": "Verschlüsselte Nachrichten in Gruppenchats", + "Use a longer keyboard pattern with more turns": "Nutze ein längeres Tastaturmuster mit mehr Änderungen", + "Straight rows of keys are easy to guess": "Gerade Reihen von Tasten sind einfach zu erraten", + "Custom user status messages": "Angepasste Nutzerstatus-Nachrichten", + "Delete your backed up encryption keys from the server? You will no longer be able to use your recovery key to read encrypted message history": "Wirklich die gesicherten Verschlüsselungs-Schlüssel vom Server löschen? Du wirst nicht länger in der Lage sein, deinen Wiederherstellungsschlüssel zu verwenden um die verschlüsselte Nachrichtenhistorie zu lesen", + "Unable to load key backup status": "Konnte Status des Schlüsselbackups nicht laden", + "Backup has a valid signature from verified device ": "Sicherung hat eine valide Signatur von einem verifiziertem Gerät ", + "The following files cannot be uploaded:": "Die folgenden Dateien konnten nicht hochgeladen werden:", + "To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "Um deine sichere Nachrichtenhistorie zu sehen und sicherzustellen, dass du neue Nachrichten auf zukünftigen Geräten lesen kannst, richte die Sichere Nachrichten-Wiederherstellung ein.", + "If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.": "Wenn du dich abmeldest oder ein anderes Gerät verwendest, wirst du deine sichere Nachrichten-Historie verlieren. Um das zu verhindern, richte die Sichere Nachrichten-Wiederherstellung ein.", + "Secure Message Recovery": "Sichere Nachrichten-Wiederherstellung", + "Don't ask again": "Nicht erneut fragen", + "Set up": "Einrichten", + "Please review and accept all of the homeserver's policies": "Bitte sieh dir die Heimserver-Regularien an und akzeptiere sie", + "Failed to load group members": "Konnte Gruppenmitglieder nicht laden", + "That doesn't look like a valid email address": "Sieht nicht nach einer validen E-Mail-Adresse aus", + "Unable to load commit detail: %(msg)s": "Konnte Commit-Details nicht laden: %(msg)s", + "Only use lower case letters, numbers and '=_-./'": "Nutze nur Kleinbuchstaben, Nummern und '=_-./'", + "Checking...": "Überprüfe...", + "Unable to load backup status": "Konnte Backupstatus nicht laden", + "Failed to decrypt %(failedCount)s sessions!": "Konnte %(failedCount)s Sitzungen nicht entschlüsseln!", + "Restored %(sessionCount)s session keys": "%(sessionCount)s Sitzungsschlüssel wiederhergestellt", + "Access your secure message history and set up secure messaging by entering your recovery passphrase.": "Greife auf deinen sicheren Chatverlauf zu und richte sicheres Schreiben ein indem du deine Wiederherstellungspassphrase eingibst.", + "If you've forgotten your recovery passphrase you can use your recovery key or set up new recovery options": "Wenn du deinen Wiederherstellungspassphrase vergessen hast, kannst du deinen Wiederherstellungsschlüssel benutzen oder neue Wiederherstellungsoptionen einrichten", + "You've previously used a newer version of Riot on %(host)s. To use this version again with end to end encryption, you will need to sign out and back in again. ": "Du hast kürzlich eine neuere Version von Riot auf %(host)s verwendet. Um diese Version erneut mit Ende-zu-Ende-Verschlüsselung zu nutzen, musst du dich ab- und wieder anmelden. ", + "Access your secure message history and set up secure messaging by entering your recovery key.": "Auf sichere Nachrichtenhistorie zugreifen und sicheren Nachrichtenversand einrichten indem du deinen Wiederherstellungsschlüssel eingibst.", + "If you've forgotten your recovery passphrase you can ": "Wenn du deine Wiederherstellungspassphrase vergessen hast, kannst du ", + "Set a new status...": "Setze einen neuen Status...", + "Clear status": "Status löschen", + "Invalid configuration: Cannot supply a default homeserver URL and a default server name": "Fehlerhafte Konfiguration: Kann keine Standard-Heimserver-URL und Standard-Servernamen bereitstellen", + "Unknown error discovering homeserver": "Unbekannter Fehler beim Aufspüren des Heimservers", + "%(count)s Notifications|other": "%(count)s Benachrichtigungen", + "%(count)s Notifications|one": "%(count)s Benachrichtigung", + "File is too big. Maximum file size is %(fileSize)s": "Datei ist zu groß. Maximale Dateigröße ist %(fileSize)s", + "Invalid homeserver discovery response": "Ungültige Antwort beim Aufspüren des Heimservers", + "Invalid identity server discovery response": "Ungültige Antwort beim Aufspüren des Identitätsservers", + "General failure": "Allgemeiner Fehler", + "Failed to perform homeserver discovery": "Fehler beim Aufspüren des Heimservers", + "Unknown failure discovering homeserver": "Unbekannter Fehler beim Aufspüren des Heimservers", + "Great! This passphrase looks strong enough.": "Gut! Diese Passphrase sieht start genug aus.", + "Secure your encrypted message history with a Recovery Passphrase.": "Sichere deine sichere Nachrichtenhistorie mit einer Wiederherstellungspassphrase.", + "If you don't want encrypted message history to be available on other devices, .": "Wenn du deine verschlüsselte Nachrichtenhistorie nicht auf anderen Geräten verfügbar haben möchtest, .", + "Or, if you don't want to create a Recovery Passphrase, skip this step and .": "Oder, wenn du keine Wiederherstellungspassphrase erzeugen möchtest, überspringe diesen Schritt und .", + "Type in your Recovery Passphrase to confirm you remember it. If it helps, add it to your password manager or store it somewhere safe.": "Gebe deine Wiederherstellungspassphrase ein um zu bestätigen, dass du dich daran erinnern kannst. Wenn es hilft, füge sie deinem Passwortmanager hinzu oder speichere sie an einem sicheren Ort.", + "As a safety net, you can use it to restore your encrypted message history if you forget your Recovery Passphrase.": "Als Sicherheitsnetz kannst du ihn benutzen um deine verschlüsselte Nachrichtenhistorie wiederherzustellen, falls du deine Wiederherstellungspassphrase vergessen hast.", + "As a safety net, you can use it to restore your encrypted message history.": "Als Sicherheitsnetz kannst du ihn benutzen um deine verschlüsselte Nachrichtenhistorie wiederherzustellen.", + "Your Recovery Key has been copied to your clipboard, paste it to:": "Dein Wiederherstellungsschlüssel wurde in deine Zwischenablage kopiert. Füge ihn hier ein:", + "Your Recovery Key is in your Downloads folder.": "Dein Wiederherstellungsschlüssel ist in deinem Downloads-Ordner.", + "Set up Secure Message Recovery": "Richte Sichere Nachrichten-Wiederherstellung ein", + "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Ohne Sichere Nachrichten-Wiederherstellung einzurichten, wirst du deine sichere Nachrichtenhistorie verlieren, wenn du dich abmeldest.", + "If you don't want to set this up now, you can later in Settings.": "Wenn du dies jetzt nicht einrichten willst, kannst du dies später in den Einstellungen tun.", + "New Recovery Method": "Neue Wiederherstellungsmethode", + "A new recovery passphrase and key for Secure Messages has been detected.": "Eine neue Wiederherstellungspassphrase und ein neuer -schlüssel für sichere Nachrichten wurde entdeckt.", + "Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "Beim einrichten von Sichere Nachrichten auf diesem Gerät wird die Nachrichtenhistorie mit der neuen Wiederherstellungsmethode erneut verschlüsselt.", + "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Wenn du die neue Wiederherstellungsmethode nicht eingerichtet hast, kann ein Angreifer versuchen Zugang zu deinem Konto zu erlangen. Ändere sofort dein Passwort und setze eine neue Wiederherstellungsmethode.", + "Set up Secure Messages": "Richte sichere Nachrichten ein", + "Go to Settings": "Gehe zu Einstellungen", + "Sign in with single sign-on": "Mit Single Sign-On anmelden", + "Without setting up Secure Message Recovery, you won't be able to restore your encrypted message history if you log out or use another device.": "Wenn du die Sichere Nachrichten-Wiederherstellung nicht einrichtest, wirst du nicht in der Lage sein deine verschlüsselte Nachrichtenhistorie wiederherzustellen, wenn du dich abmeldest oder ein weiteres Gerät benutzt." } From cb5ad8d6f900073925244f6d59c07396d94c2c80 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Sun, 13 Jan 2019 14:47:08 +0000 Subject: [PATCH 0089/1528] Limit the length of topics and names in the RoomDirectory --- src/components/structures/RoomDirectory.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/components/structures/RoomDirectory.js b/src/components/structures/RoomDirectory.js index 4c7d004015..762185146c 100644 --- a/src/components/structures/RoomDirectory.js +++ b/src/components/structures/RoomDirectory.js @@ -34,6 +34,9 @@ import { _t } from '../../languageHandler'; import {instanceForInstanceId, protocolNameForInstanceId} from '../../utils/DirectoryUtils'; +const MAX_NAME_LENGTH = 80; +const MAX_TOPIC_LENGTH = 160; + linkifyMatrix(linkify); module.exports = React.createClass({ @@ -390,7 +393,6 @@ module.exports = React.createClass({ const self = this; let guestRead; let guestJoin; let perms; for (let i = 0; i < rooms.length; i++) { - const name = rooms[i].name || get_display_alias_for_room(rooms[i]) || _t('Unnamed room'); guestRead = null; guestJoin = null; @@ -410,7 +412,15 @@ module.exports = React.createClass({ perms =
    {guestRead}{guestJoin}
    ; } + let name = rooms[i].name || get_display_alias_for_room(rooms[i]) || _t('Unnamed room'); + if (name.length > MAX_NAME_LENGTH) { + name = `${name.substring(0, MAX_NAME_LENGTH)}...`; + } + let topic = rooms[i].topic || ''; + if (topic.length > MAX_TOPIC_LENGTH) { + topic = `${topic.substring(0, MAX_TOPIC_LENGTH)}...`; + } topic = linkifyString(sanitizeHtml(topic)); rows.push( From 961e0d24dfe05101469b741857fa341fa5b97c8f Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 14 Jan 2019 14:41:31 +0100 Subject: [PATCH 0090/1528] flex-basis to 0 so sublists shrink/grow not-relative to their content --- res/css/structures/_RoomSubList.scss | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/res/css/structures/_RoomSubList.scss b/res/css/structures/_RoomSubList.scss index 08e7eec6d7..b7fe19ca89 100644 --- a/res/css/structures/_RoomSubList.scss +++ b/res/css/structures/_RoomSubList.scss @@ -39,7 +39,15 @@ limitations under the License. } .mx_RoomSubList.resized-sized { - flex: 0 1 auto; + /* + flex-basis to 0 so sublists + are not shrinking/growing relative + to their content (as would be the case with auto), + as this intervenes with sizing an item exactly + when not available space is available + in the flex container + */ + flex: 1 1 0; } .mx_RoomSubList_nonEmpty { From 9ecb23ce71103ec7316799b895ba280e03fd09f9 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 14 Jan 2019 20:24:54 +0100 Subject: [PATCH 0091/1528] cleanup - move some methods to ResizeItem subclass - allow distributor to instanciate sizer and resizeitem it needs through static factory methods, instead of passing in another ctor a distributor can only function with the right item and sizer anyways. - use consistent import/export style - remove obsolete code --- src/components/views/rooms/RoomList.js | 2 +- src/resizer/distributors.js | 43 ++++++---- src/resizer/index.js | 8 +- src/resizer/item.js | 27 ++++--- src/resizer/resizer.js | 30 ++----- src/resizer/room.js | 108 +++++++++---------------- src/resizer/sizer.js | 9 +-- 7 files changed, 94 insertions(+), 133 deletions(-) diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 636000c175..79b608ac95 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -167,7 +167,7 @@ module.exports = React.createClass({ const cfg = { onResized: this._onSubListResize, }; - this.resizer = new Resizer(this.resizeContainer, RoomDistributor, cfg, RoomSizer); + this.resizer = new Resizer(this.resizeContainer, RoomDistributor, cfg); this.resizer.setClassNames({ handle: "mx_ResizeHandle", vertical: "mx_ResizeHandle_vertical", diff --git a/src/resizer/distributors.js b/src/resizer/distributors.js index f19b864a09..d273f2782b 100644 --- a/src/resizer/distributors.js +++ b/src/resizer/distributors.js @@ -14,6 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ +import ResizeItem from "./item"; +import Sizer from "./sizer"; + /** distributors translate a moving cursor into CSS/DOM changes by calling the sizer @@ -26,7 +29,15 @@ they have two methods: the offset from the container edge of where the mouse cursor is. */ -class FixedDistributor { +export class FixedDistributor { + static createItem(resizeHandle, resizer, sizer) { + return new ResizeItem(resizeHandle, resizer, sizer); + } + + static createSizer(containerElement, vertical, reverse) { + return new Sizer(containerElement, vertical, reverse); + } + constructor(item) { this.item = item; this.beforeOffset = item.offset(); @@ -45,12 +56,23 @@ class FixedDistributor { finish() {} } +class CollapseItem extends ResizeItem { + notifyCollapsed(collapsed) { + const callback = this.resizer.config.onCollapsed; + if (callback) { + callback(collapsed, this.id, this.domNode); + } + } +} -class CollapseDistributor extends FixedDistributor { - constructor(item, sizer, _container, config) { +export class CollapseDistributor extends FixedDistributor { + static createItem(resizeHandle, resizer, sizer) { + return new CollapseItem(resizeHandle, resizer, sizer); + } + + constructor(item, config) { super(item); this.toggleSize = config && config.toggleSize; - this.onCollapsed = config && config.onCollapsed; this.isCollapsed = false; } @@ -58,13 +80,9 @@ class CollapseDistributor extends FixedDistributor { const isCollapsedSize = newSize < this.toggleSize; if (isCollapsedSize && !this.isCollapsed) { this.isCollapsed = true; - if (this.onCollapsed) { - this.onCollapsed(true, this.item); - } + this.item.notifyCollapsed(true); } else if (!isCollapsedSize && this.isCollapsed) { - if (this.onCollapsed) { - this.onCollapsed(false, this.item); - } + this.item.notifyCollapsed(false); this.isCollapsed = false; } if (!isCollapsedSize) { @@ -72,8 +90,3 @@ class CollapseDistributor extends FixedDistributor { } } } - -module.exports = { - FixedDistributor, - CollapseDistributor, -}; diff --git a/src/resizer/index.js b/src/resizer/index.js index 0720fa36ce..364d077037 100644 --- a/src/resizer/index.js +++ b/src/resizer/index.js @@ -14,17 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {Sizer, FlexSizer} from "./sizer"; import {FixedDistributor, CollapseDistributor} from "./distributors"; -import {Resizer} from "./resizer"; -import {RoomSizer, RoomDistributor} from "./room"; +import Resizer from "./resizer"; +import RoomDistributor from "./room"; module.exports = { Resizer, - Sizer, - FlexSizer, FixedDistributor, CollapseDistributor, - RoomSizer, RoomDistributor, }; diff --git a/src/resizer/item.js b/src/resizer/item.js index ac47e3aea6..6192c6eebb 100644 --- a/src/resizer/item.js +++ b/src/resizer/item.js @@ -15,7 +15,11 @@ limitations under the License. */ export default class ResizeItem { - constructor(domNode, id, reverse, resizer, sizer) { + constructor(handle, resizer, sizer) { + const id = handle.getAttribute("data-id"); + const reverse = resizer.isReverseResizeHandle(handle); + const domNode = reverse ? handle.nextElementSibling : handle.previousElementSibling; + this.domNode = domNode; this.id = id; this.reverse = reverse; @@ -23,11 +27,9 @@ export default class ResizeItem { this.sizer = sizer; } - static fromResizeHandle(handle, resizer, sizer) { - const id = handle.getAttribute("data-id"); - const reverse = resizer.isReverseResizeHandle(handle); - const domNode = reverse ? handle.nextElementSibling : handle.previousElementSibling; - return new ResizeItem(domNode, id, reverse, resizer, sizer); + _copyWith(handle, resizer, sizer) { + const Ctor = this.constructor; + return new Ctor(handle, resizer, sizer); } _advance(forwards) { @@ -43,9 +45,10 @@ export default class ResizeItem { } else { handle = handle.previousElementSibling; } - } while(handle && !this.resizer.isResizeHandle(handle)); + } while (handle && !this.resizer.isResizeHandle(handle)); + if (handle) { - const nextHandle = ResizeItem.fromResizeHandle(handle, this.resizer, this.sizer); + const nextHandle = this._copyWith(handle, this.resizer, this.sizer); nextHandle.reverse = this.reverse; return nextHandle; } @@ -69,7 +72,7 @@ export default class ResizeItem { setSize(size) { this.sizer.setItemSize(this.domNode, size); - const callback = this.resizer.distributorCfg.onResized; + const callback = this.resizer.config.onResized; if (callback) { callback(size, this.id, this.domNode); } @@ -77,7 +80,7 @@ export default class ResizeItem { clearSize() { this.sizer.clearItemSize(this.domNode); - const callback = this.resizer.distributorCfg.onResized; + const callback = this.resizer.config.onResized; if (callback) { callback(null, this.id, this.domNode); } @@ -89,7 +92,7 @@ export default class ResizeItem { return this.resizer.isResizeHandle(el); }); if (firstHandle) { - return ResizeItem.fromResizeHandle(firstHandle, this.resizer, this.sizer); + return this._copyWith(firstHandle, this.resizer, this.sizer); } } @@ -98,7 +101,7 @@ export default class ResizeItem { return this.resizer.isResizeHandle(el); }); if (lastHandle) { - return ResizeItem.fromResizeHandle(lastHandle, this.resizer, this.sizer); + return this._copyWith(lastHandle, this.resizer, this.sizer); } } } diff --git a/src/resizer/resizer.js b/src/resizer/resizer.js index 5d63073da9..4d999652a6 100644 --- a/src/resizer/resizer.js +++ b/src/resizer/resizer.js @@ -14,9 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {Sizer} from "./sizer"; -import ResizeItem from "./item"; - /* classNames: // class on resize-handle @@ -30,14 +27,13 @@ classNames: */ -export class Resizer { +export default class Resizer { // TODO move vertical/horizontal to config option/container class // as it doesn't make sense to mix them within one container/Resizer - constructor(container, distributorCtor, distributorCfg, sizerCtor = Sizer) { + constructor(container, distributorCtor, config) { this.container = container; this.distributorCtor = distributorCtor; - this.distributorCfg = distributorCfg; - this.sizerCtor = sizerCtor; + this.config = config; this.classNames = { handle: "resizer-handle", reverse: "resizer-reverse", @@ -132,25 +128,13 @@ export class Resizer { _createSizerAndDistributor(resizeHandle) { const vertical = resizeHandle.classList.contains(this.classNames.vertical); const reverse = this.isReverseResizeHandle(resizeHandle); - // eslint-disable-next-line new-cap - const sizer = new this.sizerCtor(this.container, vertical, reverse); - const item = ResizeItem.fromResizeHandle(resizeHandle, this, sizer); - // eslint-disable-next-line new-cap - const distributor = new this.distributorCtor( - item, - sizer, - this.container, - this.distributorCfg - ); + const Distributor = this.distributorCtor; + const sizer = Distributor.createSizer(this.container, vertical, reverse); + const item = Distributor.createItem(resizeHandle, this, sizer); + const distributor = new Distributor(item, this.config); return {sizer, distributor}; } - _getResizableItems(reverse) { - return this._getResizeHandles().map((handle) => { - return ResizeItem.fromResizeHandle(handle); - }); - } - _getResizeHandles() { return Array.from(this.container.children).filter(el => { return this.isResizeHandle(el); diff --git a/src/resizer/room.js b/src/resizer/room.js index 6b2951a605..e8c57b0450 100644 --- a/src/resizer/room.js +++ b/src/resizer/room.js @@ -14,16 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {Sizer} from "./sizer"; +import Sizer from "./sizer"; +import ResizeItem from "./item"; class RoomSizer extends Sizer { setItemSize(item, size) { item.style.maxHeight = `${Math.round(size)}px`; item.classList.add("resized-sized"); - // const total = this.getTotalSize(); - // const percent = size / total; - // const growFactor = Math.round(1 + (percent * 100)); - // item.style.flexGrow = `${growFactor}`; } clearItemSize(item) { @@ -32,38 +29,36 @@ class RoomSizer extends Sizer { } } -/* -class RoomSubList extends ResizeItem { - collapsed() { - - } - - id() { - +class RoomSubListItem extends ResizeItem { + isCollapsed() { + return this.domNode.classList.contains("mx_RoomSubList_hidden"); } maxSize() { - + const scrollItem = this.domNode.querySelector(".mx_RoomSubList_scroll"); + const header = this.domNode.querySelector(".mx_RoomSubList_labelContainer"); + const headerHeight = this.sizer.getItemSize(header); + return headerHeight + scrollItem.scrollHeight; } minSize() { + return 74; //size of header + 1 room tile + } + isSized() { + return this.domNode.classList.contains("resized-sized"); } } -*/ -const MIN_SIZE = 74; -// would be good to have a way in here to know if the item can be resized -// - collapsed items can't be resized (.mx_RoomSubList_hidden) -// - items at MIN_SIZE can't be resized smaller -// - items at maxContentHeight can't be resized larger +export default class RoomDistributor { + static createItem(resizeHandle, resizer, sizer) { + return new RoomSubListItem(resizeHandle, resizer, sizer); + } + + static createSizer(containerElement, vertical, reverse) { + return new RoomSizer(containerElement, vertical, reverse); + } -// if you shrink the predecesor, and start dragging down again afterwards, which item has to grow? -/* - either items before (starting from first or last) - or -*/ -class RoomDistributor { constructor(item) { this.item = item; } @@ -72,57 +67,40 @@ class RoomDistributor { return 1; } - _isCollapsed(item) { - return item.domNode.classList.contains("mx_RoomSubList_hidden"); - } - - _contentSize(item) { - const scrollItem = item.domNode.querySelector(".mx_RoomSubList_scroll"); - const header = item.domNode.querySelector(".mx_RoomSubList_labelContainer"); - const headerHeight = item.sizer.getItemSize(header); - return headerHeight + scrollItem.scrollHeight; - } - - _isSized(item) { - return item.domNode.classList.contains("resized-sized"); - } - resize(size) { - console.log("*** starting resize session with size", size); + //console.log("*** starting resize session with size", size); let item = this.item; while (item) { - if (this._isCollapsed(item)) { + const minSize = item.minSize(); + if (item.isCollapsed()) { item = item.previous(); - } - else if (size <= MIN_SIZE) { - console.log(" - resizing", item.id, "to min size", MIN_SIZE); - item.setSize(MIN_SIZE); - const remainder = MIN_SIZE - size; + } else if (size <= minSize) { + //console.log(" - resizing", item.id, "to min size", minSize); + item.setSize(minSize); + const remainder = minSize - size; item = item.previous(); if (item) { size = item.size() - remainder - this._handleSize(); } - } - else { - const contentSize = this._contentSize(item); - if (size > contentSize) { - // console.log(" - resizing", item.id, "to contentSize", contentSize); - item.setSize(contentSize); - const remainder = size - contentSize; + } else { + const maxSize = item.maxSize(); + if (size > maxSize) { + // console.log(" - resizing", item.id, "to maxSize", maxSize); + item.setSize(maxSize); + const remainder = size - maxSize; item = item.previous(); if (item) { size = item.size() + remainder; // todo: handle size here? } - } - else { - console.log(" - resizing", item.id, "to size", size); + } else { + //console.log(" - resizing", item.id, "to size", size); item.setSize(size); item = null; size = 0; } } } - console.log("*** ending resize session"); + //console.log("*** ending resize session"); } resizeFromContainerOffset(containerOffset) { @@ -130,10 +108,10 @@ class RoomDistributor { } start() { - console.log("RoomDistributor::start: setting all items to their actual size in pixels"); + // set all max-height props to the actual height. let item = this.item.first(); - while(item) { - if (!this._isCollapsed(item)) { + while (item) { + if (!item.isCollapsed() && item.isSized()) { item.setSize(item.size()); } item = item.next(); @@ -141,11 +119,5 @@ class RoomDistributor { } finish() { - } } - -module.exports = { - RoomSizer, - RoomDistributor, -}; diff --git a/src/resizer/sizer.js b/src/resizer/sizer.js index cdb11f3270..50861d34d5 100644 --- a/src/resizer/sizer.js +++ b/src/resizer/sizer.js @@ -18,7 +18,7 @@ limitations under the License. implements DOM/CSS operations for resizing. The sizer determines what CSS mechanism is used for sizing items, like flexbox, ... */ -export class Sizer { +export default class Sizer { constructor(container, vertical, reverse) { this.container = container; this.reverse = reverse; @@ -86,10 +86,3 @@ export class Sizer { } } } - -export class FlexSizer extends Sizer { - setItemSize(item, size) { - item.style.flexGrow = `0`; - item.style.flexBasis = `${Math.round(size)}px`; - } -} From 7e395f0fb6a06cd82b356213285866b2694dbff3 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 14 Jan 2019 20:33:33 +0100 Subject: [PATCH 0092/1528] cleanup - part II reshuffle file structure to make more sense --- src/components/views/rooms/RoomList.js | 4 +- src/resizer/distributors/collapse.js | 53 +++++++++++++++++++ .../fixed.js} | 41 ++------------ .../{room.js => distributors/roomsublist.js} | 6 +-- src/resizer/index.js | 7 +-- 5 files changed, 65 insertions(+), 46 deletions(-) create mode 100644 src/resizer/distributors/collapse.js rename src/resizer/{distributors.js => distributors/fixed.js} (58%) rename src/resizer/{room.js => distributors/roomsublist.js} (97%) diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 79b608ac95..cb3cb49cd4 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -36,7 +36,7 @@ import GroupStore from '../../../stores/GroupStore'; import RoomSubList from '../../structures/RoomSubList'; import ResizeHandle from '../elements/ResizeHandle'; -import {Resizer, RoomDistributor, RoomSizer} from '../../../resizer' +import {Resizer, RoomSubListDistributor} from '../../../resizer' const HIDE_CONFERENCE_CHANS = true; const STANDARD_TAGS_REGEX = /^(m\.(favourite|lowpriority|server_notice)|im\.vector\.fake\.(invite|recent|direct|archived))$/; @@ -167,7 +167,7 @@ module.exports = React.createClass({ const cfg = { onResized: this._onSubListResize, }; - this.resizer = new Resizer(this.resizeContainer, RoomDistributor, cfg); + this.resizer = new Resizer(this.resizeContainer, RoomSubListDistributor, cfg); this.resizer.setClassNames({ handle: "mx_ResizeHandle", vertical: "mx_ResizeHandle_vertical", diff --git a/src/resizer/distributors/collapse.js b/src/resizer/distributors/collapse.js new file mode 100644 index 0000000000..d9d596299d --- /dev/null +++ b/src/resizer/distributors/collapse.js @@ -0,0 +1,53 @@ +/* +Copyright 2018 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import FixedDistributor from "./fixed"; +import ResizeItem from "../item"; + +class CollapseItem extends ResizeItem { + notifyCollapsed(collapsed) { + const callback = this.resizer.config.onCollapsed; + if (callback) { + callback(collapsed, this.id, this.domNode); + } + } +} + +export default class CollapseDistributor extends FixedDistributor { + static createItem(resizeHandle, resizer, sizer) { + return new CollapseItem(resizeHandle, resizer, sizer); + } + + constructor(item, config) { + super(item); + this.toggleSize = config && config.toggleSize; + this.isCollapsed = false; + } + + resize(newSize) { + const isCollapsedSize = newSize < this.toggleSize; + if (isCollapsedSize && !this.isCollapsed) { + this.isCollapsed = true; + this.item.notifyCollapsed(true); + } else if (!isCollapsedSize && this.isCollapsed) { + this.item.notifyCollapsed(false); + this.isCollapsed = false; + } + if (!isCollapsedSize) { + super.resize(newSize); + } + } +} diff --git a/src/resizer/distributors.js b/src/resizer/distributors/fixed.js similarity index 58% rename from src/resizer/distributors.js rename to src/resizer/distributors/fixed.js index d273f2782b..843d8367e0 100644 --- a/src/resizer/distributors.js +++ b/src/resizer/distributors/fixed.js @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import ResizeItem from "./item"; -import Sizer from "./sizer"; +import ResizeItem from "../item"; +import Sizer from "../sizer"; /** distributors translate a moving cursor into @@ -29,7 +29,7 @@ they have two methods: the offset from the container edge of where the mouse cursor is. */ -export class FixedDistributor { +export default class FixedDistributor { static createItem(resizeHandle, resizer, sizer) { return new ResizeItem(resizeHandle, resizer, sizer); } @@ -55,38 +55,3 @@ export class FixedDistributor { finish() {} } - -class CollapseItem extends ResizeItem { - notifyCollapsed(collapsed) { - const callback = this.resizer.config.onCollapsed; - if (callback) { - callback(collapsed, this.id, this.domNode); - } - } -} - -export class CollapseDistributor extends FixedDistributor { - static createItem(resizeHandle, resizer, sizer) { - return new CollapseItem(resizeHandle, resizer, sizer); - } - - constructor(item, config) { - super(item); - this.toggleSize = config && config.toggleSize; - this.isCollapsed = false; - } - - resize(newSize) { - const isCollapsedSize = newSize < this.toggleSize; - if (isCollapsedSize && !this.isCollapsed) { - this.isCollapsed = true; - this.item.notifyCollapsed(true); - } else if (!isCollapsedSize && this.isCollapsed) { - this.item.notifyCollapsed(false); - this.isCollapsed = false; - } - if (!isCollapsedSize) { - super.resize(newSize); - } - } -} diff --git a/src/resizer/room.js b/src/resizer/distributors/roomsublist.js similarity index 97% rename from src/resizer/room.js rename to src/resizer/distributors/roomsublist.js index e8c57b0450..1e5ce0fc92 100644 --- a/src/resizer/room.js +++ b/src/resizer/distributors/roomsublist.js @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import Sizer from "./sizer"; -import ResizeItem from "./item"; +import Sizer from "../sizer"; +import ResizeItem from "../item"; class RoomSizer extends Sizer { setItemSize(item, size) { @@ -50,7 +50,7 @@ class RoomSubListItem extends ResizeItem { } } -export default class RoomDistributor { +export default class RoomSubListDistributor { static createItem(resizeHandle, resizer, sizer) { return new RoomSubListItem(resizeHandle, resizer, sizer); } diff --git a/src/resizer/index.js b/src/resizer/index.js index 364d077037..bc4c8f388c 100644 --- a/src/resizer/index.js +++ b/src/resizer/index.js @@ -14,13 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {FixedDistributor, CollapseDistributor} from "./distributors"; +import FixedDistributor from "./distributors/fixed"; +import CollapseDistributor from "./distributors/collapse"; +import RoomSubListDistributor from "./distributors/roomsublist"; import Resizer from "./resizer"; -import RoomDistributor from "./room"; module.exports = { Resizer, FixedDistributor, CollapseDistributor, - RoomDistributor, + RoomSubListDistributor, }; From aa90e9591ade9eb1f8edffedce2ce0f8d1a29b97 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 15 Jan 2019 12:56:33 +0100 Subject: [PATCH 0093/1528] fix min & max size for empty sublists --- src/resizer/distributors/roomsublist.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/resizer/distributors/roomsublist.js b/src/resizer/distributors/roomsublist.js index 1e5ce0fc92..516c4da3e2 100644 --- a/src/resizer/distributors/roomsublist.js +++ b/src/resizer/distributors/roomsublist.js @@ -35,14 +35,15 @@ class RoomSubListItem extends ResizeItem { } maxSize() { - const scrollItem = this.domNode.querySelector(".mx_RoomSubList_scroll"); const header = this.domNode.querySelector(".mx_RoomSubList_labelContainer"); + const scrollItem = this.domNode.querySelector(".mx_RoomSubList_scroll"); const headerHeight = this.sizer.getItemSize(header); - return headerHeight + scrollItem.scrollHeight; + return headerHeight + (scrollItem ? scrollItem.scrollHeight : 0); } minSize() { - return 74; //size of header + 1 room tile + const isNotEmpty = this.domNode.classList.contains("mx_RoomSubList_nonEmpty"); + return isNotEmpty ? 74 : 31; //size of header + 1? room tile (see room sub list css) } isSized() { From 3c7bed97ac8c5f2c06ca77d9ce13f29be364ca60 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 15 Jan 2019 12:56:48 +0100 Subject: [PATCH 0094/1528] size all items to rendered height when starting drag operation before, we'd only normalize the sublists that had already been sized manually. As non-sized items still have flex-basis: auto, they would claim all the space, and mixing sized and unsized items would be badly broken. Now, on the first click, all items are sized to their rendered size which means they won't flex anymore, but at least the resizing works this way Another downside is that when resizing while a sublist is collapsed, it's reverted to 100px and if a size had been set before, it's forgotten. No way around this with this approach I'm afraid. --- src/resizer/distributors/roomsublist.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/resizer/distributors/roomsublist.js b/src/resizer/distributors/roomsublist.js index 516c4da3e2..e6f07a648d 100644 --- a/src/resizer/distributors/roomsublist.js +++ b/src/resizer/distributors/roomsublist.js @@ -111,12 +111,20 @@ export default class RoomSubListDistributor { start() { // set all max-height props to the actual height. let item = this.item.first(); + const sizes = []; while (item) { - if (!item.isCollapsed() && item.isSized()) { - item.setSize(item.size()); + if (!item.isCollapsed()) { + sizes.push(item.size()); + } else { + sizes.push(100); } item = item.next(); } + item = this.item.first(); + sizes.forEach((size) => { + item.setSize(size); + item = item.next(); + }); } finish() { From ef78036a7220c9b7e29253ade82332c9a8762fa3 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 15 Jan 2019 14:40:58 +0000 Subject: [PATCH 0095/1528] fix vector-im/riot-web#8105 --- src/components/views/dialogs/ChangelogDialog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/dialogs/ChangelogDialog.js b/src/components/views/dialogs/ChangelogDialog.js index 3c9414fd88..965029c069 100644 --- a/src/components/views/dialogs/ChangelogDialog.js +++ b/src/components/views/dialogs/ChangelogDialog.js @@ -36,7 +36,7 @@ export default class ChangelogDialog extends React.Component { for (let i=0; i { if (response.statusCode < 200 || response.statusCode >= 300) { this.setState({ [REPOS[i]]: response.statusText }); From 77a62b917491b0d0209d0a8d547a7cf943e9a4c2 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 15 Jan 2019 16:20:04 +0100 Subject: [PATCH 0096/1528] style search bar --- res/css/views/rooms/_RoomHeader.scss | 2 +- res/css/views/rooms/_SearchBar.scss | 99 ++++++++++--------------- src/components/views/rooms/SearchBar.js | 38 +++++++++- 3 files changed, 77 insertions(+), 62 deletions(-) diff --git a/res/css/views/rooms/_RoomHeader.scss b/res/css/views/rooms/_RoomHeader.scss index 0697ccf40f..1359bc5f57 100644 --- a/res/css/views/rooms/_RoomHeader.scss +++ b/res/css/views/rooms/_RoomHeader.scss @@ -98,6 +98,7 @@ limitations under the License. font-size: 18px; margin: 0 7px; border-bottom: 1px solid transparent; + display: flex; } .mx_RoomHeader_nametext { @@ -111,7 +112,6 @@ limitations under the License. } .mx_RoomHeader_searchStatus { - display: inline-block; font-weight: normal; opacity: 0.6; } diff --git a/res/css/views/rooms/_SearchBar.scss b/res/css/views/rooms/_SearchBar.scss index 079ea16c68..612ad81fe5 100644 --- a/res/css/views/rooms/_SearchBar.scss +++ b/res/css/views/rooms/_SearchBar.scss @@ -15,69 +15,52 @@ limitations under the License. */ .mx_SearchBar { - padding-top: 5px; - padding-bottom: 5px; + height: 56px; display: flex; align-items: center; -} + border-bottom: 1px solid $primary-hairline-color; -.mx_SearchBar_input { - display: inline block; - border-radius: 3px 0px 0px 3px; - border: 1px solid $input-border-color; - font-size: 15px; - padding: 9px; - padding-left: 11px; - width: auto; - flex: 1 1 0; -} + .mx_SearchBar_input { + // border: 1px solid $input-border-color; + // font-size: 15px; + flex: 1 1 0; + margin-left: 22px; + } -.mx_SearchBar_searchButton { - cursor: pointer; - margin-right: 10px; - width: 37px; - height: 37px; - border-radius: 0px 3px 3px 0px; - background-color: $accent-color; -} + .mx_SearchBar_searchButton { + cursor: pointer; + width: 37px; + height: 37px; + background-color: $accent-color; + mask: url('../../../img/feather-icons/search-input.svg'); + mask-repeat: no-repeat; + mask-position: center; + } -@keyframes pulsate { - 0% { opacity: 1.0; } - 50% { opacity: 0.1; } - 100% { opacity: 1.0; } -} + .mx_SearchBar_button { + border: 0; + margin: 0 0 0 22px; + padding: 5px; + font-size: 15px; + cursor: pointer; + color: $primary-fg-color; + border-bottom: 2px solid $accent-color; + font-weight: 600; + } -.mx_SearchBar_searching img { - animation: pulsate 0.5s ease-out; - animation-iteration-count: infinite; -} + .mx_SearchBar_unselected { + color: $input-darker-fg-color; + border-color: transparent; + } -.mx_SearchBar_button { - display: inline; - border: 0px; - border-radius: 36px; - font-weight: 400; - font-size: 15px; - color: $accent-fg-color; - background-color: $accent-color; - width: auto; - margin: auto; - margin-left: 7px; - padding-top: 6px; - padding-bottom: 4px; - padding-left: 24px; - padding-right: 24px; - cursor: pointer; -} - -.mx_SearchBar_unselected { - background-color: $primary-bg-color; - color: $accent-color; - border: $accent-color 1px solid; -} - -.mx_SearchBar_cancel { - padding-left: 14px; - padding-right: 14px; - cursor: pointer; + .mx_SearchBar_cancel { + background-color: $warning-color; + mask: url('../../../img/cancel.svg'); + mask-repeat: no-repeat; + mask-position: center; + mask-size: 12px; + padding: 10px; + margin: 0 12px 0 3px; + cursor: pointer; + } } diff --git a/src/components/views/rooms/SearchBar.js b/src/components/views/rooms/SearchBar.js index 05fc661c1c..d48cb0e08b 100644 --- a/src/components/views/rooms/SearchBar.js +++ b/src/components/views/rooms/SearchBar.js @@ -60,12 +60,44 @@ module.exports = React.createClass({ return (
    - - {_t("Search")} {_t("This Room")} {_t("All Rooms")} - +
    + + +
    +
    ); + + + + +/* +const clearButton = this.state.searchTerm.length > 0 ? + ( {this._clearSearch("button")} }> + ) : undefined; + + return ( +
    + + { clearButton } +
    + ); +*/ + + }, }); From 6f62158f9490aba065b01c2fd5f45ffa9acdb480 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 15 Jan 2019 09:52:06 -0700 Subject: [PATCH 0097/1528] Fix setting label for unknown invites Fixes https://github.com/vector-im/riot-web/issues/8126 --- src/components/structures/UserSettings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index 6ba7bcc4dc..37f60c47bf 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -86,7 +86,7 @@ const SIMPLE_SETTINGS = [ { id: "pinMentionedRooms" }, { id: "pinUnreadRooms" }, { id: "showDeveloperTools" }, - { id: "alwaysRetryInvites" }, + { id: "alwaysInviteUnknownUsers" }, ]; // These settings must be defined in SettingsStore From e08c70b82089299bbf736f92dafe6a8ec5daf773 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Fri, 11 Jan 2019 14:59:14 -0600 Subject: [PATCH 0098/1528] Prune unsupported setting RoomSubList.showEmpty The code reading this setting was previously removed in #2229. --- src/components/structures/UserSettings.js | 1 - src/i18n/strings/en_EN.json | 1 - src/settings/Settings.js | 5 ----- 3 files changed, 7 deletions(-) diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index 15b9181d21..dc469c0ca3 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -82,7 +82,6 @@ const SIMPLE_SETTINGS = [ { id: "VideoView.flipVideoHorizontally" }, { id: "TagPanel.disableTagPanel" }, { id: "enableWidgetScreenshots" }, - { id: "RoomSubList.showEmpty" }, { id: "pinMentionedRooms" }, { id: "pinUnreadRooms" }, { id: "showDeveloperTools" }, diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 0086ed0378..a7b75c136b 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -296,7 +296,6 @@ "Pin rooms I'm mentioned in to the top of the room list": "Pin rooms I'm mentioned in to the top of the room list", "Pin unread rooms to the top of the room list": "Pin unread rooms to the top of the room list", "Enable widget screenshots on supported widgets": "Enable widget screenshots on supported widgets", - "Show empty room list headings": "Show empty room list headings", "Always invite users which may not exist": "Always invite users which may not exist", "Show developer tools": "Show developer tools", "Collecting app version information": "Collecting app version information", diff --git a/src/settings/Settings.js b/src/settings/Settings.js index a04301e31e..f64e999a32 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -324,11 +324,6 @@ export const SETTINGS = { supportedLevels: ['room-device'], default: false, }, - "RoomSubList.showEmpty": { - supportedLevels: LEVELS_ACCOUNT_SETTINGS, - displayName: _td('Show empty room list headings'), - default: true, - }, "alwaysInviteUnknownUsers": { supportedLevels: LEVELS_ACCOUNT_SETTINGS, displayName: _td('Always invite users which may not exist'), From c76b273fae2d200c24d718cdc34237a45802b266 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Fri, 11 Jan 2019 18:24:06 -0600 Subject: [PATCH 0099/1528] Update RoomTiles on custom status change --- src/components/views/rooms/RoomTile.js | 8 ++++- src/settings/Settings.js | 2 ++ .../controllers/CustomStatusController.js | 29 +++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/settings/controllers/CustomStatusController.js diff --git a/src/components/views/rooms/RoomTile.js b/src/components/views/rooms/RoomTile.js index 95073b7be8..8778340601 100644 --- a/src/components/views/rooms/RoomTile.js +++ b/src/components/views/rooms/RoomTile.js @@ -112,7 +112,13 @@ module.exports = React.createClass({ this.setState({ notificationCount: this.props.room.getUnreadNotificationCount(), }); - break; + break; + // RoomTiles are one of the few components that may show custom status and + // also remain on screen while in Settings toggling the feature. This ensures + // you can clearly see the status hide and show when toggling the feature. + case 'feature_custom_status_changed': + this.forceUpdate(); + break; } }, diff --git a/src/settings/Settings.js b/src/settings/Settings.js index f64e999a32..836e906b6e 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -22,6 +22,7 @@ import { NotificationsEnabledController, } from "./controllers/NotificationControllers"; import LazyLoadingController from "./controllers/LazyLoadingController"; +import CustomStatusController from "./controllers/CustomStatusController"; // These are just a bunch of helper arrays to avoid copy/pasting a bunch of times const LEVELS_ROOM_SETTINGS = ['device', 'room-device', 'room-account', 'account', 'config']; @@ -88,6 +89,7 @@ export const SETTINGS = { displayName: _td("Custom user status messages"), supportedLevels: LEVELS_FEATURE, default: false, + controller: new CustomStatusController(), }, "feature_lazyloading": { isFeature: true, diff --git a/src/settings/controllers/CustomStatusController.js b/src/settings/controllers/CustomStatusController.js new file mode 100644 index 0000000000..183947972b --- /dev/null +++ b/src/settings/controllers/CustomStatusController.js @@ -0,0 +1,29 @@ +/* +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. +*/ + +import SettingController from "./SettingController"; +import dis from "../../dispatcher"; + +export default class CustomStatusController extends SettingController { + onChange(level, roomId, newValue) { + // Dispatch setting change so that some components that are still visible when the + // Settings page is open (such as RoomTiles) can reflect the change. + dis.dispatch({ + action: "feature_custom_status_changed", + value: newValue, + }); + } +} From 7d6b996952e2982f461fcc6e974beab51c484e27 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Fri, 11 Jan 2019 20:00:12 -0600 Subject: [PATCH 0100/1528] Tweak composer button padding so it won't affect status --- res/css/views/rooms/_MessageComposer.scss | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/res/css/views/rooms/_MessageComposer.scss b/res/css/views/rooms/_MessageComposer.scss index 39640575ba..c1acf56232 100644 --- a/res/css/views/rooms/_MessageComposer.scss +++ b/res/css/views/rooms/_MessageComposer.scss @@ -65,10 +65,6 @@ limitations under the License. display: block; } -.mx_MessageComposer .mx_AccessibleButton { - padding: 0 12px 0 0; -} - .mx_MessageComposer_composecontrols { width: 100%; } @@ -185,7 +181,7 @@ limitations under the License. /*display: table-cell;*/ /*vertical-align: middle;*/ /*padding-left: 10px;*/ - padding-right: 5px; + padding-right: 12px; cursor: pointer; padding-top: 4px; } From eae1e4c9aa5395a01a2970153d3bfb10b49950a4 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 14 Jan 2019 10:26:11 -0600 Subject: [PATCH 0101/1528] Tweak custom status avatar ring Adjusts the appearance of the avatar ring to match the latest comps. In addition, we now always render the surrounding button element, which simplifies styling since the same size is now occupied both with and without the feature. This improves alignment between text in the composer and text in the message history (https://github.com/vector-im/riot-web/issues/8111). --- .../avatars/_MemberStatusMessageAvatar.scss | 16 +++++++++++---- res/css/views/rooms/_MessageComposer.scss | 2 +- .../avatars/MemberStatusMessageAvatar.js | 20 +++++++++++-------- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/res/css/views/avatars/_MemberStatusMessageAvatar.scss b/res/css/views/avatars/_MemberStatusMessageAvatar.scss index 29cae9df34..03e7fdd188 100644 --- a/res/css/views/avatars/_MemberStatusMessageAvatar.scss +++ b/res/css/views/avatars/_MemberStatusMessageAvatar.scss @@ -14,8 +14,16 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_MemberStatusMessageAvatar_hasStatus { - border: 2px solid $accent-color; - border-radius: 40px; - padding-right: 0 !important; /* Override AccessibleButton styling */ +.mx_MemberStatusMessageAvatar .mx_BaseAvatar { + padding: 1.5px; + border: 1.2px solid transparent; + border-radius: 14px; +} + +.mx_MemberStatusMessageAvatar .mx_BaseAvatar_initial { + left: 1.5px; +} + +.mx_MemberStatusMessageAvatar_hasStatus .mx_BaseAvatar { + border-color: $accent-color; } diff --git a/res/css/views/rooms/_MessageComposer.scss b/res/css/views/rooms/_MessageComposer.scss index c1acf56232..4a052482ad 100644 --- a/res/css/views/rooms/_MessageComposer.scss +++ b/res/css/views/rooms/_MessageComposer.scss @@ -58,7 +58,7 @@ limitations under the License. } .mx_MessageComposer .mx_MessageComposer_avatar { - padding: 0 28px; + padding: 0 27px; } .mx_MessageComposer .mx_MessageComposer_avatar .mx_BaseAvatar { diff --git a/src/components/views/avatars/MemberStatusMessageAvatar.js b/src/components/views/avatars/MemberStatusMessageAvatar.js index aebd1741b7..5118a25cdb 100644 --- a/src/components/views/avatars/MemberStatusMessageAvatar.js +++ b/src/components/views/avatars/MemberStatusMessageAvatar.js @@ -96,21 +96,25 @@ export default class MemberStatusMessageAvatar extends React.Component { }; render() { - if (!SettingsStore.isFeatureEnabled("feature_custom_status")) { - return ; - } + const customStatusFeatureEnabled = + SettingsStore.isFeatureEnabled("feature_custom_status"); - const hasStatus = this.props.member.user ? !!this.props.member.user._unstable_statusMessage : false; + let onClick = null; + let hasStatus = false; + + if (customStatusFeatureEnabled) { + onClick = this._onClick; + if (this.props.member.user) { + hasStatus = !!this.props.member.user._unstable_statusMessage; + } + } const classes = classNames({ "mx_MemberStatusMessageAvatar": true, "mx_MemberStatusMessageAvatar_hasStatus": hasStatus, }); - return + return Date: Mon, 14 Jan 2019 11:43:56 -0600 Subject: [PATCH 0102/1528] Update context menu styling to match custom status comps --- res/css/structures/_ContextualMenu.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/css/structures/_ContextualMenu.scss b/res/css/structures/_ContextualMenu.scss index fa69c6fb90..a01cd896a8 100644 --- a/res/css/structures/_ContextualMenu.scss +++ b/res/css/structures/_ContextualMenu.scss @@ -30,8 +30,8 @@ limitations under the License. } .mx_ContextualMenu { - border-radius: 2px; - box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.21); + border-radius: 4px; + box-shadow: 4px 4px 12px 0 rgba(118, 131, 156, 0.6);; background-color: $menu-bg-color; color: $primary-fg-color; position: absolute; From fc3055f54149ed3bb63b02721d1b57258a06a5d8 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 14 Jan 2019 12:47:50 -0600 Subject: [PATCH 0103/1528] Tweak custom status menu size and placement --- .../views/avatars/MemberStatusMessageAvatar.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/views/avatars/MemberStatusMessageAvatar.js b/src/components/views/avatars/MemberStatusMessageAvatar.js index 5118a25cdb..a11e887efe 100644 --- a/src/components/views/avatars/MemberStatusMessageAvatar.js +++ b/src/components/views/avatars/MemberStatusMessageAvatar.js @@ -79,18 +79,18 @@ export default class MemberStatusMessageAvatar extends React.Component { const elementRect = e.target.getBoundingClientRect(); - // The window X and Y offsets are to adjust position when zoomed in to page - const x = (elementRect.left + window.pageXOffset) - (elementRect.width / 2) + 3; - const chevronOffset = 12; - let y = elementRect.top + (elementRect.height / 2) + window.pageYOffset; - y = y - (chevronOffset + 4); // where 4 is 1/4 the height of the chevron + const x = (elementRect.left + window.pageXOffset); + const chevronWidth = 16; // See .mx_ContextualMenu_chevron_bottom + const chevronOffset = (elementRect.width - chevronWidth) / 2; + const chevronMargin = 1; // Add some spacing away from target + const y = elementRect.top + window.pageYOffset - chevronMargin; ContextualMenu.createMenu(StatusMessageContextMenu, { chevronOffset: chevronOffset, chevronFace: 'bottom', left: x, top: y, - menuWidth: 190, + menuWidth: 226, user: this.props.member.user, }); }; From 5b88b64950fc6033347a7003dbf2681868adad36 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 14 Jan 2019 16:41:14 -0600 Subject: [PATCH 0104/1528] Rework custom status context menu This updates the custom status context menu to match the latest comps. A single button is used for setting / clearing, depending on what is appropriate. The state logic is also changed to depend on events and storage from js-sdk for the committed status message. This makes it easy to distinguish the value being edited from what's currently committed. --- .../_StatusMessageContextMenu.scss | 55 ++++++----- res/img/icons-checkmark.svg | 17 ---- res/themes/dharma/css/_dharma.scss | 4 +- res/themes/light/css/_base.scss | 2 + .../context_menus/StatusMessageContextMenu.js | 98 +++++++++++++------ src/i18n/strings/en_EN.json | 4 +- 6 files changed, 103 insertions(+), 77 deletions(-) delete mode 100644 res/img/icons-checkmark.svg diff --git a/res/css/views/context_menus/_StatusMessageContextMenu.scss b/res/css/views/context_menus/_StatusMessageContextMenu.scss index 873ad99495..8b25f3a122 100644 --- a/res/css/views/context_menus/_StatusMessageContextMenu.scss +++ b/res/css/views/context_menus/_StatusMessageContextMenu.scss @@ -14,42 +14,43 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_StatusMessageContextMenu_message { - display: inline-block; - border-radius: 3px 0 0 3px; +.mx_StatusMessageContextMenu { + padding: 10px; +} + +.mx_StatusMessageContextMenu_form { + display: flex; + flex-direction: column; +} + +input.mx_StatusMessageContextMenu_message { + border-radius: 4px; border: 1px solid $input-border-color; - font-size: 13px; - padding: 7px 7px 7px 9px; - width: 135px; - background-color: $primary-bg-color !important; + padding: 6.5px 11px; + background-color: $primary-bg-color; + font-weight: normal; + margin: 0 0 10px; } -.mx_StatusMessageContextMenu_submit { - display: inline-block; +.mx_StatusMessageContextMenu_message::placeholder { + color: $memberstatus-placeholder-color; } -.mx_StatusMessageContextMenu_submitFaded { - opacity: 0.5; +.mx_StatusMessageContextMenu_submit, +.mx_StatusMessageContextMenu_clear { + @mixin mx_DialogButton; + align-self: start; + font-size: 12px; + padding: 6px 1em; + border: 1px solid transparent; } -.mx_StatusMessageContextMenu_submit img { - vertical-align: middle; - margin-left: 8px; -} - -.mx_StatusMessageContextMenu hr { - border: 0.5px solid $menu-border-color; -} - -.mx_StatusMessageContextMenu_clearIcon { - margin: 5px 15px 5px 5px; - vertical-align: middle; +.mx_StatusMessageContextMenu_submit[disabled] { + opacity: 0.49; } .mx_StatusMessageContextMenu_clear { - padding: 2px; -} - -.mx_StatusMessageContextMenu_hasStatus .mx_StatusMessageContextMenu_clear { color: $warning-color; + background-color: transparent; + border: 1px solid $warning-color; } diff --git a/res/img/icons-checkmark.svg b/res/img/icons-checkmark.svg deleted file mode 100644 index 3c5392003d..0000000000 --- a/res/img/icons-checkmark.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - Tick - Created with Sketch. - - - - - - - - - - - - diff --git a/res/themes/dharma/css/_dharma.scss b/res/themes/dharma/css/_dharma.scss index 732cabf494..73dc0a71e4 100644 --- a/res/themes/dharma/css/_dharma.scss +++ b/res/themes/dharma/css/_dharma.scss @@ -68,7 +68,7 @@ $event-selected-color: #f7f7f7; $primary-hairline-color: #e5e5e5; // used for the border of input text fields -$input-border-color: #f0f0f0; +$input-border-color: #e7e7e7; $input-darker-bg-color: rgba(193, 201, 214, 0.29); $input-darker-fg-color: #9fa9ba; $input-lighter-bg-color: #f2f5f8; @@ -192,6 +192,8 @@ $progressbar-color: #000; $room-warning-bg-color: #fff8e3; +$memberstatus-placeholder-color: $roomtile-name-color; + /*** form elements ***/ // .mx_textinput is a container for a text input diff --git a/res/themes/light/css/_base.scss b/res/themes/light/css/_base.scss index 10a8fcd1e5..cf539bd1f2 100644 --- a/res/themes/light/css/_base.scss +++ b/res/themes/light/css/_base.scss @@ -188,6 +188,8 @@ $progressbar-color: #000; $room-warning-bg-color: #fff8e3; +$memberstatus-placeholder-color: $roomtile-name-color; + // ***** Mixins! ***** @define-mixin mx_DialogButton { diff --git a/src/components/views/context_menus/StatusMessageContextMenu.js b/src/components/views/context_menus/StatusMessageContextMenu.js index d062fc2a3e..9916f5d347 100644 --- a/src/components/views/context_menus/StatusMessageContextMenu.js +++ b/src/components/views/context_menus/StatusMessageContextMenu.js @@ -19,7 +19,6 @@ import PropTypes from 'prop-types'; import { _t } from '../../../languageHandler'; import MatrixClientPeg from '../../../MatrixClientPeg'; import AccessibleButton from '../elements/AccessibleButton'; -import classNames from 'classnames'; export default class StatusMessageContextMenu extends React.Component { static propTypes = { @@ -31,13 +30,42 @@ export default class StatusMessageContextMenu extends React.Component { super(props, context); this.state = { - message: props.user ? props.user._unstable_statusMessage : "", + message: this.comittedStatusMessage, }; } + componentWillMount() { + const { user } = this.props; + if (!user) { + return; + } + user.on("User._unstable_statusMessage", this._onStatusMessageCommitted); + } + + componentWillUmount() { + const { user } = this.props; + if (!user) { + return; + } + user.removeListener( + "User._unstable_statusMessage", + this._onStatusMessageCommitted, + ); + } + + get comittedStatusMessage() { + return this.props.user ? this.props.user._unstable_statusMessage : ""; + } + + _onStatusMessageCommitted = () => { + // The `User` object has observed a status message change. + this.setState({ + message: this.comittedStatusMessage, + }); + }; + _onClearClick = async (e) => { await MatrixClientPeg.get()._unstable_setStatusMessage(""); - this.setState({message: ""}); }; _onSubmit = (e) => { @@ -46,41 +74,49 @@ export default class StatusMessageContextMenu extends React.Component { }; _onStatusChange = (e) => { - this.setState({message: e.target.value}); + // The input field's value was changed. + this.setState({ + message: e.target.value, + }); }; render() { - const formSubmitClasses = classNames({ - "mx_StatusMessageContextMenu_submit": true, - "mx_StatusMessageContextMenu_submitFaded": !this.state.message, // no message == faded - }); + let actionButton; + if (this.comittedStatusMessage) { + if (this.state.message === this.comittedStatusMessage) { + actionButton = + {_t("Clear status")} + ; + } else { + actionButton = + {_t("Update status")} + ; + } + } else { + actionButton = + {_t("Set status")} + ; + } - const form =
    - - - - + const form = + + {actionButton}
    ; - const clearIcon = this.state.message ? "img/cancel-red.svg" : "img/cancel.svg"; - const clearButton = - {_t('Clear - {_t("Clear status")} - ; - - const menuClasses = classNames({ - "mx_StatusMessageContextMenu": true, - "mx_StatusMessageContextMenu_hasStatus": this.state.message, - }); - - return
    + return
    { form } -
    - { clearButton }
    ; } } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index a7b75c136b..ef0ff1ebf7 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1087,8 +1087,10 @@ "Forget": "Forget", "Low Priority": "Low Priority", "Direct Chat": "Direct Chat", - "Set a new status...": "Set a new status...", "Clear status": "Clear status", + "Update status": "Update status", + "Set status": "Set status", + "Set a new status...": "Set a new status...", "View as Grid": "View as Grid", "View Community": "View Community", "Sorry, your browser is not able to run Riot.": "Sorry, your browser is not able to run Riot.", From 233288475ecc8d56b91cdb880d4ccb58c38839cc Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 14 Jan 2019 16:59:15 -0600 Subject: [PATCH 0105/1528] Use status events for avatar ring Similar to changes in `StatusMessageContextMenu`, this changes to using the new status message event emitted in js-sdk to simplify state handling for the avatar ring when a status is present. --- .../avatars/MemberStatusMessageAvatar.js | 60 +++++++++++-------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/src/components/views/avatars/MemberStatusMessageAvatar.js b/src/components/views/avatars/MemberStatusMessageAvatar.js index a11e887efe..a98fcaa537 100644 --- a/src/components/views/avatars/MemberStatusMessageAvatar.js +++ b/src/components/views/avatars/MemberStatusMessageAvatar.js @@ -40,38 +40,50 @@ export default class MemberStatusMessageAvatar extends React.Component { constructor(props, context) { super(props, context); + + this.state = { + hasStatus: this.hasStatus, + }; } componentWillMount() { if (this.props.member.userId !== MatrixClientPeg.get().getUserId()) { throw new Error("Cannot use MemberStatusMessageAvatar on anyone but the logged in user"); } - } - - componentDidMount() { - MatrixClientPeg.get().on("RoomState.events", this._onRoomStateEvents); - - if (this.props.member.user) { - this.setState({message: this.props.member.user._unstable_statusMessage}); - } else { - this.setState({message: ""}); + if (!SettingsStore.isFeatureEnabled("feature_custom_status")) { + return; } - } - - componentWillUnmount() { - if (MatrixClientPeg.get()) { - MatrixClientPeg.get().removeListener("RoomState.events", this._onRoomStateEvents); + const { user } = this.props.member; + if (!user) { + return; } + user.on("User._unstable_statusMessage", this._onStatusMessageCommitted); } - _onRoomStateEvents = (ev, state) => { - if (ev.getStateKey() !== MatrixClientPeg.get().getUserId()) return; - if (ev.getType() !== "im.vector.user_status") return; - // TODO: We should be relying on `this.props.member.user._unstable_statusMessage` - // We don't currently because the js-sdk doesn't emit a specific event for this - // change, and we don't want to race it. This should be improved when we rip out - // the im.vector.user_status stuff and replace it with a complete solution. - this.setState({message: ev.getContent()["status"]}); + componentWillUmount() { + const { user } = this.props.member; + if (!user) { + return; + } + user.removeListener( + "User._unstable_statusMessage", + this._onStatusMessageCommitted, + ); + } + + get hasStatus() { + const { user } = this.props.member; + if (!user) { + return false; + } + return !!user._unstable_statusMessage; + } + + _onStatusMessageCommitted = () => { + // The `User` object has observed a status message change. + this.setState({ + hasStatus: this.hasStatus, + }); }; _onClick = (e) => { @@ -104,9 +116,7 @@ export default class MemberStatusMessageAvatar extends React.Component { if (customStatusFeatureEnabled) { onClick = this._onClick; - if (this.props.member.user) { - hasStatus = !!this.props.member.user._unstable_statusMessage; - } + hasStatus = this.state.hasStatus; } const classes = classNames({ From 443198c180c95d487764da3d6cf03eaa16f27d41 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 14 Jan 2019 17:27:35 -0600 Subject: [PATCH 0106/1528] Fix lints in MemberTile.js --- .eslintignore.errorfiles | 1 - src/components/views/rooms/MemberTile.js | 9 ++++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.eslintignore.errorfiles b/.eslintignore.errorfiles index 2b57d4e9e2..30cc55377c 100644 --- a/.eslintignore.errorfiles +++ b/.eslintignore.errorfiles @@ -48,7 +48,6 @@ src/components/views/rooms/LinkPreviewWidget.js src/components/views/rooms/MemberDeviceInfo.js src/components/views/rooms/MemberInfo.js src/components/views/rooms/MemberList.js -src/components/views/rooms/MemberTile.js src/components/views/rooms/MessageComposer.js src/components/views/rooms/PinnedEventTile.js src/components/views/rooms/RoomList.js diff --git a/src/components/views/rooms/MemberTile.js b/src/components/views/rooms/MemberTile.js index ba951792d0..4189e406b5 100644 --- a/src/components/views/rooms/MemberTile.js +++ b/src/components/views/rooms/MemberTile.js @@ -21,10 +21,8 @@ import SettingsStore from "../../../settings/SettingsStore"; const React = require('react'); import PropTypes from 'prop-types'; -const MatrixClientPeg = require('../../../MatrixClientPeg'); const sdk = require('../../../index'); const dis = require('../../../dispatcher'); -const Modal = require("../../../Modal"); import { _t } from '../../../languageHandler'; module.exports = React.createClass({ @@ -74,17 +72,18 @@ module.exports = React.createClass({ }, getPowerLabel: function() { - return _t("%(userName)s (power %(powerLevelNumber)s)", {userName: this.props.member.userId, powerLevelNumber: this.props.member.powerLevel}); + return _t("%(userName)s (power %(powerLevelNumber)s)", { + userName: this.props.member.userId, + powerLevelNumber: this.props.member.powerLevel, + }); }, render: function() { const MemberAvatar = sdk.getComponent('avatars.MemberAvatar'); - const BaseAvatar = sdk.getComponent('avatars.BaseAvatar'); const EntityTile = sdk.getComponent('rooms.EntityTile'); const member = this.props.member; const name = this._getDisplayName(); - const active = -1; const presenceState = member.user ? member.user.presence : null; let statusMessage = null; From 77cee8e67ea4b3937746d6f863680d4821c45fef Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 14 Jan 2019 17:51:42 -0600 Subject: [PATCH 0107/1528] Update MemberTile on status change --- src/components/views/rooms/MemberTile.js | 43 ++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/MemberTile.js b/src/components/views/rooms/MemberTile.js index 4189e406b5..926734a767 100644 --- a/src/components/views/rooms/MemberTile.js +++ b/src/components/views/rooms/MemberTile.js @@ -40,7 +40,46 @@ module.exports = React.createClass({ }, getInitialState: function() { - return {}; + return { + statusMessage: this.getStatusMessage(), + }; + }, + + componentDidMount() { + if (!SettingsStore.isFeatureEnabled("feature_custom_status")) { + return; + } + const { user } = this.props.member; + if (!user) { + return; + } + user.on("User._unstable_statusMessage", this._onStatusMessageCommitted); + }, + + componentWillUmount() { + const { user } = this.props.member; + if (!user) { + return; + } + user.removeListener( + "User._unstable_statusMessage", + this._onStatusMessageCommitted, + ); + }, + + getStatusMessage() { + const { user } = this.props.member; + if (!user) { + return ""; + } + return user._unstable_statusMessage; + }, + + _onStatusMessageCommitted() { + // The `User` object has observed a status message change. + this.setState({ + statusMessage: this.getStatusMessage(), + }); }, shouldComponentUpdate: function(nextProps, nextState) { @@ -88,7 +127,7 @@ module.exports = React.createClass({ let statusMessage = null; if (member.user && SettingsStore.isFeatureEnabled("feature_custom_status")) { - statusMessage = member.user._unstable_statusMessage; + statusMessage = this.state.statusMessage; } const av = ( From d8de607edcf06112ec82983e5f46538e1b3762f2 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Tue, 15 Jan 2019 09:20:43 -0600 Subject: [PATCH 0108/1528] Update RoomTile on status change --- src/components/views/rooms/RoomTile.js | 65 ++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 8 deletions(-) diff --git a/src/components/views/rooms/RoomTile.js b/src/components/views/rooms/RoomTile.js index 8778340601..1f9c0c1523 100644 --- a/src/components/views/rooms/RoomTile.js +++ b/src/components/views/rooms/RoomTile.js @@ -62,6 +62,7 @@ module.exports = React.createClass({ notifState: RoomNotifs.getRoomNotifsState(this.props.room.roomId), notificationCount: this.props.room.getUnreadNotificationCount(), selected: this.props.room.roomId === ActiveRoomObserver.getActiveRoomId(), + statusMessage: this._getStatusMessage(), }); }, @@ -79,6 +80,33 @@ module.exports = React.createClass({ return Boolean(dmRooms); }, + _shouldShowStatusMessage() { + if (!SettingsStore.isFeatureEnabled("feature_custom_status")) { + return false; + } + const isInvite = this.props.room.getMyMembership() === "invite"; + const isJoined = this.props.room.getMyMembership() === "join"; + const looksLikeDm = this.props.room.getInvitedAndJoinedMemberCount() === 2; + return !isInvite && isJoined && looksLikeDm; + }, + + _getStatusMessageUser() { + const selfId = MatrixClientPeg.get().getUserId(); + const otherMember = this.props.room.currentState.getMembersExcept([selfId])[0]; + if (!otherMember) { + return null; + } + return otherMember.user; + }, + + _getStatusMessage() { + const statusUser = this._getStatusMessageUser(); + if (!statusUser) { + return ""; + } + return statusUser._unstable_statusMessage; + }, + onRoomTimeline: function(ev, room) { if (room !== this.props.room) return; this.setState({ @@ -134,6 +162,16 @@ module.exports = React.createClass({ MatrixClientPeg.get().on("Room.name", this.onRoomName); ActiveRoomObserver.addListener(this.props.room.roomId, this._onActiveRoomChange); this.dispatcherRef = dis.register(this.onAction); + + if (this._shouldShowStatusMessage()) { + const statusUser = this._getStatusMessageUser(); + if (statusUser) { + statusUser.on( + "User._unstable_statusMessage", + this._onStatusMessageCommitted, + ); + } + } }, componentWillUnmount: function() { @@ -145,6 +183,16 @@ module.exports = React.createClass({ } ActiveRoomObserver.removeListener(this.props.room.roomId, this._onActiveRoomChange); dis.unregister(this.dispatcherRef); + + if (this._shouldShowStatusMessage()) { + const statusUser = this._getStatusMessageUser(); + if (statusUser) { + statusUser.removeListener( + "User._unstable_statusMessage", + this._onStatusMessageCommitted, + ); + } + } }, componentWillReceiveProps: function(props) { @@ -172,6 +220,13 @@ module.exports = React.createClass({ return false; }, + _onStatusMessageCommitted() { + // The status message `User` object has observed a message change. + this.setState({ + statusMessage: this._getStatusMessage(), + }); + }, + onClick: function(ev) { if (this.props.onClick) { this.props.onClick(this.props.room.roomId, ev); @@ -257,15 +312,9 @@ module.exports = React.createClass({ const mentionBadges = this.props.highlight && this._shouldShowMentionBadge(); const badges = notifBadges || mentionBadges; - const isJoined = this.props.room.getMyMembership() === "join"; - const looksLikeDm = this.props.room.getInvitedAndJoinedMemberCount() === 2; let subtext = null; - if (!isInvite && isJoined && looksLikeDm && SettingsStore.isFeatureEnabled("feature_custom_status")) { - const selfId = MatrixClientPeg.get().getUserId(); - const otherMember = this.props.room.currentState.getMembersExcept([selfId])[0]; - if (otherMember && otherMember.user && otherMember.user._unstable_statusMessage) { - subtext = otherMember.user._unstable_statusMessage; - } + if (this._shouldShowStatusMessage()) { + subtext = this.state.statusMessage; } const classes = classNames({ From 632bbde59813d4394ad31ba6d883faad08b013f3 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Tue, 15 Jan 2019 09:27:12 -0600 Subject: [PATCH 0109/1528] Remove usused setting value from CustomStatusController --- src/settings/controllers/CustomStatusController.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/settings/controllers/CustomStatusController.js b/src/settings/controllers/CustomStatusController.js index 183947972b..0fc6619d92 100644 --- a/src/settings/controllers/CustomStatusController.js +++ b/src/settings/controllers/CustomStatusController.js @@ -23,7 +23,6 @@ export default class CustomStatusController extends SettingController { // Settings page is open (such as RoomTiles) can reflect the change. dis.dispatch({ action: "feature_custom_status_changed", - value: newValue, }); } } From 4b13774585bc7952986d7d4db0103a7c3bbe0dcb Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Tue, 15 Jan 2019 10:20:27 -0600 Subject: [PATCH 0110/1528] Revert to avatar only when custom status disabled This returns to the previous behavior of avatar only without a button when the custom status feature is disabled so that you don't get pointer cursor for something that does nothing when clicked. The avatar ring spacing is kept consistent with and without the feature enabled by using a different class in CSS. --- .../avatars/_MemberStatusMessageAvatar.scss | 4 +-- .../avatars/MemberStatusMessageAvatar.js | 27 +++++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/res/css/views/avatars/_MemberStatusMessageAvatar.scss b/res/css/views/avatars/_MemberStatusMessageAvatar.scss index 03e7fdd188..7ac4036eef 100644 --- a/res/css/views/avatars/_MemberStatusMessageAvatar.scss +++ b/res/css/views/avatars/_MemberStatusMessageAvatar.scss @@ -14,13 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_MemberStatusMessageAvatar .mx_BaseAvatar { +.mx_MessageComposer_avatar .mx_BaseAvatar { padding: 1.5px; border: 1.2px solid transparent; border-radius: 14px; } -.mx_MemberStatusMessageAvatar .mx_BaseAvatar_initial { +.mx_MessageComposer_avatar .mx_BaseAvatar_initial { left: 1.5px; } diff --git a/src/components/views/avatars/MemberStatusMessageAvatar.js b/src/components/views/avatars/MemberStatusMessageAvatar.js index a98fcaa537..0258c4b0c8 100644 --- a/src/components/views/avatars/MemberStatusMessageAvatar.js +++ b/src/components/views/avatars/MemberStatusMessageAvatar.js @@ -108,27 +108,26 @@ export default class MemberStatusMessageAvatar extends React.Component { }; render() { - const customStatusFeatureEnabled = - SettingsStore.isFeatureEnabled("feature_custom_status"); + const avatar = ; - let onClick = null; - let hasStatus = false; - - if (customStatusFeatureEnabled) { - onClick = this._onClick; - hasStatus = this.state.hasStatus; + if (!SettingsStore.isFeatureEnabled("feature_custom_status")) { + return avatar; } const classes = classNames({ "mx_MemberStatusMessageAvatar": true, - "mx_MemberStatusMessageAvatar_hasStatus": hasStatus, + "mx_MemberStatusMessageAvatar_hasStatus": this.state.hasStatus, }); - return - + return + {avatar} ; } } From d2de542838d4997d3720e0b081773b0889ddebf0 Mon Sep 17 00:00:00 2001 From: RainSlide Date: Mon, 14 Jan 2019 12:22:30 +0000 Subject: [PATCH 0111/1528] Translated using Weblate (Chinese (Simplified)) Currently translated at 91.7% (1301 of 1418 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/zh_Hans/ --- src/i18n/strings/zh_Hans.json | 53 +++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/src/i18n/strings/zh_Hans.json b/src/i18n/strings/zh_Hans.json index e062663cad..62746d31e9 100644 --- a/src/i18n/strings/zh_Hans.json +++ b/src/i18n/strings/zh_Hans.json @@ -156,7 +156,7 @@ "Add a topic": "添加主题", "Admin": "管理员", "Admin Tools": "管理员工具", - "VoIP": "IP 电话", + "VoIP": "VoIP", "Missing Media Permissions, click here to request.": "没有媒体存储权限,点此获取。", "No Microphones detected": "未检测到麦克风", "No Webcams detected": "未检测到摄像头", @@ -1275,5 +1275,54 @@ "%(senderName)s removed %(count)s %(removedAddresses)s as addresses for this room.|one": "%(senderName)s 移除了一个聊天室地址 %(removedAddresses)s。", "%(senderName)s added %(addedAddresses)s and removed %(removedAddresses)s as addresses for this room.": "%(senderName)s 添加了聊天室地址 %(addedAddresses)s 并移除了地址 %(removedAddresses)s。", "%(senderName)s set the main address for this room to %(address)s.": "%(senderName)s 将此聊天室的主地址设为了 %(address)s。", - "%(senderName)s removed the main address for this room.": "%(senderName)s 移除了此聊天室的主地址。" + "%(senderName)s removed the main address for this room.": "%(senderName)s 移除了此聊天室的主地址。", + "Unable to load! Check your network connectivity and try again.": "无法加载!请检查您的网络连接并重试。", + "User %(user_id)s does not exist": "用户 %(user_id)s 不存在", + "There was an error joining the room": "加入聊天室时发生错误", + "Custom user status messages": "自定义用户状态信息", + "Backup of encryption keys to server": "将加密密钥备份至服务器", + "Show developer tools": "显示开发者工具", + "Messages containing @room": "含有 @room 的消息", + "Delete Backup": "删除备份", + "Delete your backed up encryption keys from the server? You will no longer be able to use your recovery key to read encrypted message history": "是否从服务器中删除您备份的加密密钥?您将无法再次使用您的还原密钥来解密历史加密消息", + "Delete backup": "删除备份", + "Backup version: ": "备份版本: ", + "Algorithm: ": "算法: ", + "Restore backup": "恢复备份", + "Joining room...": "正在加入聊天室…", + "Don't ask again": "不再询问", + "Set up": "设置", + "Open Devtools": "打开开发者工具", + "Secure Message Recovery": "安全消息还原", + "If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.": "若您退出登录或在其他设备上登录,您将无法查看本客户端上的历史加密消息。为避免这种情况,请设置安全消息还原。", + "Failed to load group members": "聊天室成员加载失败", + "Incompatible local cache": "本地缓存不兼容", + "Clear cache and resync": "清除缓存并重新同步", + "Incompatible Database": "数据库不兼容", + "Continue With Encryption Disabled": "在停用加密的情况下继续", + "Checking...": "正在检查…", + "Updating Riot": "正在更新 Riot", + "Backup Restored": "备份已还原", + "No backup found!": "找不到备份!", + "Unable to restore backup": "无法还原备份", + "Unable to load backup status": "无法获取备份状态", + "Next": "下一个", + "Copy to clipboard": "复制到剪贴板", + "Download": "下载", + "Got it": "知道了", + "Retry": "重试", + "Go to Settings": "打开设置", + "You do not have permission to invite people to this room.": "您没有权限将其他用户邀请至本聊天室。", + "Unknown server error": "未知服务器错误", + "Failed to invite users to the room:": "邀请失败:", + "No need for symbols, digits, or uppercase letters": "不一定要有符号、数字或大写字母", + "Use a longer keyboard pattern with more turns": "使用变化更丰富的字符组合方式", + "Avoid repeated words and characters": "避免重复词语与字符", + "Avoid sequences": "避免递增或递减的序列", + "Avoid recent years": "避免年份", + "Avoid years that are associated with you": "避免与您相关联的年份", + "Avoid dates and years that are associated with you": "避免与您相关联的日期与年份", + "Capitalization doesn't help very much": "大写字母并没有很大的作用", + "All-uppercase is almost as easy to guess as all-lowercase": "全大写的密码通常比全小写的更容易猜测", + "Reversed words aren't much harder to guess": "把单词倒过来不会比原来的难猜很多" } From 0b37797d227b6ec6caf65d0987427cbb6ce59521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Kosi=C4=87?= Date: Sat, 12 Jan 2019 14:02:20 +0000 Subject: [PATCH 0112/1528] Translated using Weblate (Croatian) Currently translated at 0.4% (7 of 1418 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/hr/ --- src/i18n/strings/hr.json | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/hr.json b/src/i18n/strings/hr.json index 0967ef424b..c91c82c8b4 100644 --- a/src/i18n/strings/hr.json +++ b/src/i18n/strings/hr.json @@ -1 +1,9 @@ -{} +{ + "This email address is already in use": "Ova email adresa se već koristi", + "This phone number is already in use": "Ovaj broj telefona se već koristi", + "Failed to verify email address: make sure you clicked the link in the email": "Nismo u mogućnosti verificirati Vašu email adresu. Provjerite dali ste kliknuli link u mailu", + "The platform you're on": "Platforma na kojoj se nalazite", + "The version of Riot.im": "Verzija Riot.im", + "Whether or not you're logged in (we don't record your user name)": "Dali ste prijavljeni ili ne (mi ne spremamo Vaše korisničko ime)", + "Your language of choice": "Izabrani jezik" +} From a3d8bfc260708a0c412ef304a9c2e4a952e71321 Mon Sep 17 00:00:00 2001 From: Moo Date: Sun, 13 Jan 2019 23:02:45 +0000 Subject: [PATCH 0113/1528] Translated using Weblate (Lithuanian) Currently translated at 64.1% (909 of 1418 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/lt/ --- src/i18n/strings/lt.json | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/lt.json b/src/i18n/strings/lt.json index 1f8963babb..39f6adda76 100644 --- a/src/i18n/strings/lt.json +++ b/src/i18n/strings/lt.json @@ -883,5 +883,32 @@ "Disinvite": "Atšaukti pakvietimą", "Disinvite this user?": "Atšaukti pakvietimą šiam naudotojui?", "Unknown for %(duration)s": "Nežinoma jau %(duration)s", - "(warning: cannot be disabled again!)": "(įspėjimas: nebeįmanoma bus išjungti!)" + "(warning: cannot be disabled again!)": "(įspėjimas: nebeįmanoma bus išjungti!)", + "Unable to load! Check your network connectivity and try again.": "Nepavyko įkelti! Patikrinkite savo tinklo ryšį ir bandykite dar kartą.", + "%(targetName)s joined the room.": "%(targetName)s atėjo į kambarį.", + "User %(user_id)s does not exist": "Naudotojo %(user_id)s nėra", + "Unknown server error": "Nežinoma serverio klaida", + "Avoid sequences": "Venkite sekų", + "Avoid recent years": "Venkite paskiausių metų", + "Avoid years that are associated with you": "Venkite su jumis susijusių metų", + "Avoid dates and years that are associated with you": "Venkite su jumis susijusių metų ir datų", + "Capitalization doesn't help very much": "Rašymas didžiosiomis raidėmis nelabai padeda", + "All-uppercase is almost as easy to guess as all-lowercase": "Visas didžiąsias raides taip pat lengva atspėti kaip ir visas mažąsias", + "Reversed words aren't much harder to guess": "Žodžius atvirkštine tvarka nėra sunkiau atspėti", + "Predictable substitutions like '@' instead of 'a' don't help very much": "Nuspėjami pakaitalai, tokie kaip \"@\" vietoj \"a\", nelabai padeda", + "Add another word or two. Uncommon words are better.": "Pridėkite dar vieną žodį ar du. Geriau nedažnai vartojamus žodžius.", + "Repeats like \"aaa\" are easy to guess": "Tokius pasikartojimus kaip \"aaa\" yra lengva atspėti", + "Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Tokius pasikartojimus kaip \"abcabcabc\" yra tik truputėlį sunkiau atspėti nei \"abc\"", + "Sequences like abc or 6543 are easy to guess": "Tokias sekas kaip \"abc\" ar \"6543\" yra lengva atspėti", + "Recent years are easy to guess": "Paskiausius metus yra lengva atspėti", + "Dates are often easy to guess": "Datas, dažniausiai, yra lengva atspėti", + "This is a top-10 common password": "Tai yra vienas iš 10 dažniausiai naudojamų slaptažodžių", + "This is a top-100 common password": "Tai yra vienas iš 100 dažniausiai naudojamų slaptažodžių", + "This is a very common password": "Tai yra labai dažnai naudojamas slaptažodis", + "This is similar to a commonly used password": "Šis yra panašus į dažnai naudojamą slaptažodį", + "A word by itself is easy to guess": "Patį žodį savaime yra lengva atspėti", + "Names and surnames by themselves are easy to guess": "Pačius vardus ar pavardes yra lengva atspėti", + "Common names and surnames are easy to guess": "Dažnai naudojamus vardus ar pavardes yra lengva atspėti", + "Straight rows of keys are easy to guess": "Klavišų eilę yra lengva atspėti", + "Short keyboard patterns are easy to guess": "Trumpus klaviatūros šablonus yra lengva atspėti" } From eebb75ba778a845ccd4d5a0ecbcdd2bf29d5bc0e Mon Sep 17 00:00:00 2001 From: Karol Kosek Date: Sun, 13 Jan 2019 01:21:58 +0000 Subject: [PATCH 0114/1528] Translated using Weblate (Polish) Currently translated at 92.1% (1307 of 1418 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/pl/ --- src/i18n/strings/pl.json | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/i18n/strings/pl.json b/src/i18n/strings/pl.json index bfab119be8..aac89f6048 100644 --- a/src/i18n/strings/pl.json +++ b/src/i18n/strings/pl.json @@ -170,7 +170,7 @@ "Conference calls are not supported in this client": "Połączenia konferencyjne nie są obsługiwane w tym kliencie", "Could not connect to the integration server": "Nie można połączyć się z serwerem integracji", "Create a new chat or reuse an existing one": "Utwórz nowy czat lub użyj istniejącego", - "Curve25519 identity key": "Curve25519 klucz tożsamości", + "Curve25519 identity key": "Klucz tożsamości Curve25519", "Custom": "Własny", "Custom level": "Własny poziom", "/ddg is not a command": "/ddg nie jest poleceniem", @@ -279,7 +279,7 @@ "Invalid file%(extra)s": "Nieprawidłowy plik %(extra)s", "%(senderName)s invited %(targetName)s.": "%(senderName)s zaprosił %(targetName)s.", "Invite new room members": "Zaproś nowych członków do pokoju", - "Invited": "Zaproszony", + "Invited": "Zaproszeni", "Invites": "Zaproszenia", "Invites user with given id to current room": "Zaprasza użytkownika o danym ID do obecnego pokoju", "'%(alias)s' is not a valid format for an address": "'%(alias)s' nie jest poprawnym formatem adresu", @@ -295,7 +295,7 @@ "Kick": "Wyrzuć", "Kicks user with given id": "Wyrzuca użytkownika o danym ID", "Labs": "Laboratoria", - "Last seen": "Ostatnio widziany", + "Last seen": "Ostatnio widziany(-a)", "Leave room": "Opuść pokój", "%(targetName)s left the room.": "%(targetName)s opuścił pokój.", "Level:": "Poziom:", @@ -304,9 +304,9 @@ "Logged in as:": "Zalogowany jako:", "Logout": "Wyloguj", "Low priority": "Niski priorytet", - "%(senderName)s made future room history visible to all room members, from the point they are invited.": "%(senderName)s uczynił przyszłą historię pokoju widoczną dla wszyscy członkowie pokoju, od momentu ich zaproszenia.", - "%(senderName)s made future room history visible to all room members, from the point they joined.": "%(senderName)s uczynił przyszłą historię pokoju widoczną dla wszyscy członkowie pokoju, od momentu ich dołączenia.", - "%(senderName)s made future room history visible to all room members.": "%(senderName)s uczynił przyszłą historię pokoju widoczną dla wszyscy członkowie pokoju.", + "%(senderName)s made future room history visible to all room members, from the point they are invited.": "%(senderName)s uczynił(a) przyszłą historię pokoju widoczną dla wszyscy członkowie pokoju, od momentu ich zaproszenia.", + "%(senderName)s made future room history visible to all room members, from the point they joined.": "%(senderName)s uczynił(a) przyszłą historię pokoju widoczną dla wszyscy członkowie pokoju, od momentu ich dołączenia.", + "%(senderName)s made future room history visible to all room members.": "%(senderName)s uczynił(a) przyszłą historię pokoju widoczną dla wszyscy członkowie pokoju.", "%(senderName)s made future room history visible to anyone.": "%(senderName)s uczynił przyszłą historię pokoju widoczną dla kazdego.", "%(senderName)s made future room history visible to unknown (%(visibility)s).": "%(senderName)s uczynił przyszłą historię pokoju widoczną dla nieznany (%(visibility)s).", "Manage Integrations": "Zarządzaj integracjami", @@ -373,7 +373,7 @@ "%(senderName)s removed their display name (%(oldDisplayName)s).": "%(senderName)s usunął(-ęła) swoją wyświetlaną nazwę (%(oldDisplayName)s).", "%(senderName)s removed their profile picture.": "%(senderName)s usunął(-ęła) swoje zdjęcie profilowe.", "Remove %(threePid)s?": "Usunąć %(threePid)s?", - "%(senderName)s requested a VoIP conference.": "%(senderName)s zażądał grupowego połączenia głosowego VoIP.", + "%(senderName)s requested a VoIP conference.": "%(senderName)s zażądał(a) grupowego połączenia głosowego VoIP.", "Results from DuckDuckGo": "Wyniki z DuckDuckGo", "Return to login screen": "Wróć do ekranu logowania", "Riot does not have permission to send you notifications - please check your browser settings": "Riot nie ma uprawnień, by wysyłać ci powiadomienia - sprawdź ustawienia swojej przeglądarki", @@ -715,8 +715,8 @@ "Enable inline URL previews by default": "Włącz domyślny podgląd URL w tekście", "Enable URL previews for this room (only affects you)": "Włącz podgląd URL dla tego pokoju (dotyczy tylko Ciebie)", "Enable URL previews by default for participants in this room": "Włącz domyślny podgląd URL dla uczestników w tym pokoju", - "Delete %(count)s devices|other": "Usunięto %(count)s urządzeń", - "Delete %(count)s devices|one": "Usunięto urządzenie", + "Delete %(count)s devices|other": "Usuń %(count)s urządzeń", + "Delete %(count)s devices|one": "Usuń urządzenie", "Select devices": "Wybierz urządzenia", "%(senderName)s sent an image": "%(senderName)s wysłał(a) obrazek", "%(senderName)s sent a video": "%(senderName)s wysłał(a) wideo", @@ -1319,5 +1319,8 @@ "Upgrade room to version %(ver)s": "Zaktualizuj pokój do wersji %(ver)s", "Don't ask again": "Nie pytaj ponownie", "Messages containing @room": "Wiadomości zawierające @room", - "This is similar to a commonly used password": "Jest to podobne do powszechnie stosowanego hasła" + "This is similar to a commonly used password": "Jest to podobne do powszechnie stosowanego hasła", + "Print it and store it somewhere safe": "Wydrukuj przechowuj w bezpiecznym miejscu", + "Your Recovery Key is in your Downloads folder.": "Twój Klucz Odzyskiwania znajduje się w Twoim katalogu Pobrane.", + "That doesn't match.": "To się nie zgadza." } From 9c2bdba9d3ebb7fba9f8395914e9de4bb32eca18 Mon Sep 17 00:00:00 2001 From: Paulo Miranda Date: Thu, 10 Jan 2019 14:23:34 +0000 Subject: [PATCH 0115/1528] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (1418 of 1418 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/pt_BR/ --- src/i18n/strings/pt_BR.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/pt_BR.json b/src/i18n/strings/pt_BR.json index 010fc6a037..a2916229f4 100644 --- a/src/i18n/strings/pt_BR.json +++ b/src/i18n/strings/pt_BR.json @@ -462,7 +462,7 @@ "Please check your email to continue registration.": "Por favor, verifique o seu e-mail para continuar o processo de registro.", "Token incorrect": "Token incorreto", "Please enter the code it contains:": "Por favor, entre com o código que está na mensagem:", - "powered by Matrix": "rodando a partir do Matrix", + "powered by Matrix": "oferecido por Matrix", "If you don't specify an email address, you won't be able to reset your password. Are you sure?": "Se não especificar um endereço de e-mail, você não poderá redefinir sua senha. Tem certeza?", "You are registering with %(SelectedTeamName)s": "Você está se registrando com %(SelectedTeamName)s", "Default server": "Servidor padrão", From db5eb87f57ed2931c107b0697edaf4d0a18c450e Mon Sep 17 00:00:00 2001 From: Paulo Miranda Date: Tue, 15 Jan 2019 17:35:25 +0000 Subject: [PATCH 0116/1528] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (1425 of 1425 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/pt_BR/ --- src/i18n/strings/pt_BR.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/pt_BR.json b/src/i18n/strings/pt_BR.json index a2916229f4..38d9d6013c 100644 --- a/src/i18n/strings/pt_BR.json +++ b/src/i18n/strings/pt_BR.json @@ -1430,5 +1430,12 @@ "Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "A configuração de mensagens seguras neste dispositivo criptografará novamente o histórico de mensagens deste dispositivo com o novo método de recuperação.", "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Se você não definiu o novo método de recuperação, um invasor pode estar tentando acessar sua conta. Altere a senha da sua conta e defina um novo método de recuperação imediatamente em Configurações.", "Set up Secure Messages": "Configurar mensagens seguras", - "Go to Settings": "Ir para as configurações" + "Go to Settings": "Ir para as configurações", + "Unrecognised address": "Endereço não reconhecido", + "User %(user_id)s may or may not exist": "Usuário %(user_id)s pode existir ou não", + "Always invite users which may not exist": "Sempre convidar usuários que talvez não existam", + "The following users may not exist": "Os seguintes usuários podem não existir", + "The following users may not exist - would you like to invite them anyways?": "Os seguintes usuários podem não existir - você gostaria de convidá-los de qualquer maneira?", + "Invite anyways and never warn me again": "Convide mesmo assim e nunca mais me alerte", + "Invite anyways": "Convidar mesmo assim" } From c07470be7bf8f80e1ca34df9c9d538e7bc84dedc Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 15 Jan 2019 18:45:56 +0100 Subject: [PATCH 0117/1528] show a spinner while searching --- res/css/structures/_RoomView.scss | 33 ++++++++++++++++++++++----- src/components/structures/RoomView.js | 30 ++++++++++++------------ 2 files changed, 42 insertions(+), 21 deletions(-) diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index 72dca953f9..900300b03d 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -95,12 +95,10 @@ limitations under the License. flex-direction: column; } -.mx_RoomView_body .mx_RoomView_messagePanel { - order: 2; -} - -.mx_RoomView_body .mx_RoomView_messagePanelSpinner { - order: 2; +.mx_RoomView_body { + .mx_RoomView_messagePanel, .mx_RoomView_messagePanelSpinner, .mx_RoomView_messagePanelSearchSpinner{ + order: 2; + } } .mx_RoomView_body .mx_RoomView_statusArea { @@ -116,6 +114,29 @@ limitations under the License. overflow-y: auto; } +.mx_RoomView_messagePanelSearchSpinner { + flex: 1; + background-image: url('../../img/typing-indicator-2x.gif'); + background-position: center 367px; + background-size: 25px; + background-repeat: no-repeat; + position: relative; +} + +.mx_RoomView_messagePanelSearchSpinner:before { + background-color: $greyed-fg-color; + mask: url('../../../img/feather-icons/search-input.svg'); + mask-repeat: no-repeat; + mask-position: center; + mask-size: 50px; + content: ''; + position: absolute; + top: 286px; + left: 0; + right: 0; + height: 50px; +} + .mx_RoomView_messageListWrapper { min-height: 100%; diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 368aeb4f19..2511e80e05 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -1135,11 +1135,6 @@ module.exports = React.createClass({ // XXX: todo: merge overlapping results somehow? // XXX: why doesn't searching on name work? - if (this.state.searchResults.results === undefined) { - // awaiting results - return []; - } - const ret = []; if (this.state.searchInProgress) { @@ -1820,16 +1815,21 @@ module.exports = React.createClass({ let hideMessagePanel = false; if (this.state.searchResults) { - searchResultsPanel = ( - -
  • - { this.getSearchResultTiles() } -
    - ); + // show searching spinner + if (this.state.searchResults.results === undefined) { + searchResultsPanel = (
    ); + } else { + searchResultsPanel = ( + +
  • + { this.getSearchResultTiles() } +
    + ); + } hideMessagePanel = true; } From 1d2538a7bcb8240dde72b0ed32fe1ebfbb6ba7f0 Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 15 Jan 2019 18:08:13 +0000 Subject: [PATCH 0118/1528] First working version of SAS --- src/MatrixClientPeg.js | 2 + src/components/structures/MatrixChat.js | 7 + .../views/dialogs/DeviceVerifyDialog.js | 312 +++++++++++++++--- .../views/dialogs/IncomingSasDialog.js | 218 ++++++++++++ src/i18n/strings/en_EN.json | 21 +- src/settings/Settings.js | 6 + 6 files changed, 517 insertions(+), 49 deletions(-) create mode 100644 src/components/views/dialogs/IncomingSasDialog.js diff --git a/src/MatrixClientPeg.js b/src/MatrixClientPeg.js index 9a77901d2e..0cf67a3551 100644 --- a/src/MatrixClientPeg.js +++ b/src/MatrixClientPeg.js @@ -29,6 +29,7 @@ import SettingsStore from './settings/SettingsStore'; import MatrixActionCreators from './actions/MatrixActionCreators'; import {phasedRollOutExpiredForUser} from "./PhasedRollOut"; import Modal from './Modal'; +import {verificationMethods} from 'matrix-js-sdk/lib/crypto'; interface MatrixClientCreds { homeserverUrl: string, @@ -184,6 +185,7 @@ class MatrixClientPeg { deviceId: creds.deviceId, timelineSupport: true, forceTURN: SettingsStore.getValue('webRtcForceTURN', false), + verificationMethods: [verificationMethods.SAS] }; this.matrixClient = createMatrixClient(opts, useIndexedDb); diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 2d1c928494..7167e50fb2 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -1277,6 +1277,7 @@ export default React.createClass({ this.firstSyncComplete = false; this.firstSyncPromise = Promise.defer(); const cli = MatrixClientPeg.get(); + const IncomingSasDialog = sdk.getComponent('views.dialogs.IncomingSasDialog'); // Allow the JS SDK to reap timeline events. This reduces the amount of // memory consumed as the JS SDK stores multiple distinct copies of room @@ -1476,6 +1477,12 @@ export default React.createClass({ } }); + cli.on("crypto.verification.start", (verifier) => { + Modal.createTrackedDialog('Incoming Verification', '', IncomingSasDialog, { + verifier, + }); + }); + // Fire the tinter right on startup to ensure the default theme is applied // A later sync can/will correct the tint to be the right value for the user const colorScheme = SettingsStore.getValue("roomColor"); diff --git a/src/components/views/dialogs/DeviceVerifyDialog.js b/src/components/views/dialogs/DeviceVerifyDialog.js index 6bec933389..169dc26c52 100644 --- a/src/components/views/dialogs/DeviceVerifyDialog.js +++ b/src/components/views/dialogs/DeviceVerifyDialog.js @@ -1,6 +1,7 @@ /* Copyright 2016 OpenMarket Ltd Copyright 2017 Vector Creations Ltd +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. @@ -21,58 +22,273 @@ import MatrixClientPeg from '../../../MatrixClientPeg'; import sdk from '../../../index'; import * as FormattingUtils from '../../../utils/FormattingUtils'; import { _t } from '../../../languageHandler'; +import SettingsStore from '../../../settings/SettingsStore'; +import {verificationMethods} from 'matrix-js-sdk/lib/crypto'; +import {renderSasWaitAccept} from '../../../sas_ui'; -export default function DeviceVerifyDialog(props) { - const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); +const MODE_LEGACY = 'legacy'; +const MODE_SAS = 'sas'; - const key = FormattingUtils.formatCryptoKey(props.device.getFingerprint()); - const body = ( -
    -

    - { _t("To verify that this device can be trusted, please contact its " + - "owner using some other means (e.g. in person or a phone call) " + - "and ask them whether the key they see in their User Settings " + - "for this device matches the key below:") } -

    -
    -
      -
    • { props.device.getDisplayName() }
    • -
    • { props.device.deviceId }
    • -
    • { key }
    • -
    -
    -

    - { _t("If it matches, press the verify button below. " + - "If it doesn't, then someone else is intercepting this device " + - "and you probably want to press the blacklist button instead.") } -

    -

    - { _t("In future this verification process will be more sophisticated.") } -

    -
    - ); +const PHASE_START = 0; +const PHASE_WAIT_FOR_PARTNER_TO_ACCEPT = 1; +const PHASE_SHOW_SAS = 2; +const PHASE_WAIT_FOR_PARTNER_TO_CONFIRM = 3; +const PHASE_VERIFIED = 4; +const PHASE_CANCELLED = 5; - function onFinished(confirm) { - if (confirm) { - MatrixClientPeg.get().setDeviceVerified( - props.userId, props.device.deviceId, true, - ); - } - props.onFinished(confirm); +export default class DeviceVerifyDialog extends React.Component { + static propTypes = { + userId: PropTypes.string.isRequired, + device: PropTypes.object.isRequired, + onFinished: PropTypes.func.isRequired, + }; + + constructor() { + super(); + this._verifier = null; + this._showSasEvent = null; + this.state = { + phase: PHASE_START, + mode: SettingsStore.isFeatureEnabled("feature_sas") ? MODE_SAS : MODE_LEGACY, + }; } - return ( - - ); + componentWillUnmount() { + if (this._verifier) { + this._verifier.removeListener('show_sas', this._onVerifierShowSas); + this._verifier.cancel('User cancel'); + } + } + + _onSwitchToLegacyClick = () => { + this.setState({mode: MODE_LEGACY}); + } + + _onSwitchToSasClick = () => { + this.setState({mode: MODE_SAS}); + } + + _onCancelClick = () => { + this.props.onFinished(false); + } + + _onLegacyFinished = (confirm) => { + if (confirm) { + MatrixClientPeg.get().setDeviceVerified( + this.props.userId, this.props.device.deviceId, true, + ); + } + this.props.onFinished(confirm); + } + + _onSasRequestClick = () => { + this.setState({ + phase: PHASE_WAIT_FOR_PARTNER_TO_ACCEPT, + }); + this._verifier = MatrixClientPeg.get().beginKeyVerification( + verificationMethods.SAS, this.props.userId, this.props.device.deviceId, + ); + this._verifier.on('show_sas', this._onVerifierShowSas); + this._verifier.verify().then(() => { + this.setState({phase: PHASE_VERIFIED}); + this._verifier.removeListener('show_sas', this._onVerifierShowSas); + this._verifier = null; + }).catch((e) => { + console.log("Verification failed", e); + this.setState({ + phase: PHASE_CANCELLED, + }); + this._verifier = null; + }); + } + + _onSasMatchesClick = () => { + this._showSasEvent.confirm(); + this.setState({ + phase: PHASE_WAIT_FOR_PARTNER_TO_CONFIRM, + }); + } + + _onVerifiedDoneClick = () => { + this.props.onFinished(true); + } + + _onVerifierShowSas = (e) => { + this._showSasEvent = e; + this.setState({ + phase: PHASE_SHOW_SAS, + }); + } + + _renderSasVerification() { + let body; + switch (this.state.phase) { + case PHASE_START: + body = this._renderSasVerificationPhaseStart(); + break; + case PHASE_WAIT_FOR_PARTNER_TO_ACCEPT: + //body = this._renderSasVerificationPhaseWaitForPartnerToAccept(); + body = renderSasWaitAccept(this.props.userId); + break; + case PHASE_SHOW_SAS: + body = this._renderSasVerificationPhaseShowSas(); + break; + case PHASE_WAIT_FOR_PARTNER_TO_CONFIRM: + body = this._renderSasVerificationPhaseWaitForPartnerToConfirm(); + break; + case PHASE_VERIFIED: + body = this._renderSasVerificationPhaseVerified(); + break; + case PHASE_CANCELLED: + body = this._renderSasVerificationPhaseCancelled(); + break; + } + + const BaseDialog = sdk.getComponent("dialogs.BaseDialog"); + return ( + + {body} + + ); + } + + _renderSasVerificationPhaseStart() { + const AccessibleButton = sdk.getComponent('views.elements.AccessibleButton'); + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + return ( +
    + + {_t("Use Legacy Verification (for older clients)")} + +

    + { _t("Do clicky clicky button press request verify user send to do.") } +

    + +
    + ); + } + + _renderSasVerificationPhaseShowSas() { + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + return
    +

    {_t( + "Verify this user by confirming the following number appears on their screen" + )}

    +

    {_t( + "For maximum security, we reccommend you do this in person or use another " + + "trusted means of communication" + )}

    +
    {this._showSasEvent.sas}
    + +
    ; + } + + _renderSasVerificationPhaseWaitForPartnerToConfirm() { + const Spinner = sdk.getComponent('views.elements.Spinner'); + return
    + +

    {_t( + "Waiting for %(userId)s to confirm...", {userId: this.props.userId}, + )}

    +
    ; + } + + _renderSasVerificationPhaseVerified() { + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + return
    +

    {_t("Verification complete!")}

    + +
    ; + } + + _renderSasVerificationPhaseCancelled() { + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + + return ( +
    +

    {_t( + "%(userId)s cancelled the verification.", {userId: this.props.userId}, + )}

    + +
    + ); + } + + _renderLegacyVerification() { + const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); + const AccessibleButton = sdk.getComponent('views.elements.AccessibleButton'); + + const key = FormattingUtils.formatCryptoKey(this.props.device.getFingerprint()); + const body = ( +
    + + {_t("Use two-way text verification")} + +

    + { _t("To verify that this device can be trusted, please contact its " + + "owner using some other means (e.g. in person or a phone call) " + + "and ask them whether the key they see in their User Settings " + + "for this device matches the key below:") } +

    +
    +
      +
    • { this.props.device.getDisplayName() }
    • +
    • { this.props.device.deviceId }
    • +
    • { key }
    • +
    +
    +

    + { _t("If it matches, press the verify button below. " + + "If it doesn't, then someone else is intercepting this device " + + "and you probably want to press the blacklist button instead.") } +

    +

    + { _t("In future this verification process will be more sophisticated.") } +

    +
    + ); + + return ( + + ); + } + + render() { + if (this.state.mode === MODE_LEGACY) { + return this._renderLegacyVerification(); + } else { + return
    + {this._renderSasVerification()} +
    ; + } + } } -DeviceVerifyDialog.propTypes = { - userId: PropTypes.string.isRequired, - device: PropTypes.object.isRequired, - onFinished: PropTypes.func.isRequired, -}; diff --git a/src/components/views/dialogs/IncomingSasDialog.js b/src/components/views/dialogs/IncomingSasDialog.js new file mode 100644 index 0000000000..732ce2a461 --- /dev/null +++ b/src/components/views/dialogs/IncomingSasDialog.js @@ -0,0 +1,218 @@ +/* +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. +*/ + +import React from 'react'; +import PropTypes from 'prop-types'; +import MatrixClientPeg from '../../../MatrixClientPeg'; +import sdk from '../../../index'; +import { _t } from '../../../languageHandler'; +import {verificationMethods} from 'matrix-js-sdk/lib/crypto'; + +const PHASE_START = 0; +const PHASE_SHOW_SAS = 1; +const PHASE_WAIT_FOR_PARTNER_TO_CONFIRM = 2; +const PHASE_VERIFIED = 3; +const PHASE_CANCELLED = 4; + +export default class IncomingSasDialog extends React.Component { + static propTypes = { + verifier: PropTypes.object.isRequired, + }; + + constructor(props) { + super(props); + + this._showSasEvent = null; + this.state = { + phase: PHASE_START, + }; + this.props.verifier.on('show_sas', this._onVerifierShowSas); + this.props.verifier.on('cancel', this._onVerifierCancel); + } + + componentWillUnmount() { + if (this.state.phase !== PHASE_CANCELLED && this.state.phase !== PHASE_VERIFIED) { + this.props.verifier.cancel('User cancel'); + } + this.props.verifier.removeListener('show_sas', this._onVerifierShowSas); + } + + _onFinished = () => { + this.props.onFinished(this.state.phase === PHASE_VERIFIED); + } + + _onCancelClick = () => { + this.props.onFinished(this.state.phase === PHASE_VERIFIED); + } + + _onContinueClick = () => { + this.setState({phase: PHASE_WAIT_FOR_PARTNER_TO_CONFIRM}); + this.props.verifier.verify().then(() => { + this.setState({phase: PHASE_VERIFIED}); + }).catch((e) => { + console.log("Verification failed", e); + }); + } + + _onVerifierShowSas = (e) => { + this._showSasEvent = e; + this.setState({ + phase: PHASE_SHOW_SAS, + sas: e.sas, + }); + } + + _onVerifierCancel = (e) => { + this.setState({ + phase: PHASE_CANCELLED, + }); + } + + _onSasMatchesClick = () => { + this._showSasEvent.confirm(); + this.setState({ + phase: PHASE_WAIT_FOR_PARTNER_TO_CONFIRM, + }); + } + + _onVerifiedDoneClick = () => { + this.props.onFinished(true); + } + + _renderPhaseStart() { + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + + return ( +
    +

    {this.props.verifier.userId}

    +

    {_t( + "Verify this user to mark them as trusted. " + + "Trusting users gives you extra peace of mind when using " + + "end-to-end encrypted messages." + )}

    +

    {_t( + // NB. Below wording adjusted to singular 'device' until we have + // cross-signing + "Verifying this user will mark their device as trusted, and " + + "also mark your device as trusted to them" + )}

    + +
    + ); + } + + _renderPhaseShowSas() { + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + return
    +

    {_t( + "Verify this user by confirming the following number appears on their screen" + )}

    +

    {_t( + "For maximum security, we reccommend you do this in person or use another " + + "trusted means of communication" + )}

    +
    {this._showSasEvent.sas}
    + +
    ; + } + + _renderPhaseWaitForPartnerToConfirm() { + const Spinner = sdk.getComponent("views.elements.Spinner"); + + return ( +
    + +

    {_t("Waiting for partner to confirm...")}

    +
    + ); + } + + _renderPhaseVerified() { + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + + return ( +
    +

    {_t( + "Verification Complete!" + )}

    + +
    + ); + } + + _renderPhaseCancelled() { + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + + return ( +
    +

    {_t( + "The other party cancelled the verification." + )}

    + +
    + ); + } + + render() { + console.log("rendering pahse "+this.state.phase); + let body; + switch (this.state.phase) { + case PHASE_START: + body = this._renderPhaseStart(); + break; + case PHASE_SHOW_SAS: + body = this._renderPhaseShowSas(); + break; + case PHASE_WAIT_FOR_PARTNER_TO_CONFIRM: + body = this._renderPhaseWaitForPartnerToConfirm(); + break; + case PHASE_VERIFIED: + body = this._renderPhaseVerified(); + break; + case PHASE_CANCELLED: + body = this._renderPhaseCancelled(); + break; + } + + const BaseDialog = sdk.getComponent("dialogs.BaseDialog"); + return ( + + {body} + + ); + } +} + diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 0fbed11e20..c26330dda4 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -114,6 +114,8 @@ "Failed to invite": "Failed to invite", "Failed to invite users to the room:": "Failed to invite users to the room:", "Failed to invite the following users to the %(roomName)s room:": "Failed to invite the following users to the %(roomName)s room:", + "Waiting for %(userId)s to accept...": "Waiting for %(userId)s to accept...", + "Waiting for %(userId)s to confirm...": "Waiting for %(userId)s to confirm...", "You need to be logged in.": "You need to be logged in.", "You need to be able to invite users to do that.": "You need to be able to invite users to do that.", "Unable to create widget.": "Unable to create widget.", @@ -264,6 +266,7 @@ "Backup of encryption keys to server": "Backup of encryption keys to server", "Render simple counters in room header": "Render simple counters in room header", "Allow up to 6 rooms in a community to be shown simultaneously in a grid via the context menu": "Allow up to 6 rooms in a community to be shown simultaneously in a grid via the context menu", + "Two-way device verification using short text": "Two-way device verification using short text", "Disable Emoji suggestions while typing": "Disable Emoji suggestions while typing", "Use compact timeline layout": "Use compact timeline layout", "Hide removed messages": "Hide removed messages", @@ -938,12 +941,22 @@ "Please forget all messages I have sent when my account is deactivated (Warning: this will cause future users to see an incomplete view of conversations)": "Please forget all messages I have sent when my account is deactivated (Warning: this will cause future users to see an incomplete view of conversations)", "To continue, please enter your password:": "To continue, please enter your password:", "password": "password", + "Verify device": "Verify device", + "Use Legacy Verification (for older clients)": "Use Legacy Verification (for older clients)", + "Do clicky clicky button press request verify user send to do.": "Do clicky clicky button press request verify user send to do.", + "Send Verification Request": "Send Verification Request", + "Verify this user by confirming the following number appears on their screen": "Verify this user by confirming the following number appears on their screen", + "For maximum security, we reccommend you do this in person or use another trusted means of communication": "For maximum security, we reccommend you do this in person or use another trusted means of communication", + "This Matches": "This Matches", + "Verification complete!": "Verification complete!", + "Done": "Done", + "%(userId)s cancelled the verification.": "%(userId)s cancelled the verification.", + "Use two-way text verification": "Use two-way text verification", "To verify that this device can be trusted, please contact its owner using some other means (e.g. in person or a phone call) and ask them whether the key they see in their User Settings for this device matches the key below:": "To verify that this device can be trusted, please contact its owner using some other means (e.g. in person or a phone call) and ask them whether the key they see in their User Settings for this device matches the key below:", "Device name": "Device name", "Device key": "Device key", "If it matches, press the verify button below. If it doesn't, then someone else is intercepting this device and you probably want to press the blacklist button instead.": "If it matches, press the verify button below. If it doesn't, then someone else is intercepting this device and you probably want to press the blacklist button instead.", "In future this verification process will be more sophisticated.": "In future this verification process will be more sophisticated.", - "Verify device": "Verify device", "I verify that the keys match": "I verify that the keys match", "Back": "Back", "Send Custom Event": "Send Custom Event", @@ -960,6 +973,12 @@ "Toolbox": "Toolbox", "Developer Tools": "Developer Tools", "An error has occurred.": "An error has occurred.", + "Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.": "Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.", + "Verifying this user will mark their device as trusted, and also mark your device as trusted to them": "Verifying this user will mark their device as trusted, and also mark your device as trusted to them", + "Waiting for partner to confirm...": "Waiting for partner to confirm...", + "Verification Complete!": "Verification Complete!", + "The other party cancelled the verification.": "The other party cancelled the verification.", + "Incoming Verification Request": "Incoming Verification Request", "You added a new device '%(displayName)s', which is requesting encryption keys.": "You added a new device '%(displayName)s', which is requesting encryption keys.", "Your unverified device '%(displayName)s' is requesting encryption keys.": "Your unverified device '%(displayName)s' is requesting encryption keys.", "Start verification": "Start verification", diff --git a/src/settings/Settings.js b/src/settings/Settings.js index 9b46f9406b..9e8cd7a672 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -114,6 +114,12 @@ export const SETTINGS = { supportedLevels: LEVELS_FEATURE, default: false, }, + "feature_sas": { + isFeature: true, + displayName: _td("Two-way device verification using short text"), + supportedLevels: LEVELS_FEATURE, + default: false, + }, "MessageComposerInput.dontSuggestEmoji": { supportedLevels: LEVELS_ACCOUNT_SETTINGS, displayName: _td('Disable Emoji suggestions while typing'), From 0c33c477646ccb82d61d494bb0eb51dabf2c1d9b Mon Sep 17 00:00:00 2001 From: Szimszon Date: Tue, 15 Jan 2019 18:45:48 +0000 Subject: [PATCH 0119/1528] Translated using Weblate (Hungarian) Currently translated at 100.0% (1425 of 1425 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/hu/ --- src/i18n/strings/hu.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json index 01239599a9..c82206d5d3 100644 --- a/src/i18n/strings/hu.json +++ b/src/i18n/strings/hu.json @@ -1450,5 +1450,12 @@ "Set a new status...": "Új állapot beállítása...", "Clear status": "Állapot törlése", "Unable to load commit detail: %(msg)s": "Sikertelen betöltés részletek: \n%(msg)s", - "To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "Ahhoz, hogy a múltbeli titkosított üzeneteidet és az újakat a leendő eszközeiden láthasd, állítsd be a Biztonságos Üzenet Visszaállítást." + "To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "Ahhoz, hogy a múltbeli titkosított üzeneteidet és az újakat a leendő eszközeiden láthasd, állítsd be a Biztonságos Üzenet Visszaállítást.", + "Unrecognised address": "Ismeretlen cím", + "User %(user_id)s may or may not exist": "%(user_id)s felhasználó lehet, hogy nem létezik", + "Always invite users which may not exist": "Valószínűleg nem létező felhasználókat is meghívhat", + "The following users may not exist": "Az alábbi felhasználók lehet, hogy nem léteznek", + "The following users may not exist - would you like to invite them anyways?": "Az alábbi felhasználók lehet, hogy nem léteznek - mégis meghívod őket?", + "Invite anyways and never warn me again": "Mindig meghívom és többet nem kérek figyelmeztetést", + "Invite anyways": "Mindig meghív" } From 807d3aba6e9669d263fc90277b90d7cc947ad35e Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Tue, 15 Jan 2019 16:02:08 -0600 Subject: [PATCH 0120/1528] Use integer padding / border for avatar It seems fractional spacing results in different behavior across browsers, including unbalanced spacing, making the avatar appear uncentered. Here we avoid this by using integers that seem to closely match the comps. Fixes https://github.com/vector-im/riot-web/issues/8134. --- res/css/views/avatars/_MemberStatusMessageAvatar.scss | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/res/css/views/avatars/_MemberStatusMessageAvatar.scss b/res/css/views/avatars/_MemberStatusMessageAvatar.scss index 7ac4036eef..c101a5d8a8 100644 --- a/res/css/views/avatars/_MemberStatusMessageAvatar.scss +++ b/res/css/views/avatars/_MemberStatusMessageAvatar.scss @@ -15,13 +15,13 @@ limitations under the License. */ .mx_MessageComposer_avatar .mx_BaseAvatar { - padding: 1.5px; - border: 1.2px solid transparent; - border-radius: 14px; + padding: 2px; + border: 1px solid transparent; + border-radius: 15px; } .mx_MessageComposer_avatar .mx_BaseAvatar_initial { - left: 1.5px; + left: 2px; } .mx_MemberStatusMessageAvatar_hasStatus .mx_BaseAvatar { From e2f3ff37b8692e503514ccf8eaa26162170dcbaa Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Wed, 16 Jan 2019 06:17:12 +0000 Subject: [PATCH 0121/1528] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (1425 of 1425 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/zh_Hant/ --- src/i18n/strings/zh_Hant.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/zh_Hant.json b/src/i18n/strings/zh_Hant.json index a474724c11..d2c84d3c6f 100644 --- a/src/i18n/strings/zh_Hant.json +++ b/src/i18n/strings/zh_Hant.json @@ -1448,5 +1448,12 @@ "Unable to load commit detail: %(msg)s": "無法載入遞交的詳細資訊:%(msg)s", "Set a new status...": "設定新狀態……", "Clear status": "清除狀態", - "To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "要檢視您的安全訊息歷史並確保可以在將來的裝置上檢視新訊息,請設定安全訊息復原。" + "To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "要檢視您的安全訊息歷史並確保可以在將來的裝置上檢視新訊息,請設定安全訊息復原。", + "Unrecognised address": "無法識別的位置", + "User %(user_id)s may or may not exist": "使用者 %(user_id)s 可能存在也可能不存在", + "Always invite users which may not exist": "總是邀請可能不存在的使用者", + "The following users may not exist": "以下的使用者可能不存在", + "The following users may not exist - would you like to invite them anyways?": "以下的使用者可能不存在,您無論如何都想邀請他們嗎?", + "Invite anyways and never warn me again": "總是邀請而且不要再警告我", + "Invite anyways": "總是邀請" } From 0dd851949164b181895e768669c6eaaa5322db1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20C?= Date: Wed, 16 Jan 2019 10:06:33 +0000 Subject: [PATCH 0122/1528] Translated using Weblate (French) Currently translated at 100.0% (1425 of 1425 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/fr/ --- src/i18n/strings/fr.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json index 3c162bfae6..e8955726eb 100644 --- a/src/i18n/strings/fr.json +++ b/src/i18n/strings/fr.json @@ -1450,5 +1450,12 @@ "Unable to load commit detail: %(msg)s": "Impossible de charger les détails de l'envoi : %(msg)s", "Set a new status...": "Configurer un nouveau statut…", "Clear status": "Effacer le statut", - "To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "Pour voir votre historique de messages sécurisé et vous assurer que vous pouvez voir les nouveaux messages sur de futurs appareils, configurez la récupération de messages sécurisée." + "To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "Pour voir votre historique de messages sécurisé et vous assurer que vous pouvez voir les nouveaux messages sur de futurs appareils, configurez la récupération de messages sécurisée.", + "Unrecognised address": "Adresse non reconnue", + "User %(user_id)s may or may not exist": "L'utilisateur %(user_id)s pourrait exister", + "Always invite users which may not exist": "Toujours inviter les utilisateurs qui pourraient ne pas exister", + "The following users may not exist": "Les utilisateurs suivants pourraient ne pas exister", + "The following users may not exist - would you like to invite them anyways?": "Les utilisateurs suivants pourraient ne pas exister. Souhaitez-vous quand même les inviter ?", + "Invite anyways and never warn me again": "Les inviter quand même et ne plus m'avertir", + "Invite anyways": "Les inviter quand même" } From cbe3afaa1f5474a513ddc6d51ea60706f477c493 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 16 Jan 2019 11:13:35 +0100 Subject: [PATCH 0123/1528] resubmit query when switching between "This Room" / "All Rooms" --- src/components/views/rooms/SearchBar.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/SearchBar.js b/src/components/views/rooms/SearchBar.js index d48cb0e08b..78c7e7bbb3 100644 --- a/src/components/views/rooms/SearchBar.js +++ b/src/components/views/rooms/SearchBar.js @@ -33,11 +33,11 @@ module.exports = React.createClass({ }, onThisRoomClick: function() { - this.setState({ scope: 'Room' }); + this.setState({ scope: 'Room' }, () => this._searchIfQuery()); }, onAllRoomsClick: function() { - this.setState({ scope: 'All' }); + this.setState({ scope: 'All' }, () => this._searchIfQuery()); }, onSearchChange: function(e) { @@ -49,6 +49,12 @@ module.exports = React.createClass({ } }, + _searchIfQuery: function() { + if (this.refs.search_term.value) { + this.onSearch(); + } + }, + onSearch: function() { this.props.onSearch(this.refs.search_term.value, this.state.scope); }, From 8d16ac1d3135ca66a50d80f5c8f30707ba0199d6 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 16 Jan 2019 11:14:05 +0100 Subject: [PATCH 0124/1528] make room name header smaller --- src/components/structures/RoomView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 2511e80e05..b73f85650d 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -1191,7 +1191,7 @@ module.exports = React.createClass({ const roomName = room ? room.name : _t("Unknown room %(roomId)s", { roomId: roomId }); ret.push(
  • -

    { _t("Room") }: { roomName }

    +

    { _t("Room") }: { roomName }

  • ); lastRoomId = roomId; } From b14d436e98c9d19321f352ef5dfe4b3f1a5f2e88 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 16 Jan 2019 11:14:19 +0100 Subject: [PATCH 0125/1528] make cancel button icon slightly larger --- res/css/views/rooms/_SearchBar.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/css/views/rooms/_SearchBar.scss b/res/css/views/rooms/_SearchBar.scss index 612ad81fe5..dddc87e5dd 100644 --- a/res/css/views/rooms/_SearchBar.scss +++ b/res/css/views/rooms/_SearchBar.scss @@ -58,8 +58,8 @@ limitations under the License. mask: url('../../../img/cancel.svg'); mask-repeat: no-repeat; mask-position: center; - mask-size: 12px; - padding: 10px; + mask-size: 14px; + padding: 9px; margin: 0 12px 0 3px; cursor: pointer; } From 924e1f9e4a0f92c955628bc3d2718e2bb2828c9f Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 16 Jan 2019 11:14:30 +0100 Subject: [PATCH 0126/1528] don't show event search results with underline/blue --- res/css/structures/_RoomView.scss | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index 900300b03d..d8926c68e4 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -147,8 +147,15 @@ limitations under the License. justify-content: flex-end; } -.mx_RoomView_searchResultsPanel .mx_RoomView_messageListWrapper { - justify-content: flex-start; +.mx_RoomView_searchResultsPanel { + .mx_RoomView_messageListWrapper { + justify-content: flex-start; + } + + a { + text-decoration: none; + color: inherit; + } } .mx_RoomView_empty { From a5424f32a510b6212ecec46f9eac75e55d7a89f2 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 16 Jan 2019 10:29:05 +0000 Subject: [PATCH 0127/1528] Update src/resizer/item.js Co-Authored-By: bwindels --- src/resizer/item.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resizer/item.js b/src/resizer/item.js index 6192c6eebb..2e06ad217c 100644 --- a/src/resizer/item.js +++ b/src/resizer/item.js @@ -1,5 +1,5 @@ /* -Copyright 2018 New Vector Ltd +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. From 2bd65e14b770d92d950b21b726dc070c1ba551fc Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 16 Jan 2019 10:29:15 +0000 Subject: [PATCH 0128/1528] Update src/resizer/distributors/fixed.js Co-Authored-By: bwindels --- src/resizer/distributors/fixed.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resizer/distributors/fixed.js b/src/resizer/distributors/fixed.js index 843d8367e0..584d0c1894 100644 --- a/src/resizer/distributors/fixed.js +++ b/src/resizer/distributors/fixed.js @@ -1,5 +1,5 @@ /* -Copyright 2018 New Vector Ltd +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. From 98aa657052df0f374870ab0e3dd5e51a7941cb58 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 16 Jan 2019 10:29:22 +0000 Subject: [PATCH 0129/1528] Update src/resizer/distributors/collapse.js Co-Authored-By: bwindels --- src/resizer/distributors/collapse.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resizer/distributors/collapse.js b/src/resizer/distributors/collapse.js index d9d596299d..784532a0eb 100644 --- a/src/resizer/distributors/collapse.js +++ b/src/resizer/distributors/collapse.js @@ -1,5 +1,5 @@ /* -Copyright 2018 New Vector Ltd +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. From fed256cbaa60acf52ebac5c6978616296f0698bb Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 16 Jan 2019 10:29:30 +0000 Subject: [PATCH 0130/1528] Update src/resizer/distributors/roomsublist.js Co-Authored-By: bwindels --- src/resizer/distributors/roomsublist.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resizer/distributors/roomsublist.js b/src/resizer/distributors/roomsublist.js index e6f07a648d..cc7875bfb0 100644 --- a/src/resizer/distributors/roomsublist.js +++ b/src/resizer/distributors/roomsublist.js @@ -1,5 +1,5 @@ /* -Copyright 2018 New Vector Ltd +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. From 313bbaaeaac981bd35fbb14c5e38cc449587f8a3 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 16 Jan 2019 11:33:41 +0100 Subject: [PATCH 0131/1528] remove obsolete comments --- src/resizer/distributors/fixed.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/resizer/distributors/fixed.js b/src/resizer/distributors/fixed.js index 584d0c1894..e93c6fbcee 100644 --- a/src/resizer/distributors/fixed.js +++ b/src/resizer/distributors/fixed.js @@ -26,8 +26,6 @@ they have two methods: `resizeFromContainerOffset` receives resize handle location within the container bounding box. For internal use. This method usually ends up calling `resize` once the start offset is subtracted. -the offset from the container edge of where -the mouse cursor is. */ export default class FixedDistributor { static createItem(resizeHandle, resizer, sizer) { From 622b11fd9143c03e7ddd34a1dc86ae7601015def Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 16 Jan 2019 13:04:49 +0100 Subject: [PATCH 0132/1528] remove commented out code from shifting things around --- src/components/views/rooms/SearchBar.js | 30 ------------------------- 1 file changed, 30 deletions(-) diff --git a/src/components/views/rooms/SearchBar.js b/src/components/views/rooms/SearchBar.js index 78c7e7bbb3..fb9c3103ab 100644 --- a/src/components/views/rooms/SearchBar.js +++ b/src/components/views/rooms/SearchBar.js @@ -75,35 +75,5 @@ module.exports = React.createClass({
    ); - - - - -/* -const clearButton = this.state.searchTerm.length > 0 ? - ( {this._clearSearch("button")} }> - ) : undefined; - - return ( -
    - - { clearButton } -
    - ); -*/ - - }, }); From 1082f548d3666aa23f1130df17dac2273a50066a Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Wed, 16 Jan 2019 12:53:46 +0000 Subject: [PATCH 0133/1528] hack nunito italics for now with CSS skew fixes https://github.com/google/fonts/issues/1726 --- res/css/views/elements/_RichText.scss | 5 +++++ res/css/views/rooms/_EventTile.scss | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/res/css/views/elements/_RichText.scss b/res/css/views/elements/_RichText.scss index e35f4d60f4..0847aa7c9b 100644 --- a/res/css/views/elements/_RichText.scss +++ b/res/css/views/elements/_RichText.scss @@ -79,6 +79,11 @@ .mx_Markdown_ITALIC { font-style: italic; + + // compensate for Nunito italics being terrible + // https://github.com/google/fonts/issues/1726 + transform: skewX(-14deg); + display: inline-block; } .mx_Markdown_CODE { diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss index 6b22c4fe66..7fb6812c79 100644 --- a/res/css/views/rooms/_EventTile.scss +++ b/res/css/views/rooms/_EventTile.scss @@ -453,6 +453,13 @@ limitations under the License. display: inline ! important; } +// compensate for Nunito italics being terrible +// https://github.com/google/fonts/issues/1726 +.mx_EventTile_content .markdown-body em { + transform: skewX(-14deg); + display: inline-block; +} + /* end of overrides */ .mx_MatrixChat_useCompactLayout { From 4da4e0c37afb91cda644a75a8de89deebb292f8c Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 16 Jan 2019 13:57:18 +0000 Subject: [PATCH 0134/1528] Iminimal lint-fixes to make develop CI build --- .../views/dialogs/keybackup/NewRecoveryMethodDialog.js | 2 +- src/autocomplete/CommunityProvider.js | 2 +- src/components/structures/GroupView.js | 2 +- .../views/context_menus/GroupInviteTileContextMenu.js | 2 +- src/components/views/context_menus/StatusMessageContextMenu.js | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/async-components/views/dialogs/keybackup/NewRecoveryMethodDialog.js b/src/async-components/views/dialogs/keybackup/NewRecoveryMethodDialog.js index e88e0444bc..194842ffa5 100644 --- a/src/async-components/views/dialogs/keybackup/NewRecoveryMethodDialog.js +++ b/src/async-components/views/dialogs/keybackup/NewRecoveryMethodDialog.js @@ -32,7 +32,7 @@ export default class NewRecoveryMethodDialog extends React.PureComponent { dis.dispatch({ action: 'view_user_settings' }); } - onSetupClick = async() => { + onSetupClick = async () => { // TODO: Should change to a restore key backup flow that checks the // recovery passphrase while at the same time also cross-signing the // device as well in a single flow. Since we don't have that yet, we'll diff --git a/src/autocomplete/CommunityProvider.js b/src/autocomplete/CommunityProvider.js index b85c09b320..d164fab46a 100644 --- a/src/autocomplete/CommunityProvider.js +++ b/src/autocomplete/CommunityProvider.js @@ -61,7 +61,7 @@ export default class CommunityProvider extends AutocompleteProvider { if (command) { const joinedGroups = cli.getGroups().filter(({myMembership}) => myMembership === 'join'); - const groups = (await Promise.all(joinedGroups.map(async({groupId}) => { + const groups = (await Promise.all(joinedGroups.map(async ({groupId}) => { try { return FlairStore.getGroupProfileCached(cli, groupId); } catch (e) { // if FlairStore failed, fall back to just groupId diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js index 56e6575793..47969ce81b 100644 --- a/src/components/structures/GroupView.js +++ b/src/components/structures/GroupView.js @@ -778,7 +778,7 @@ export default React.createClass({ ), button: _t("Leave"), danger: this.state.isUserPrivileged, - onFinished: async(confirmed) => { + onFinished: async (confirmed) => { if (!confirmed) return; this.setState({membershipBusy: true}); diff --git a/src/components/views/context_menus/GroupInviteTileContextMenu.js b/src/components/views/context_menus/GroupInviteTileContextMenu.js index 2dd611843a..e30acca16d 100644 --- a/src/components/views/context_menus/GroupInviteTileContextMenu.js +++ b/src/components/views/context_menus/GroupInviteTileContextMenu.js @@ -48,7 +48,7 @@ export default class GroupInviteTileContextMenu extends React.Component { Modal.createTrackedDialog('Reject community invite', '', QuestionDialog, { title: _t('Reject invitation'), description: _t('Are you sure you want to reject the invitation?'), - onFinished: async(shouldLeave) => { + onFinished: async (shouldLeave) => { if (!shouldLeave) return; // FIXME: controller shouldn't be loading a view :( diff --git a/src/components/views/context_menus/StatusMessageContextMenu.js b/src/components/views/context_menus/StatusMessageContextMenu.js index f07220db44..d062fc2a3e 100644 --- a/src/components/views/context_menus/StatusMessageContextMenu.js +++ b/src/components/views/context_menus/StatusMessageContextMenu.js @@ -35,7 +35,7 @@ export default class StatusMessageContextMenu extends React.Component { }; } - _onClearClick = async(e) => { + _onClearClick = async (e) => { await MatrixClientPeg.get()._unstable_setStatusMessage(""); this.setState({message: ""}); }; From 6dcee227a9d3c648b736b71300570336bbd534b8 Mon Sep 17 00:00:00 2001 From: Besnik Bleta Date: Wed, 16 Jan 2019 08:43:13 +0000 Subject: [PATCH 0135/1528] Translated using Weblate (Albanian) Currently translated at 98.9% (1410 of 1425 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/sq/ --- src/i18n/strings/sq.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/sq.json b/src/i18n/strings/sq.json index 9535635b07..b30b072c47 100644 --- a/src/i18n/strings/sq.json +++ b/src/i18n/strings/sq.json @@ -1420,5 +1420,7 @@ "Unable to load commit detail: %(msg)s": "S’arrihet të ngarkohen hollësi depozitimi: %(msg)s", "Set a new status...": "Caktoni një gjendje të re…", "Clear status": "Pastroji gjendjen", - "To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "Që të shihni historik mesazhesh të sigurta dhe të garantoni se mund t’i shihni mesazhet e reja në pajisje të ardhshme, ujdisni Rimarrje Mesazhesh të Sigurt." + "To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "Që të shihni historik mesazhesh të sigurta dhe të garantoni se mund t’i shihni mesazhet e reja në pajisje të ardhshme, ujdisni Rimarrje Mesazhesh të Sigurt.", + "Unrecognised address": "Adresë jo e pranuar", + "User %(user_id)s may or may not exist": "Përdoruesi %(user_id)s mund të ekzistojë ose jo" } From 7551f3102ab075e367e287183a4333e38f598a7c Mon Sep 17 00:00:00 2001 From: Moo Date: Tue, 15 Jan 2019 22:41:11 +0000 Subject: [PATCH 0136/1528] Translated using Weblate (Lithuanian) Currently translated at 69.4% (990 of 1425 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/lt/ --- src/i18n/strings/lt.json | 83 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/lt.json b/src/i18n/strings/lt.json index 39f6adda76..f60ac73069 100644 --- a/src/i18n/strings/lt.json +++ b/src/i18n/strings/lt.json @@ -910,5 +910,86 @@ "Names and surnames by themselves are easy to guess": "Pačius vardus ar pavardes yra lengva atspėti", "Common names and surnames are easy to guess": "Dažnai naudojamus vardus ar pavardes yra lengva atspėti", "Straight rows of keys are easy to guess": "Klavišų eilę yra lengva atspėti", - "Short keyboard patterns are easy to guess": "Trumpus klaviatūros šablonus yra lengva atspėti" + "Short keyboard patterns are easy to guess": "Trumpus klaviatūros šablonus yra lengva atspėti", + "Avoid repeated words and characters": "Venkite pasikartojančių žodžių ir simbolių", + "Use a few words, avoid common phrases": "Naudokite kelis žodžius, venkite dažnai naudojamų frazių", + "No need for symbols, digits, or uppercase letters": "Nereikia simbolių, skaitmenų ar didžiųjų raidžių", + "Encrypted messages in group chats": "Šifruotos žinutės grupės pokalbiuose", + "Delete Backup": "Ištrinti atsarginę kopiją", + "Delete backup": "Ištrinti atsarginę kopiją", + "Backup version: ": "Atsarginės kopijos versija: ", + "Algorithm: ": "Algoritmas: ", + "Restore backup": "Atkurti atsarginę kopiją", + "No backup is present": "Nėra jokios atsarginės kopijos", + "Don't ask again": "Daugiau nebeklausti", + "Set up": "Nustatyti", + "Publish this room to the public in %(domain)s's room directory?": "Paskelbti šį kambarį į viešąjį %(domain)s kambarių katalogą?", + "Start authentication": "Pradėti tapatybės nustatymą", + "Failed to load group members": "Nepavyko įkelti grupės dalyvių", + "Integrations Error": "Integracijų klaida", + "Manage Integrations": "Tvarkyti integracijas", + "Matrix Room ID": "Matrix kambario ID", + "That doesn't look like a valid email address": "Tai nepanašu į teisingą el. pašto adresą", + "Preparing to send logs": "Ruošiamasi išsiųsti žurnalus", + "Notes:": "Pastabos:", + "Incompatible Database": "Nesuderinama duomenų bazė", + "Deactivate Account": "Pasyvinti paskyrą", + "I verify that the keys match": "Aš patvirtinu, kad raktai sutampa", + "Incompatible local cache": "Nesuderinamas vietinis podėlis", + "Updating Riot": "Atnaujinama Riot", + "This doesn't appear to be a valid email address": "Tai nepanašu į teisingą el. pašto adresą", + "Unable to add email address": "Nepavyko pridėti el. pašto adreso", + "Unable to verify email address.": "Nepavyko patvirtinti el. pašto adreso.", + "This will allow you to reset your password and receive notifications.": "Tai jums leis atstatyti savo slaptažodį ir gauti pranešimus.", + "Skip": "Praleisti", + "Username not available": "Naudotojo vardas neprieinamas", + "Username invalid: %(errMessage)s": "Neteisingas naudotojo vardas: %(errMessage)s", + "An error occurred: %(error_string)s": "Įvyko klaida: %(error_string)s", + "Checking...": "Tikrinama...", + "Username available": "Naudotojo vardas yra prieinamas", + "To get started, please pick a username!": "Norėdami pradėti, pasirinkite naudotojo vardą!", + "If you already have a Matrix account you can log in instead.": "Jeigu jau turite Matrix paskyrą, tuomet vietoj to, galite prisijungti.", + "Room contains unknown devices": "Kambaryje yra nežinomų įrenginių", + "\"%(RoomName)s\" contains devices that you haven't seen before.": "Kambaryje \"%(RoomName)s\" yra jums anksčiau nematytų įrenginių.", + "Unknown devices": "Nežinomi įrenginiai", + "Unable to restore backup": "Nepavyko atkurti atsarginės kopijos", + "No backup found!": "Nerasta jokios atsarginės kopijos!", + "Backup Restored": "Atsarginė kopija atkurta", + "Failed to decrypt %(failedCount)s sessions!": "Nepavyko iššifruoti %(failedCount)s seansų!", + "Next": "Kitas", + "Private Chat": "Privatus pokalbis", + "Public Chat": "Viešas pokalbis", + "Topic": "Tema", + "There are no visible files in this room": "Šiame kambaryje nėra matomų failų", + "Add a Room": "Pridėti kambarį", + "Add a User": "Pridėti naudotoją", + "Long Description (HTML)": "Ilgasis aprašas (HTML)", + "Description": "Aprašas", + "Community %(groupId)s not found": "Bendruomenė %(groupId)s nerasta", + "Failed to load %(groupId)s": "Nepavyko įkelti%(groupId)s", + "You are currently using Riot anonymously as a guest.": "Šiuo metu naudojate Riot anonimiškai, kaip svečias.", + "Signed Out": "Atsijungta", + "For security, this session has been signed out. Please sign in again.": "Saugumo sumetimais, šis seansas buvo atjungtas. Prisijunkite dar kartą.", + "Your Communities": "Jūsų bendruomenės", + "Create a new community": "Sukurti naują bendruomenę", + "You have no visible notifications": "Jūs neturite matomų pranešimų", + "%(count)s Notifications|one": "%(count)s pranešimas", + "Message not sent due to unknown devices being present": "Žinutė neišsiųsta dėl to, kad yra nežinomų įrenginių", + "File is too big. Maximum file size is %(fileSize)s": "Failas yra per didelis. Didžiausias failo dydis yra %(fileSize)s", + "Submit Debug Logs": "Pateikti derinimo žurnalus", + "Failed to perform homeserver discovery": "Nepavyko atlikti namų serverio aptikimo", + "Unknown failure discovering homeserver": "Nežinoma nesėkmė aptinkant namų serverį", + "Error: Problem communicating with the given homeserver.": "Klaida: Problemos susisiekiant su nurodytu namų serveriu.", + "This server does not support authentication with a phone number.": "Šis serveris nepalaiko tapatybės nustatymo telefono numeriu.", + "An email address is required to register on this homeserver.": "Norint užsiregistruoti šiame namų serveryje, reikalingas el. pašto adresas.", + "A phone number is required to register on this homeserver.": "Norint užsiregistruoti šiame namų serveryje, reikalingas telefono numeris.", + "Great! This passphrase looks strong enough.": "Puiku! Ši slaptafrazė atrodo pakankamai stipri.", + "Your Recovery Key": "Jūsų atkūrimo raktas", + "Copy to clipboard": "Kopijuoti į iškarpinę", + "Download": "Atsisiųsti", + "I've made a copy": "Aš pasidariau kopiją", + "Got it": "Supratau", + "Backup created": "Atsarginė kopija sukurta", + "Recovery Key": "Atkūrimo raktas", + "Retry": "Bandyti dar kartą" } From 11f1b71cc69829bff006348bfecffa93f369a4c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20V=C3=A1gner?= Date: Wed, 16 Jan 2019 12:02:38 +0000 Subject: [PATCH 0137/1528] Translated using Weblate (Slovak) Currently translated at 95.2% (1357 of 1425 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/sk/ --- src/i18n/strings/sk.json | 106 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 102 insertions(+), 4 deletions(-) diff --git a/src/i18n/strings/sk.json b/src/i18n/strings/sk.json index 6799458320..ef3392917d 100644 --- a/src/i18n/strings/sk.json +++ b/src/i18n/strings/sk.json @@ -387,7 +387,7 @@ "To send messages, you must be a": "Aby ste mohli posielať správy, musíte byť", "To invite users into the room, you must be a": "Aby ste mohli pozývať používateľov do miestnosti, musíte byť", "To configure the room, you must be a": "Aby ste mohli nastavovať miestnosť, musíte byť", - "To kick users, you must be a": "Aby ste mohli vykazovať používateľov, musíte byť", + "To kick users, you must be a": "Aby ste mohli vykázať používateľov, musíte byť", "To ban users, you must be a": "Aby ste používateľom mohli zakazovať vstup, musíte byť", "To remove other users' messages, you must be a": "Aby ste mohli odstraňovať správy, ktoré poslali iní používatelia, musíte byť", "To send events of type , you must be a": "Aby ste mohli posielať udalosti typu , musíte byť", @@ -1184,14 +1184,14 @@ "Encrypting": "Šifrovanie", "Encrypted, not sent": "Zašifrované, ale neodoslané", "Share Link to User": "Zdieľať odkaz na používateľa", - "Share room": "Zdieľaj miestnosť", + "Share room": "Zdieľať miestnosť", "Share Room": "Zdieľať miestnosť", "Link to most recent message": "Odkaz na najnovšiu správu", "Share User": "Zdieľať používateľa", "Share Community": "Zdieľať komunitu", "Link to selected message": "Odkaz na vybratú správu", "COPY": "Kopírovať", - "Share Message": "Zdieľaj správu", + "Share Message": "Zdieľať správu", "No Audio Outputs detected": "Neboli rozpoznané žiadne zvukové výstupy", "Audio Output": "Výstup zvuku", "Try the app first": "Vyskúšať si aplikáciu", @@ -1278,5 +1278,103 @@ "Legal": "Právne", "Unable to query for supported registration methods": "Nie je možné vyžiadať podporované metódy registrácie", "An email address is required to register on this homeserver.": "Na registráciu na tomto domovskom servery je vyžadovaná emailová adresa.", - "A phone number is required to register on this homeserver.": "Na registráciu na tomto domovskom servery je vyžadované telefónne číslo." + "A phone number is required to register on this homeserver.": "Na registráciu na tomto domovskom servery je vyžadované telefónne číslo.", + "Unable to load! Check your network connectivity and try again.": "Nie je možné načítať! Skontrolujte prístup na internet a skúste neskôr.", + "Failed to invite users to the room:": "Používateľov sa nepodarilo pozvať do miestnosti:", + "Unrecognised address": "Nerozpoznaná adresa", + "You do not have permission to invite people to this room.": "Nemáte pridelené oprávnenie pozývať ľudí do tejto miestnosti.", + "User %(user_id)s does not exist": "Používateľ %(user_id)s neexistuje", + "User %(user_id)s may or may not exist": "Nie je možné určiť, či používateľ %(user_id)s existuje", + "Unknown server error": "Neznáma chyba servera", + "Use a few words, avoid common phrases": "Použite niekoľko slov, vyhýbajte sa bežným frázam", + "No need for symbols, digits, or uppercase letters": "Nemusí obsahovať len veľké písmená, číslice alebo interpunkčné znaky", + "Use a longer keyboard pattern with more turns": "Zadajte dlhšiu frázu so znakmi rozmiestnenými po celej klávesnici", + "Avoid repeated words and characters": "Neopakujte krátke slová, znaky alebo ich skupiny", + "Avoid sequences": "Nestláčajte klávesy umiestnené v poradí vedľa seba", + "Avoid recent years": "Nepíšte čísla podľa aktuálneho alebo posledných rokov", + "Avoid years that are associated with you": "Nepíšte roky zo života", + "Avoid dates and years that are associated with you": "Nepíšte dôležité dátumy zo života", + "Capitalization doesn't help very much": "Veľkosť písmen nie je veľmi rozhodujúca", + "All-uppercase is almost as easy to guess as all-lowercase": "Všetky veľké písmená je možné uhádnuť rovnako ľahko ako všetky malé písmená", + "Reversed words aren't much harder to guess": "Slová napísané odzadu tiež nie je omnoho náročnejšie uhádnuť", + "Predictable substitutions like '@' instead of 'a' don't help very much": "Predvídateľné nahrádzanie znakov ako „@“ namiesto „a“ veľmi nepomáha", + "Add another word or two. Uncommon words are better.": "Pridajte ešte jedno dve slová. Lepšie sú tie, nie bežne používané.", + "Repeats like \"aaa\" are easy to guess": "Opakovanie znakov ako „aaa“ je možné veľmi ľahko uhádnuť", + "Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Opakovanie skupín znakov napríklad „abcabcabc“ je len o trochu zložitejšie uhádnuť než „abc“", + "Sequences like abc or 6543 are easy to guess": "Sekvencie znakov ako sú „abc“ alebo „6543“ je veľmi ľahko možné uhádnuť", + "Recent years are easy to guess": "Nedávne roky je veľmi ľahké uhádnuť", + "Dates are often easy to guess": "Dátumy je často možné ľahko uhádnuť", + "This is a top-10 common password": "Toto heslo je z 10 najpoužívanejších", + "This is a top-100 common password": "Toto heslo je zo 100 najpoužívanejších", + "This is a very common password": "Toto je veľmi často používané heslo", + "This is similar to a commonly used password": "Toto je veľmi podobné často používanému heslu", + "A word by itself is easy to guess": "Samostatné slovo je ľahké uhádnuť", + "Names and surnames by themselves are easy to guess": "Mená a priezviská je samé o sebe ľahké uhádnuť", + "Common names and surnames are easy to guess": "Bežné mená a priezviská je ľahké uhádnuť", + "Straight rows of keys are easy to guess": "Po sebe nasledujúce rady klávesov je ľahké uhádnuť", + "Short keyboard patterns are easy to guess": "Krátke vzory z klávesov je ľahké uhádnuť", + "There was an error joining the room": "Pri vstupovaní do miestnosti sa vyskytla chyba", + "Custom user status messages": "Vlastné správy o stave používateľa", + "Backup of encryption keys to server": "Záloha šifrovacích kľúčov na server", + "Show a reminder to enable Secure Message Recovery in encrypted rooms": "V šifrovaných konverzáciách zobrazovať upozornenie na možnosť aktivovať Bezpečné obnovenie správ", + "Pin rooms I'm mentioned in to the top of the room list": "Pripnúť miestnosti, kde som spomenutý na vrch zoznamu", + "Pin unread rooms to the top of the room list": "Pripnúť miestnosti s neprečítanými správami na vrch zoznamu", + "Always invite users which may not exist": "Vždy pozývať používateľov, ktorí nemusia existovať", + "Show developer tools": "Zobraziť nástroje pre vývojárov", + "Messages containing @room": "Správy obsahujúce @room", + "Encrypted messages in one-to-one chats": "Šifrované správy v priamych konverzáciách", + "Encrypted messages in group chats": "Šifrované správy v skupinových konverzáciách", + "Delete Backup": "Vymazať zálohu", + "Delete your backed up encryption keys from the server? You will no longer be able to use your recovery key to read encrypted message history": "Chcete naozaj vymazať šifrované kľúče zálohované na servery? Nebudete viac môcť čítať históriu šifrovaných konverzácií pomocou kľúča určeného na obnovu", + "Delete backup": "Vymazať zálohu", + "Unable to load key backup status": "Nie je možné načítať stav zálohy kľúčov", + "This device is uploading keys to this backup": "Z tohoto zariadenia nahrávate kľúče do tejto zálohy", + "This device is not uploading keys to this backup": "Z tohoto zariadenia nenahrávate kľúče do tejto zálohy", + "Backup has a valid signature from this device": "Záloha je podpísaná platným kľúčom z tohoto zariadenia", + "Backup has a valid signature from verified device ": "Záloha je podpísaná platným kľúčom z tohoto zariadenia\nZáloha je podpísaná správnym kľúčom z overeného zariadenia ", + "Backup has a valid signature from unverified device ": "Záloha je podpísaná platným kľúčom z neovereného zariadenia ", + "Backup has an invalid signature from verified device ": "Záloha je podpísaná neplatným kľúčom z overeného zariadenia ", + "Backup has an invalid signature from unverified device ": "Záloha je podpísaná neplatným kľúčom z neovereného zariadenia ", + "Backup is not signed by any of your devices": "Záloha nie je podpísaná žiadnym z vašich zariadení", + "Backup version: ": "Verzia zálohy: ", + "Algorithm: ": "Algoritmus: ", + "Restore backup": "Obnoviť zo zálohy", + "No backup is present": "Nemáte žiadnu zálohu", + "Start a new backup": "Vytvoriť zálohu", + "The following files cannot be uploaded:": "Nie je možné nahrať nasledujúce súbory:", + "Joining room...": "Vstup do miestnosti...", + "To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "Aby ste mohli čítať históriu zašifrovaných konverzácií a čítať šifrované správy aj na vašich nových zariadeniach v budúcnosti, nastavte si Bezpečnú obnovu správ.", + "If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.": "Keď sa odhlásite alebo použijete iné zariadenie, stratíte prístup k histórii šifrovaných konverzácií. Predísť tomu môžete, ak si nastavíte Bezpečnú obnovu správ.", + "Secure Message Recovery": "Bezpečná obnova správ", + "Don't ask again": "Viac sa nepýtať", + "Set up": "Nastaviť", + "Open Devtools": "Otvoriť nástroje pre vývojárov", + "Add some now": "Pridajte si nejaké teraz", + "Please review and accept all of the homeserver's policies": "Prosím, prečítajte si a odsúhlaste všetky podmienky tohoto domovského servera", + "Please review and accept the policies of this homeserver:": "Prosím, prečítajte si a odsúhlaste podmienky používania tohoto domovského servera:", + "Failed to load group members": "Nepodarilo sa načítať zoznam členov skupiny", + "That doesn't look like a valid email address": "Toto nevyzerá byť platná emailová adresa", + "The following users may not exist": "Nasledujúci používatelia pravdepodobne neexistujú", + "The following users may not exist - would you like to invite them anyways?": "Nie je možné určiť, či nasledujúci používatelia skutočne existujú - chcete ich napriek tomu pozvať?", + "Invite anyways and never warn me again": "Napriek tomu pozvať a v budúcnosti ma viac neupozorňovať", + "Invite anyways": "Napriek tomu pozvať", + "Unable to load commit detail: %(msg)s": "Nie je možné načítať podrobnosti commit: %(msg)s", + "To avoid losing your chat history, you must export your room keys before logging out. You will need to go back to the newer version of Riot to do this": "Aby ste po odhlásení neprišli o možnosť čítať históriu šifrovaných konverzácií, mali by ste si ešte pred odhlásením exportovať šifrovacie kľúče miestností. Prosím vráťte sa k novšej verzii Riot a exportujte si kľúče", + "You've previously used a newer version of Riot on %(host)s. To use this version again with end to end encryption, you will need to sign out and back in again. ": "Už ste použili novšiu verziu Riot na adrese %(host)s. Ak chcete znovu používať túto verziu aj s E2E šifrovaním, musíte sa odhlásiť a potom zas znovu prihlásiť. ", + "Incompatible Database": "Nekompatibilná databáza", + "Continue With Encryption Disabled": "Pokračovať s vypnutým šifrovaním", + "You've previously used Riot on %(host)s with lazy loading of members enabled. In this version lazy loading is disabled. As the local cache is not compatible between these two settings, Riot needs to resync your account.": "Použili ste aj Riot na adrese %(host)s so zapnutou voľbou Načítanie zoznamu členov pri prvom zobrazení. V tejto verzii je Načítanie zoznamu členov pri prvom zobrazení vypnuté. Keď že lokálna vyrovnávacia pamäť nie je vzájomne kompatibilná s takýmito nastaveniami, Riot potrebuje znovu synchronizovať údaje z vašeho účtu.", + "If the other version of Riot is still open in another tab, please close it as using Riot on the same host with both lazy loading enabled and disabled simultaneously will cause issues.": "Ak máte Riot s iným nastavením otvorený na ďalšej karte, prosím zatvorte ju, pretože použitie Riot s rôznym nastavením na jednom zariadení vám spôsobí len problémy.", + "Incompatible local cache": "Nekompatibilná lokálna vyrovnávacia pamäť", + "Clear cache and resync": "Vymazať vyrovnávaciu pamäť a synchronizovať znovu", + "Only use lower case letters, numbers and '=_-./'": "Len malé písmená, číslice a znaky „=_-./“", + "Checking...": "Kontrola…", + "Unable to load backup status": "Nie je možné načítať stav zálohy", + "Unable to restore backup": "Nie je možné obnoviť zo zálohy", + "No backup found!": "Nebola nájdená žiadna záloha!", + "Backup Restored": "Obnova zo zálohy je hotová", + "Failed to decrypt %(failedCount)s sessions!": "Nepodarilo sa dešifrovať %(failedCount)s relácií!", + "Restored %(sessionCount)s session keys": "Obnovených %(sessionCount)s kľúčov relácií", + "Enter Recovery Passphrase": "Zadajte heslo bezpečného obnovenia", + "Access your secure message history and set up secure messaging by entering your recovery passphrase.": "Vložením vlastného hesla pre bezpečné obnovenie správ, si nastavíte Bezpečnú obnovu správ, aby ste mali neustále prístup k zašifrovaným konverzáciám." } From 55889d5491634a25abe8e02aa7b1f78367464ca3 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 16 Jan 2019 15:07:30 +0000 Subject: [PATCH 0138/1528] Change wording of 'invite anyway' setting https://github.com/vector-im/riot-web/issues/7922 --- src/components/structures/UserSettings.js | 2 +- src/components/views/dialogs/AskInviteAnywayDialog.js | 8 ++++---- src/i18n/strings/en_EN.json | 10 ++++++---- src/settings/Settings.js | 6 +++--- src/utils/MultiInviter.js | 4 ++-- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index 37f60c47bf..d476060e0b 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -86,7 +86,7 @@ const SIMPLE_SETTINGS = [ { id: "pinMentionedRooms" }, { id: "pinUnreadRooms" }, { id: "showDeveloperTools" }, - { id: "alwaysInviteUnknownUsers" }, + { id: "promptBeforeInviteUnknownUsers" }, ]; // These settings must be defined in SettingsStore diff --git a/src/components/views/dialogs/AskInviteAnywayDialog.js b/src/components/views/dialogs/AskInviteAnywayDialog.js index 5c61c3a694..d4b073eb01 100644 --- a/src/components/views/dialogs/AskInviteAnywayDialog.js +++ b/src/components/views/dialogs/AskInviteAnywayDialog.js @@ -35,7 +35,7 @@ export default React.createClass({ }, _onInviteNeverWarnClicked: function() { - SettingsStore.setValue("alwaysInviteUnknownUsers", null, SettingLevel.ACCOUNT, true); + SettingsStore.setValue("promptBeforeInviteUnknownUsers", null, SettingLevel.ACCOUNT, false); this.props.onInviteAnyways(); this.props.onFinished(true); }, @@ -58,7 +58,7 @@ export default React.createClass({ contentId='mx_Dialog_content' >
    -

    {_t("The following users may not exist - would you like to invite them anyways?")}

    +

    {_t("Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?")}

      { errorList }
    @@ -69,10 +69,10 @@ export default React.createClass({ { _t('Close') }
    diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 4f8674db2f..c6701156cb 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -114,6 +114,8 @@ "Failed to invite": "Failed to invite", "Failed to invite users to the room:": "Failed to invite users to the room:", "Failed to invite the following users to the %(roomName)s room:": "Failed to invite the following users to the %(roomName)s room:", + "Waiting for %(userId)s to accept...": "Waiting for %(userId)s to accept...", + "Waiting for %(userId)s to confirm...": "Waiting for %(userId)s to confirm...", "You need to be logged in.": "You need to be logged in.", "You need to be able to invite users to do that.": "You need to be able to invite users to do that.", "Unable to create widget.": "Unable to create widget.", @@ -293,7 +295,7 @@ "Pin unread rooms to the top of the room list": "Pin unread rooms to the top of the room list", "Enable widget screenshots on supported widgets": "Enable widget screenshots on supported widgets", "Show empty room list headings": "Show empty room list headings", - "Always invite users which may not exist": "Always invite users which may not exist", + "Prompt before sending invites to potentially invalid matrix IDs": "Prompt before sending invites to potentially invalid matrix IDs", "Show developer tools": "Show developer tools", "Collecting app version information": "Collecting app version information", "Collecting logs": "Collecting logs", @@ -885,9 +887,9 @@ "You have entered an invalid address.": "You have entered an invalid address.", "Try using one of the following valid address types: %(validTypesList)s.": "Try using one of the following valid address types: %(validTypesList)s.", "The following users may not exist": "The following users may not exist", - "The following users may not exist - would you like to invite them anyways?": "The following users may not exist - would you like to invite them anyways?", - "Invite anyways and never warn me again": "Invite anyways and never warn me again", - "Invite anyways": "Invite anyways", + "Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?", + "Invite anyway and never warn me again": "Invite anyway and never warn me again", + "Invite anyway": "Invite anyway", "Preparing to send logs": "Preparing to send logs", "Logs sent": "Logs sent", "Thank you!": "Thank you!", diff --git a/src/settings/Settings.js b/src/settings/Settings.js index a007f78c1f..86377f3bc2 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -317,10 +317,10 @@ export const SETTINGS = { displayName: _td('Show empty room list headings'), default: true, }, - "alwaysInviteUnknownUsers": { + "promptBeforeInviteUnknownUsers": { supportedLevels: LEVELS_ACCOUNT_SETTINGS, - displayName: _td('Always invite users which may not exist'), - default: false, + displayName: _td('Prompt before sending invites to potentially invalid matrix IDs'), + default: true, }, "showDeveloperTools": { supportedLevels: LEVELS_ACCOUNT_SETTINGS, diff --git a/src/utils/MultiInviter.js b/src/utils/MultiInviter.js index b5f4f960a9..4278ee1c90 100644 --- a/src/utils/MultiInviter.js +++ b/src/utils/MultiInviter.js @@ -101,7 +101,7 @@ export default class MultiInviter { if (addrType === 'email') { return MatrixClientPeg.get().inviteByEmail(roomId, addr); } else if (addrType === 'mx-user-id') { - if (!ignoreProfile && !SettingsStore.getValue("alwaysInviteUnknownUsers", this.roomId)) { + if (!ignoreProfile && SettingsStore.getValue("promptBeforeInviteUnknownUsers", this.roomId)) { try { const profile = await MatrixClientPeg.get().getProfileInfo(addr); if (!profile) { @@ -204,7 +204,7 @@ export default class MultiInviter { Promise.all(promises).then(() => this.deferred.resolve(this.completionStates)); }; - if (SettingsStore.getValue("alwaysInviteUnknownUsers", this.roomId)) { + if (!SettingsStore.getValue("promptBeforeInviteUnknownUsers", this.roomId)) { inviteUnknowns(); return; } From 859f2a86461d13aa2d142b23a013136d165656f1 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Tue, 15 Jan 2019 17:04:26 -0600 Subject: [PATCH 0139/1528] Show spinner while waiting on status message to commit It can take some time to actually set the status message and see it play back as a committed event. This adds a spinner for immediate feedback so it's clear that something is happening. Fixes https://github.com/vector-im/riot-web/issues/8135. --- .../_StatusMessageContextMenu.scss | 9 +++++++ .../context_menus/StatusMessageContextMenu.js | 26 ++++++++++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/res/css/views/context_menus/_StatusMessageContextMenu.scss b/res/css/views/context_menus/_StatusMessageContextMenu.scss index 8b25f3a122..972f608caf 100644 --- a/res/css/views/context_menus/_StatusMessageContextMenu.scss +++ b/res/css/views/context_menus/_StatusMessageContextMenu.scss @@ -36,6 +36,10 @@ input.mx_StatusMessageContextMenu_message { color: $memberstatus-placeholder-color; } +.mx_StatusMessageContextMenu_actionContainer { + display: flex; +} + .mx_StatusMessageContextMenu_submit, .mx_StatusMessageContextMenu_clear { @mixin mx_DialogButton; @@ -43,6 +47,7 @@ input.mx_StatusMessageContextMenu_message { font-size: 12px; padding: 6px 1em; border: 1px solid transparent; + margin-right: 10px; } .mx_StatusMessageContextMenu_submit[disabled] { @@ -54,3 +59,7 @@ input.mx_StatusMessageContextMenu_message { background-color: transparent; border: 1px solid $warning-color; } + +.mx_StatusMessageContextMenu_actionContainer .mx_Spinner { + justify-content: start; +} diff --git a/src/components/views/context_menus/StatusMessageContextMenu.js b/src/components/views/context_menus/StatusMessageContextMenu.js index 9916f5d347..5a275c59f0 100644 --- a/src/components/views/context_menus/StatusMessageContextMenu.js +++ b/src/components/views/context_menus/StatusMessageContextMenu.js @@ -18,12 +18,15 @@ import React from 'react'; import PropTypes from 'prop-types'; import { _t } from '../../../languageHandler'; import MatrixClientPeg from '../../../MatrixClientPeg'; +import sdk from '../../../index'; import AccessibleButton from '../elements/AccessibleButton'; export default class StatusMessageContextMenu extends React.Component { static propTypes = { // js-sdk User object. Not required because it might not exist. user: PropTypes.object, + // True when waiting for status change to complete. + waiting: false, }; constructor(props, context) { @@ -61,16 +64,23 @@ export default class StatusMessageContextMenu extends React.Component { // The `User` object has observed a status message change. this.setState({ message: this.comittedStatusMessage, + waiting: false, }); }; - _onClearClick = async (e) => { - await MatrixClientPeg.get()._unstable_setStatusMessage(""); + _onClearClick = (e) => { + MatrixClientPeg.get()._unstable_setStatusMessage(""); + this.setState({ + waiting: true, + }); }; _onSubmit = (e) => { e.preventDefault(); MatrixClientPeg.get()._unstable_setStatusMessage(this.state.message); + this.setState({ + waiting: true, + }); }; _onStatusChange = (e) => { @@ -81,6 +91,8 @@ export default class StatusMessageContextMenu extends React.Component { }; render() { + const Spinner = sdk.getComponent('views.elements.Spinner'); + let actionButton; if (this.comittedStatusMessage) { if (this.state.message === this.comittedStatusMessage) { @@ -104,6 +116,11 @@ export default class StatusMessageContextMenu extends React.Component {
    ; } + let spinner = null; + if (this.state.waiting) { + spinner = ; + } + const form =
    @@ -112,7 +129,10 @@ export default class StatusMessageContextMenu extends React.Component { autoFocus={true} maxLength="60" value={this.state.message} onChange={this._onStatusChange} /> - {actionButton} +
    + {actionButton} + {spinner} +
    ; return
    From 2e8368ce0ba49db82a4103ad77e758a29bb637bd Mon Sep 17 00:00:00 2001 From: Paulo Miranda Date: Wed, 16 Jan 2019 16:32:13 +0000 Subject: [PATCH 0140/1528] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (1427 of 1427 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/pt_BR/ --- src/i18n/strings/pt_BR.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/pt_BR.json b/src/i18n/strings/pt_BR.json index 38d9d6013c..8a40801f42 100644 --- a/src/i18n/strings/pt_BR.json +++ b/src/i18n/strings/pt_BR.json @@ -1437,5 +1437,11 @@ "The following users may not exist": "Os seguintes usuários podem não existir", "The following users may not exist - would you like to invite them anyways?": "Os seguintes usuários podem não existir - você gostaria de convidá-los de qualquer maneira?", "Invite anyways and never warn me again": "Convide mesmo assim e nunca mais me alerte", - "Invite anyways": "Convidar mesmo assim" + "Invite anyways": "Convidar mesmo assim", + "Waiting for %(userId)s to accept...": "Aguardando que %(userId)s aceite...", + "Waiting for %(userId)s to confirm...": "Aguardando que %(userId)s confirme...", + "Prompt before sending invites to potentially invalid matrix IDs": "Avisar antes de enviar convites para IDs da Matrix potencialmente inválidas", + "Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "Não é possível encontrar perfis para os IDs da Matrix listados abaixo - você gostaria de convidá-los mesmo assim?", + "Invite anyway and never warn me again": "Convide mesmo assim e nunca mais me avise", + "Invite anyway": "Convide mesmo assim" } From e199d5384e7488a464603901db3f3e342b7fe551 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20C?= Date: Wed, 16 Jan 2019 19:07:24 +0000 Subject: [PATCH 0141/1528] Translated using Weblate (French) Currently translated at 100.0% (1427 of 1427 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/fr/ --- src/i18n/strings/fr.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json index e8955726eb..73a12323e4 100644 --- a/src/i18n/strings/fr.json +++ b/src/i18n/strings/fr.json @@ -1457,5 +1457,11 @@ "The following users may not exist": "Les utilisateurs suivants pourraient ne pas exister", "The following users may not exist - would you like to invite them anyways?": "Les utilisateurs suivants pourraient ne pas exister. Souhaitez-vous quand même les inviter ?", "Invite anyways and never warn me again": "Les inviter quand même et ne plus m'avertir", - "Invite anyways": "Les inviter quand même" + "Invite anyways": "Les inviter quand même", + "Prompt before sending invites to potentially invalid matrix IDs": "Demander avant d'envoyer des invitations à des identifiants matrix potentiellement non valides", + "Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "Impossible de trouver les profils pour les identifiants Matrix listés ci-dessous. Voulez-vous quand même les inviter ?", + "Invite anyway and never warn me again": "Inviter quand même et ne plus me prévenir", + "Invite anyway": "Inviter quand même", + "Waiting for %(userId)s to accept...": "Attente de l'acceptation de %(userId)s…", + "Waiting for %(userId)s to confirm...": "Attente de la confirmation de %(userId)s…" } From 7d9f84c87300adffacf37d6b4a2422a7cfa27ad0 Mon Sep 17 00:00:00 2001 From: Szimszon Date: Wed, 16 Jan 2019 19:19:36 +0000 Subject: [PATCH 0142/1528] Translated using Weblate (Hungarian) Currently translated at 100.0% (1427 of 1427 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/hu/ --- src/i18n/strings/hu.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json index c82206d5d3..3d749a3c5c 100644 --- a/src/i18n/strings/hu.json +++ b/src/i18n/strings/hu.json @@ -1457,5 +1457,11 @@ "The following users may not exist": "Az alábbi felhasználók lehet, hogy nem léteznek", "The following users may not exist - would you like to invite them anyways?": "Az alábbi felhasználók lehet, hogy nem léteznek - mégis meghívod őket?", "Invite anyways and never warn me again": "Mindig meghívom és többet nem kérek figyelmeztetést", - "Invite anyways": "Mindig meghív" + "Invite anyways": "Mindig meghív", + "Waiting for %(userId)s to accept...": "Várakozás %(userId)s felhasználóra, hogy elfogadja...", + "Waiting for %(userId)s to confirm...": "Várakozás %(userId)s felhasználóra, hogy megerősítse...", + "Prompt before sending invites to potentially invalid matrix IDs": "Vélhetően hibás matrix ID-kra való meghívó küldés előtt figyelmeztessen", + "Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "Az alábbi Matrix ID-koz nem sikerül megtalálni a profilokat - így is meghívod őket?", + "Invite anyway and never warn me again": "Mindenképpen meghív és ne figyelmeztess többet", + "Invite anyway": "Mindenképpen meghív" } From 8c30d05eb8eef1361d226dbe2af3f03fa9e6060c Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 17 Jan 2019 10:29:37 +0100 Subject: [PATCH 0143/1528] Revert "Merge pull request #2348 from matrix-org/bwindels/roomgridview-experimental" This reverts commit ece5cb1fcc78589442eb549f234b60254bb8d038, reversing changes made to 64a3d2521c4e29c785e56a38a8f102993da9ad4f. --- res/css/_components.scss | 1 - res/css/structures/_GroupGridView.scss | 130 -------- res/css/structures/_MatrixChat.scss | 3 +- res/css/views/rooms/_MemberList.scss | 4 - res/img/feather-icons/toggle-right-panel.svg | 17 -- res/themes/dark/css/_dark.scss | 4 - res/themes/dharma/css/_dharma.scss | 3 - res/themes/light/css/_base.scss | 4 - src/ActiveRoomObserver.js | 30 +- src/PageTypes.js | 1 - src/UserActivity.js | 1 - src/components/structures/GroupGridView.js | 127 -------- src/components/structures/LoggedInView.js | 13 +- src/components/structures/MainSplit.js | 11 +- src/components/structures/MatrixChat.js | 12 - src/components/structures/RightPanel.js | 2 +- src/components/structures/RoomView.js | 100 +++---- .../views/context_menus/TagTileContextMenu.js | 23 -- .../views/right_panel/HeaderButtons.js | 1 + src/components/views/rooms/MemberInfo.js | 4 +- src/components/views/rooms/MessageComposer.js | 25 +- .../views/rooms/MessageComposerInput.js | 54 ++-- src/components/views/rooms/ReplyPreview.js | 5 +- src/components/views/rooms/RoomHeader.js | 23 +- src/components/views/rooms/RoomTile.js | 7 +- src/dispatcher.js | 36 ++- src/matrix-dispatcher.js | 53 ---- src/settings/Settings.js | 6 - src/stores/OpenRoomsStore.js | 277 ------------------ src/stores/RoomViewStore.js | 52 +++- src/utils/Timer.js | 4 +- 31 files changed, 187 insertions(+), 846 deletions(-) delete mode 100644 res/css/structures/_GroupGridView.scss delete mode 100644 res/img/feather-icons/toggle-right-panel.svg delete mode 100644 src/components/structures/GroupGridView.js delete mode 100644 src/matrix-dispatcher.js delete mode 100644 src/stores/OpenRoomsStore.js diff --git a/res/css/_components.scss b/res/css/_components.scss index 1e2d7ae156..8f6f4d5936 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -5,7 +5,6 @@ @import "./structures/_ContextualMenu.scss"; @import "./structures/_CreateRoom.scss"; @import "./structures/_FilePanel.scss"; -@import "./structures/_GroupGridView.scss"; @import "./structures/_GroupView.scss"; @import "./structures/_HomePage.scss"; @import "./structures/_LeftPanel.scss"; diff --git a/res/css/structures/_GroupGridView.scss b/res/css/structures/_GroupGridView.scss deleted file mode 100644 index 541052175d..0000000000 --- a/res/css/structures/_GroupGridView.scss +++ /dev/null @@ -1,130 +0,0 @@ -/* -Copyright 2017 Vector Creations 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. -*/ - -.mx_GroupGridView { - display: flex; - flex-direction: column; -} - -.mx_GroupGridView_rooms { - display: grid; - grid-template-columns: repeat(3, calc(100% / 3)); - grid-template-rows: repeat(2, calc(100% / 2)); - flex: 1 1 0; - min-width: 0; -} - -.mx_GroupGridView_rightPanel { - display: flex; - flex-direction: column; - - .mx_GroupGridView_tabs { - flex: 0 0 52px; - border-bottom: 1px solid $primary-hairline-color; - display: flex; - align-items: center; - - > div { - justify-content: flex-end; - width: 100%; - margin-right: 10px; - } - } - - .mx_RightPanel { - flex: 1 0 auto !important; - } -} - - -.mx_GroupGridView > .mx_MainSplit { - flex: 1 1 0; - display: flex; -} - -.mx_GroupGridView_emptyTile { - display: block; - margin-top: 100px; - text-align: center; - user-select: none; -} - -.mx_GroupGridView_tile { - border-right: 1px solid $panel-divider-color; - border-bottom: 1px solid $panel-divider-color; -} - -.mx_GroupGridView_activeTile { - position: relative; -} - -.mx_GroupGridView_activeTile:before, -.mx_GroupGridView_activeTile:after { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - content: ""; - pointer-events: none; - z-index: 3500; -} - -.mx_GroupGridView_activeTile:before { - border-radius: 14px; - border: 8px solid $gridview-focus-border-glow-color; - margin: -8px; -} - -.mx_GroupGridView_activeTile:after { - border-radius: 8px; - border: 2px solid $gridview-focus-border-color; - margin: -2px; -} - -.mx_GroupGridView_tile > .mx_RoomView { - height: 100%; -} - -.mx_GroupGridView_rooms > *:nth-child(1) { - grid-column: 1; - grid-row: 1; -} - -.mx_GroupGridView_rooms > *:nth-child(2) { - grid-column: 2; - grid-row: 1; -} - -.mx_GroupGridView_rooms > *:nth-child(3) { - grid-column: 3; - grid-row: 1; -} - -.mx_GroupGridView_rooms > *:nth-child(4) { - grid-column: 1; - grid-row: 2; -} - -.mx_GroupGridView_rooms > *:nth-child(5) { - grid-column: 2; - grid-row: 2; -} - -.mx_GroupGridView_rooms > *:nth-child(6) { - grid-column: 3; - grid-row: 2; -} diff --git a/res/css/structures/_MatrixChat.scss b/res/css/structures/_MatrixChat.scss index 6d8b79ecb2..f2ce7e1d5c 100644 --- a/res/css/structures/_MatrixChat.scss +++ b/res/css/structures/_MatrixChat.scss @@ -81,8 +81,7 @@ limitations under the License. Empirically this stops the MessagePanel's width exploding outwards when gemini is in 'prevented' mode */ - // disabling this for now as it clips the active room rect on the grid view - // overflow-x: auto; + overflow-x: auto; /* To fix https://github.com/vector-im/riot-web/issues/3298 where Safari needed height 100% all the way down to the HomePage. Height does not diff --git a/res/css/views/rooms/_MemberList.scss b/res/css/views/rooms/_MemberList.scss index 567727fb64..6f9491b22f 100644 --- a/res/css/views/rooms/_MemberList.scss +++ b/res/css/views/rooms/_MemberList.scss @@ -53,10 +53,6 @@ limitations under the License. .mx_MemberList_query, .mx_GroupMemberList_query, .mx_GroupRoomList_query { - flex: 0 0 auto; -} - -.mx_MemberList .gm-scrollbar-container { flex: 1 1 0; } diff --git a/res/img/feather-icons/toggle-right-panel.svg b/res/img/feather-icons/toggle-right-panel.svg deleted file mode 100644 index 4cadf89564..0000000000 --- a/res/img/feather-icons/toggle-right-panel.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - Group 2 - Created with Sketch. - - - - - - - - - - - - \ No newline at end of file diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index 257b723ccf..997a74e6aa 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -162,10 +162,6 @@ $lightbox-bg-color: #454545; $lightbox-fg-color: #ffffff; $lightbox-border-color: #ffffff; -/*** GroupGridView ***/ -$gridview-focus-border-glow-color: rgba(134, 193, 165, 0.5); -$gridview-focus-border-color: rgba(134, 193, 165, 1); - $imagebody-giflabel: rgba(1, 1, 1, 0.7); $imagebody-giflabel-border: rgba(1, 1, 1, 0.2); $imagebody-giflabel-color: rgba(0, 0, 0, 1); diff --git a/res/themes/dharma/css/_dharma.scss b/res/themes/dharma/css/_dharma.scss index 73dc0a71e4..c70d7f020a 100644 --- a/res/themes/dharma/css/_dharma.scss +++ b/res/themes/dharma/css/_dharma.scss @@ -184,9 +184,6 @@ $lightbox-bg-color: #454545; $lightbox-fg-color: #ffffff; $lightbox-border-color: #ffffff; -/*** GroupGridView ***/ -$gridview-focus-border-glow-color: rgba(134, 193, 165, 0.5); -$gridview-focus-border-color: rgba(134, 193, 165, 1); // unused? $progressbar-color: #000; diff --git a/res/themes/light/css/_base.scss b/res/themes/light/css/_base.scss index cf539bd1f2..96c179f6f5 100644 --- a/res/themes/light/css/_base.scss +++ b/res/themes/light/css/_base.scss @@ -175,10 +175,6 @@ $lightbox-bg-color: #454545; $lightbox-fg-color: #ffffff; $lightbox-border-color: #ffffff; -/*** GroupGridView ***/ -$gridview-focus-border-glow-color: rgba(134, 193, 165, 0.5); -$gridview-focus-border-color: rgba(134, 193, 165, 1); - $imagebody-giflabel: rgba(0, 0, 0, 0.7); $imagebody-giflabel-border: rgba(0, 0, 0, 0.2); $imagebody-giflabel-color: rgba(255, 255, 255, 1); diff --git a/src/ActiveRoomObserver.js b/src/ActiveRoomObserver.js index c276cccb5d..d6fbb460b5 100644 --- a/src/ActiveRoomObserver.js +++ b/src/ActiveRoomObserver.js @@ -14,10 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -import OpenRoomsStore from './stores/OpenRoomsStore'; +import RoomViewStore from './stores/RoomViewStore'; /** - * Consumes changes from the OpenRoomsStore and notifies specific things + * Consumes changes from the RoomViewStore and notifies specific things * about when the active room changes. Unlike listening for RoomViewStore * changes, you can subscribe to only changes relevant to a particular * room. @@ -28,15 +28,11 @@ import OpenRoomsStore from './stores/OpenRoomsStore'; class ActiveRoomObserver { constructor() { this._listeners = {}; - const roomStore = OpenRoomsStore.getActiveRoomStore(); - this._activeRoomId = roomStore && roomStore.getRoomId(); + + this._activeRoomId = RoomViewStore.getRoomId(); // TODO: We could self-destruct when the last listener goes away, or at least // stop listening. - this._roomStoreToken = OpenRoomsStore.addListener(this._onOpenRoomsStoreUpdate.bind(this)); - } - - getActiveRoomId() { - return this._activeRoomId; + this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate.bind(this)); } addListener(roomId, listener) { @@ -55,23 +51,23 @@ class ActiveRoomObserver { } } - _emit(roomId, newActiveRoomId) { + _emit(roomId) { if (!this._listeners[roomId]) return; for (const l of this._listeners[roomId]) { - l.call(l, newActiveRoomId); + l.call(); } } - _onOpenRoomsStoreUpdate() { - const activeRoomStore = OpenRoomsStore.getActiveRoomStore(); - const newActiveRoomId = activeRoomStore && activeRoomStore.getRoomId(); + _onRoomViewStoreUpdate() { // emit for the old room ID - if (this._activeRoomId) this._emit(this._activeRoomId, newActiveRoomId); + if (this._activeRoomId) this._emit(this._activeRoomId); + // update our cache - this._activeRoomId = newActiveRoomId; + this._activeRoomId = RoomViewStore.getRoomId(); + // and emit for the new one - if (this._activeRoomId) this._emit(this._activeRoomId, this._activeRoomId); + if (this._activeRoomId) this._emit(this._activeRoomId); } } diff --git a/src/PageTypes.js b/src/PageTypes.js index e4e1916c8b..60111723fb 100644 --- a/src/PageTypes.js +++ b/src/PageTypes.js @@ -19,7 +19,6 @@ limitations under the License. export default { HomePage: "home_page", RoomView: "room_view", - GroupGridView: "group_grid_view", UserSettings: "user_settings", RoomDirectory: "room_directory", UserView: "user_view", diff --git a/src/UserActivity.js b/src/UserActivity.js index 145b23e36e..4e3667274c 100644 --- a/src/UserActivity.js +++ b/src/UserActivity.js @@ -44,7 +44,6 @@ class UserActivity { * Can be called multiple times with the same already running timer, which is a NO-OP. * Can be called before the user becomes active, in which case it is only started * later on when the user does become active. - * @param {Timer} timer the timer to use */ timeWhileActive(timer) { // important this happens first diff --git a/src/components/structures/GroupGridView.js b/src/components/structures/GroupGridView.js deleted file mode 100644 index a1a9e1b183..0000000000 --- a/src/components/structures/GroupGridView.js +++ /dev/null @@ -1,127 +0,0 @@ -/* -Copyright 2017 Vector Creations Ltd. -Copyright 2017, 2018 New Vector Ltd. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import React from 'react'; -import OpenRoomsStore from '../../stores/OpenRoomsStore'; -import dis from '../../dispatcher'; -import {_t} from '../../languageHandler'; -import RoomView from './RoomView'; -import classNames from 'classnames'; -import MainSplit from './MainSplit'; -import RightPanel from './RightPanel'; -import RoomHeaderButtons from '../views/right_panel/RoomHeaderButtons'; - -export default class RoomGridView extends React.Component { - constructor(props) { - super(props); - this.state = { - roomStores: OpenRoomsStore.getRoomStores(), - activeRoomStore: OpenRoomsStore.getActiveRoomStore(), - }; - this.onRoomsChanged = this.onRoomsChanged.bind(this); - } - - componentDidUpdate(_, prevState) { - const store = this.state.activeRoomStore; - if (store) { - store.getDispatcher().dispatch({action: 'focus_composer'}); - } - } - - componentDidMount() { - this.componentDidUpdate(); - } - - componentWillMount() { - this._unmounted = false; - this._openRoomsStoreRegistration = OpenRoomsStore.addListener(this.onRoomsChanged); - } - - componentWillUnmount() { - this._unmounted = true; - if (this._openRoomsStoreRegistration) { - this._openRoomsStoreRegistration.remove(); - } - } - - onRoomsChanged() { - if (this._unmounted) return; - this.setState({ - roomStores: OpenRoomsStore.getRoomStores(), - activeRoomStore: OpenRoomsStore.getActiveRoomStore(), - }); - } - - _setActive(i) { - const store = OpenRoomsStore.getRoomStoreAt(i); - if (store !== this.state.activeRoomStore) { - dis.dispatch({ - action: 'group_grid_set_active', - room_id: store.getRoomId(), - }); - } - } - - render() { - let roomStores = this.state.roomStores.slice(0, 6); - const emptyCount = 6 - roomStores.length; - if (emptyCount) { - const emptyTiles = Array.from({length: emptyCount}, () => null); - roomStores = roomStores.concat(emptyTiles); - } - const activeRoomId = this.state.activeRoomStore && this.state.activeRoomStore.getRoomId(); - let rightPanel; - if (activeRoomId) { - rightPanel = ( -
    -
    - -
    - ); - } - - return (
    - -
    - { roomStores.map((roomStore, i) => { - if (roomStore) { - const isActive = roomStore === this.state.activeRoomStore; - const tileClasses = classNames({ - "mx_GroupGridView_tile": true, - "mx_GroupGridView_activeTile": isActive, - }); - return (
    {this._setActive(i);}} - key={roomStore.getRoomId()} - className={tileClasses} - > - -
    ); - } else { - return (
    {_t("No room in this tile yet.")}
    ); - } - }) } -
    -
    -
    ); - } -} diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index 67d7d41701..0433ce25b3 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -31,7 +31,6 @@ import sessionStore from '../../stores/SessionStore'; import MatrixClientPeg from '../../MatrixClientPeg'; import SettingsStore from "../../settings/SettingsStore"; import RoomListStore from "../../stores/RoomListStore"; -import OpenRoomsStore from "../../stores/OpenRoomsStore"; import TagOrderActions from '../../actions/TagOrderActions'; import RoomListActions from '../../actions/RoomListActions'; @@ -417,7 +416,6 @@ const LoggedInView = React.createClass({ const RoomDirectory = sdk.getComponent('structures.RoomDirectory'); const HomePage = sdk.getComponent('structures.HomePage'); const GroupView = sdk.getComponent('structures.GroupView'); - const GroupGridView = sdk.getComponent('structures.GroupGridView'); const MyGroups = sdk.getComponent('structures.MyGroups'); const MatrixToolbar = sdk.getComponent('globals.MatrixToolbar'); const CookieBar = sdk.getComponent('globals.CookieBar'); @@ -430,14 +428,7 @@ const LoggedInView = React.createClass({ switch (this.props.page_type) { case PageTypes.RoomView: - if (!OpenRoomsStore.getActiveRoomStore()) { - console.warn(`LoggedInView: getCurrentRoomStore not set!`); - } - else if (OpenRoomsStore.getActiveRoomStore().getRoomId() !== this.props.currentRoomId) { - console.warn(`LoggedInView: room id in store not the same as in props: ${OpenRoomsStore.getActiveRoomStore().getRoomId()} & ${this.props.currentRoomId}`); - } page_element = ; break; - case PageTypes.GroupGridView: - page_element = ; - break; + case PageTypes.UserSettings: page_element = ; } else if (this.state.phase === RightPanel.Phase.RoomMemberInfo) { - panel = ; + panel = ; } else if (this.state.phase === RightPanel.Phase.GroupMemberInfo) { panel = { - this.props.roomViewStore.getDispatcher().dispatch({action: 'start_registration'}); + dis.dispatch({action: 'start_registration'}); close(); }, onLoginClick: (ev) => { - this.props.roomViewStore.getDispatcher().dispatch({action: 'start_login'}); + dis.dispatch({action: 'start_login'}); close(); }, }).close; @@ -921,7 +922,7 @@ module.exports = React.createClass({ Promise.resolve().then(() => { const signUrl = this.props.thirdPartyInvite ? this.props.thirdPartyInvite.inviteSignUrl : undefined; - this.props.roomViewStore.getDispatcher().dispatch({ + dis.dispatch({ action: 'join_room', opts: { inviteSignUrl: signUrl, viaServers: this.props.viaServers }, }); @@ -986,10 +987,10 @@ module.exports = React.createClass({ }, uploadFile: async function(file) { - this.props.roomViewStore.getDispatcher().dispatch({action: 'focus_composer'}); + dis.dispatch({action: 'focus_composer'}); if (MatrixClientPeg.get().isGuest()) { - this.props.roomViewStore.getDispatcher().dispatch({action: 'require_registration'}); + dis.dispatch({action: 'require_registration'}); return; } @@ -1013,14 +1014,14 @@ module.exports = React.createClass({ } // Send message_sent callback, for things like _checkIfAlone because after all a file is still a message. - this.props.roomViewStore.getDispatcher().dispatch({ + dis.dispatch({ action: 'message_sent', }); }, injectSticker: function(url, info, text) { if (MatrixClientPeg.get().isGuest()) { - this.props.roomViewStore.getDispatcher().dispatch({action: 'require_registration'}); + dis.dispatch({action: 'require_registration'}); return; } @@ -1221,7 +1222,7 @@ module.exports = React.createClass({ }, onSettingsClick: function() { - this.props.roomViewStore.getDispatcher().dispatch({ action: 'open_room_settings' }); + dis.dispatch({ action: 'open_room_settings' }); }, onSettingsSaveClick: function() { @@ -1254,31 +1255,31 @@ module.exports = React.createClass({ }); // still editing room settings } else { - this.props.roomViewStore.getDispatcher().dispatch({ action: 'close_settings' }); + dis.dispatch({ action: 'close_settings' }); } }).finally(() => { this.setState({ uploadingRoomSettings: false, }); - this.props.roomViewStore.getDispatcher().dispatch({ action: 'close_settings' }); + dis.dispatch({ action: 'close_settings' }); }).done(); }, onCancelClick: function() { console.log("updateTint from onCancelClick"); this.updateTint(); - this.props.roomViewStore.getDispatcher().dispatch({ action: 'close_settings' }); + dis.dispatch({ action: 'close_settings' }); if (this.state.forwardingEvent) { - this.props.roomViewStore.getDispatcher().dispatch({ + dis.dispatch({ action: 'forward_event', event: null, }); } - this.props.roomViewStore.getDispatcher().dispatch({action: 'focus_composer'}); + dis.dispatch({action: 'focus_composer'}); }, onLeaveClick: function() { - this.props.roomViewStore.getDispatcher().dispatch({ + dis.dispatch({ action: 'leave_room', room_id: this.state.room.roomId, }); @@ -1286,7 +1287,7 @@ module.exports = React.createClass({ onForgetClick: function() { MatrixClientPeg.get().forget(this.state.room.roomId).done(function() { - this.props.roomViewStore.getDispatcher().dispatch({ action: 'view_next_room' }); + dis.dispatch({ action: 'view_next_room' }); }, function(err) { const errCode = err.errcode || _t("unknown error code"); const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); @@ -1303,7 +1304,7 @@ module.exports = React.createClass({ rejecting: true, }); MatrixClientPeg.get().leave(this.state.roomId).done(function() { - this.props.roomViewStore.getDispatcher().dispatch({ action: 'view_next_room' }); + dis.dispatch({ action: 'view_next_room' }); self.setState({ rejecting: false, }); @@ -1329,7 +1330,7 @@ module.exports = React.createClass({ // using /leave rather than /join. In the short term though, we // just ignore them. // https://github.com/vector-im/vector-web/issues/1134 - this.props.roomViewStore.getDispatcher().dispatch({ + dis.dispatch({ action: 'view_room_directory', }); }, @@ -1348,7 +1349,7 @@ module.exports = React.createClass({ // jump down to the bottom of this room, where new events are arriving jumpToLiveTimeline: function() { this.refs.messagePanel.jumpToLiveTimeline(); - this.props.roomViewStore.getDispatcher().dispatch({action: 'focus_composer'}); + dis.dispatch({action: 'focus_composer'}); }, // jump up to wherever our read marker is @@ -1438,7 +1439,7 @@ module.exports = React.createClass({ }, onFullscreenClick: function() { - this.props.roomViewStore.getDispatcher().dispatch({ + dis.dispatch({ action: 'video_fullscreen', fullscreen: true, }, true); @@ -1563,7 +1564,6 @@ module.exports = React.createClass({
    @@ -1610,7 +1610,6 @@ module.exports = React.createClass({
    @@ -1752,9 +1751,7 @@ module.exports = React.createClass({ if (canSpeak) { messageComposer = : - undefined; + const rightPanel = this.state.room ? : undefined; return (
    - - { _t('View as Grid') } -
    ); - } return
    { _t('View Community') }
    - { gridViewOption }
    diff --git a/src/components/views/right_panel/HeaderButtons.js b/src/components/views/right_panel/HeaderButtons.js index 3f5f58121d..f0479eb8be 100644 --- a/src/components/views/right_panel/HeaderButtons.js +++ b/src/components/views/right_panel/HeaderButtons.js @@ -78,6 +78,7 @@ export default class HeaderButtons extends React.Component { // till show_right_panel, just without the fromHeader flag // as that would hide the right panel again dis.dispatch(Object.assign({}, payload, {fromHeader: false})); + } this.setState({ phase: payload.phase, diff --git a/src/components/views/rooms/MemberInfo.js b/src/components/views/rooms/MemberInfo.js index 2b50ff5e48..6a796bc160 100644 --- a/src/components/views/rooms/MemberInfo.js +++ b/src/components/views/rooms/MemberInfo.js @@ -39,6 +39,7 @@ import Unread from '../../../Unread'; import { findReadReceiptFromUserId } from '../../../utils/Receipt'; import withMatrixClient from '../../../wrappers/withMatrixClient'; import AccessibleButton from '../elements/AccessibleButton'; +import RoomViewStore from '../../../stores/RoomViewStore'; import SdkConfig from '../../../SdkConfig'; import MultiInviter from "../../../utils/MultiInviter"; import SettingsStore from "../../../settings/SettingsStore"; @@ -49,7 +50,6 @@ module.exports = withMatrixClient(React.createClass({ propTypes: { matrixClient: PropTypes.object.isRequired, member: PropTypes.object.isRequired, - roomId: PropTypes.string, }, getInitialState: function() { @@ -713,7 +713,7 @@ module.exports = withMatrixClient(React.createClass({ } if (!member || !member.membership || member.membership === 'leave') { - const roomId = member && member.roomId ? member.roomId : this.props.roomId; + const roomId = member && member.roomId ? member.roomId : RoomViewStore.getRoomId(); const onInviteUserButton = async () => { try { // We use a MultiInviter to re-use the invite logic, even though diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index c648ca615b..91ef549185 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -22,6 +22,7 @@ import MatrixClientPeg from '../../../MatrixClientPeg'; import Modal from '../../../Modal'; import sdk from '../../../index'; import dis from '../../../dispatcher'; +import RoomViewStore from '../../../stores/RoomViewStore'; import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; import Stickerpicker from './Stickerpicker'; import { makeRoomPermalink } from '../../../matrix-to'; @@ -62,7 +63,7 @@ export default class MessageComposer extends React.Component { isRichTextEnabled: SettingsStore.getValue('MessageComposerInput.isRichTextEnabled'), }, showFormatting: SettingsStore.getValue('MessageComposer.showFormatting'), - isQuoting: Boolean(this.props.roomViewStore.getQuotingEvent()), + isQuoting: Boolean(RoomViewStore.getQuotingEvent()), tombstone: this._getRoomTombstone(), }; } @@ -74,7 +75,7 @@ export default class MessageComposer extends React.Component { // XXX: fragile as all hell - fixme somehow, perhaps with a dedicated Room.encryption event or something. MatrixClientPeg.get().on("event", this.onEvent); MatrixClientPeg.get().on("RoomState.events", this._onRoomStateEvents); - this._roomStoreToken = this.props.roomViewStore.addListener(this._onRoomViewStoreUpdate); + this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate); this._waitForOwnMember(); } @@ -123,14 +124,14 @@ export default class MessageComposer extends React.Component { } _onRoomViewStoreUpdate() { - const isQuoting = Boolean(this.props.roomViewStore.getQuotingEvent()); + const isQuoting = Boolean(RoomViewStore.getQuotingEvent()); if (this.state.isQuoting === isQuoting) return; this.setState({ isQuoting }); } onUploadClick(ev) { if (MatrixClientPeg.get().isGuest()) { - this.props.roomViewStore.getDispatcher().dispatch({action: 'require_registration'}); + dis.dispatch({action: 'require_registration'}); return; } @@ -164,7 +165,7 @@ export default class MessageComposer extends React.Component { } } - const isQuoting = Boolean(this.props.roomViewStore.getQuotingEvent()); + const isQuoting = Boolean(RoomViewStore.getQuotingEvent()); let replyToWarning = null; if (isQuoting) { replyToWarning =

    { @@ -228,7 +229,7 @@ export default class MessageComposer extends React.Component { if (!call) { return; } - this.props.roomViewStore.getDispatcher().dispatch({ + dis.dispatch({ action: 'hangup', // hangup the call for this room, which may not be the room in props // (e.g. conferences which will hangup the 1:1 room instead) @@ -237,7 +238,7 @@ export default class MessageComposer extends React.Component { } onCallClick(ev) { - this.props.roomViewStore.getDispatcher().dispatch({ + dis.dispatch({ action: 'place_call', type: ev.shiftKey ? "screensharing" : "video", room_id: this.props.room.roomId, @@ -245,7 +246,7 @@ export default class MessageComposer extends React.Component { } onVoiceCallClick(ev) { - this.props.roomViewStore.getDispatcher().dispatch({ + dis.dispatch({ action: 'place_call', type: "voice", room_id: this.props.room.roomId, @@ -287,8 +288,7 @@ export default class MessageComposer extends React.Component { const createEvent = replacementRoom.currentState.getStateEvents('m.room.create', ''); if (createEvent && createEvent.getId()) createEventId = createEvent.getId(); } - - this.props.roomViewStore.getDispatcher().dispatch({ + dis.dispatch({ action: 'view_room', highlighted: true, event_id: createEventId, @@ -432,10 +432,8 @@ export default class MessageComposer extends React.Component { controls.push( this.messageComposerInput = c} key="controls_input" - isGrid={this.props.isGrid} onResize={this.props.onResize} room={this.props.room} placeholder={placeholderText} @@ -542,6 +540,5 @@ MessageComposer.propTypes = { uploadAllowed: PropTypes.func.isRequired, // string representing the current room app drawer state - showApps: PropTypes.bool, - roomViewStore: PropTypes.object.isRequired, + showApps: PropTypes.bool }; diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index 4c800ad8d2..ff7cfcbd6d 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -38,6 +38,8 @@ import sdk from '../../../index'; import { _t } from '../../../languageHandler'; import Analytics from '../../../Analytics'; +import dis from '../../../dispatcher'; + import * as RichText from '../../../RichText'; import * as HtmlUtils from '../../../HtmlUtils'; import Autocomplete from './Autocomplete'; @@ -55,6 +57,7 @@ import { import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; import {makeUserPermalink} from "../../../matrix-to"; import ReplyPreview from "./ReplyPreview"; +import RoomViewStore from '../../../stores/RoomViewStore'; import ReplyThread from "../elements/ReplyThread"; import {ContentHelpers} from 'matrix-js-sdk'; @@ -108,6 +111,15 @@ const SLATE_SCHEMA = { }, }; +function onSendMessageFailed(err, room) { + // XXX: temporary logging to try to diagnose + // https://github.com/vector-im/riot-web/issues/3148 + console.log('MessageComposer got send failure: ' + err.name + '('+err+')'); + dis.dispatch({ + action: 'message_send_failed', + }); +} + function rangeEquals(a: Range, b: Range): boolean { return (a.anchor.key === b.anchor.key && a.anchor.offset === b.anchorOffset @@ -117,18 +129,6 @@ function rangeEquals(a: Range, b: Range): boolean { && a.isBackward === b.isBackward); } -class NoopHistoryManager { - getItem() {} - save() {} - - get currentIndex() { return 0; } - set currentIndex(_) {} - - get history() { return []; } - set history(_) {} -} - - /* * The textInput part of the MessageComposer */ @@ -144,7 +144,6 @@ export default class MessageComposerInput extends React.Component { onFilesPasted: PropTypes.func, onInputStateChanged: PropTypes.func, - roomViewStore: PropTypes.object.isRequired, }; client: MatrixClient; @@ -339,31 +338,18 @@ export default class MessageComposerInput extends React.Component { } componentWillMount() { - this.dispatcherRef = this.props.roomViewStore.getDispatcher().register(this.onAction); - if (this.props.isGrid) { - this.historyManager = new NoopHistoryManager(); - } else { - this.historyManager = new ComposerHistoryManager(this.props.room.roomId, 'mx_slate_composer_history_'); - } + this.dispatcherRef = dis.register(this.onAction); + this.historyManager = new ComposerHistoryManager(this.props.room.roomId, 'mx_slate_composer_history_'); } componentWillUnmount() { - this.props.roomViewStore.getDispatcher().unregister(this.dispatcherRef); + dis.unregister(this.dispatcherRef); } _collectEditor = (e) => { this._editor = e; } - onSendMessageFailed = (err, room) => { - // XXX: temporary logging to try to diagnose - // https://github.com/vector-im/riot-web/issues/3148 - console.log('MessageComposer got send failure: ' + err.name + '('+err+')'); - this.props.roomViewStore.getDispatcher().dispatch({ - action: 'message_send_failed', - }); - } - onAction = (payload) => { const editorState = this.state.editorState; @@ -1129,7 +1115,7 @@ export default class MessageComposerInput extends React.Component { return true; } - const replyingToEv = this.props.roomViewStore.getQuotingEvent(); + const replyingToEv = RoomViewStore.getQuotingEvent(); const mustSendHTML = Boolean(replyingToEv); if (this.state.isRichTextEnabled) { @@ -1217,18 +1203,18 @@ export default class MessageComposerInput extends React.Component { // Clear reply_to_event as we put the message into the queue // if the send fails, retry will handle resending. - this.props.roomViewStore.getDispatcher().dispatch({ + dis.dispatch({ action: 'reply_to_event', event: null, }); } this.client.sendMessage(this.props.room.roomId, content).then((res) => { - this.props.roomViewStore.getDispatcher().dispatch({ + dis.dispatch({ action: 'message_sent', }); }).catch((e) => { - this.onSendMessageFailed(e, this.props.room); + onSendMessageFailed(e, this.props.room); }); this.setState({ @@ -1599,7 +1585,7 @@ export default class MessageComposerInput extends React.Component { return (

    - + this.autocomplete = e} room={this.props.room} diff --git a/src/components/views/rooms/ReplyPreview.js b/src/components/views/rooms/ReplyPreview.js index 04ff9d0778..46e2826634 100644 --- a/src/components/views/rooms/ReplyPreview.js +++ b/src/components/views/rooms/ReplyPreview.js @@ -18,6 +18,7 @@ import React from 'react'; import dis from '../../../dispatcher'; import sdk from '../../../index'; import { _t } from '../../../languageHandler'; +import RoomViewStore from '../../../stores/RoomViewStore'; import SettingsStore from "../../../settings/SettingsStore"; function cancelQuoting() { @@ -37,7 +38,7 @@ export default class ReplyPreview extends React.Component { this._onRoomViewStoreUpdate = this._onRoomViewStoreUpdate.bind(this); - this._roomStoreToken = this.props.roomViewStore.addListener(this._onRoomViewStoreUpdate); + this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate); this._onRoomViewStoreUpdate(); } @@ -49,7 +50,7 @@ export default class ReplyPreview extends React.Component { } _onRoomViewStoreUpdate() { - const event = this.props.roomViewStore.getQuotingEvent(); + const event = RoomViewStore.getQuotingEvent(); if (this.state.event !== event) { this.setState({ event }); } diff --git a/src/components/views/rooms/RoomHeader.js b/src/components/views/rooms/RoomHeader.js index 91ca73dd59..4292fa6a4d 100644 --- a/src/components/views/rooms/RoomHeader.js +++ b/src/components/views/rooms/RoomHeader.js @@ -24,7 +24,6 @@ import { _t } from '../../../languageHandler'; import MatrixClientPeg from '../../../MatrixClientPeg'; import Modal from "../../../Modal"; import RateLimitedFunc from '../../../ratelimitedfunc'; -import dis from '../../../dispatcher'; import * as linkify from 'linkifyjs'; import linkifyElement from 'linkifyjs/element'; @@ -153,14 +152,6 @@ module.exports = React.createClass({ }); }, - onToggleRightPanelClick: function(ev) { - if (this.props.collapsedRhs) { - dis.dispatch({action: "show_right_panel"}); - } else { - dis.dispatch({action: "hide_right_panel"}); - } - }, - _hasUnreadPins: function() { const currentPinEvent = this.props.room.currentState.getStateEvents("m.room.pinned_events", ''); if (!currentPinEvent) return false; @@ -418,17 +409,6 @@ module.exports = React.createClass({
    ; } - let toggleRightPanelButton; - if (this.props.isGrid) { - toggleRightPanelButton = - - - ; - } - return (
    @@ -439,8 +419,7 @@ module.exports = React.createClass({ { saveButton } { cancelButton } { rightRow } - { !this.props.isGrid ? : undefined } - { toggleRightPanelButton } +
    ); diff --git a/src/components/views/rooms/RoomTile.js b/src/components/views/rooms/RoomTile.js index 1f9c0c1523..1a17fcf5ea 100644 --- a/src/components/views/rooms/RoomTile.js +++ b/src/components/views/rooms/RoomTile.js @@ -29,6 +29,7 @@ import * as RoomNotifs from '../../../RoomNotifs'; import * as FormattingUtils from '../../../utils/FormattingUtils'; import AccessibleButton from '../elements/AccessibleButton'; import ActiveRoomObserver from '../../../ActiveRoomObserver'; +import RoomViewStore from '../../../stores/RoomViewStore'; import SettingsStore from "../../../settings/SettingsStore"; module.exports = React.createClass({ @@ -61,7 +62,7 @@ module.exports = React.createClass({ roomName: this.props.room.name, notifState: RoomNotifs.getRoomNotifsState(this.props.room.roomId), notificationCount: this.props.room.getUnreadNotificationCount(), - selected: this.props.room.roomId === ActiveRoomObserver.getActiveRoomId(), + selected: this.props.room.roomId === RoomViewStore.getRoomId(), statusMessage: this._getStatusMessage(), }); }, @@ -150,9 +151,9 @@ module.exports = React.createClass({ } }, - _onActiveRoomChange: function(activeRoomId) { + _onActiveRoomChange: function() { this.setState({ - selected: this.props.room.roomId === activeRoomId, + selected: this.props.room.roomId === RoomViewStore.getRoomId(), }); }, diff --git a/src/dispatcher.js b/src/dispatcher.js index 4dc6e1e37d..48c8dc86e9 100644 --- a/src/dispatcher.js +++ b/src/dispatcher.js @@ -17,10 +17,42 @@ limitations under the License. 'use strict'; -import MatrixDispatcher from "./matrix-dispatcher"; +const flux = require("flux"); + +class MatrixDispatcher extends flux.Dispatcher { + /** + * @param {Object|function} payload Required. The payload to dispatch. + * If an Object, must contain at least an 'action' key. + * If a function, must have the signature (dispatch) => {...}. + * @param {boolean=} sync Optional. Pass true to dispatch + * synchronously. This is useful for anything triggering + * an operation that the browser requires user interaction + * for. + */ + dispatch(payload, sync) { + // Allow for asynchronous dispatching by accepting payloads that have the + // type `function (dispatch) {...}` + if (typeof payload === 'function') { + payload((action) => { + this.dispatch(action, sync); + }); + return; + } + + if (sync) { + super.dispatch(payload); + } else { + // Unless the caller explicitly asked for us to dispatch synchronously, + // we always set a timeout to do this: The flux dispatcher complains + // if you dispatch from within a dispatch, so rather than action + // handlers having to worry about not calling anything that might + // then dispatch, we just do dispatches asynchronously. + setTimeout(super.dispatch.bind(this, payload), 0); + } + } +} if (global.mxDispatcher === undefined) { global.mxDispatcher = new MatrixDispatcher(); } - module.exports = global.mxDispatcher; diff --git a/src/matrix-dispatcher.js b/src/matrix-dispatcher.js deleted file mode 100644 index fb81ed837f..0000000000 --- a/src/matrix-dispatcher.js +++ /dev/null @@ -1,53 +0,0 @@ -/* -Copyright 2015, 2016 OpenMarket Ltd -Copyright 2017 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. -*/ - -'use strict'; - -const flux = require("flux"); - -export default class MatrixDispatcher extends flux.Dispatcher { - /** - * @param {Object|function} payload Required. The payload to dispatch. - * If an Object, must contain at least an 'action' key. - * If a function, must have the signature (dispatch) => {...}. - * @param {boolean=} sync Optional. Pass true to dispatch - * synchronously. This is useful for anything triggering - * an operation that the browser requires user interaction - * for. - */ - dispatch(payload, sync) { - // Allow for asynchronous dispatching by accepting payloads that have the - // type `function (dispatch) {...}` - if (typeof payload === 'function') { - payload((action) => { - this.dispatch(action, sync); - }); - return; - } - - if (sync) { - super.dispatch(payload); - } else { - // Unless the caller explicitly asked for us to dispatch synchronously, - // we always set a timeout to do this: The flux dispatcher complains - // if you dispatch from within a dispatch, so rather than action - // handlers having to worry about not calling anything that might - // then dispatch, we just do dispatches asynchronously. - setTimeout(super.dispatch.bind(this, payload), 0); - } - } -} diff --git a/src/settings/Settings.js b/src/settings/Settings.js index 836e906b6e..66353c67a6 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -110,12 +110,6 @@ export const SETTINGS = { supportedLevels: LEVELS_FEATURE, default: false, }, - "feature_gridview": { - isFeature: true, - displayName: _td("Allow up to 6 rooms in a community to be shown simultaneously in a grid via the context menu"), - supportedLevels: LEVELS_FEATURE, - default: false, - }, "MessageComposerInput.dontSuggestEmoji": { supportedLevels: LEVELS_ACCOUNT_SETTINGS, displayName: _td('Disable Emoji suggestions while typing'), diff --git a/src/stores/OpenRoomsStore.js b/src/stores/OpenRoomsStore.js deleted file mode 100644 index 21f02fe28d..0000000000 --- a/src/stores/OpenRoomsStore.js +++ /dev/null @@ -1,277 +0,0 @@ -/* -Copyright 2018 New Vector Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -import MatrixDispatcher from '../matrix-dispatcher'; -import dis from '../dispatcher'; -import {RoomViewStore} from './RoomViewStore'; -import GroupStore from './GroupStore'; -import {Store} from 'flux/utils'; -import MatrixClientPeg from '../MatrixClientPeg'; - - -function matchesRoom(payload, roomStore) { - if (!roomStore) { - return false; - } - if (payload.room_alias) { - return payload.room_alias === roomStore.getRoomAlias(); - } - return payload.room_id === roomStore.getRoomId(); -} - -/** - * A class for keeping track of the RoomViewStores of the rooms shown on the screen. - * Routes the dispatcher actions to the store of currently active room. - */ -class OpenRoomsStore extends Store { - constructor() { - super(dis); - - // Initialise state - this._state = { - rooms: [], - currentIndex: null, - group_id: null, - }; - - this._forwardingEvent = null; - } - - getRoomStores() { - return this._state.rooms.map((r) => r.store); - } - - getActiveRoomStore() { - const openRoom = this._getActiveOpenRoom(); - if (openRoom) { - return openRoom.store; - } - } - - getRoomStoreAt(index) { - if (index >= 0 && index < this._state.rooms.length) { - return this._state.rooms[index].store; - } - } - - _getActiveOpenRoom() { - const index = this._state.currentIndex; - if (index !== null && index < this._state.rooms.length) { - return this._state.rooms[index]; - } - } - - _setState(newState) { - this._state = Object.assign(this._state, newState); - this.__emitChange(); - } - - _hasRoom(payload) { - return this._roomIndex(payload) !== -1; - } - - _roomIndex(payload) { - return this._state.rooms.findIndex((r) => matchesRoom(payload, r.store)); - } - - _cleanupOpenRooms() { - this._state.rooms.forEach((room) => { - room.dispatcher.unregister(room.dispatcherRef); - room.dispatcher.unregister(room.store.getDispatchToken()); - }); - this._setState({ - rooms: [], - group_id: null, - currentIndex: null, - }); - } - - _createOpenRoom(roomId, roomAlias) { - const dispatcher = new MatrixDispatcher(); - // forward all actions coming from the room dispatcher - // to the global one - const dispatcherRef = dispatcher.register((payload) => { - // block a view_room action for the same room because it will switch to - // single room mode in MatrixChat - if (payload.action === 'view_room' && roomId === payload.room_id) { - return; - } - payload.grid_src_room_id = roomId; - payload.grid_src_room_alias = roomAlias; - this.getDispatcher().dispatch(payload); - }); - const openRoom = { - store: new RoomViewStore(dispatcher), - dispatcher, - dispatcherRef, - }; - - dispatcher.dispatch({ - action: 'view_room', - room_id: roomId, - room_alias: roomAlias, - }, true); - - return openRoom; - } - - _setSingleOpenRoom(payload) { - this._setState({ - rooms: [this._createOpenRoom(payload.room_id, payload.room_alias)], - currentIndex: 0, - }); - } - - _setGroupOpenRooms(groupId) { - this._cleanupOpenRooms(); - // TODO: register to GroupStore updates - const rooms = GroupStore.getGroupRooms(groupId); - const openRooms = rooms.map((room) => { - return this._createOpenRoom(room.roomId); - }); - this._setState({ - rooms: openRooms, - group_id: groupId, - currentIndex: 0, - }); - } - - _forwardAction(payload) { - // don't forward an event to a room dispatcher - // if the event originated from that dispatcher, as this - // would cause the event to be observed twice in that - // dispatcher - if (payload.grid_src_room_id || payload.grid_src_room_alias) { - const srcPayload = { - room_id: payload.grid_src_room_id, - room_alias: payload.grid_src_room_alias, - }; - const srcIndex = this._roomIndex(srcPayload); - if (srcIndex === this._state.currentIndex) { - return; - } - } - const currentRoom = this._getActiveOpenRoom(); - if (currentRoom) { - currentRoom.dispatcher.dispatch(payload, true); - } - } - - async _resolveRoomAlias(payload) { - try { - const result = await MatrixClientPeg.get() - .getRoomIdForAlias(payload.room_alias); - this.getDispatcher().dispatch({ - action: 'view_room', - room_id: result.room_id, - event_id: payload.event_id, - highlighted: payload.highlighted, - room_alias: payload.room_alias, - auto_join: payload.auto_join, - oob_data: payload.oob_data, - }); - } catch (err) { - this._forwardAction({ - action: 'view_room_error', - room_id: null, - room_alias: payload.room_alias, - err: err, - }); - } - } - - _viewRoom(payload) { - console.log("!!! OpenRoomsStore: view_room", payload); - if (!payload.room_id && payload.room_alias) { - this._resolveRoomAlias(payload); - } - const currentStore = this.getActiveRoomStore(); - if (!matchesRoom(payload, currentStore)) { - if (this._hasRoom(payload)) { - const roomIndex = this._roomIndex(payload); - this._setState({currentIndex: roomIndex}); - } else { - this._cleanupOpenRooms(); - } - } - if (!this.getActiveRoomStore()) { - console.log("OpenRoomsStore: _setSingleOpenRoom"); - this._setSingleOpenRoom(payload); - } - console.log("OpenRoomsStore: _forwardAction"); - this._forwardAction(payload); - if (this._forwardingEvent) { - this.getDispatcher().dispatch({ - action: 'send_event', - room_id: payload.room_id, - event: this._forwardingEvent, - }); - this._forwardingEvent = null; - } - } - - __onDispatch(payload) { - let proposedIndex; - switch (payload.action) { - // view_room: - // - room_alias: '#somealias:matrix.org' - // - room_id: '!roomid123:matrix.org' - // - event_id: '$213456782:matrix.org' - // - event_offset: 100 - // - highlighted: true - case 'view_room': - this._viewRoom(payload); - break; - case 'view_my_groups': - case 'view_group': - this._forwardAction(payload); - this._cleanupOpenRooms(); - break; - case 'will_join': - case 'cancel_join': - case 'join_room': - case 'join_room_error': - case 'on_logged_out': - case 'reply_to_event': - case 'open_room_settings': - case 'close_settings': - case 'focus_composer': - this._forwardAction(payload); - break; - case 'forward_event': - this._forwardingEvent = payload.event; - break; - case 'group_grid_set_active': - proposedIndex = this._roomIndex(payload); - if (proposedIndex !== -1) { - this._setState({ - currentIndex: proposedIndex, - }); - } - break; - case 'group_grid_view': - if (payload.group_id !== this._state.group_id) { - this._setGroupOpenRooms(payload.group_id); - } - break; - } - } -} - -let singletonOpenRoomsStore = null; -if (!singletonOpenRoomsStore) { - singletonOpenRoomsStore = new OpenRoomsStore(); -} -module.exports = singletonOpenRoomsStore; diff --git a/src/stores/RoomViewStore.js b/src/stores/RoomViewStore.js index a0b831ad17..9e048e5d8e 100644 --- a/src/stores/RoomViewStore.js +++ b/src/stores/RoomViewStore.js @@ -14,6 +14,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ +import dis from '../dispatcher'; import {Store} from 'flux/utils'; import MatrixClientPeg from '../MatrixClientPeg'; import sdk from '../index'; @@ -52,12 +53,12 @@ const INITIAL_STATE = { * with a subset of the js-sdk. * ``` */ -export class RoomViewStore extends Store { - constructor(dispatcher) { - super(dispatcher); +class RoomViewStore extends Store { + constructor() { + super(dis); // Initialise state - this._state = Object.assign({}, INITIAL_STATE); + this._state = INITIAL_STATE; } _setState(newState) { @@ -84,8 +85,6 @@ export class RoomViewStore extends Store { }); break; case 'view_room_error': - // should not go over dispatcher anymore - // but be internal to RoomViewStore this._viewRoomError(payload); break; case 'will_join': @@ -151,11 +150,22 @@ export class RoomViewStore extends Store { // pull the user out of Room Settings isEditingSettings: false, }; + + if (this._state.forwardingEvent) { + dis.dispatch({ + action: 'send_event', + room_id: newState.roomId, + event: this._state.forwardingEvent, + }); + } + this._setState(newState); + if (payload.auto_join) { this._joinRoom(payload); } } else if (payload.room_alias) { + // Resolve the alias and then do a second dispatch with the room ID acquired this._setState({ roomId: null, initialEventId: null, @@ -165,6 +175,25 @@ export class RoomViewStore extends Store { roomLoading: true, roomLoadError: null, }); + MatrixClientPeg.get().getRoomIdForAlias(payload.room_alias).done( + (result) => { + dis.dispatch({ + action: 'view_room', + room_id: result.room_id, + event_id: payload.event_id, + highlighted: payload.highlighted, + room_alias: payload.room_alias, + auto_join: payload.auto_join, + oob_data: payload.oob_data, + }); + }, (err) => { + dis.dispatch({ + action: 'view_room_error', + room_id: null, + room_alias: payload.room_alias, + err: err, + }); + }); } } @@ -190,7 +219,7 @@ export class RoomViewStore extends Store { // stream yet, and that's the point at which we'd consider // the user joined to the room. }, (err) => { - this.getDispatcher().dispatch({ + dis.dispatch({ action: 'join_room_error', err: err, }); @@ -306,7 +335,8 @@ export class RoomViewStore extends Store { } } -const MatrixDispatcher = require("../matrix-dispatcher"); -const backwardsCompatInstance = new RoomViewStore(new MatrixDispatcher()); - -export default backwardsCompatInstance; +let singletonRoomViewStore = null; +if (!singletonRoomViewStore) { + singletonRoomViewStore = new RoomViewStore(); +} +module.exports = singletonRoomViewStore; diff --git a/src/utils/Timer.js b/src/utils/Timer.js index ca06237fbf..aeac0887c9 100644 --- a/src/utils/Timer.js +++ b/src/utils/Timer.js @@ -26,6 +26,7 @@ Once a timer is finished or aborted, it can't be started again a new one through `clone()` or `cloneIfRun()`. */ export default class Timer { + constructor(timeout) { this._timeout = timeout; this._onTimeout = this._onTimeout.bind(this); @@ -69,7 +70,6 @@ export default class Timer { /** * if not started before, starts the timer. - * @returns {Timer} the same timer */ start() { if (!this.isRunning()) { @@ -81,7 +81,6 @@ export default class Timer { /** * (re)start the timer. If it's running, reset the timeout. If not, start it. - * @returns {Timer} the same timer */ restart() { if (this.isRunning()) { @@ -99,7 +98,6 @@ export default class Timer { /** * if the timer is running, abort it, * and reject the promise for this timer. - * @returns {Timer} the same timer */ abort() { if (this.isRunning()) { From a7d21ebb8e2f6f40d710e21d3721a382da96f723 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 17 Jan 2019 10:43:01 +0100 Subject: [PATCH 0144/1528] re-apply Timer linting fixes that happened in the tiled ui PR --- src/UserActivity.js | 1 + src/utils/Timer.js | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/UserActivity.js b/src/UserActivity.js index 4e3667274c..145b23e36e 100644 --- a/src/UserActivity.js +++ b/src/UserActivity.js @@ -44,6 +44,7 @@ class UserActivity { * Can be called multiple times with the same already running timer, which is a NO-OP. * Can be called before the user becomes active, in which case it is only started * later on when the user does become active. + * @param {Timer} timer the timer to use */ timeWhileActive(timer) { // important this happens first diff --git a/src/utils/Timer.js b/src/utils/Timer.js index aeac0887c9..6d6dbb0996 100644 --- a/src/utils/Timer.js +++ b/src/utils/Timer.js @@ -70,6 +70,7 @@ export default class Timer { /** * if not started before, starts the timer. + * @returns {Timer} the same timer */ start() { if (!this.isRunning()) { @@ -81,6 +82,7 @@ export default class Timer { /** * (re)start the timer. If it's running, reset the timeout. If not, start it. + * @returns {Timer} the same timer */ restart() { if (this.isRunning()) { @@ -98,6 +100,7 @@ export default class Timer { /** * if the timer is running, abort it, * and reject the promise for this timer. + * @returns {Timer} the same timer */ abort() { if (this.isRunning()) { From 506ee39a093335ce69c5103d66315a4759b54e3f Mon Sep 17 00:00:00 2001 From: Besnik Bleta Date: Wed, 16 Jan 2019 16:11:26 +0000 Subject: [PATCH 0145/1528] Translated using Weblate (Albanian) Currently translated at 99.2% (1417 of 1427 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/sq/ --- src/i18n/strings/sq.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/sq.json b/src/i18n/strings/sq.json index b30b072c47..c12a6ec183 100644 --- a/src/i18n/strings/sq.json +++ b/src/i18n/strings/sq.json @@ -1422,5 +1422,12 @@ "Clear status": "Pastroji gjendjen", "To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "Që të shihni historik mesazhesh të sigurta dhe të garantoni se mund t’i shihni mesazhet e reja në pajisje të ardhshme, ujdisni Rimarrje Mesazhesh të Sigurt.", "Unrecognised address": "Adresë jo e pranuar", - "User %(user_id)s may or may not exist": "Përdoruesi %(user_id)s mund të ekzistojë ose jo" + "User %(user_id)s may or may not exist": "Përdoruesi %(user_id)s mund të ekzistojë ose jo", + "Waiting for %(userId)s to accept...": "Po pritet që %(userId)s të pranojë…", + "Waiting for %(userId)s to confirm...": "Po pritet që %(userId)s të bëjë ripohimin…", + "Prompt before sending invites to potentially invalid matrix IDs": "Pyet, përpara se të dërgohen ftesa te ID Matrix potencialisht të pavlefshme", + "The following users may not exist": "Përdoruesit vijues mund të mos ekzistojnë", + "Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "S’arrihet të gjenden profile për ID-të Matrix të treguara më poshtë - do të donit të ftohe, sido qoftë?", + "Invite anyway and never warn me again": "Ftoji sido që të jetë dhe mos më sinjalizo më kurrë", + "Invite anyway": "Ftoji sido qoftë" } From 0eac643ac687f4d2b1e452ccf624afc5d93ec9e7 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 17 Jan 2019 10:50:07 +0000 Subject: [PATCH 0146/1528] js-sdk rc.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6dc9a6bfcf..3ceeccbda8 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "linkifyjs": "^2.1.6", "lodash": "^4.13.1", "lolex": "2.3.2", - "matrix-js-sdk": "0.14.2", + "matrix-js-sdk": "0.14.3-rc.1", "optimist": "^0.6.1", "pako": "^1.0.5", "prop-types": "^15.5.8", From df273e0712ded97543dd6c73a99b7ec0c4d82335 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 17 Jan 2019 10:54:52 +0000 Subject: [PATCH 0147/1528] Prepare changelog for v0.14.8-rc.1 --- CHANGELOG.md | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 742b8b4529..f192708dab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,71 @@ +Changes in [0.14.8-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.14.8-rc.1) (2019-01-17) +=============================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.14.7...v0.14.8-rc.1) + + * Change wording of 'invite anyway' setting + [\#2450](https://github.com/matrix-org/matrix-react-sdk/pull/2450) + * Minimal lint-fixes to make develop CI build + [\#2449](https://github.com/matrix-org/matrix-react-sdk/pull/2449) + * Develop->Experimental + [\#2445](https://github.com/matrix-org/matrix-react-sdk/pull/2445) + * Limit line length in the room directory + [\#2438](https://github.com/matrix-org/matrix-react-sdk/pull/2438) + * Develop->Experimental + [\#2444](https://github.com/matrix-org/matrix-react-sdk/pull/2444) + * Fix setting label for unknown invites + [\#2443](https://github.com/matrix-org/matrix-react-sdk/pull/2443) + * Merge develop -> experimental + [\#2441](https://github.com/matrix-org/matrix-react-sdk/pull/2441) + * Give a route for retrying invites for users which may not exist + [\#2434](https://github.com/matrix-org/matrix-react-sdk/pull/2434) + * Show in-room reminder when key backup creating device unverified + [\#2394](https://github.com/matrix-org/matrix-react-sdk/pull/2394) + * Consistent flair ordering. + [\#2389](https://github.com/matrix-org/matrix-react-sdk/pull/2389) + * Fetch matching e2e-test branch + [\#2387](https://github.com/matrix-org/matrix-react-sdk/pull/2387) + * Add some logging for riot-web#7838 + [\#2385](https://github.com/matrix-org/matrix-react-sdk/pull/2385) + * Handle well-known data in the login response + [\#2384](https://github.com/matrix-org/matrix-react-sdk/pull/2384) + * Custom status messages + [\#2347](https://github.com/matrix-org/matrix-react-sdk/pull/2347) + * React-sdk changes to support sandboxed electron + [\#2372](https://github.com/matrix-org/matrix-react-sdk/pull/2372) + * Make sure to grab the InlineSpinner object + [\#2363](https://github.com/matrix-org/matrix-react-sdk/pull/2363) + * Standardize errors about localpart structure + [\#2351](https://github.com/matrix-org/matrix-react-sdk/pull/2351) + * Fix translation error on notification icon + [\#2352](https://github.com/matrix-org/matrix-react-sdk/pull/2352) + * Introduce a default_server_name for aesthetics and rework .well-known + [\#2327](https://github.com/matrix-org/matrix-react-sdk/pull/2327) + * Show the number of unread notifications above the bell on the right + [\#2336](https://github.com/matrix-org/matrix-react-sdk/pull/2336) + * Check to make sure email addresses look roughly valid before inviting them + to rooms + [\#2338](https://github.com/matrix-org/matrix-react-sdk/pull/2338) + * Expose hidden notification rules in UI + [\#2346](https://github.com/matrix-org/matrix-react-sdk/pull/2346) + * Avoid preserving HS url at logout + [\#2340](https://github.com/matrix-org/matrix-react-sdk/pull/2340) + * Speed up room unread checks by not hitting the SettingsStore so often + [\#2339](https://github.com/matrix-org/matrix-react-sdk/pull/2339) + * Remove outdated info about custom skins + [\#2337](https://github.com/matrix-org/matrix-react-sdk/pull/2337) + * Show the IncomingCallBox if the call is for the RoomSubList + [\#2333](https://github.com/matrix-org/matrix-react-sdk/pull/2333) + * Don't consider ACL'd servers as permalink candidates + [\#2331](https://github.com/matrix-org/matrix-react-sdk/pull/2331) + * Fix pinning of rooms without badges + [\#2330](https://github.com/matrix-org/matrix-react-sdk/pull/2330) + * Sort translations by file name + [\#2329](https://github.com/matrix-org/matrix-react-sdk/pull/2329) + * Update React guide in code style + [\#2335](https://github.com/matrix-org/matrix-react-sdk/pull/2335) + * Remove temporary account_deactivation_preferences + [\#2259](https://github.com/matrix-org/matrix-react-sdk/pull/2259) + Changes in [0.14.7](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.14.7) (2018-12-10) ===================================================================================================== [Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.14.7-rc.2...v0.14.7) From fcd234f286b25fd7ebec212a9ca3509874739d39 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 17 Jan 2019 10:54:53 +0000 Subject: [PATCH 0148/1528] v0.14.8-rc.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3ceeccbda8..26792463aa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "0.14.7", + "version": "0.14.8-rc.1", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { From 921906897fb6cd1b7f23f96b28980a7b15bfab55 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 17 Jan 2019 13:49:52 +0100 Subject: [PATCH 0149/1528] css url paths are relative to location of compiled file, not project structure --- res/css/structures/_RoomView.scss | 2 +- res/css/views/rooms/_SearchBar.scss | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index d8926c68e4..4a84a55cd4 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -125,7 +125,7 @@ limitations under the License. .mx_RoomView_messagePanelSearchSpinner:before { background-color: $greyed-fg-color; - mask: url('../../../img/feather-icons/search-input.svg'); + mask: url('../../img/feather-icons/search-input.svg'); mask-repeat: no-repeat; mask-position: center; mask-size: 50px; diff --git a/res/css/views/rooms/_SearchBar.scss b/res/css/views/rooms/_SearchBar.scss index dddc87e5dd..390d6606c1 100644 --- a/res/css/views/rooms/_SearchBar.scss +++ b/res/css/views/rooms/_SearchBar.scss @@ -32,7 +32,7 @@ limitations under the License. width: 37px; height: 37px; background-color: $accent-color; - mask: url('../../../img/feather-icons/search-input.svg'); + mask: url('../../img/feather-icons/search-input.svg'); mask-repeat: no-repeat; mask-position: center; } @@ -55,7 +55,7 @@ limitations under the License. .mx_SearchBar_cancel { background-color: $warning-color; - mask: url('../../../img/cancel.svg'); + mask: url('../../img/cancel.svg'); mask-repeat: no-repeat; mask-position: center; mask-size: 14px; From 2bec088591c1afe83b2888f9800e637881119979 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 17 Jan 2019 14:07:33 +0100 Subject: [PATCH 0150/1528] show hand cursor in topleft menu so its clear you can click it --- res/css/views/context_menus/_TopLeftMenu.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/res/css/views/context_menus/_TopLeftMenu.scss b/res/css/views/context_menus/_TopLeftMenu.scss index 960e052a30..fb2c972fe3 100644 --- a/res/css/views/context_menus/_TopLeftMenu.scss +++ b/res/css/views/context_menus/_TopLeftMenu.scss @@ -27,6 +27,7 @@ limitations under the License. padding: 0; li { + cursor: pointer; white-space: nowrap; padding: 5px 20px; } From 2899d7d3c499afdc3a521340d5961c21016ee4db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20V=C3=A1gner?= Date: Thu, 17 Jan 2019 14:19:53 +0000 Subject: [PATCH 0151/1528] Translated using Weblate (Slovak) Currently translated at 100.0% (1427 of 1427 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/sk/ --- src/i18n/strings/sk.json | 76 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/sk.json b/src/i18n/strings/sk.json index ef3392917d..a5e8f5e9fa 100644 --- a/src/i18n/strings/sk.json +++ b/src/i18n/strings/sk.json @@ -1376,5 +1376,79 @@ "Failed to decrypt %(failedCount)s sessions!": "Nepodarilo sa dešifrovať %(failedCount)s relácií!", "Restored %(sessionCount)s session keys": "Obnovených %(sessionCount)s kľúčov relácií", "Enter Recovery Passphrase": "Zadajte heslo bezpečného obnovenia", - "Access your secure message history and set up secure messaging by entering your recovery passphrase.": "Vložením vlastného hesla pre bezpečné obnovenie správ, si nastavíte Bezpečnú obnovu správ, aby ste mali neustále prístup k zašifrovaným konverzáciám." + "Access your secure message history and set up secure messaging by entering your recovery passphrase.": "Vložením vlastného hesla pre bezpečné obnovenie správ, si nastavíte Bezpečnú obnovu správ, aby ste mali neustále prístup k zašifrovaným konverzáciám.", + "Waiting for %(userId)s to accept...": "Čakanie na prijatie od používateľa %(userId)s…", + "Waiting for %(userId)s to confirm...": "Čakanie na potvrdenie od používateľa %(userId)s…", + "Prompt before sending invites to potentially invalid matrix IDs": "Upozorniť pred odoslaním pozvaní na potenciálne neexistujúce Matrix ID", + "Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "Nie je možné nájsť používateľský profil pre Matrix ID zobrazené nižšie. Chcete ich napriek tomu pozvať?", + "Invite anyway and never warn me again": "Napriek tomu pozvať a viac neupozorňovať", + "Invite anyway": "Napriek tomu pozvať", + "Next": "Ďalej", + "If you've forgotten your recovery passphrase you can use your recovery key or set up new recovery options": "Ak ste zabudli heslo bezpečného obnovenia, môžete použiť kľúč alebo nastaviť obnovenie znovu", + "Enter Recovery Key": "Zadajte kľúč bezpečného obnovenia", + "This looks like a valid recovery key!": "Toto vyzerá ako platný kľúč obnovenia!", + "Not a valid recovery key": "Neplatný kľúč obnovenia", + "Access your secure message history and set up secure messaging by entering your recovery key.": "Zabezpečte svoju komunikáciu a prístup k šifrovanej histórii konverzácií zadaním kľúča obnovenia.", + "If you've forgotten your recovery passphrase you can ": "Ak ste zabudli heslo obnovenia, ", + "Set a new status...": "Nastaviť nový stav…", + "Clear status": "Zrušiť stav", + "You are an administrator of this community. You will not be able to rejoin without an invite from another administrator.": "Ste správcom tejto komunity. Nebudete môcť znovu vstúpiť bez pozvania od iného správcu.", + "You are currently using Riot anonymously as a guest.": "Momentálne používate Riot anonymne ako hosť.", + "If you would like to create a Matrix account you can register now.": "Ak si chcete vytvoriť účet Matrix, môžete sa zaregistrovať teraz.", + "Invalid configuration: Cannot supply a default homeserver URL and a default server name": "Neplatná konfigurácia: nie je možné poskytnúť predvolenú URL adresu ani názov domovského servera", + "Unknown error discovering homeserver": "Neznáma chyba pri zisťovaní domovského servera", + "%(count)s Notifications|other": "%(count)s oznámení", + "%(count)s Notifications|one": "%(count)s oznámenie", + "File is too big. Maximum file size is %(fileSize)s": "Súbor je príliš veľký. Maximálna povolená veľkosť je %(fileSize)s", + "Key Backup": "Záloha kľúčov", + "Invalid homeserver discovery response": "Neplatná odpoveď pri zisťovaní domovského servera", + "Invalid identity server discovery response": "Neplatná odpoveď pri zisťovaní servera totožností", + "General failure": "Všeobecná chyba", + "Failed to perform homeserver discovery": "Nepodarilo sa zistiť adresu domovského servera", + "Unknown failure discovering homeserver": "Neznáma chyba pri zisťovaní domovského servera", + "Sign in with single sign-on": "Prihlásiť sa pomocou jediného prihlasovania", + "Great! This passphrase looks strong enough.": "Výborne! Toto je dostatočne silné heslo.", + "Secure your encrypted message history with a Recovery Passphrase.": "Zabezpečte si históriu šifrovaných konverzácií zadaním hesla.", + "You'll need it if you log out or lose access to this device.": "Budete to potrebovať, keď sa odhlásite, alebo keď stratíte prístup k tomuto zariadeniu.", + "Enter a passphrase...": "Zadajte heslo…", + "If you don't want encrypted message history to be available on other devices, .": "Ak k histórií šifrovaných konverzácií nechcete pristupovať z ostatných zariadení, .", + "Or, if you don't want to create a Recovery Passphrase, skip this step and .": "Alebo ak si nechcete nastaviť heslo obnovenia, preskočte tento krok a .", + "That matches!": "Zhoda!", + "That doesn't match.": "Nezhodujú sa.", + "Go back to set it again.": "Vráťte sa späť a nastavte znovu.", + "Type in your Recovery Passphrase to confirm you remember it. If it helps, add it to your password manager or store it somewhere safe.": "Zadajte svoje heslo obnovenia, aby ste si potvrdili, že si ho pamätáte správne. Potom si ho môžete pridať do správcu hesiel alebo bezpečne uchovať inde.", + "Repeat your passphrase...": "Zopakujte heslo…", + "As a safety net, you can use it to restore your encrypted message history if you forget your Recovery Passphrase.": "Ak zabudnete svoje heslo obnovenia, tento kľúč môžete použiť ako ďalší bezpečnostný prvok na obnovenie histórii šifrovaných konverzácií.", + "As a safety net, you can use it to restore your encrypted message history.": "Tento kľúč môžete použiť ako ďalší bezpečnostný prvok na obnovenie histórii šifrovaných konverzácií.", + "Make a copy of this Recovery Key and keep it safe.": "Skopírujte si tento kľúč obnovenia a uchovajte na bezpečnom mieste.", + "Your Recovery Key": "Váš kľúč obnovenia", + "Copy to clipboard": "Kopírovať do schránky", + "Download": "Stiahnuť", + "I've made a copy": "Uschoval som si kópiu", + "Your Recovery Key has been copied to your clipboard, paste it to:": "Váš kľúč obnovenia bol skopírovaný do schránky, vložte ho do:", + "Your Recovery Key is in your Downloads folder.": "Váš kľúč obnovenia je uložený v priečinku so stiahnutými súbormi.", + "Print it and store it somewhere safe": "Vytlačte si ho a uchovajte na bezpečnom mieste", + "Save it on a USB key or backup drive": "Uložte si ho na USB kľúč alebo iné zálohovacie médium", + "Copy it to your personal cloud storage": "Skopírujte si ho na osobné úložisko v cloude", + "Got it": "Rozumiem", + "Backup created": "Záloha vytvorená", + "Your encryption keys are now being backed up to your Homeserver.": "Prebieha záloha vašich šifrovacích kľúčov na domovský server.", + "Without setting up Secure Message Recovery, you won't be able to restore your encrypted message history if you log out or use another device.": "Ak si nenastavíte bezpečné obnovenie správ, nebudete si môcť po odhlásení alebo prihlásení sa na inom zariadení čítať históriu šifrovaných konverzácií.", + "Set up Secure Message Recovery": "Nastaviť bezpečné obnovenie správ", + "Create a Recovery Passphrase": "Vytvoriť heslo obnovenia", + "Confirm Recovery Passphrase": "Potvrdiť heslo obnovenia", + "Recovery Key": "Kľúč obnovenia", + "Keep it safe": "Bezpečne ho uchovajte", + "Backing up...": "Zálohovanie…", + "Create Key Backup": "Vytvoriť zálohu kľúčov", + "Unable to create key backup": "Nie je možné vytvoriť zálohu šifrovacích kľúčov", + "Retry": "Skúsiť znovu", + "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Ak si nenastavíte Bezpečné obnovenie správ, po odhlásení stratíte prístup k histórii šifrovaných konverzácií.", + "If you don't want to set this up now, you can later in Settings.": "Ak nechcete pokračovať v nastavení teraz, môžete sa k tomu vrátiť neskôr v časti nastavenia.", + "New Recovery Method": "Nový spôsob obnovi", + "A new recovery passphrase and key for Secure Messages has been detected.": "Bolo nájdené nové heslo a kľúč Bezpečného obnovenia správ.", + "Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "Nastavením Bezpečného obnovenia správ na tomto zariadení znovu zašifrujete históriu šifrovaných konverzácií novou metódov obnovenia.", + "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Ak ste si nenastavili nový spôsob obnovenia útočníci sa môžu pokúsiť dostať k vášmu účtu. Ihneď si v nastaveniach zmente heslo a nastavte nový spôsob obnovi.", + "Set up Secure Messages": "Nastaviť bezpečné obnovenie správ", + "Go to Settings": "Otvoriť nastavenia" } From 7df8951efa0a11415237f1bb35a8fa3fcba24a94 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 17 Jan 2019 16:30:55 +0100 Subject: [PATCH 0152/1528] wait to hide typing bar until event arrives or 5s timeout --- src/components/views/rooms/WhoIsTypingTile.js | 89 +++++++++++++++++-- 1 file changed, 84 insertions(+), 5 deletions(-) diff --git a/src/components/views/rooms/WhoIsTypingTile.js b/src/components/views/rooms/WhoIsTypingTile.js index 9d49c35d83..144057dfd6 100644 --- a/src/components/views/rooms/WhoIsTypingTile.js +++ b/src/components/views/rooms/WhoIsTypingTile.js @@ -19,6 +19,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import sdk from '../../../index'; import WhoIsTyping from '../../../WhoIsTyping'; +import Timer from '../../../utils/Timer'; import MatrixClientPeg from '../../../MatrixClientPeg'; import MemberAvatar from '../avatars/MemberAvatar'; @@ -43,11 +44,13 @@ module.exports = React.createClass({ getInitialState: function() { return { usersTyping: WhoIsTyping.usersTypingApartFromMe(this.props.room), + userTimers: {}, }; }, componentWillMount: function() { MatrixClientPeg.get().on("RoomMember.typing", this.onRoomMemberTyping); + MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline); }, componentDidUpdate: function(_, prevState) { @@ -64,18 +67,89 @@ module.exports = React.createClass({ const client = MatrixClientPeg.get(); if (client) { client.removeListener("RoomMember.typing", this.onRoomMemberTyping); + client.removeListener("Room.timeline", this.onRoomTimeline); + } + Object.values(this.state.userTimers).forEach((t) => t.abort()); + }, + + onRoomTimeline: function(event, room) { + if (room.roomId === this.props.room.roomId) { + console.log(`WhoIsTypingTile: incoming timeline event for ${event.getSender()}`); + this._abortUserTimer(event.getSender(), "timeline event"); } }, onRoomMemberTyping: function(ev, member) { + console.log(`WhoIsTypingTile: incoming typing event for`, ev.getContent().user_ids); + const usersTyping = WhoIsTyping.usersTypingApartFromMeAndIgnored(this.props.room); this.setState({ - usersTyping: WhoIsTyping.usersTypingApartFromMeAndIgnored(this.props.room), + userTimers: this._updateUserTimers(usersTyping), + usersTyping, }); }, - _renderTypingIndicatorAvatars: function(limit) { - let users = this.state.usersTyping; + _updateUserTimers(usersTyping) { + const usersThatStoppedTyping = this.state.usersTyping.filter((a) => { + return !usersTyping.some((b) => a.userId === b.userId); + }); + const usersThatStartedTyping = usersTyping.filter((a) => { + return !this.state.usersTyping.some((b) => a.userId === b.userId); + }); + // abort all the timers for the users that started typing again + usersThatStartedTyping.forEach((m) => { + const timer = this.state.userTimers[m.userId]; + timer && timer.abort(); + }); + // prepare new userTimers object to update state with + let userTimers = Object.assign({}, this.state.userTimers); + // remove members that started typing again + userTimers = usersThatStartedTyping.reduce((userTimers, m) => { + if (userTimers[m.userId]) { + console.log(`WhoIsTypingTile: stopping timer for ${m.userId} because started typing again`); + } + delete userTimers[m.userId]; + return userTimers; + }, userTimers); + // start timer for members that stopped typing + userTimers = usersThatStoppedTyping.reduce((userTimers, m) => { + if (!userTimers[m.userId]) { + console.log(`WhoIsTypingTile: starting 5s timer for ${m.userId}`); + const timer = new Timer(5000); + userTimers[m.userId] = timer; + timer.start(); + timer.finished().then( + () => { + console.log(`WhoIsTypingTile: elapsed 5s timer for ${m.userId}`); + this._removeUserTimer(m.userId); + }, //on elapsed + () => {/* aborted */}, + ); + } + return userTimers; + }, userTimers); + return userTimers; + }, + + _abortUserTimer: function(userId, reason) { + const timer = this.state.userTimers[userId]; + if (timer) { + console.log(`WhoIsTypingTile: aborting timer for ${userId} because ${reason}`); + timer.abort(); + this._removeUserTimer(userId); + } + }, + + _removeUserTimer: function(userId) { + const timer = this.state.userTimers[userId]; + if (timer) { + const userTimers = Object.assign({}, this.state.userTimers); + delete userTimers[userId]; + this.setState({userTimers}); + } + }, + + _renderTypingIndicatorAvatars: function(users, limit) { let othersCount = 0; if (users.length > limit) { othersCount = users.length - limit + 1; @@ -106,8 +180,13 @@ module.exports = React.createClass({ }, render: function() { + let usersTyping = this.state.usersTyping; + const stoppedUsersOnTimer = Object.keys(this.state.userTimers) + .map((userId) => this.props.room.getMember(userId)); + usersTyping = usersTyping.concat(stoppedUsersOnTimer); + const typingString = WhoIsTyping.whoIsTypingString( - this.state.usersTyping, + usersTyping, this.props.whoIsTypingLimit, ); if (!typingString) { @@ -119,7 +198,7 @@ module.exports = React.createClass({ return (
  • - { this._renderTypingIndicatorAvatars(this.props.whoIsTypingLimit) } + { this._renderTypingIndicatorAvatars(usersTyping, this.props.whoIsTypingLimit) }
    { typingString } From b551d2f43a0a1fb2f23f32e9e832a49d662b5fe4 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 17 Jan 2019 16:45:00 +0000 Subject: [PATCH 0153/1528] Say when backup is signed by unknown device rather than say it isn't signed by any devices https://github.com/vector-im/riot-web/issues/8142 Requires https://github.com/matrix-org/matrix-js-sdk/pull/826 --- src/components/views/settings/KeyBackupPanel.js | 13 +++++++++---- src/i18n/strings/en_EN.json | 9 ++++----- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/components/views/settings/KeyBackupPanel.js b/src/components/views/settings/KeyBackupPanel.js index b1c94c3067..473b52ff12 100644 --- a/src/components/views/settings/KeyBackupPanel.js +++ b/src/components/views/settings/KeyBackupPanel.js @@ -186,18 +186,23 @@ export default class KeyBackupPanel extends React.PureComponent { } let backupSigStatuses = this.state.backupSigStatus.sigs.map((sig, i) => { - const deviceName = sig.device.getDisplayName() || sig.device.deviceId; + const deviceName = sig.device ? (sig.device.getDisplayName() || sig.device.deviceId) : null; const validity = sub => {sub} ; const verify = sub => - + {sub} ; const device = sub => {deviceName}; let sigStatus; - if (sig.device.getFingerprint() === MatrixClientPeg.get().getDeviceEd25519Key()) { + if (!sig.device) { + sigStatus = _t( + "Backup has a signature from unknown device with ID %(deviceId)s.", + { deviceId: sig.deviceId }, { verify }, + ); + } else if (sig.device.getFingerprint() === MatrixClientPeg.get().getDeviceEd25519Key()) { sigStatus = _t( "Backup has a valid signature from this device", {}, { validity }, @@ -229,7 +234,7 @@ export default class KeyBackupPanel extends React.PureComponent { } let verifyButton; - if (!sig.device.isVerified()) { + if (!sig.device || !sig.device.isVerified()) { verifyButton =

    { _t("Verify...") } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index ef0ff1ebf7..f6e1fd4f5e 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -114,6 +114,8 @@ "Failed to invite": "Failed to invite", "Failed to invite users to the room:": "Failed to invite users to the room:", "Failed to invite the following users to the %(roomName)s room:": "Failed to invite the following users to the %(roomName)s room:", + "Waiting for %(userId)s to accept...": "Waiting for %(userId)s to accept...", + "Waiting for %(userId)s to confirm...": "Waiting for %(userId)s to confirm...", "You need to be logged in.": "You need to be logged in.", "You need to be able to invite users to do that.": "You need to be able to invite users to do that.", "Unable to create widget.": "Unable to create widget.", @@ -265,7 +267,6 @@ "Increase performance by only loading room members on first view": "Increase performance by only loading room members on first view", "Backup of encryption keys to server": "Backup of encryption keys to server", "Render simple counters in room header": "Render simple counters in room header", - "Allow up to 6 rooms in a community to be shown simultaneously in a grid via the context menu": "Allow up to 6 rooms in a community to be shown simultaneously in a grid via the context menu", "Disable Emoji suggestions while typing": "Disable Emoji suggestions while typing", "Use compact timeline layout": "Use compact timeline layout", "Hide removed messages": "Hide removed messages", @@ -361,6 +362,7 @@ "This device is not using key backup": "This device is not using key backup", "Backing up %(sessionsRemaining)s keys...": "Backing up %(sessionsRemaining)s keys...", "All keys backed up": "All keys backed up", + "Backup has a signature from unknown device with ID %(deviceId)s.": "Backup has a signature from unknown device with ID %(deviceId)s.", "Backup has a valid signature from this device": "Backup has a valid signature from this device", "Backup has a valid signature from verified device ": "Backup has a valid signature from verified device ", "Backup has a valid signature from unverified device ": "Backup has a valid signature from unverified device ", @@ -542,7 +544,6 @@ "Forget room": "Forget room", "Search": "Search", "Share room": "Share room", - "Toggle right panel": "Toggle right panel", "Drop here to favourite": "Drop here to favourite", "Drop here to tag direct chat": "Drop here to tag direct chat", "Drop here to restore": "Drop here to restore", @@ -644,9 +645,9 @@ "This room version is vulnerable to malicious modification of room state.": "This room version is vulnerable to malicious modification of room state.", "Click here to upgrade to the latest room version and ensure room integrity is protected.": "Click here to upgrade to the latest room version and ensure room integrity is protected.", "Only room administrators will see this warning": "Only room administrators will see this warning", - "Search…": "Search…", "This Room": "This Room", "All Rooms": "All Rooms", + "Search…": "Search…", "Cancel": "Cancel", "You don't currently have any stickerpacks enabled": "You don't currently have any stickerpacks enabled", "Add some now": "Add some now", @@ -1091,7 +1092,6 @@ "Update status": "Update status", "Set status": "Set status", "Set a new status...": "Set a new status...", - "View as Grid": "View as Grid", "View Community": "View Community", "Sorry, your browser is not able to run Riot.": "Sorry, your browser is not able to run Riot.", "Riot uses many advanced browser features, some of which are not available or experimental in your current browser.": "Riot uses many advanced browser features, some of which are not available or experimental in your current browser.", @@ -1102,7 +1102,6 @@ "You must register to use this functionality": "You must register to use this functionality", "You must join the room to see its files": "You must join the room to see its files", "There are no visible files in this room": "There are no visible files in this room", - "No room in this tile yet.": "No room in this tile yet.", "

    HTML for your community's page

    \n

    \n Use the long description to introduce new members to the community, or distribute\n some important links\n

    \n

    \n You can even use 'img' tags\n

    \n": "

    HTML for your community's page

    \n

    \n Use the long description to introduce new members to the community, or distribute\n some important links\n

    \n

    \n You can even use 'img' tags\n

    \n", "Add rooms to the community summary": "Add rooms to the community summary", "Which rooms would you like to add to this summary?": "Which rooms would you like to add to this summary?", From d787d3d821d704683b411802dee0462a69c7a8de Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 17 Jan 2019 18:26:11 +0100 Subject: [PATCH 0154/1528] clear typing bar when receiving event from user --- src/components/views/rooms/WhoIsTypingTile.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/WhoIsTypingTile.js b/src/components/views/rooms/WhoIsTypingTile.js index 144057dfd6..2097f7e99d 100644 --- a/src/components/views/rooms/WhoIsTypingTile.js +++ b/src/components/views/rooms/WhoIsTypingTile.js @@ -74,12 +74,23 @@ module.exports = React.createClass({ onRoomTimeline: function(event, room) { if (room.roomId === this.props.room.roomId) { - console.log(`WhoIsTypingTile: incoming timeline event for ${event.getSender()}`); - this._abortUserTimer(event.getSender(), "timeline event"); + const userId = event.getSender(); + const userWasTyping = this.state.usersTyping.some((m) => m.userId === userId); + if (userWasTyping) { + console.log(`WhoIsTypingTile: remove ${userId} from usersTyping`); + } + const usersTyping = this.state.usersTyping.filter((m) => m.userId !== userId); + this.setState({usersTyping}); + + if (this.state.userTimers[userId]) { + console.log(`WhoIsTypingTile: incoming timeline event for ${userId}`); + } + this._abortUserTimer(userId, "timeline event"); } }, onRoomMemberTyping: function(ev, member) { + //TODO: don't we need to check the roomId here? console.log(`WhoIsTypingTile: incoming typing event for`, ev.getContent().user_ids); const usersTyping = WhoIsTyping.usersTypingApartFromMeAndIgnored(this.props.room); this.setState({ From 1db6f1b652494741b0c84e954f22303737cb83a6 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 17 Jan 2019 18:32:46 +0100 Subject: [PATCH 0155/1528] remove logging --- src/components/views/rooms/WhoIsTypingTile.js | 25 +++---------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/src/components/views/rooms/WhoIsTypingTile.js b/src/components/views/rooms/WhoIsTypingTile.js index 2097f7e99d..c704f4fd11 100644 --- a/src/components/views/rooms/WhoIsTypingTile.js +++ b/src/components/views/rooms/WhoIsTypingTile.js @@ -75,23 +75,14 @@ module.exports = React.createClass({ onRoomTimeline: function(event, room) { if (room.roomId === this.props.room.roomId) { const userId = event.getSender(); - const userWasTyping = this.state.usersTyping.some((m) => m.userId === userId); - if (userWasTyping) { - console.log(`WhoIsTypingTile: remove ${userId} from usersTyping`); - } + // remove user from usersTyping const usersTyping = this.state.usersTyping.filter((m) => m.userId !== userId); this.setState({usersTyping}); - - if (this.state.userTimers[userId]) { - console.log(`WhoIsTypingTile: incoming timeline event for ${userId}`); - } - this._abortUserTimer(userId, "timeline event"); + this._abortUserTimer(userId); } }, onRoomMemberTyping: function(ev, member) { - //TODO: don't we need to check the roomId here? - console.log(`WhoIsTypingTile: incoming typing event for`, ev.getContent().user_ids); const usersTyping = WhoIsTyping.usersTypingApartFromMeAndIgnored(this.props.room); this.setState({ userTimers: this._updateUserTimers(usersTyping), @@ -115,24 +106,17 @@ module.exports = React.createClass({ let userTimers = Object.assign({}, this.state.userTimers); // remove members that started typing again userTimers = usersThatStartedTyping.reduce((userTimers, m) => { - if (userTimers[m.userId]) { - console.log(`WhoIsTypingTile: stopping timer for ${m.userId} because started typing again`); - } delete userTimers[m.userId]; return userTimers; }, userTimers); // start timer for members that stopped typing userTimers = usersThatStoppedTyping.reduce((userTimers, m) => { if (!userTimers[m.userId]) { - console.log(`WhoIsTypingTile: starting 5s timer for ${m.userId}`); const timer = new Timer(5000); userTimers[m.userId] = timer; timer.start(); timer.finished().then( - () => { - console.log(`WhoIsTypingTile: elapsed 5s timer for ${m.userId}`); - this._removeUserTimer(m.userId); - }, //on elapsed + () => this._removeUserTimer(m.userId), //on elapsed () => {/* aborted */}, ); } @@ -142,10 +126,9 @@ module.exports = React.createClass({ return userTimers; }, - _abortUserTimer: function(userId, reason) { + _abortUserTimer: function(userId) { const timer = this.state.userTimers[userId]; if (timer) { - console.log(`WhoIsTypingTile: aborting timer for ${userId} because ${reason}`); timer.abort(); this._removeUserTimer(userId); } From 146e651daec47d2e50450beea0c2026154ac70cb Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 17 Jan 2019 18:32:53 +0100 Subject: [PATCH 0156/1528] add comments --- src/components/views/rooms/WhoIsTypingTile.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/components/views/rooms/WhoIsTypingTile.js b/src/components/views/rooms/WhoIsTypingTile.js index c704f4fd11..f15e2c8e52 100644 --- a/src/components/views/rooms/WhoIsTypingTile.js +++ b/src/components/views/rooms/WhoIsTypingTile.js @@ -45,6 +45,11 @@ module.exports = React.createClass({ return { usersTyping: WhoIsTyping.usersTypingApartFromMe(this.props.room), userTimers: {}, + // a map with userid => Timer to delay + // hiding the "x is typing" message for a + // user so hiding it can coincide + // with the sent message by the other side + // resulting in less timeline jumpiness }; }, @@ -78,6 +83,7 @@ module.exports = React.createClass({ // remove user from usersTyping const usersTyping = this.state.usersTyping.filter((m) => m.userId !== userId); this.setState({usersTyping}); + // abort timer if any this._abortUserTimer(userId); } }, @@ -177,6 +183,9 @@ module.exports = React.createClass({ let usersTyping = this.state.usersTyping; const stoppedUsersOnTimer = Object.keys(this.state.userTimers) .map((userId) => this.props.room.getMember(userId)); + // append the users that have been reported not typing anymore + // but have a timeout timer running so they can disappear + // when a message comes in usersTyping = usersTyping.concat(stoppedUsersOnTimer); const typingString = WhoIsTyping.whoIsTypingString( From 2920deaefe10a102cf431f56c809f51aa3b0e5f9 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 17 Jan 2019 18:52:22 +0100 Subject: [PATCH 0157/1528] better naming --- src/components/views/rooms/WhoIsTypingTile.js | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/components/views/rooms/WhoIsTypingTile.js b/src/components/views/rooms/WhoIsTypingTile.js index f15e2c8e52..5a2b6afc96 100644 --- a/src/components/views/rooms/WhoIsTypingTile.js +++ b/src/components/views/rooms/WhoIsTypingTile.js @@ -44,12 +44,12 @@ module.exports = React.createClass({ getInitialState: function() { return { usersTyping: WhoIsTyping.usersTypingApartFromMe(this.props.room), - userTimers: {}, // a map with userid => Timer to delay // hiding the "x is typing" message for a // user so hiding it can coincide // with the sent message by the other side // resulting in less timeline jumpiness + delayedStopTypingTimers: {}, }; }, @@ -74,7 +74,7 @@ module.exports = React.createClass({ client.removeListener("RoomMember.typing", this.onRoomMemberTyping); client.removeListener("Room.timeline", this.onRoomTimeline); } - Object.values(this.state.userTimers).forEach((t) => t.abort()); + Object.values(this.state.delayedStopTypingTimers).forEach((t) => t.abort()); }, onRoomTimeline: function(event, room) { @@ -91,12 +91,12 @@ module.exports = React.createClass({ onRoomMemberTyping: function(ev, member) { const usersTyping = WhoIsTyping.usersTypingApartFromMeAndIgnored(this.props.room); this.setState({ - userTimers: this._updateUserTimers(usersTyping), + delayedStopTypingTimers: this._updateDelayedStopTypingTimers(usersTyping), usersTyping, }); }, - _updateUserTimers(usersTyping) { + _updateDelayedStopTypingTimers(usersTyping) { const usersThatStoppedTyping = this.state.usersTyping.filter((a) => { return !usersTyping.some((b) => a.userId === b.userId); }); @@ -105,35 +105,35 @@ module.exports = React.createClass({ }); // abort all the timers for the users that started typing again usersThatStartedTyping.forEach((m) => { - const timer = this.state.userTimers[m.userId]; + const timer = this.state.delayedStopTypingTimers[m.userId]; timer && timer.abort(); }); - // prepare new userTimers object to update state with - let userTimers = Object.assign({}, this.state.userTimers); + // prepare new delayedStopTypingTimers object to update state with + let delayedStopTypingTimers = Object.assign({}, this.state.delayedStopTypingTimers); // remove members that started typing again - userTimers = usersThatStartedTyping.reduce((userTimers, m) => { - delete userTimers[m.userId]; - return userTimers; - }, userTimers); + delayedStopTypingTimers = usersThatStartedTyping.reduce((delayedStopTypingTimers, m) => { + delete delayedStopTypingTimers[m.userId]; + return delayedStopTypingTimers; + }, delayedStopTypingTimers); // start timer for members that stopped typing - userTimers = usersThatStoppedTyping.reduce((userTimers, m) => { - if (!userTimers[m.userId]) { + delayedStopTypingTimers = usersThatStoppedTyping.reduce((delayedStopTypingTimers, m) => { + if (!delayedStopTypingTimers[m.userId]) { const timer = new Timer(5000); - userTimers[m.userId] = timer; + delayedStopTypingTimers[m.userId] = timer; timer.start(); timer.finished().then( () => this._removeUserTimer(m.userId), //on elapsed () => {/* aborted */}, ); } - return userTimers; - }, userTimers); + return delayedStopTypingTimers; + }, delayedStopTypingTimers); - return userTimers; + return delayedStopTypingTimers; }, _abortUserTimer: function(userId) { - const timer = this.state.userTimers[userId]; + const timer = this.state.delayedStopTypingTimers[userId]; if (timer) { timer.abort(); this._removeUserTimer(userId); @@ -141,11 +141,11 @@ module.exports = React.createClass({ }, _removeUserTimer: function(userId) { - const timer = this.state.userTimers[userId]; + const timer = this.state.delayedStopTypingTimers[userId]; if (timer) { - const userTimers = Object.assign({}, this.state.userTimers); - delete userTimers[userId]; - this.setState({userTimers}); + const delayedStopTypingTimers = Object.assign({}, this.state.delayedStopTypingTimers); + delete delayedStopTypingTimers[userId]; + this.setState({delayedStopTypingTimers}); } }, @@ -181,7 +181,7 @@ module.exports = React.createClass({ render: function() { let usersTyping = this.state.usersTyping; - const stoppedUsersOnTimer = Object.keys(this.state.userTimers) + const stoppedUsersOnTimer = Object.keys(this.state.delayedStopTypingTimers) .map((userId) => this.props.room.getMember(userId)); // append the users that have been reported not typing anymore // but have a timeout timer running so they can disappear From 9b6ef8af721c5cc30c4843c94ee78b56436510a6 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 17 Jan 2019 15:59:05 -0700 Subject: [PATCH 0158/1528] Add an /upgraderoom command to make upgrading easier for development --- src/SlashCommands.js | 12 ++++++++++++ src/i18n/strings/en_EN.json | 1 + 2 files changed, 13 insertions(+) diff --git a/src/SlashCommands.js b/src/SlashCommands.js index 47c6c26b45..b9fc4e4334 100644 --- a/src/SlashCommands.js +++ b/src/SlashCommands.js @@ -86,6 +86,18 @@ export const CommandMap = { hideCompletionAfterSpace: true, }), + upgraderoom: new Command({ + name: 'upgraderoom', + args: '', + description: _td('Upgrades a room to a new version'), + runFn: function(roomId, args) { + if (args) { + return success(MatrixClientPeg.get().upgradeRoom(roomId, args)); + } + return reject(this.getUsage()); + }, + }), + nick: new Command({ name: 'nick', args: '', diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index ef0ff1ebf7..eb353f2508 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -130,6 +130,7 @@ "Searches DuckDuckGo for results": "Searches DuckDuckGo for results", "/ddg is not a command": "/ddg is not a command", "To use it, just wait for autocomplete results to load and tab through them.": "To use it, just wait for autocomplete results to load and tab through them.", + "Upgrades a room to a new version": "Upgrades a room to a new version", "Changes your display nickname": "Changes your display nickname", "Changes colour scheme of current room": "Changes colour scheme of current room", "Sets the room topic": "Sets the room topic", From 9a7a8da6c06b22b0acc9323c19d63ed03f08bbdc Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 9 Jan 2019 14:46:31 -0600 Subject: [PATCH 0159/1528] Use font-family from theme in all components --- res/css/structures/_UserSettings.scss | 2 +- res/css/views/dialogs/_DevtoolsDialog.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/res/css/structures/_UserSettings.scss b/res/css/structures/_UserSettings.scss index 6fae8d6c1a..74d8c2c718 100644 --- a/res/css/structures/_UserSettings.scss +++ b/res/css/structures/_UserSettings.scss @@ -173,7 +173,7 @@ limitations under the License. padding: 0px; width: 240px; color: $input-fg-color; - font-family: 'Open Sans', Helvetica, Arial, Sans-Serif; + font-family: $font-family; font-size: 16px; } diff --git a/res/css/views/dialogs/_DevtoolsDialog.scss b/res/css/views/dialogs/_DevtoolsDialog.scss index a4a868bd11..572d6ee8c7 100644 --- a/res/css/views/dialogs/_DevtoolsDialog.scss +++ b/res/css/views/dialogs/_DevtoolsDialog.scss @@ -61,7 +61,7 @@ limitations under the License. padding: 0; width: 240px; color: $input-fg-color; - font-family: 'Open Sans', Helvetica, Arial, Sans-Serif; + font-family: $font-family; font-size: 16px; } From 7678b9c43b0d0fca601b2b72c3fcea8f0bf42ca1 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 9 Jan 2019 14:59:44 -0600 Subject: [PATCH 0160/1528] Lift font SCSS partials to theme root This means that themes which include `light/css/_base.scss` (currently Dark and Status) won't be forced to have Light's font-faces included. This only really matters for Status, which uses different fonts throughout. --- res/themes/dark/css/dark.scss | 2 +- res/themes/dharma/css/_dharma.scss | 2 -- res/themes/dharma/css/dharma.scss | 2 +- res/themes/light/css/_base.scss | 2 -- res/themes/light/css/light.scss | 2 +- 5 files changed, 3 insertions(+), 7 deletions(-) diff --git a/res/themes/dark/css/dark.scss b/res/themes/dark/css/dark.scss index b69f096db7..5cc6a0d659 100644 --- a/res/themes/dark/css/dark.scss +++ b/res/themes/dark/css/dark.scss @@ -1,4 +1,4 @@ +@import "../../light/css/_fonts.scss"; @import "../../light/css/_base.scss"; @import "_dark.scss"; @import "../../../../res/css/_components.scss"; - diff --git a/res/themes/dharma/css/_dharma.scss b/res/themes/dharma/css/_dharma.scss index c70d7f020a..2d76bd7da3 100644 --- a/res/themes/dharma/css/_dharma.scss +++ b/res/themes/dharma/css/_dharma.scss @@ -1,5 +1,3 @@ -@import "_fonts.scss"; - // XXX: check this? /* Nunito lacks combining diacritics, so these will fall through to the next font. Helevetica's diacritics however do not combine diff --git a/res/themes/dharma/css/dharma.scss b/res/themes/dharma/css/dharma.scss index 0f4db55fd2..7e3e69de34 100644 --- a/res/themes/dharma/css/dharma.scss +++ b/res/themes/dharma/css/dharma.scss @@ -1,3 +1,3 @@ +@import "_fonts.scss"; @import "_dharma.scss"; @import "../../../../res/css/_components.scss"; - diff --git a/res/themes/light/css/_base.scss b/res/themes/light/css/_base.scss index 96c179f6f5..44f9042554 100644 --- a/res/themes/light/css/_base.scss +++ b/res/themes/light/css/_base.scss @@ -1,5 +1,3 @@ -@import "_fonts.scss"; - /* Open Sans lacks combining diacritics, so these will fall through to the next font. Helevetica's diacritics however do not combine nicely with Open Sans (on OSX, at least) and result in a huge diff --git a/res/themes/light/css/light.scss b/res/themes/light/css/light.scss index 2099f41f60..62464316f4 100644 --- a/res/themes/light/css/light.scss +++ b/res/themes/light/css/light.scss @@ -1,3 +1,3 @@ +@import "_fonts.scss"; @import "_base.scss"; @import "../../../../res/css/_components.scss"; - From b2387f4cff314d26b53eb776641dc2b7a3e6b20c Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 31 Dec 2018 17:22:40 -0600 Subject: [PATCH 0161/1528] Define SCSS variable for resource dir Adds a `$res` SCSS variable set to the path from the root SCSS file to the `res` directory. This is a different base path than previously used in CSS URLs (it goes up 3 directories instead of 2), because Webpack will now be resolving images relative to the root SCSS file, so the path corresponds to a source tree location, instead of a path in the build output tree. Defining this variable has two main goals: * URLs are a bit easier to read * The path can be overridden, which is needed for external (riot-web) themes --- res/css/structures/_MyGroups.scss | 2 +- res/css/structures/_RoomSubList.scss | 4 ++-- res/css/structures/_RoomView.scss | 4 ++-- res/css/structures/_SearchBox.scss | 2 +- res/css/structures/_TagPanel.scss | 4 ++-- .../keybackup/_KeyBackupFailedDialog.scss | 2 +- res/css/views/elements/_DirectorySearchBox.scss | 4 ++-- res/css/views/elements/_ImageView.scss | 2 +- res/css/views/rooms/_EntityTile.scss | 2 +- res/css/views/rooms/_MemberList.scss | 2 +- res/css/views/rooms/_RoomTile.scss | 2 +- res/css/views/rooms/_SearchBar.scss | 4 ++-- res/css/views/rooms/_TopUnreadMessagesBar.scss | 2 +- res/css/views/rooms/_WhoIsTypingTile.scss | 2 +- res/themes/dark/css/_dark.scss | 4 ++-- res/themes/dark/css/dark.scss | 1 + res/themes/dharma/css/_dharma.scss | 6 +++--- res/themes/dharma/css/_fonts.scss | 16 ++++++++-------- res/themes/dharma/css/dharma.scss | 1 + res/themes/light/css/_base.scss | 4 ++-- res/themes/light/css/_fonts.scss | 16 ++++++++-------- res/themes/light/css/_paths.scss | 3 +++ res/themes/light/css/light.scss | 1 + 23 files changed, 48 insertions(+), 42 deletions(-) create mode 100644 res/themes/light/css/_paths.scss diff --git a/res/css/structures/_MyGroups.scss b/res/css/structures/_MyGroups.scss index f9433909a5..b3a5c4f473 100644 --- a/res/css/structures/_MyGroups.scss +++ b/res/css/structures/_MyGroups.scss @@ -54,7 +54,7 @@ limitations under the License. &:before { background-color: $accent-fg-color; - mask: url('../../img/icons-create-room.svg'); + mask: url('$(res)/img/icons-create-room.svg'); mask-repeat: no-repeat; mask-position: center; mask-size: 80%; diff --git a/res/css/structures/_RoomSubList.scss b/res/css/structures/_RoomSubList.scss index b7fe19ca89..4a60650cef 100644 --- a/res/css/structures/_RoomSubList.scss +++ b/res/css/structures/_RoomSubList.scss @@ -105,7 +105,7 @@ limitations under the License. .mx_RoomSubList_addRoom { background-color: $roomheader-addroom-color; color: $roomsublist-background; - background-image: url('../../img/icons-room-add.svg'); + background-image: url('$(res)/img/icons-room-add.svg'); background-repeat: no-repeat; background-position: center; border-radius: 10px; // 16/2 + 2 padding @@ -120,7 +120,7 @@ limitations under the License. .mx_RoomSubList_chevron { pointer-events: none; - background-image: url('../../img/topleft-chevron.svg'); + background-image: url('$(res)/img/topleft-chevron.svg'); background-repeat: no-repeat; transition: transform 0.2s ease-in; width: 10px; diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index 4a84a55cd4..a21d273475 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -116,7 +116,7 @@ limitations under the License. .mx_RoomView_messagePanelSearchSpinner { flex: 1; - background-image: url('../../img/typing-indicator-2x.gif'); + background-image: url('$(res)/img/typing-indicator-2x.gif'); background-position: center 367px; background-size: 25px; background-repeat: no-repeat; @@ -125,7 +125,7 @@ limitations under the License. .mx_RoomView_messagePanelSearchSpinner:before { background-color: $greyed-fg-color; - mask: url('../../img/feather-icons/search-input.svg'); + mask: url('$(res)/img/feather-icons/search-input.svg'); mask-repeat: no-repeat; mask-position: center; mask-size: 50px; diff --git a/res/css/structures/_SearchBox.scss b/res/css/structures/_SearchBox.scss index e559236569..9434d93bd2 100644 --- a/res/css/structures/_SearchBox.scss +++ b/res/css/structures/_SearchBox.scss @@ -16,7 +16,7 @@ limitations under the License. .mx_SearchBox_closeButton { cursor: pointer; - background-image: url('../../img/icons-close.svg'); + background-image: url('$(res)/img/icons-close.svg'); background-repeat: no-repeat; width: 16px; height: 16px; diff --git a/res/css/structures/_TagPanel.scss b/res/css/structures/_TagPanel.scss index 77eefc7e10..bf1746bd0e 100644 --- a/res/css/structures/_TagPanel.scss +++ b/res/css/structures/_TagPanel.scss @@ -130,12 +130,12 @@ limitations under the License. } .mx_TagPanel_groupsButton > .mx_GroupsButton:before { - mask: url('../../img/feather-icons/users.svg'); + mask: url('$(res)/img/feather-icons/users.svg'); mask-position: center 11px; } .mx_TagPanel_groupsButton > .mx_TagPanel_report:before { - mask: url('../../img/feather-icons/life-buoy.svg'); + mask: url('$(res)/img/feather-icons/life-buoy.svg'); mask-position: center 9px; } diff --git a/res/css/views/dialogs/keybackup/_KeyBackupFailedDialog.scss b/res/css/views/dialogs/keybackup/_KeyBackupFailedDialog.scss index 4a050b6fc4..bd703badaa 100644 --- a/res/css/views/dialogs/keybackup/_KeyBackupFailedDialog.scss +++ b/res/css/views/dialogs/keybackup/_KeyBackupFailedDialog.scss @@ -24,7 +24,7 @@ limitations under the License. padding-bottom: 10px; &:before { - mask: url("../../img/e2e/lock-warning.svg"); + mask: url("$(res)/img/e2e/lock-warning.svg"); mask-repeat: no-repeat; background-color: $primary-fg-color; content: ""; diff --git a/res/css/views/elements/_DirectorySearchBox.scss b/res/css/views/elements/_DirectorySearchBox.scss index 94a92b23ce..1a8c2b93de 100644 --- a/res/css/views/elements/_DirectorySearchBox.scss +++ b/res/css/views/elements/_DirectorySearchBox.scss @@ -44,7 +44,7 @@ input[type=text].mx_DirectorySearchBox_input:focus { padding-right: 10px; background-color: $plinth-bg-color; border-radius: 3px; - background-image: url('../../img/icon-return.svg'); + background-image: url('$(res)/img/icon-return.svg'); background-position: 8px 70%; background-repeat: no-repeat; text-indent: 18px; @@ -61,7 +61,7 @@ input[type=text].mx_DirectorySearchBox_input:focus { .mx_DirectorySearchBox_clear { display: inline-block; vertical-align: middle; - background: url('../../img/icon_context_delete.svg'); + background: url('$(res)/img/icon_context_delete.svg'); background-position: 0 50%; background-repeat: no-repeat; width: 15px; diff --git a/res/css/views/elements/_ImageView.scss b/res/css/views/elements/_ImageView.scss index 8ed0698a72..9bf23b1025 100644 --- a/res/css/views/elements/_ImageView.scss +++ b/res/css/views/elements/_ImageView.scss @@ -50,7 +50,7 @@ limitations under the License. max-height: 100%; /* object-fit hack needed for Chrome due to Chrome not re-laying-out until you refresh */ object-fit: contain; - /* background-image: url('../../img/trans.png'); */ + /* background-image: url('$(res)/img/trans.png'); */ pointer-events: all; } diff --git a/res/css/views/rooms/_EntityTile.scss b/res/css/views/rooms/_EntityTile.scss index c4d4d944a6..80b8126b54 100644 --- a/res/css/views/rooms/_EntityTile.scss +++ b/res/css/views/rooms/_EntityTile.scss @@ -22,7 +22,7 @@ limitations under the License. } .mx_EntityTile:hover { - background-image: url('../../img/member_chevron.png'); + background-image: url('$(res)/img/member_chevron.png'); background-position: center right 10px; background-repeat: no-repeat; padding-right: 30px; diff --git a/res/css/views/rooms/_MemberList.scss b/res/css/views/rooms/_MemberList.scss index 6f9491b22f..ab3b68b346 100644 --- a/res/css/views/rooms/_MemberList.scss +++ b/res/css/views/rooms/_MemberList.scss @@ -83,7 +83,7 @@ limitations under the License. .mx_MemberList_invite span { margin: 0 auto; - background-image: url('../../img/feather-icons/user-add.svg'); + background-image: url('$(res)/img/feather-icons/user-add.svg'); background-repeat: no-repeat; background-position: center left; padding-left: 25px; diff --git a/res/css/views/rooms/_RoomTile.scss b/res/css/views/rooms/_RoomTile.scss index 56ca715b51..395dcd68d9 100644 --- a/res/css/views/rooms/_RoomTile.scss +++ b/res/css/views/rooms/_RoomTile.scss @@ -29,7 +29,7 @@ limitations under the License. display: none; flex: 0 0 16px; height: 16px; - background-image: url('../../img/icon_context.svg'); + background-image: url('$(res)/img/icon_context.svg'); background-repeat: no-repeat; background-position: center; } diff --git a/res/css/views/rooms/_SearchBar.scss b/res/css/views/rooms/_SearchBar.scss index 390d6606c1..b89cb0ce13 100644 --- a/res/css/views/rooms/_SearchBar.scss +++ b/res/css/views/rooms/_SearchBar.scss @@ -32,7 +32,7 @@ limitations under the License. width: 37px; height: 37px; background-color: $accent-color; - mask: url('../../img/feather-icons/search-input.svg'); + mask: url('$(res)/img/feather-icons/search-input.svg'); mask-repeat: no-repeat; mask-position: center; } @@ -55,7 +55,7 @@ limitations under the License. .mx_SearchBar_cancel { background-color: $warning-color; - mask: url('../../img/cancel.svg'); + mask: url('$(res)/img/cancel.svg'); mask-repeat: no-repeat; mask-position: center; mask-size: 14px; diff --git a/res/css/views/rooms/_TopUnreadMessagesBar.scss b/res/css/views/rooms/_TopUnreadMessagesBar.scss index 67579552c1..a4b7a6aa51 100644 --- a/res/css/views/rooms/_TopUnreadMessagesBar.scss +++ b/res/css/views/rooms/_TopUnreadMessagesBar.scss @@ -54,7 +54,7 @@ limitations under the License. position: absolute; width: 38px; height: 38px; - mask: url('../../img/icon-jump-to-first-unread.svg'); + mask: url('$(res)/img/icon-jump-to-first-unread.svg'); mask-repeat: no-repeat; mask-position: 9px 13px; background: $roomtile-name-color; diff --git a/res/css/views/rooms/_WhoIsTypingTile.scss b/res/css/views/rooms/_WhoIsTypingTile.scss index 217a10be8d..eb51595858 100644 --- a/res/css/views/rooms/_WhoIsTypingTile.scss +++ b/res/css/views/rooms/_WhoIsTypingTile.scss @@ -61,7 +61,7 @@ limitations under the License. } .mx_WhoIsTypingTile_label > span { - background-image: url('../../img/typing-indicator-2x.gif'); + background-image: url('$(res)/img/typing-indicator-2x.gif'); background-size: 25px; background-position: left bottom; background-repeat: no-repeat; diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index 997a74e6aa..0afa6a91e1 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -149,8 +149,8 @@ $event-redacted-border-color: #000000; // event timestamp $event-timestamp-color: #acacac; -$edit-button-url: "../../img/icon_context_message_dark.svg"; -$copy-button-url: "../../img/icon_copy_message_dark.svg"; +$edit-button-url: "$(res)/img/icon_context_message_dark.svg"; +$copy-button-url: "$(res)/img/icon_copy_message_dark.svg"; // e2e $e2e-verified-color: #76cfa5; // N.B. *NOT* the same as $accent-color diff --git a/res/themes/dark/css/dark.scss b/res/themes/dark/css/dark.scss index 5cc6a0d659..a7d18fa1a6 100644 --- a/res/themes/dark/css/dark.scss +++ b/res/themes/dark/css/dark.scss @@ -1,3 +1,4 @@ +@import "../../light/css/_paths.scss"; @import "../../light/css/_fonts.scss"; @import "../../light/css/_base.scss"; @import "_dark.scss"; diff --git a/res/themes/dharma/css/_dharma.scss b/res/themes/dharma/css/_dharma.scss index 2d76bd7da3..7de20c1ed4 100644 --- a/res/themes/dharma/css/_dharma.scss +++ b/res/themes/dharma/css/_dharma.scss @@ -169,8 +169,8 @@ $event-redacted-border-color: #cccccc; // event timestamp $event-timestamp-color: #acacac; -$edit-button-url: "../../img/icon_context_message.svg"; -$copy-button-url: "../../img/icon_copy_message.svg"; +$edit-button-url: "$(res)/img/icon_context_message.svg"; +$copy-button-url: "$(res)/img/icon_copy_message.svg"; // e2e $e2e-verified-color: #76cfa5; // N.B. *NOT* the same as $accent-color @@ -273,7 +273,7 @@ input[type=search].mx_textinput_icon { // FIXME THEME - Tint by CSS rather than referencing a duplicate asset input[type=text].mx_textinput_icon.mx_textinput_search, input[type=search].mx_textinput_icon.mx_textinput_search { - background-image: url('../../img/feather-icons/search-input.svg'); + background-image: url('$(res)/img/feather-icons/search-input.svg'); } // dont search UI as not all browsers support it, diff --git a/res/themes/dharma/css/_fonts.scss b/res/themes/dharma/css/_fonts.scss index bb45432262..93fa9afbfa 100644 --- a/res/themes/dharma/css/_fonts.scss +++ b/res/themes/dharma/css/_fonts.scss @@ -11,37 +11,37 @@ font-family: 'Nunito'; font-style: italic; font-weight: 400; - src: url('../../fonts/Nunito/XRXX3I6Li01BKofIMNaDRss.ttf') format('truetype'); + src: url('$(res)/fonts/Nunito/XRXX3I6Li01BKofIMNaDRss.ttf') format('truetype'); } @font-face { font-family: 'Nunito'; font-style: italic; font-weight: 600; - src: url('../../fonts/Nunito/XRXQ3I6Li01BKofIMN5cYtvKUTo.ttf') format('truetype'); + src: url('$(res)/fonts/Nunito/XRXQ3I6Li01BKofIMN5cYtvKUTo.ttf') format('truetype'); } @font-face { font-family: 'Nunito'; font-style: italic; font-weight: 700; - src: url('../../fonts/Nunito/XRXQ3I6Li01BKofIMN44Y9vKUTo.ttf') format('truetype'); + src: url('$(res)/fonts/Nunito/XRXQ3I6Li01BKofIMN44Y9vKUTo.ttf') format('truetype'); } @font-face { font-family: 'Nunito'; font-style: normal; font-weight: 400; - src: url('../../fonts/Nunito/XRXV3I6Li01BKofINeaE.ttf') format('truetype'); + src: url('$(res)/fonts/Nunito/XRXV3I6Li01BKofINeaE.ttf') format('truetype'); } @font-face { font-family: 'Nunito'; font-style: normal; font-weight: 600; - src: url('../../fonts/Nunito/XRXW3I6Li01BKofA6sKUYevN.ttf') format('truetype'); + src: url('$(res)/fonts/Nunito/XRXW3I6Li01BKofA6sKUYevN.ttf') format('truetype'); } @font-face { font-family: 'Nunito'; font-style: normal; font-weight: 700; - src: url('../../fonts/Nunito/XRXW3I6Li01BKofAjsOUYevN.ttf') format('truetype'); + src: url('$(res)/fonts/Nunito/XRXW3I6Li01BKofAjsOUYevN.ttf') format('truetype'); } /* @@ -51,14 +51,14 @@ @font-face { font-family: 'Fira Mono'; - src: url('../../fonts/Fira_Mono/FiraMono-Regular.ttf') format('truetype'); + src: url('$(res)/fonts/Fira_Mono/FiraMono-Regular.ttf') format('truetype'); font-weight: 400; font-style: normal; } @font-face { font-family: 'Fira Mono'; - src: url('../../fonts/Fira_Mono/FiraMono-Bold.ttf') format('truetype'); + src: url('$(res)/fonts/Fira_Mono/FiraMono-Bold.ttf') format('truetype'); font-weight: 700; font-style: normal; } diff --git a/res/themes/dharma/css/dharma.scss b/res/themes/dharma/css/dharma.scss index 7e3e69de34..24dc0ce18d 100644 --- a/res/themes/dharma/css/dharma.scss +++ b/res/themes/dharma/css/dharma.scss @@ -1,3 +1,4 @@ +@import "../../light/css/_paths.scss"; @import "_fonts.scss"; @import "_dharma.scss"; @import "../../../../res/css/_components.scss"; diff --git a/res/themes/light/css/_base.scss b/res/themes/light/css/_base.scss index 44f9042554..4b3501cbaf 100644 --- a/res/themes/light/css/_base.scss +++ b/res/themes/light/css/_base.scss @@ -160,8 +160,8 @@ $event-redacted-border-color: #cccccc; // event timestamp $event-timestamp-color: #acacac; -$edit-button-url: "../../img/icon_context_message.svg"; -$copy-button-url: "../../img/icon_copy_message.svg"; +$edit-button-url: "$(res)/img/icon_context_message.svg"; +$copy-button-url: "$(res)/img/icon_copy_message.svg"; // e2e $e2e-verified-color: #76cfa5; // N.B. *NOT* the same as $accent-color diff --git a/res/themes/light/css/_fonts.scss b/res/themes/light/css/_fonts.scss index 52ac95b569..c080663acf 100644 --- a/res/themes/light/css/_fonts.scss +++ b/res/themes/light/css/_fonts.scss @@ -7,42 +7,42 @@ */ @font-face { font-family: 'Open Sans'; - src: url('../../fonts/Open_Sans/OpenSans-Regular.ttf') format('truetype'); + src: url('$(res)/fonts/Open_Sans/OpenSans-Regular.ttf') format('truetype'); font-weight: 400; font-style: normal; } @font-face { font-family: 'Open Sans'; - src: url('../../fonts/Open_Sans/OpenSans-Italic.ttf') format('truetype'); + src: url('$(res)/fonts/Open_Sans/OpenSans-Italic.ttf') format('truetype'); font-weight: 400; font-style: italic; } @font-face { font-family: 'Open Sans'; - src: url('../../fonts/Open_Sans/OpenSans-Semibold.ttf') format('truetype'); + src: url('$(res)/fonts/Open_Sans/OpenSans-Semibold.ttf') format('truetype'); font-weight: 600; font-style: normal; } @font-face { font-family: 'Open Sans'; - src: url('../../fonts/Open_Sans/OpenSans-SemiboldItalic.ttf') format('truetype'); + src: url('$(res)/fonts/Open_Sans/OpenSans-SemiboldItalic.ttf') format('truetype'); font-weight: 600; font-style: italic; } @font-face { font-family: 'Open Sans'; - src: url('../../fonts/Open_Sans/OpenSans-Bold.ttf') format('truetype'); + src: url('$(res)/fonts/Open_Sans/OpenSans-Bold.ttf') format('truetype'); font-weight: 700; font-style: normal; } @font-face { font-family: 'Open Sans'; - src: url('../../fonts/Open_Sans/OpenSans-BoldItalic.ttf') format('truetype'); + src: url('$(res)/fonts/Open_Sans/OpenSans-BoldItalic.ttf') format('truetype'); font-weight: 700; font-style: italic; } @@ -54,14 +54,14 @@ @font-face { font-family: 'Fira Mono'; - src: url('../../fonts/Fira_Mono/FiraMono-Regular.ttf') format('truetype'); + src: url('$(res)/fonts/Fira_Mono/FiraMono-Regular.ttf') format('truetype'); font-weight: 400; font-style: normal; } @font-face { font-family: 'Fira Mono'; - src: url('../../fonts/Fira_Mono/FiraMono-Bold.ttf') format('truetype'); + src: url('$(res)/fonts/Fira_Mono/FiraMono-Bold.ttf') format('truetype'); font-weight: 700; font-style: normal; } diff --git a/res/themes/light/css/_paths.scss b/res/themes/light/css/_paths.scss new file mode 100644 index 0000000000..0744347826 --- /dev/null +++ b/res/themes/light/css/_paths.scss @@ -0,0 +1,3 @@ +// Path from root SCSS file (such as `light.scss`) to `res` dir in the source tree +// This value is overridden by external themes in `riot-web`. +$res: ../../..; diff --git a/res/themes/light/css/light.scss b/res/themes/light/css/light.scss index 62464316f4..6ac8d0feba 100644 --- a/res/themes/light/css/light.scss +++ b/res/themes/light/css/light.scss @@ -1,3 +1,4 @@ +@import "_paths.scss"; @import "_fonts.scss"; @import "_base.scss"; @import "../../../../res/css/_components.scss"; From 989227d435eced84a8355629b3c20d0c1ae29a09 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Thu, 10 Jan 2019 19:18:21 -0600 Subject: [PATCH 0162/1528] Fix line length lint warnings I am about to run some code replacements that might make lines too long, so with this change I know we're starting from 0 line length warnings. --- package.json | 2 +- src/components/structures/IndicatorScrollbar.js | 6 +++++- src/components/structures/MatrixChat.js | 11 +++++++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 7b55a09948..15d1eff836 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "start:init": "babel src -d lib --source-maps --copy-files", "lint": "eslint src/", "lintall": "eslint src/ test/", - "lintwithexclusions": "eslint --max-warnings 18 --ignore-path .eslintignore.errorfiles src test", + "lintwithexclusions": "eslint --max-warnings 13 --ignore-path .eslintignore.errorfiles src test", "clean": "rimraf lib", "prepublish": "npm run clean && npm run build && git rev-parse HEAD > git-revision.txt", "test": "karma start --single-run=true --browsers ChromeHeadless", diff --git a/src/components/structures/IndicatorScrollbar.js b/src/components/structures/IndicatorScrollbar.js index 0fe246050c..c3e54ee900 100644 --- a/src/components/structures/IndicatorScrollbar.js +++ b/src/components/structures/IndicatorScrollbar.js @@ -66,7 +66,11 @@ export default class IndicatorScrollbar extends React.Component { } render() { - return ( + return ( { this.props.children } ); } diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 06ec2b5513..e5cf6a986a 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -302,7 +302,10 @@ export default React.createClass({ // will check their settings. this.setState({ defaultServerName: null, // To un-hide any secrets people might be keeping - defaultServerDiscoveryError: _t("Invalid configuration: Cannot supply a default homeserver URL and a default server name"), + defaultServerDiscoveryError: _t( + "Invalid configuration: Cannot supply a default homeserver URL and " + + "a default server name", + ), }); } @@ -1833,7 +1836,11 @@ export default React.createClass({ render: function() { // console.log(`Rendering MatrixChat with view ${this.state.view}`); - if (this.state.view === VIEWS.LOADING || this.state.view === VIEWS.LOGGING_IN || this.state.loadingDefaultHomeserver) { + if ( + this.state.view === VIEWS.LOADING || + this.state.view === VIEWS.LOGGING_IN || + this.state.loadingDefaultHomeserver + ) { const Spinner = sdk.getComponent('elements.Spinner'); return (
    From 20e296b20e4bf27f78ff57f37330a43303645175 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Thu, 10 Jan 2019 19:37:28 -0600 Subject: [PATCH 0163/1528] Convert image URLs in React to `require` calls This allows Webpack to insert the proper image URL after builds steps like adding a hash and so on. The path you supply to `require` is relative to the JS source file, just like any other would be. --- res/css/views/rooms/_EventTile.scss | 4 +-- src/Avatar.js | 2 +- src/components/structures/GroupView.js | 18 +++++------ src/components/structures/HomePage.js | 2 +- src/components/structures/MyGroups.js | 4 +-- src/components/structures/RoomDirectory.js | 2 +- src/components/structures/RoomStatusBar.js | 10 +++--- src/components/structures/RoomView.js | 8 ++--- src/components/structures/TagPanel.js | 2 +- .../structures/TopLeftMenuButton.js | 2 +- src/components/structures/UploadBar.js | 4 +-- src/components/structures/UserSettings.js | 8 ++--- .../GroupInviteTileContextMenu.js | 2 +- .../context_menus/RoomTileContextMenu.js | 32 +++++++++---------- .../views/context_menus/TagTileContextMenu.js | 4 +-- src/components/views/dialogs/BaseDialog.js | 2 +- .../views/dialogs/ChatCreateOrReuseDialog.js | 2 +- src/components/views/dialogs/ShareDialog.js | 12 +++---- .../views/directory/NetworkDropdown.js | 4 +-- .../views/elements/AddressSelector.js | 2 +- src/components/views/elements/AddressTile.js | 4 +-- .../views/elements/AppPermission.js | 2 +- src/components/views/elements/AppTile.js | 16 ++++++---- src/components/views/elements/AppWarning.js | 2 +- .../views/elements/CreateRoomButton.js | 2 +- .../views/elements/EditableItemList.js | 4 +-- src/components/views/elements/HomeButton.js | 2 +- src/components/views/elements/ImageView.js | 2 +- .../views/elements/InlineSpinner.js | 2 +- .../views/elements/ManageIntegsButton.js | 8 +++-- .../views/elements/MessageSpinner.js | 2 +- .../views/elements/RoomDirectoryButton.js | 2 +- .../views/elements/SettingsButton.js | 2 +- src/components/views/elements/Spinner.js | 2 +- .../views/elements/StartChatButton.js | 2 +- src/components/views/globals/CookieBar.js | 4 +-- src/components/views/globals/MatrixToolbar.js | 4 +-- src/components/views/globals/NewVersionBar.js | 2 +- .../views/globals/PasswordNagBar.js | 2 +- .../views/globals/UpdateCheckBar.js | 6 ++-- .../views/groups/GroupMemberInfo.js | 2 +- .../views/groups/GroupMemberList.js | 4 +-- src/components/views/groups/GroupRoomInfo.js | 2 +- src/components/views/groups/GroupRoomList.js | 4 +-- src/components/views/login/CountryDropdown.js | 2 +- src/components/views/messages/MAudioBody.js | 4 +-- src/components/views/messages/MFileBody.js | 10 +++--- src/components/views/messages/MImageBody.js | 9 ++++-- src/components/views/messages/MStickerBody.js | 2 +- src/components/views/messages/MVideoBody.js | 4 +-- src/components/views/messages/RoomCreate.js | 2 +- .../views/right_panel/GroupHeaderButtons.js | 4 +-- .../views/right_panel/RoomHeaderButtons.js | 6 ++-- .../views/room_settings/ColorSettings.js | 2 +- src/components/views/rooms/AuxPanel.js | 2 +- src/components/views/rooms/EntityTile.js | 6 ++-- src/components/views/rooms/EventTile.js | 20 ++++++++---- .../views/rooms/LinkPreviewWidget.js | 2 +- .../views/rooms/MemberDeviceInfo.js | 6 ++-- src/components/views/rooms/MemberInfo.js | 4 +-- src/components/views/rooms/MemberList.js | 2 +- src/components/views/rooms/MessageComposer.js | 26 +++++++-------- .../views/rooms/MessageComposerInput.js | 2 +- src/components/views/rooms/PinnedEventTile.js | 2 +- .../views/rooms/PinnedEventsPanel.js | 2 +- src/components/views/rooms/ReplyPreview.js | 2 +- src/components/views/rooms/RoomHeader.js | 16 +++++----- src/components/views/rooms/RoomPreviewBar.js | 2 +- src/components/views/rooms/RoomSettings.js | 6 ++-- src/components/views/rooms/RoomTile.js | 8 ++++- .../views/rooms/SearchableEntityList.js | 2 +- .../views/rooms/SimpleRoomHeader.js | 2 +- src/components/views/rooms/Stickerpicker.js | 6 ++-- .../views/settings/AddPhoneNumber.js | 2 +- src/components/views/voip/IncomingCallBox.js | 2 +- 75 files changed, 201 insertions(+), 176 deletions(-) diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss index 7fb6812c79..ee9971887e 100644 --- a/res/css/views/rooms/_EventTile.scss +++ b/res/css/views/rooms/_EventTile.scss @@ -291,8 +291,8 @@ limitations under the License. } /* always override hidden attribute for blocked and warning */ -.mx_EventTile_e2eIcon_hidden[src="img/e2e-blocked.svg"], -.mx_EventTile_e2eIcon_hidden[src="img/e2e-warning.svg"] { +.mx_EventTile_e2eIcon_hidden[src*="img/e2e-blocked.svg"], +.mx_EventTile_e2eIcon_hidden[src*="img/e2e-warning.svg"] { display: block; } diff --git a/src/Avatar.js b/src/Avatar.js index d41a3f6a79..d3df12eb49 100644 --- a/src/Avatar.js +++ b/src/Avatar.js @@ -56,6 +56,6 @@ module.exports = { for (let i = 0; i < s.length; ++i) { total += s.charCodeAt(i); } - return 'img/' + images[total % images.length] + '.png'; + return require('../res/img/' + images[total % images.length] + '.png'); }, }; diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js index 834fcd2340..8e0e5a3d32 100644 --- a/src/components/structures/GroupView.js +++ b/src/components/structures/GroupView.js @@ -125,7 +125,7 @@ const CategoryRoomList = React.createClass({ ( - +
    { _t('Add a Room') }
    @@ -226,7 +226,7 @@ const FeaturedRoom = React.createClass({ const deleteButton = this.props.editing ? Delete - +
    { _t('Add a User') }
    @@ -379,7 +379,7 @@ const FeaturedUser = React.createClass({ const deleteButton = this.props.editing ? Delete
    - +
    { _t('Add rooms to this community') } @@ -1189,7 +1189,7 @@ export default React.createClass({
    @@ -1255,7 +1255,7 @@ export default React.createClass({ ); rightButtons.push( - {_t("Cancel")} , ); @@ -1265,13 +1265,13 @@ export default React.createClass({ - + , ); } rightButtons.push( - + , ); } diff --git a/src/components/structures/HomePage.js b/src/components/structures/HomePage.js index 8f0c270513..aa17e63d73 100644 --- a/src/components/structures/HomePage.js +++ b/src/components/structures/HomePage.js @@ -108,7 +108,7 @@ class HomePage extends React.Component { if (this.context.matrixClient.isGuest()) { guestWarning = (
    - +
    { _t("You are currently using Riot anonymously as a guest.") } diff --git a/src/components/structures/MyGroups.js b/src/components/structures/MyGroups.js index c5bf74d561..7411c7e6c1 100644 --- a/src/components/structures/MyGroups.js +++ b/src/components/structures/MyGroups.js @@ -107,7 +107,7 @@ export default withMatrixClient(React.createClass({ } return
    - +
    @@ -124,7 +124,7 @@ export default withMatrixClient(React.createClass({
    {/*
    - +
    diff --git a/src/components/structures/RoomDirectory.js b/src/components/structures/RoomDirectory.js index 762185146c..1ddfa92305 100644 --- a/src/components/structures/RoomDirectory.js +++ b/src/components/structures/RoomDirectory.js @@ -571,7 +571,7 @@ module.exports = React.createClass({ const DirectorySearchBox = sdk.getComponent('elements.DirectorySearchBox'); return (
    - +
    -
    ); @@ -209,7 +209,7 @@ module.exports = React.createClass({ return ( - {_t("Scroll @@ -219,7 +219,7 @@ module.exports = React.createClass({ if (this.props.hasActiveCall) { const TintableSvg = sdk.getComponent("elements.TintableSvg"); return ( - + ); } @@ -327,7 +327,7 @@ module.exports = React.createClass({ } return
    - +
    { title } @@ -346,7 +346,7 @@ module.exports = React.createClass({ if (this._shouldShowConnectionError()) { return (
    - /!\ + /!\
    { _t('Connectivity to the server has been lost.') } diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index e93d58a3dc..c34b618645 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -1777,20 +1777,20 @@ module.exports = React.createClass({ if (call.type === "video") { zoomButton = (
    - +
    ); videoMuteButton =
    -
    ; } voiceMuteButton =
    -
    ; @@ -1802,7 +1802,7 @@ module.exports = React.createClass({ { videoMuteButton } { zoomButton } { statusBar } - +
    ; } diff --git a/src/components/structures/TagPanel.js b/src/components/structures/TagPanel.js index 7e77a64e62..af463efaf9 100644 --- a/src/components/structures/TagPanel.js +++ b/src/components/structures/TagPanel.js @@ -136,7 +136,7 @@ const TagPanel = React.createClass({ let clearButton; if (itemsSelected) { clearButton = - diff --git a/src/components/structures/TopLeftMenuButton.js b/src/components/structures/TopLeftMenuButton.js index 00e669acdd..592b64634f 100644 --- a/src/components/structures/TopLeftMenuButton.js +++ b/src/components/structures/TopLeftMenuButton.js @@ -89,7 +89,7 @@ export default class TopLeftMenuButton extends React.Component { resizeMethod="crop" /> { nameElement } - + ); } diff --git a/src/components/structures/UploadBar.js b/src/components/structures/UploadBar.js index fed4ff33b3..b54ea00c16 100644 --- a/src/components/structures/UploadBar.js +++ b/src/components/structures/UploadBar.js @@ -91,8 +91,8 @@ module.exports = React.createClass({displayName: 'UploadBar',
    - - +
    diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index d76e1c1716..65e1897137 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -1227,7 +1227,7 @@ module.exports = React.createClass({ />
    -
    @@ -1252,7 +1252,7 @@ module.exports = React.createClass({ onValueChanged={this._onAddEmailEditFinished} />
    - +
    ); @@ -1322,7 +1322,7 @@ module.exports = React.createClass({
    - {_t("Remove
    diff --git a/src/components/views/context_menus/GroupInviteTileContextMenu.js b/src/components/views/context_menus/GroupInviteTileContextMenu.js index e30acca16d..4a8a33614b 100644 --- a/src/components/views/context_menus/GroupInviteTileContextMenu.js +++ b/src/components/views/context_menus/GroupInviteTileContextMenu.js @@ -79,7 +79,7 @@ export default class GroupInviteTileContextMenu extends React.Component { render() { return
    - + { _t('Reject') }
    ; diff --git a/src/components/views/context_menus/RoomTileContextMenu.js b/src/components/views/context_menus/RoomTileContextMenu.js index 8e56c055f9..521282488e 100644 --- a/src/components/views/context_menus/RoomTileContextMenu.js +++ b/src/components/views/context_menus/RoomTileContextMenu.js @@ -245,26 +245,26 @@ module.exports = React.createClass({ return (
    - +
    - - + + { _t('All messages (noisy)') }
    - - + + { _t('All messages') }
    - - + + { _t('Mentions only') }
    - - + + { _t('Mute') }
    @@ -298,7 +298,7 @@ module.exports = React.createClass({ return (
    - + { leaveText }
    @@ -327,18 +327,18 @@ module.exports = React.createClass({ return (
    - - + + { _t('Favourite') }
    - - + + { _t('Low Priority') }
    - - + + { _t('Direct Chat') }
    diff --git a/src/components/views/context_menus/TagTileContextMenu.js b/src/components/views/context_menus/TagTileContextMenu.js index 32f5365b82..8b868e7b11 100644 --- a/src/components/views/context_menus/TagTileContextMenu.js +++ b/src/components/views/context_menus/TagTileContextMenu.js @@ -59,7 +59,7 @@ export default class TagTileContextMenu extends React.Component {
    @@ -67,7 +67,7 @@ export default class TagTileContextMenu extends React.Component {

    - + { _t('Remove') }
    ; diff --git a/src/components/views/dialogs/BaseDialog.js b/src/components/views/dialogs/BaseDialog.js index 3e9052cc34..82ea649db4 100644 --- a/src/components/views/dialogs/BaseDialog.js +++ b/src/components/views/dialogs/BaseDialog.js @@ -111,7 +111,7 @@ export default React.createClass({ let cancelButton; if (this.props.hasCancel) { cancelButton = - + ; } diff --git a/src/components/views/dialogs/ChatCreateOrReuseDialog.js b/src/components/views/dialogs/ChatCreateOrReuseDialog.js index 19b7d83717..3171c2db39 100644 --- a/src/components/views/dialogs/ChatCreateOrReuseDialog.js +++ b/src/components/views/dialogs/ChatCreateOrReuseDialog.js @@ -127,7 +127,7 @@ export default class ChatCreateOrReuseDialog extends React.Component { onClick={this.props.onNewDMClick} >
    - +
    { _t("Start new chat") }
    ; diff --git a/src/components/views/dialogs/ShareDialog.js b/src/components/views/dialogs/ShareDialog.js index f074d9b1fa..3a0b00adf2 100644 --- a/src/components/views/dialogs/ShareDialog.js +++ b/src/components/views/dialogs/ShareDialog.js @@ -26,11 +26,11 @@ import * as ContextualMenu from "../../structures/ContextualMenu"; const socials = [ { name: 'Facebook', - img: 'img/social/facebook.png', + img: require("../../../../res/img/social/facebook.png"), url: (url) => `https://www.facebook.com/sharer/sharer.php?u=${url}`, }, { name: 'Twitter', - img: 'img/social/twitter-2.png', + img: require("../../../../res/img/social/twitter-2.png"), url: (url) => `https://twitter.com/home?status=${url}`, }, /* // icon missing name: 'Google Plus', @@ -38,15 +38,15 @@ const socials = [ url: (url) => `https://plus.google.com/share?url=${url}`, },*/ { name: 'LinkedIn', - img: 'img/social/linkedin.png', + img: require("../../../../res/img/social/linkedin.png"), url: (url) => `https://www.linkedin.com/shareArticle?mini=true&url=${url}`, }, { name: 'Reddit', - img: 'img/social/reddit.png', + img: require("../../../../res/img/social/reddit.png"), url: (url) => `http://www.reddit.com/submit?url=${url}`, }, { name: 'email', - img: 'img/social/email-1.png', + img: require("../../../../res/img/social/email-1.png"), url: (url) => `mailto:?body=${url}`, }, ]; @@ -202,7 +202,7 @@ export default class ShareDialog extends React.Component {
    - +
    { diff --git a/src/components/views/directory/NetworkDropdown.js b/src/components/views/directory/NetworkDropdown.js index ad51f501fb..053849863c 100644 --- a/src/components/views/directory/NetworkDropdown.js +++ b/src/components/views/directory/NetworkDropdown.js @@ -18,7 +18,7 @@ import React from 'react'; import MatrixClientPeg from '../../../MatrixClientPeg'; import {instanceForInstanceId} from '../../../utils/DirectoryUtils'; -const DEFAULT_ICON_URL = "img/network-matrix.svg"; +const DEFAULT_ICON_URL = require("../../../../res/img/network-matrix.svg"); export default class NetworkDropdown extends React.Component { constructor(props) { @@ -191,7 +191,7 @@ export default class NetworkDropdown extends React.Component { } else if (!instance) { key = server + '_all'; name = 'Matrix'; - icon = ; + icon = ; span_class = 'mx_NetworkDropdown_menu_network'; } else { key = server + '_inst_' + instance.instance_id; diff --git a/src/components/views/elements/AddressSelector.js b/src/components/views/elements/AddressSelector.js index b4279c7f70..23e6939a24 100644 --- a/src/components/views/elements/AddressSelector.js +++ b/src/components/views/elements/AddressSelector.js @@ -150,7 +150,7 @@ export default React.createClass({ showAddress={this.props.showAddress} justified={true} networkName="vector" - networkUrl="img/search-icon-vector.svg" + networkUrl={require("../../../../res/img/search-icon-vector.svg")} />
    , ); diff --git a/src/components/views/elements/AddressTile.js b/src/components/views/elements/AddressTile.js index 16e340756a..8011a6c55f 100644 --- a/src/components/views/elements/AddressTile.js +++ b/src/components/views/elements/AddressTile.js @@ -54,7 +54,7 @@ export default React.createClass({ address.avatarMxc, 25, 25, 'crop', )); } else if (address.addressType === 'email') { - imgUrls.push('img/icon-email-user.svg'); + imgUrls.push(require("../../../../res/img/icon-email-user.svg")); } // Removing networks for now as they're not really supported @@ -141,7 +141,7 @@ export default React.createClass({ if (this.props.canDismiss) { dismiss = (
    - +
    ); } diff --git a/src/components/views/elements/AppPermission.js b/src/components/views/elements/AppPermission.js index 6b4536b620..8f4a434df0 100644 --- a/src/components/views/elements/AppPermission.js +++ b/src/components/views/elements/AppPermission.js @@ -47,7 +47,7 @@ export default class AppPermission extends React.Component { return (
    - {_t('Warning!')} + {_t('Warning!')}
    { _t('Do you want to load widget from URL:') } { this.state.curlBase } diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index f4f929a3c2..85d28baee7 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -582,19 +582,21 @@ export default class AppTile extends React.Component { // editing is done in scalar const showEditButton = Boolean(this._scalarClient && this._canUserModify()); const deleteWidgetLabel = this._deleteWidgetLabel(); - let deleteIcon = 'img/cancel_green.svg'; + let deleteIcon = require("../../../../res/img/cancel_green.svg"); let deleteClasses = 'mx_AppTileMenuBarWidget'; if (this._canUserModify()) { - deleteIcon = 'img/icon-delete-pink.svg'; + deleteIcon = require("../../../../res/img/icon-delete-pink.svg"); deleteClasses += ' mx_AppTileMenuBarWidgetDelete'; } // Picture snapshot - only show button when apps are maximised. const showPictureSnapshotButton = this._hasCapability('m.capability.screenshot') && this.props.show; - const showPictureSnapshotIcon = 'img/camera_green.svg'; - const popoutWidgetIcon = 'img/button-new-window.svg'; - const reloadWidgetIcon = 'img/button-refresh.svg'; - const windowStateIcon = (this.props.show ? 'img/minimize.svg' : 'img/maximize.svg'); + const showPictureSnapshotIcon = require("../../../../res/img/camera_green.svg"); + const popoutWidgetIcon = require("../../../../res/img/button-new-window.svg"); + const reloadWidgetIcon = require("../../../../res/img/button-refresh.svg"); + const minimizeIcon = require("../../../../res/img/minimize.svg"); + const maximizeIcon = require("../../../../res/img/maximize.svg"); + const windowStateIcon = (this.props.show ? minimizeIcon : maximizeIcon); let appTileClass; if (this.props.miniMode) { @@ -653,7 +655,7 @@ export default class AppTile extends React.Component { { /* Edit widget */ } { showEditButton && { return (
    - +
    { props.errorMsg } diff --git a/src/components/views/elements/CreateRoomButton.js b/src/components/views/elements/CreateRoomButton.js index 177d033c75..da937be3e1 100644 --- a/src/components/views/elements/CreateRoomButton.js +++ b/src/components/views/elements/CreateRoomButton.js @@ -25,7 +25,7 @@ const CreateRoomButton = function(props) { diff --git a/src/components/views/elements/EditableItemList.js b/src/components/views/elements/EditableItemList.js index 02fdc96a78..f4c016d9f2 100644 --- a/src/components/views/elements/EditableItemList.js +++ b/src/components/views/elements/EditableItemList.js @@ -62,13 +62,13 @@ const EditableItem = React.createClass({ { this.props.onAdd ?
    {_t("Add")}
    :
    {_t("Delete")}
    } diff --git a/src/components/views/elements/HomeButton.js b/src/components/views/elements/HomeButton.js index 05e21487eb..ecfce9b5f2 100644 --- a/src/components/views/elements/HomeButton.js +++ b/src/components/views/elements/HomeButton.js @@ -24,7 +24,7 @@ const HomeButton = function(props) { return ( diff --git a/src/components/views/elements/ImageView.js b/src/components/views/elements/ImageView.js index 4ac5eda170..2c0f4a0d86 100644 --- a/src/components/views/elements/ImageView.js +++ b/src/components/views/elements/ImageView.js @@ -176,7 +176,7 @@ module.exports = React.createClass({
    - { + {
    diff --git a/src/components/views/elements/InlineSpinner.js b/src/components/views/elements/InlineSpinner.js index cce4705512..f82f309493 100644 --- a/src/components/views/elements/InlineSpinner.js +++ b/src/components/views/elements/InlineSpinner.js @@ -26,7 +26,7 @@ module.exports = React.createClass({ return (
    - +
    ); }, diff --git a/src/components/views/elements/ManageIntegsButton.js b/src/components/views/elements/ManageIntegsButton.js index f45053de44..40d4cf9377 100644 --- a/src/components/views/elements/ManageIntegsButton.js +++ b/src/components/views/elements/ManageIntegsButton.js @@ -80,7 +80,11 @@ export default class ManageIntegsButton extends React.Component { }); if (this.state.scalarError && !this.scalarClient.hasCredentials()) { - integrationsWarningTriangle = ; + integrationsWarningTriangle = ; // Popup shown when hovering over integrationsButton_error (via CSS) integrationsErrorPopup = ( @@ -91,7 +95,7 @@ export default class ManageIntegsButton extends React.Component { integrationsButton = ( - + { integrationsWarningTriangle } { integrationsErrorPopup } diff --git a/src/components/views/elements/MessageSpinner.js b/src/components/views/elements/MessageSpinner.js index 500c919d45..19d804f511 100644 --- a/src/components/views/elements/MessageSpinner.js +++ b/src/components/views/elements/MessageSpinner.js @@ -27,7 +27,7 @@ module.exports = React.createClass({ return (
    { msg }
      - +
    ); }, diff --git a/src/components/views/elements/RoomDirectoryButton.js b/src/components/views/elements/RoomDirectoryButton.js index d8f88034e3..1498157ee4 100644 --- a/src/components/views/elements/RoomDirectoryButton.js +++ b/src/components/views/elements/RoomDirectoryButton.js @@ -25,7 +25,7 @@ const RoomDirectoryButton = function(props) { diff --git a/src/components/views/elements/SettingsButton.js b/src/components/views/elements/SettingsButton.js index 215d757e6c..f63d17d93c 100644 --- a/src/components/views/elements/SettingsButton.js +++ b/src/components/views/elements/SettingsButton.js @@ -24,7 +24,7 @@ const SettingsButton = function(props) { return ( diff --git a/src/components/views/elements/Spinner.js b/src/components/views/elements/Spinner.js index 67fde4bf66..ca1ee0ef42 100644 --- a/src/components/views/elements/Spinner.js +++ b/src/components/views/elements/Spinner.js @@ -27,7 +27,7 @@ module.exports = React.createClass({ const imgClass = this.props.imgClassName || ""; return (
    - +
    ); }, diff --git a/src/components/views/elements/StartChatButton.js b/src/components/views/elements/StartChatButton.js index 199c5e44a6..2132d63940 100644 --- a/src/components/views/elements/StartChatButton.js +++ b/src/components/views/elements/StartChatButton.js @@ -25,7 +25,7 @@ const StartChatButton = function(props) { diff --git a/src/components/views/globals/CookieBar.js b/src/components/views/globals/CookieBar.js index deb1cbffa8..f2bcd647d7 100644 --- a/src/components/views/globals/CookieBar.js +++ b/src/components/views/globals/CookieBar.js @@ -51,7 +51,7 @@ export default class CookieBar extends React.Component { const toolbarClasses = "mx_MatrixToolbar"; return (
    - +
    { this.props.policyUrl ? _t( "Please help improve Riot.im by sending anonymous usage data. " + @@ -95,7 +95,7 @@ export default class CookieBar extends React.Component { { _t("Yes, I want to help!") } - {_t('Close')} + {_t('Close')}
    ); diff --git a/src/components/views/globals/MatrixToolbar.js b/src/components/views/globals/MatrixToolbar.js index 400d9e0c83..efcbfcba48 100644 --- a/src/components/views/globals/MatrixToolbar.js +++ b/src/components/views/globals/MatrixToolbar.js @@ -35,11 +35,11 @@ module.exports = React.createClass({ render: function() { return (
    - +
    { _t('You are not receiving desktop notifications') } { _t('Enable them now') }
    - {_t('Close')} + {_t('Close')}
    ); }, diff --git a/src/components/views/globals/NewVersionBar.js b/src/components/views/globals/NewVersionBar.js index 47eed4dc59..d802af63d4 100644 --- a/src/components/views/globals/NewVersionBar.js +++ b/src/components/views/globals/NewVersionBar.js @@ -96,7 +96,7 @@ export default React.createClass({ } return (
    - +
    {_t("A new version of Riot is available.")}
    diff --git a/src/components/views/globals/PasswordNagBar.js b/src/components/views/globals/PasswordNagBar.js index 5e3da3ad6d..71901ad922 100644 --- a/src/components/views/globals/PasswordNagBar.js +++ b/src/components/views/globals/PasswordNagBar.js @@ -31,7 +31,7 @@ export default React.createClass({ return (
    ; + image = ; } else { - image = ; + image = ; } return ( @@ -83,7 +83,7 @@ export default React.createClass({ {message}
    - {_t('Close')} + {_t('Close')}
    ); diff --git a/src/components/views/groups/GroupMemberInfo.js b/src/components/views/groups/GroupMemberInfo.js index ca59075912..aa40f1c8b3 100644 --- a/src/components/views/groups/GroupMemberInfo.js +++ b/src/components/views/groups/GroupMemberInfo.js @@ -188,7 +188,7 @@ module.exports = React.createClass({
    - +
    { avatar } diff --git a/src/components/views/groups/GroupMemberList.js b/src/components/views/groups/GroupMemberList.js index 9a8196f12b..9045c92a2e 100644 --- a/src/components/views/groups/GroupMemberList.js +++ b/src/components/views/groups/GroupMemberList.js @@ -87,7 +87,7 @@ export default React.createClass({ const text = _t("and %(count)s others...", { count: overflowCount }); return ( + } name={text} presenceState="online" suppressOnHover={true} onClick={this._showFullMemberList} /> ); @@ -214,7 +214,7 @@ export default React.createClass({ onClick={this.onInviteToGroupButtonClick} >
    - +
    { _t('Invite to this community') }
    ); diff --git a/src/components/views/groups/GroupRoomInfo.js b/src/components/views/groups/GroupRoomInfo.js index 41e5f68736..05c6b9cfd4 100644 --- a/src/components/views/groups/GroupRoomInfo.js +++ b/src/components/views/groups/GroupRoomInfo.js @@ -215,7 +215,7 @@ module.exports = React.createClass({
    - +
    { avatar } diff --git a/src/components/views/groups/GroupRoomList.js b/src/components/views/groups/GroupRoomList.js index 81fcfa8c8b..ec41cd036b 100644 --- a/src/components/views/groups/GroupRoomList.js +++ b/src/components/views/groups/GroupRoomList.js @@ -77,7 +77,7 @@ export default React.createClass({ const text = _t("and %(count)s others...", { count: overflowCount }); return ( + } name={text} presenceState="online" suppressOnHover={true} onClick={this._showFullRoomList} /> ); @@ -137,7 +137,7 @@ export default React.createClass({ onClick={this.onAddRoomToGroupButtonClick} >
    - +
    { _t('Add rooms to this community') }
    diff --git a/src/components/views/login/CountryDropdown.js b/src/components/views/login/CountryDropdown.js index 8c4467bb99..5f5dbf41a4 100644 --- a/src/components/views/login/CountryDropdown.js +++ b/src/components/views/login/CountryDropdown.js @@ -70,7 +70,7 @@ export default class CountryDropdown extends React.Component { } _flagImgForIso2(iso2) { - return ; + return ; } _getShortOption(iso2) { diff --git a/src/components/views/messages/MAudioBody.js b/src/components/views/messages/MAudioBody.js index efc6c4a069..b4f26d0cbd 100644 --- a/src/components/views/messages/MAudioBody.js +++ b/src/components/views/messages/MAudioBody.js @@ -81,7 +81,7 @@ export default class MAudioBody extends React.Component { if (this.state.error !== null) { return ( - + { _t("Error decrypting audio") } ); @@ -94,7 +94,7 @@ export default class MAudioBody extends React.Component { // Not sure how tall the audio player is so not sure how tall it should actually be. return ( - {content.body} + {content.body} ); } diff --git a/src/components/views/messages/MFileBody.js b/src/components/views/messages/MFileBody.js index 292ac25d42..781d340252 100644 --- a/src/components/views/messages/MFileBody.js +++ b/src/components/views/messages/MFileBody.js @@ -29,15 +29,15 @@ import request from 'browser-request'; import Modal from '../../../Modal'; -// A cached tinted copy of "img/download.svg" +// A cached tinted copy of require("../../../../res/img/download.svg") let tintedDownloadImageURL; // Track a list of mounted MFileBody instances so that we can update -// the "img/download.svg" when the tint changes. +// the require("../../../../res/img/download.svg") when the tint changes. let nextMountId = 0; const mounts = {}; /** - * Updates the tinted copy of "img/download.svg" when the tint changes. + * Updates the tinted copy of require("../../../../res/img/download.svg") when the tint changes. */ function updateTintedDownloadImage() { // Download the svg as an XML document. @@ -46,7 +46,7 @@ function updateTintedDownloadImage() { // Also note that we can't use fetch here because fetch doesn't support // file URLs, which the download image will be if we're running from // the filesystem (like in an Electron wrapper). - request({uri: "img/download.svg"}, (err, response, body) => { + request({uri: require("../../../../res/img/download.svg")}, (err, response, body) => { if (err) return; const svg = new DOMParser().parseFromString(body, "image/svg+xml"); @@ -254,7 +254,7 @@ module.exports = React.createClass({ }, tint: function() { - // Update our tinted copy of "img/download.svg" + // Update our tinted copy of require("../../../../res/img/download.svg") if (this.refs.downloadImage) { this.refs.downloadImage.src = tintedDownloadImageURL; } diff --git a/src/components/views/messages/MImageBody.js b/src/components/views/messages/MImageBody.js index dc891b86ff..dd1165cf58 100644 --- a/src/components/views/messages/MImageBody.js +++ b/src/components/views/messages/MImageBody.js @@ -282,7 +282,12 @@ export default class MImageBody extends React.Component { // e2e image hasn't been decrypted yet if (content.file !== undefined && this.state.decryptedUrl === null) { - placeholder = {content.body}; + placeholder = {content.body}; } else if (!this.state.imgLoaded) { // Deliberately, getSpinner is left unimplemented here, MStickerBody overides placeholder = this.getPlaceholder(); @@ -363,7 +368,7 @@ export default class MImageBody extends React.Component { if (this.state.error !== null) { return ( - + { _t("Error decrypting image") } ); diff --git a/src/components/views/messages/MStickerBody.js b/src/components/views/messages/MStickerBody.js index 82a530d503..55263ef7b7 100644 --- a/src/components/views/messages/MStickerBody.js +++ b/src/components/views/messages/MStickerBody.js @@ -35,7 +35,7 @@ export default class MStickerBody extends MImageBody { // img onLoad hasn't fired yet. getPlaceholder() { const TintableSVG = sdk.getComponent('elements.TintableSvg'); - return ; + return ; } // Tooltip to show on mouse over diff --git a/src/components/views/messages/MVideoBody.js b/src/components/views/messages/MVideoBody.js index 37fc94d1ed..f1199263e7 100644 --- a/src/components/views/messages/MVideoBody.js +++ b/src/components/views/messages/MVideoBody.js @@ -135,7 +135,7 @@ module.exports = React.createClass({ if (this.state.error !== null) { return ( - + { _t("Error decrypting video") } ); @@ -148,7 +148,7 @@ module.exports = React.createClass({ return (
    - {content.body} + {content.body}
    ); diff --git a/src/components/views/messages/RoomCreate.js b/src/components/views/messages/RoomCreate.js index 0bb832f8ea..592afe984a 100644 --- a/src/components/views/messages/RoomCreate.js +++ b/src/components/views/messages/RoomCreate.js @@ -48,7 +48,7 @@ module.exports = React.createClass({ return
    ; // We should never have been instaniated in this case } return
    - +
    {_t("This room is a continuation of another conversation.")}
    diff --git a/src/components/views/right_panel/GroupHeaderButtons.js b/src/components/views/right_panel/GroupHeaderButtons.js index 6fcba1d815..6867b0bb9d 100644 --- a/src/components/views/right_panel/GroupHeaderButtons.js +++ b/src/components/views/right_panel/GroupHeaderButtons.js @@ -65,12 +65,12 @@ export default class GroupHeaderButtons extends HeaderButtons { ]; return [ - , - , - , - - ./ + ./
    ); } diff --git a/src/components/views/rooms/AuxPanel.js b/src/components/views/rooms/AuxPanel.js index 5370b4d8b5..f52a3c52ab 100644 --- a/src/components/views/rooms/AuxPanel.js +++ b/src/components/views/rooms/AuxPanel.js @@ -147,7 +147,7 @@ module.exports = React.createClass({
    - +
    { _t("Drop file here to upload") }
    diff --git a/src/components/views/rooms/EntityTile.js b/src/components/views/rooms/EntityTile.js index 3f3bdbf47a..009da0ebd4 100644 --- a/src/components/views/rooms/EntityTile.js +++ b/src/components/views/rooms/EntityTile.js @@ -160,7 +160,7 @@ const EntityTile = React.createClass({ if (this.props.showInviteButton) { inviteButton = (
    - +
    ); } @@ -169,8 +169,8 @@ const EntityTile = React.createClass({ const powerStatus = this.props.powerStatus; if (powerStatus) { const src = { - [EntityTile.POWER_STATUS_MODERATOR]: "img/mod.svg", - [EntityTile.POWER_STATUS_ADMIN]: "img/admin.svg", + [EntityTile.POWER_STATUS_MODERATOR]: require("../../../../res/img/mod.svg"), + [EntityTile.POWER_STATUS_ADMIN]: require("../../../../res/img/admin.svg"), }[powerStatus]; const alt = { [EntityTile.POWER_STATUS_MODERATOR]: _t("Moderator"), diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js index 692111361a..acb122ad4e 100644 --- a/src/components/views/rooms/EventTile.js +++ b/src/components/views/rooms/EventTile.js @@ -768,23 +768,31 @@ module.exports.haveTileForEvent = function(e) { function E2ePadlockUndecryptable(props) { return ( ); } function E2ePadlockEncrypting(props) { - return ; + return ( + + ); } function E2ePadlockNotSent(props) { - return ; + return ( + + ); } function E2ePadlockVerified(props) { return ( ); } @@ -792,7 +800,7 @@ function E2ePadlockVerified(props) { function E2ePadlockUnverified(props) { return ( ); } @@ -800,7 +808,7 @@ function E2ePadlockUnverified(props) { function E2ePadlockUnencrypted(props) { return ( ); } diff --git a/src/components/views/rooms/LinkPreviewWidget.js b/src/components/views/rooms/LinkPreviewWidget.js index 7f74176878..1483fbffae 100644 --- a/src/components/views/rooms/LinkPreviewWidget.js +++ b/src/components/views/rooms/LinkPreviewWidget.js @@ -135,7 +135,7 @@ module.exports = React.createClass({
    ); diff --git a/src/components/views/rooms/MemberDeviceInfo.js b/src/components/views/rooms/MemberDeviceInfo.js index 41ed995ffb..b9c276f0d1 100644 --- a/src/components/views/rooms/MemberDeviceInfo.js +++ b/src/components/views/rooms/MemberDeviceInfo.js @@ -27,19 +27,19 @@ export default class MemberDeviceInfo extends React.Component { if (this.props.device.isBlocked()) { indicator = (
    - {_t("Blacklisted")} + {_t("Blacklisted")}
    ); } else if (this.props.device.isVerified()) { indicator = (
    - {_t("Verified")} + {_t("Verified")}
    ); } else { indicator = (
    - {_t("Unverified")} + {_t("Unverified")}
    ); } diff --git a/src/components/views/rooms/MemberInfo.js b/src/components/views/rooms/MemberInfo.js index 6a796bc160..9859861870 100644 --- a/src/components/views/rooms/MemberInfo.js +++ b/src/components/views/rooms/MemberInfo.js @@ -815,7 +815,7 @@ module.exports = withMatrixClient(React.createClass({ onClick={this.onNewDMClick} >
    - +
    { _t("Start a chat") }
    ; @@ -963,7 +963,7 @@ module.exports = withMatrixClient(React.createClass({
    - {_t('Close')} + {_t('Close')} { memberName }
    diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js index 0924a5ec38..f01ef3e3ec 100644 --- a/src/components/views/rooms/MemberList.js +++ b/src/components/views/rooms/MemberList.js @@ -253,7 +253,7 @@ module.exports = React.createClass({ const text = _t("and %(count)s others...", { count: overflowCount }); return ( + } name={text} presenceState="online" suppressOnHover={true} onClick={onClick} /> ); diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index 91ef549185..7681c2dc13 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -155,12 +155,12 @@ export default class MessageComposer extends React.Component { const fileAcceptedOrError = this.props.uploadAllowed(files[i]); if (fileAcceptedOrError === true) { acceptedFiles.push(
  • - { files[i].name || _t('Attachment') } + { files[i].name || _t('Attachment') }
  • ); fileList.push(files[i]); } else { failedFiles.push(
  • - { files[i].name || _t('Attachment') }

    { _t('Reason') + ": " + fileAcceptedOrError}

    + { files[i].name || _t('Attachment') }

    { _t('Reason') + ": " + fileAcceptedOrError}

  • ); } } @@ -320,11 +320,11 @@ export default class MessageComposer extends React.Component { const roomIsEncrypted = MatrixClientPeg.get().isRoomEncrypted(this.props.room.roomId); if (roomIsEncrypted) { // FIXME: show a /!\ if there are untrusted devices in the room... - e2eImg = 'img/e2e-verified.svg'; + e2eImg = require("../../../../res/img/e2e-verified.svg"); e2eTitle = _t('Encrypted room'); e2eClass = 'mx_MessageComposer_e2eIcon'; } else { - e2eImg = 'img/e2e-unencrypted.svg'; + e2eImg = require("../../../../res/img/e2e-unencrypted.svg"); e2eTitle = _t('Unencrypted room'); e2eClass = 'mx_MessageComposer_e2eIcon mx_filterFlipColor'; } @@ -344,16 +344,16 @@ export default class MessageComposer extends React.Component { if (this.props.callState && this.props.callState !== 'ended') { hangupButton = - {_t('Hangup')} + {_t('Hangup')} ; } else { callButton = - + ; videoCallButton = - + ; } @@ -395,7 +395,7 @@ export default class MessageComposer extends React.Component { const uploadButton = ( - + @@ -451,7 +451,7 @@ export default class MessageComposer extends React.Component { controls.push(
    - + {_t("This room has been replaced and is no longer active.")}
    @@ -487,7 +487,7 @@ export default class MessageComposer extends React.Component { title={_t(name)} onMouseDown={onFormatButtonClicked} key={name} - src={`img/button-text-${name}${suffix}.svg`} + src={require(`../../../../res/img/button-text-${name}${suffix}.svg`)} height="17" />; }, ); @@ -500,11 +500,11 @@ export default class MessageComposer extends React.Component { + src={require(`../../../../res/img/button-md-${!this.state.inputState.isRichTextEnabled}.png`)} /> + src={require("../../../../res/img/icon-text-cancel.svg")} />
    ; } diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index ff7cfcbd6d..22bc965813 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -1599,7 +1599,7 @@ export default class MessageComposerInput extends React.Component { + src={require(`../../../../res/img/button-md-${!this.state.isRichTextEnabled}.png`)} /> - {_t('Unpin + {_t('Unpin
    ); } diff --git a/src/components/views/rooms/PinnedEventsPanel.js b/src/components/views/rooms/PinnedEventsPanel.js index 50c40142da..3a0bc0e326 100644 --- a/src/components/views/rooms/PinnedEventsPanel.js +++ b/src/components/views/rooms/PinnedEventsPanel.js @@ -130,7 +130,7 @@ module.exports = React.createClass({
    - +

    { _t("Pinned Messages") }

    { tiles } diff --git a/src/components/views/rooms/ReplyPreview.js b/src/components/views/rooms/ReplyPreview.js index 46e2826634..7656d21832 100644 --- a/src/components/views/rooms/ReplyPreview.js +++ b/src/components/views/rooms/ReplyPreview.js @@ -68,7 +68,7 @@ export default class ReplyPreview extends React.Component { { '💬 ' + _t('Replying') }
    -
    diff --git a/src/components/views/rooms/RoomHeader.js b/src/components/views/rooms/RoomHeader.js index 4292fa6a4d..3cdb9237be 100644 --- a/src/components/views/rooms/RoomHeader.js +++ b/src/components/views/rooms/RoomHeader.js @@ -312,14 +312,14 @@ module.exports = React.createClass({
    - {_t("Remove - + ; } @@ -353,7 +353,7 @@ module.exports = React.createClass({ { pinsIndicator } - + ; } @@ -361,7 +361,7 @@ module.exports = React.createClass({ // if (this.props.onLeaveClick) { // leave_button = //
    -// +// //
    ; // } @@ -369,7 +369,7 @@ module.exports = React.createClass({ if (this.props.onForgetClick) { forgetButton = - + ; } @@ -377,7 +377,7 @@ module.exports = React.createClass({ if (this.props.onSearchClick && this.props.inRoom) { searchButton = - + ; } @@ -385,7 +385,7 @@ module.exports = React.createClass({ if (this.props.inRoom) { shareRoomButton = - + ; } diff --git a/src/components/views/rooms/RoomPreviewBar.js b/src/components/views/rooms/RoomPreviewBar.js index 3c767b726a..dbe409d6d7 100644 --- a/src/components/views/rooms/RoomPreviewBar.js +++ b/src/components/views/rooms/RoomPreviewBar.js @@ -124,7 +124,7 @@ module.exports = React.createClass({ emailMatchBlock =
    - /!\\ + /!\\
    { _t("This invitation was sent to an email address which is not associated with this account:") } diff --git a/src/components/views/rooms/RoomSettings.js b/src/components/views/rooms/RoomSettings.js index 8cd559f2ea..9287eb3fae 100644 --- a/src/components/views/rooms/RoomSettings.js +++ b/src/components/views/rooms/RoomSettings.js @@ -616,7 +616,7 @@ module.exports = React.createClass({
    { settings } @@ -627,8 +627,8 @@ module.exports = React.createClass({
    diff --git a/src/components/views/rooms/RoomTile.js b/src/components/views/rooms/RoomTile.js index 1a17fcf5ea..ed214812b5 100644 --- a/src/components/views/rooms/RoomTile.js +++ b/src/components/views/rooms/RoomTile.js @@ -392,7 +392,13 @@ module.exports = React.createClass({ let dmIndicator; if (this._isDirectMessageRoom(this.props.room.roomId)) { - dmIndicator = dm; + dmIndicator = dm; } return + } name={text} presenceState="online" suppressOnHover={true} onClick={this._showAll} /> ); diff --git a/src/components/views/rooms/SimpleRoomHeader.js b/src/components/views/rooms/SimpleRoomHeader.js index 249ba8b93a..4ced9fb351 100644 --- a/src/components/views/rooms/SimpleRoomHeader.js +++ b/src/components/views/rooms/SimpleRoomHeader.js @@ -26,7 +26,7 @@ export function CancelButton(props) { return ( - {_t("Cancel")} ); diff --git a/src/components/views/rooms/Stickerpicker.js b/src/components/views/rooms/Stickerpicker.js index c7d9f890a7..b8fe3afb97 100644 --- a/src/components/views/rooms/Stickerpicker.js +++ b/src/components/views/rooms/Stickerpicker.js @@ -152,7 +152,7 @@ export default class Stickerpicker extends React.Component { className='mx_Stickers_contentPlaceholder'>

    { _t("You don't currently have any stickerpacks enabled") }

    { _t("Add some now") }

    - +
    ); } @@ -351,7 +351,7 @@ export default class Stickerpicker extends React.Component { onClick={this._onHideStickersClick} ref='target' title={_t("Hide Stickers")}> - + ; } else { // Show show-stickers button @@ -362,7 +362,7 @@ export default class Stickerpicker extends React.Component { className="mx_MessageComposer_stickers" onClick={this._onShowStickersClick} title={_t("Show Stickers")}> - + ; } return
    diff --git a/src/components/views/settings/AddPhoneNumber.js b/src/components/views/settings/AddPhoneNumber.js index 64822ace5f..82169c9868 100644 --- a/src/components/views/settings/AddPhoneNumber.js +++ b/src/components/views/settings/AddPhoneNumber.js @@ -166,7 +166,7 @@ export default withMatrixClient(React.createClass({
    - +
    ); diff --git a/src/components/views/voip/IncomingCallBox.js b/src/components/views/voip/IncomingCallBox.js index 6cbaabe602..43c339d182 100644 --- a/src/components/views/voip/IncomingCallBox.js +++ b/src/components/views/voip/IncomingCallBox.js @@ -66,7 +66,7 @@ module.exports = React.createClass({ const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); return (
    - +
    { incomingCallText }
    From fd2b3b9fb8b7c92220ed253c34f2c86122a7d3b4 Mon Sep 17 00:00:00 2001 From: Marco Date: Fri, 18 Jan 2019 10:23:16 +0000 Subject: [PATCH 0164/1528] Translated using Weblate (German) Currently translated at 100.0% (1427 of 1427 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/de/ --- src/i18n/strings/de_DE.json | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/de_DE.json b/src/i18n/strings/de_DE.json index cb3ee96a49..1fdb424442 100644 --- a/src/i18n/strings/de_DE.json +++ b/src/i18n/strings/de_DE.json @@ -1447,5 +1447,14 @@ "Set up Secure Messages": "Richte sichere Nachrichten ein", "Go to Settings": "Gehe zu Einstellungen", "Sign in with single sign-on": "Mit Single Sign-On anmelden", - "Without setting up Secure Message Recovery, you won't be able to restore your encrypted message history if you log out or use another device.": "Wenn du die Sichere Nachrichten-Wiederherstellung nicht einrichtest, wirst du nicht in der Lage sein deine verschlüsselte Nachrichtenhistorie wiederherzustellen, wenn du dich abmeldest oder ein weiteres Gerät benutzt." + "Without setting up Secure Message Recovery, you won't be able to restore your encrypted message history if you log out or use another device.": "Wenn du die Sichere Nachrichten-Wiederherstellung nicht einrichtest, wirst du nicht in der Lage sein deine verschlüsselte Nachrichtenhistorie wiederherzustellen, wenn du dich abmeldest oder ein weiteres Gerät benutzt.", + "Waiting for %(userId)s to accept...": "Warte darauf %(userId)s anzunehmen ...", + "Waiting for %(userId)s to confirm...": "Warte auf Bestätigung für %(userId)s ...", + "Unrecognised address": "Nicht erkannte Adresse", + "User %(user_id)s may or may not exist": "Existenz der Benutzer %(user_id)s unsicher", + "Prompt before sending invites to potentially invalid matrix IDs": "Nachfragen bevor Einladungen zu möglichen ungültigen Matrix IDs gesendet werden", + "The following users may not exist": "Eventuell existieren folgende Benutzer nicht", + "Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "Profile für die unteren Matrix IDs wurden nicht gefunden - willst Du sie trotzdem einladen?", + "Invite anyway and never warn me again": "Trotzdem einladen und mich nicht mehr warnen", + "Invite anyway": "Trotzdem einladen" } From 8b05cca7d29678d7aabc45764648b10db7890fd5 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Fri, 18 Jan 2019 10:55:00 -0600 Subject: [PATCH 0165/1528] Add file-loader to Karma so assets will resolve in tests --- karma.conf.js | 4 ++++ package.json | 1 + 2 files changed, 5 insertions(+) diff --git a/karma.conf.js b/karma.conf.js index 4d699599cb..93063dbc04 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -168,6 +168,10 @@ module.exports = function (config) { path.resolve('./test'), ] }, + { + test: /\.(gif|png|svg|ttf)$/, + loader: 'file-loader', + }, ], noParse: [ // for cross platform compatibility use [\\\/] as the path separator diff --git a/package.json b/package.json index 15d1eff836..dc46d437ec 100644 --- a/package.json +++ b/package.json @@ -125,6 +125,7 @@ "eslint-plugin-react": "^7.7.0", "estree-walker": "^0.5.0", "expect": "^23.6.0", + "file-loader": "^3.0.1", "flow-parser": "^0.57.3", "jest-mock": "^23.2.0", "karma": "^3.0.0", From ec2d51cbbbe34c26adaa1ba5072b457022894339 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 18 Jan 2019 16:56:49 +0000 Subject: [PATCH 0166/1528] SAS verification screen matching design --- res/css/_components.scss | 1 + res/css/views/elements/_HexVerify.scss | 34 ++++++ .../views/dialogs/DeviceVerifyDialog.js | 17 ++- .../views/dialogs/IncomingSasDialog.js | 17 ++- src/components/views/elements/HexVerify.js | 104 ++++++++++++++++++ src/i18n/strings/en_EN.json | 2 +- 6 files changed, 168 insertions(+), 7 deletions(-) create mode 100644 res/css/views/elements/_HexVerify.scss create mode 100644 src/components/views/elements/HexVerify.js diff --git a/res/css/_components.scss b/res/css/_components.scss index 1e2d7ae156..70c2f17e9a 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -60,6 +60,7 @@ @import "./views/elements/_DirectorySearchBox.scss"; @import "./views/elements/_Dropdown.scss"; @import "./views/elements/_EditableItemList.scss"; +@import "./views/elements/_HexVerify.scss"; @import "./views/elements/_ImageView.scss"; @import "./views/elements/_InlineSpinner.scss"; @import "./views/elements/_MemberEventListSummary.scss"; diff --git a/res/css/views/elements/_HexVerify.scss b/res/css/views/elements/_HexVerify.scss new file mode 100644 index 0000000000..3f3ee4b7ea --- /dev/null +++ b/res/css/views/elements/_HexVerify.scss @@ -0,0 +1,34 @@ +/* +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. +*/ + +.mx_HexVerify { + text-align: center; +} + +.mx_HexVerify_pair { + display: inline-block; + font-weight: bold; + padding-left: 3px; + padding-right: 3px; +} + +.mx_HexVerify_pair_verified { + color: $accent-color; +} + +.mx_HexVerify_pair:hover{ + color: $accent-color; +} diff --git a/src/components/views/dialogs/DeviceVerifyDialog.js b/src/components/views/dialogs/DeviceVerifyDialog.js index 169dc26c52..eabae56e25 100644 --- a/src/components/views/dialogs/DeviceVerifyDialog.js +++ b/src/components/views/dialogs/DeviceVerifyDialog.js @@ -50,6 +50,7 @@ export default class DeviceVerifyDialog extends React.Component { this.state = { phase: PHASE_START, mode: SettingsStore.isFeatureEnabled("feature_sas") ? MODE_SAS : MODE_LEGACY, + sasVerified: false, }; } @@ -102,6 +103,10 @@ export default class DeviceVerifyDialog extends React.Component { }); } + _onVerifyStateChanged = (newVal) => { + this.setState({sasVerified: newVal}); + } + _onSasMatchesClick = () => { this._showSasEvent.confirm(); this.setState({ @@ -127,7 +132,6 @@ export default class DeviceVerifyDialog extends React.Component { body = this._renderSasVerificationPhaseStart(); break; case PHASE_WAIT_FOR_PARTNER_TO_ACCEPT: - //body = this._renderSasVerificationPhaseWaitForPartnerToAccept(); body = renderSasWaitAccept(this.props.userId); break; case PHASE_SHOW_SAS: @@ -180,6 +184,7 @@ export default class DeviceVerifyDialog extends React.Component { _renderSasVerificationPhaseShowSas() { const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + const HexVerify = sdk.getComponent('views.elements.HexVerify'); return

    {_t( "Verify this user by confirming the following number appears on their screen" @@ -188,9 +193,15 @@ export default class DeviceVerifyDialog extends React.Component { "For maximum security, we reccommend you do this in person or use another " + "trusted means of communication" )}

    -
    {this._showSasEvent.sas}
    + +

    {_t( + "To continue, click on each pair to confirm it's correct.", + )}

    diff --git a/src/components/views/dialogs/IncomingSasDialog.js b/src/components/views/dialogs/IncomingSasDialog.js index 732ce2a461..947c757f80 100644 --- a/src/components/views/dialogs/IncomingSasDialog.js +++ b/src/components/views/dialogs/IncomingSasDialog.js @@ -38,6 +38,7 @@ export default class IncomingSasDialog extends React.Component { this._showSasEvent = null; this.state = { phase: PHASE_START, + sasVerified: false, }; this.props.verifier.on('show_sas', this._onVerifierShowSas); this.props.verifier.on('cancel', this._onVerifierCancel); @@ -81,6 +82,10 @@ export default class IncomingSasDialog extends React.Component { }); } + _onVerifiedStateChange = (newVal) => { + this.setState({sasVerified: newVal}); + } + _onSasMatchesClick = () => { this._showSasEvent.confirm(); this.setState({ @@ -121,6 +126,7 @@ export default class IncomingSasDialog extends React.Component { _renderPhaseShowSas() { const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + const HexVerify = sdk.getComponent('views.elements.HexVerify'); return

    {_t( "Verify this user by confirming the following number appears on their screen" @@ -129,9 +135,15 @@ export default class IncomingSasDialog extends React.Component { "For maximum security, we reccommend you do this in person or use another " + "trusted means of communication" )}

    -
    {this._showSasEvent.sas}
    + +

    {_t( + "To continue, click on each pair to confirm it's correct.", + )}

    @@ -184,7 +196,6 @@ export default class IncomingSasDialog extends React.Component { } render() { - console.log("rendering pahse "+this.state.phase); let body; switch (this.state.phase) { case PHASE_START: diff --git a/src/components/views/elements/HexVerify.js b/src/components/views/elements/HexVerify.js new file mode 100644 index 0000000000..667857a792 --- /dev/null +++ b/src/components/views/elements/HexVerify.js @@ -0,0 +1,104 @@ +/* +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. +*/ + +import React from "react"; +import PropTypes from "prop-types"; +import { _t } from '../../../languageHandler'; +import classnames from 'classnames'; + +import sdk from '../../../index'; + +class HexVerifyPair extends React.Component { + static propTypes = { + text: PropTypes.string.isRequired, + index: PropTypes.number, + verified: PropTypes.bool, + onChange: PropTypes.func.isRequired, + } + + _onClick = () => { + this.setState({verified: !this.props.verified}); + this.props.onChange(this.props.index, !this.props.verified); + } + + render() { + const classNames = { + mx_HexVerify_pair: true, + mx_HexVerify_pair_verified: this.props.verified, + }; + const AccessibleButton = sdk.getComponent('views.elements.AccessibleButton'); + return + {this.props.text} + + } +} + +/** + * Helps a user verify a hexadecimal code matches one displayed + * elsewhere (eg. on a different device) + */ +export default class HexVerify extends React.Component { + static propTypes = { + text: PropTypes.string.isRequired, + onVerifiedStateChange: PropTypes.func, + } + + static defaultProps = { + onVerifiedStateChange: function() {}, + } + + constructor(props) { + super(props); + this.state = { + pairsVerified: [], + }; + for (let i = 0; i < props.text.length; i += 2) { + this.state.pairsVerified.push(false); + } + } + + _onPairChange = (index, newVal) => { + const oldVerified = this.state.pairsVerified.reduce((acc, val) => { + return acc && val; + }, true); + const newPairsVerified = this.state.pairsVerified.slice(0); + newPairsVerified[index] = newVal; + const newVerified = newPairsVerified.reduce((acc, val) => { + return acc && val; + }, true); + this.setState({pairsVerified: newPairsVerified}); + if (oldVerified !== newVerified) { + this.props.onVerifiedStateChange(newVerified); + } + } + + render() { + const pairs = []; + + for (let i = 0; i < this.props.text.length / 2; ++i) { + pairs.push(); + } + return
    + {pairs} +
    ; + } +} diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index c26330dda4..7f61a13a21 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -947,7 +947,7 @@ "Send Verification Request": "Send Verification Request", "Verify this user by confirming the following number appears on their screen": "Verify this user by confirming the following number appears on their screen", "For maximum security, we reccommend you do this in person or use another trusted means of communication": "For maximum security, we reccommend you do this in person or use another trusted means of communication", - "This Matches": "This Matches", + "To continue, click on each pair to confirm it's correct.": "To continue, click on each pair to confirm it's correct.", "Verification complete!": "Verification complete!", "Done": "Done", "%(userId)s cancelled the verification.": "%(userId)s cancelled the verification.", From c9d5c4903b3215b870a52dab4508e6b7e688cbf1 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 18 Jan 2019 18:53:54 +0100 Subject: [PATCH 0167/1528] set min-height of messagelist to current height when showing typing bar this ensures the timeline never shrinks, and avoids jumpiness when typing bar disappears again. --- src/components/structures/MessagePanel.js | 8 +++++--- src/components/structures/ScrollPanel.js | 25 +++++++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index 5fe2aae471..5383cf15dc 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -631,9 +631,11 @@ module.exports = React.createClass({ } }, - _scrollDownIfAtBottom: function() { + _onTypingVisible: function() { const scrollPanel = this.refs.scrollPanel; - if (scrollPanel) { + if (scrollPanel && scrollPanel.getScrollState().stuckAtBottom) { + scrollPanel.blockShrinking(); + // scroll down if at bottom scrollPanel.checkScroll(); } }, @@ -666,7 +668,7 @@ module.exports = React.createClass({ let whoIsTyping; if (this.props.room) { - whoIsTyping = (); + whoIsTyping = (); } return ( diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index 0fdbc9a349..91a9f1ddfa 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -223,6 +223,8 @@ module.exports = React.createClass({ onResize: function() { this.props.onResize(); + // clear min-height as the height might have changed + this.clearBlockShrinking(); this.checkScroll(); if (this._gemScroll) this._gemScroll.forceUpdate(); }, @@ -372,6 +374,8 @@ module.exports = React.createClass({ } this._unfillDebouncer = setTimeout(() => { this._unfillDebouncer = null; + // if timeline shrinks, min-height should be cleared + this.clearBlockShrinking(); this.props.onUnfillRequest(backwards, markerScrollToken); }, UNFILL_REQUEST_DEBOUNCE_MS); } @@ -677,6 +681,27 @@ module.exports = React.createClass({ _collectGeminiScroll: function(gemScroll) { this._gemScroll = gemScroll; }, + /** + * Set the current height as the min height for the message list + * so the timeline cannot shrink. This is used to avoid + * jumping when the typing indicator gets replaced by a smaller message. + */ + blockShrinking: function() { + const messageList = this.refs.itemlist; + if (messageList) { + const currentHeight = messageList.clientHeight - 18; + messageList.style.minHeight = `${currentHeight}px`; + } + }, + /** + * Clear the previously set min height + */ + clearBlockShrinking: function() { + const messageList = this.refs.itemlist; + if (messageList) { + messageList.style.minHeight = null; + } + }, render: function() { const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); From 4f2f2f4f4ee57e1d73191d6e64fd9ab39987b70e Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 18 Jan 2019 18:24:38 +0000 Subject: [PATCH 0168/1528] Move common UI bits out to separate components --- .../views/dialogs/DeviceVerifyDialog.js | 65 ++++--------------- .../views/dialogs/IncomingSasDialog.js | 65 +++---------------- .../verification/VerificationCancelled.js | 40 ++++++++++++ .../verification/VerificationComplete.js | 42 ++++++++++++ .../views/verification/VerificationShowSas.js | 65 +++++++++++++++++++ src/i18n/strings/en_EN.json | 25 +++---- 6 files changed, 184 insertions(+), 118 deletions(-) create mode 100644 src/components/views/verification/VerificationCancelled.js create mode 100644 src/components/views/verification/VerificationComplete.js create mode 100644 src/components/views/verification/VerificationShowSas.js diff --git a/src/components/views/dialogs/DeviceVerifyDialog.js b/src/components/views/dialogs/DeviceVerifyDialog.js index eabae56e25..cc5c8c6ef9 100644 --- a/src/components/views/dialogs/DeviceVerifyDialog.js +++ b/src/components/views/dialogs/DeviceVerifyDialog.js @@ -103,10 +103,6 @@ export default class DeviceVerifyDialog extends React.Component { }); } - _onVerifyStateChanged = (newVal) => { - this.setState({sasVerified: newVal}); - } - _onSasMatchesClick = () => { this._showSasEvent.confirm(); this.setState({ @@ -170,10 +166,16 @@ export default class DeviceVerifyDialog extends React.Component { {_t("Use Legacy Verification (for older clients)")}

    - { _t("Do clicky clicky button press request verify user send to do.") } + { _t("Verify by comparing a short text string.") } +

    +

    + {_t( + "For maximum security, we recommend you do this in person or " + + "use another trusted means of communication.", + )}

    -

    {_t( - "Verify this user by confirming the following number appears on their screen" - )}

    -

    {_t( - "For maximum security, we reccommend you do this in person or use another " + - "trusted means of communication" - )}

    - -

    {_t( - "To continue, click on each pair to confirm it's correct.", - )}

    - -
    ; + const VerificationShowSas = sdk.getComponent('views.verification.VerificationShowSas'); + return } _renderSasVerificationPhaseWaitForPartnerToConfirm() { @@ -219,31 +200,13 @@ export default class DeviceVerifyDialog extends React.Component { } _renderSasVerificationPhaseVerified() { - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); - return
    -

    {_t("Verification complete!")}

    - -
    ; + const VerificationComplete = sdk.getComponent('views.verification.VerificationComplete'); + return } _renderSasVerificationPhaseCancelled() { - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); - - return ( -
    -

    {_t( - "%(userId)s cancelled the verification.", {userId: this.props.userId}, - )}

    - -
    - ); + const VerificationCancelled = sdk.getComponent('views.verification.VerificationCancelled'); + return } _renderLegacyVerification() { diff --git a/src/components/views/dialogs/IncomingSasDialog.js b/src/components/views/dialogs/IncomingSasDialog.js index 947c757f80..331b4fc67c 100644 --- a/src/components/views/dialogs/IncomingSasDialog.js +++ b/src/components/views/dialogs/IncomingSasDialog.js @@ -82,10 +82,6 @@ export default class IncomingSasDialog extends React.Component { }); } - _onVerifiedStateChange = (newVal) => { - this.setState({sasVerified: newVal}); - } - _onSasMatchesClick = () => { this._showSasEvent.confirm(); this.setState({ @@ -125,29 +121,12 @@ export default class IncomingSasDialog extends React.Component { } _renderPhaseShowSas() { - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); - const HexVerify = sdk.getComponent('views.elements.HexVerify'); - return
    -

    {_t( - "Verify this user by confirming the following number appears on their screen" - )}

    -

    {_t( - "For maximum security, we reccommend you do this in person or use another " + - "trusted means of communication" - )}

    - -

    {_t( - "To continue, click on each pair to confirm it's correct.", - )}

    - -
    ; + const VerificationShowSas = sdk.getComponent('views.verification.VerificationShowSas'); + return } _renderPhaseWaitForPartnerToConfirm() { @@ -162,37 +141,13 @@ export default class IncomingSasDialog extends React.Component { } _renderPhaseVerified() { - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); - - return ( -
    -

    {_t( - "Verification Complete!" - )}

    - -
    - ); + const VerificationComplete = sdk.getComponent('views.verification.VerificationComplete'); + return } _renderPhaseCancelled() { - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); - - return ( -
    -

    {_t( - "The other party cancelled the verification." - )}

    - -
    - ); + const VerificationCancelled = sdk.getComponent('views.verification.VerificationCancelled'); + return } render() { diff --git a/src/components/views/verification/VerificationCancelled.js b/src/components/views/verification/VerificationCancelled.js new file mode 100644 index 0000000000..7c08d9eb07 --- /dev/null +++ b/src/components/views/verification/VerificationCancelled.js @@ -0,0 +1,40 @@ +/* +Copyright 2019 Vector Creations Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from 'react'; +import PropTypes from 'prop-types'; +import sdk from '../../../index'; +import { _t } from '../../../languageHandler'; + +export default class VerificationCancelled extends React.Component { + static propTypes = { + onDone: PropTypes.func.isRequired, + } + + render() { + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + return
    +

    {_t( + "The other party cancelled the verification.", + )}

    + +
    ; + } +}; diff --git a/src/components/views/verification/VerificationComplete.js b/src/components/views/verification/VerificationComplete.js new file mode 100644 index 0000000000..5153ae6650 --- /dev/null +++ b/src/components/views/verification/VerificationComplete.js @@ -0,0 +1,42 @@ +/* +Copyright 2019 Vector Creations Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from 'react'; +import PropTypes from 'prop-types'; +import sdk from '../../../index'; +import { _t } from '../../../languageHandler'; + +export default class VerificationComplete extends React.Component { + static propTypes = { + onDone: PropTypes.func.isRequired, + } + + render() { + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + return
    +

    {_t("Verified!")}

    +

    {_t("You've successfully verified this user.")}

    +

    {_t( + "Secure messages with this user are end-to-end encrypted and not able to be " + + "read by third parties.", + )}

    + +
    ; + } +}; diff --git a/src/components/views/verification/VerificationShowSas.js b/src/components/views/verification/VerificationShowSas.js new file mode 100644 index 0000000000..b9b5b27ac9 --- /dev/null +++ b/src/components/views/verification/VerificationShowSas.js @@ -0,0 +1,65 @@ +/* +Copyright 2019 Vector Creations Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from 'react'; +import PropTypes from 'prop-types'; +import sdk from '../../../index'; +import { _t } from '../../../languageHandler'; + +export default class VerificationShowSas extends React.Component { + static propTypes = { + onDone: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired, + sas: PropTypes.string.isRequired, + } + + constructor() { + super(); + this.state = { + sasVerified: false, + }; + } + + _onVerifiedStateChange = (newVal) => { + this.setState({sasVerified: newVal}); + } + + render() { + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + const HexVerify = sdk.getComponent('views.elements.HexVerify'); + return
    +

    {_t( + "Verify this user by confirming the following number appears on their screen" + )}

    +

    {_t( + "For maximum security, we reccommend you do this in person or use another " + + "trusted means of communication" + )}

    + +

    {_t( + "To continue, click on each pair to confirm it's correct.", + )}

    + +
    ; + } +}; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 7f61a13a21..8cac02d9bd 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -320,6 +320,16 @@ "Incoming call from %(name)s": "Incoming call from %(name)s", "Decline": "Decline", "Accept": "Accept", + "The other party cancelled the verification.": "The other party cancelled the verification.", + "Cancel": "Cancel", + "Verified!": "Verified!", + "You've successfully verified this user.": "You've successfully verified this user.", + "Secure messages with this user are end-to-end encrypted and not able to be read by third parties.": "Secure messages with this user are end-to-end encrypted and not able to be read by third parties.", + "Got It": "Got It", + "Verify this user by confirming the following number appears on their screen": "Verify this user by confirming the following number appears on their screen", + "For maximum security, we reccommend you do this in person or use another trusted means of communication": "For maximum security, we reccommend you do this in person or use another trusted means of communication", + "To continue, click on each pair to confirm it's correct.": "To continue, click on each pair to confirm it's correct.", + "Continue": "Continue", "A text message has been sent to +%(msisdn)s. Please enter the verification code it contains": "A text message has been sent to +%(msisdn)s. Please enter the verification code it contains", "Incorrect verification code": "Incorrect verification code", "Enter Code": "Enter Code", @@ -334,7 +344,6 @@ "Passwords can't be empty": "Passwords can't be empty", "Warning!": "Warning!", "Changing password will currently reset any end-to-end encryption keys on all devices, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "Changing password will currently reset any end-to-end encryption keys on all devices, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.", - "Continue": "Continue", "Export E2E room keys": "Export E2E room keys", "Do you want to set an email address?": "Do you want to set an email address?", "Current password": "Current password", @@ -648,7 +657,6 @@ "Search…": "Search…", "This Room": "This Room", "All Rooms": "All Rooms", - "Cancel": "Cancel", "You don't currently have any stickerpacks enabled": "You don't currently have any stickerpacks enabled", "Add some now": "Add some now", "Stickerpack": "Stickerpack", @@ -943,14 +951,9 @@ "password": "password", "Verify device": "Verify device", "Use Legacy Verification (for older clients)": "Use Legacy Verification (for older clients)", - "Do clicky clicky button press request verify user send to do.": "Do clicky clicky button press request verify user send to do.", - "Send Verification Request": "Send Verification Request", - "Verify this user by confirming the following number appears on their screen": "Verify this user by confirming the following number appears on their screen", - "For maximum security, we reccommend you do this in person or use another trusted means of communication": "For maximum security, we reccommend you do this in person or use another trusted means of communication", - "To continue, click on each pair to confirm it's correct.": "To continue, click on each pair to confirm it's correct.", - "Verification complete!": "Verification complete!", - "Done": "Done", - "%(userId)s cancelled the verification.": "%(userId)s cancelled the verification.", + "Verify by comparing a short text string.": "Verify by comparing a short text string.", + "For maximum security, we recommend you do this in person or use another trusted means of communication.": "For maximum security, we recommend you do this in person or use another trusted means of communication.", + "Begin Verifying": "Begin Verifying", "Use two-way text verification": "Use two-way text verification", "To verify that this device can be trusted, please contact its owner using some other means (e.g. in person or a phone call) and ask them whether the key they see in their User Settings for this device matches the key below:": "To verify that this device can be trusted, please contact its owner using some other means (e.g. in person or a phone call) and ask them whether the key they see in their User Settings for this device matches the key below:", "Device name": "Device name", @@ -976,8 +979,6 @@ "Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.": "Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.", "Verifying this user will mark their device as trusted, and also mark your device as trusted to them": "Verifying this user will mark their device as trusted, and also mark your device as trusted to them", "Waiting for partner to confirm...": "Waiting for partner to confirm...", - "Verification Complete!": "Verification Complete!", - "The other party cancelled the verification.": "The other party cancelled the verification.", "Incoming Verification Request": "Incoming Verification Request", "You added a new device '%(displayName)s', which is requesting encryption keys.": "You added a new device '%(displayName)s', which is requesting encryption keys.", "Your unverified device '%(displayName)s' is requesting encryption keys.": "Your unverified device '%(displayName)s' is requesting encryption keys.", From 630a6a479bad5e258434b7ec761777cef143d361 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 18 Jan 2019 18:43:40 +0000 Subject: [PATCH 0169/1528] Lint --- src/components/views/dialogs/DeviceVerifyDialog.js | 10 +++++++--- src/components/views/dialogs/IncomingSasDialog.js | 12 +++++------- src/components/views/elements/HexVerify.js | 7 +++---- .../views/verification/VerificationCancelled.js | 2 +- .../views/verification/VerificationComplete.js | 2 +- .../views/verification/VerificationShowSas.js | 6 +++--- 6 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/components/views/dialogs/DeviceVerifyDialog.js b/src/components/views/dialogs/DeviceVerifyDialog.js index cc5c8c6ef9..c2c754c715 100644 --- a/src/components/views/dialogs/DeviceVerifyDialog.js +++ b/src/components/views/dialogs/DeviceVerifyDialog.js @@ -186,7 +186,11 @@ export default class DeviceVerifyDialog extends React.Component { _renderSasVerificationPhaseShowSas() { const VerificationShowSas = sdk.getComponent('views.verification.VerificationShowSas'); - return + return ; } _renderSasVerificationPhaseWaitForPartnerToConfirm() { @@ -201,12 +205,12 @@ export default class DeviceVerifyDialog extends React.Component { _renderSasVerificationPhaseVerified() { const VerificationComplete = sdk.getComponent('views.verification.VerificationComplete'); - return + return ; } _renderSasVerificationPhaseCancelled() { const VerificationCancelled = sdk.getComponent('views.verification.VerificationCancelled'); - return + return ; } _renderLegacyVerification() { diff --git a/src/components/views/dialogs/IncomingSasDialog.js b/src/components/views/dialogs/IncomingSasDialog.js index 331b4fc67c..bad1377457 100644 --- a/src/components/views/dialogs/IncomingSasDialog.js +++ b/src/components/views/dialogs/IncomingSasDialog.js @@ -16,10 +16,8 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; -import MatrixClientPeg from '../../../MatrixClientPeg'; import sdk from '../../../index'; import { _t } from '../../../languageHandler'; -import {verificationMethods} from 'matrix-js-sdk/lib/crypto'; const PHASE_START = 0; const PHASE_SHOW_SAS = 1; @@ -102,13 +100,13 @@ export default class IncomingSasDialog extends React.Component {

    {_t( "Verify this user to mark them as trusted. " + "Trusting users gives you extra peace of mind when using " + - "end-to-end encrypted messages." + "end-to-end encrypted messages.", )}

    {_t( // NB. Below wording adjusted to singular 'device' until we have // cross-signing "Verifying this user will mark their device as trusted, and " + - "also mark your device as trusted to them" + "also mark your device as trusted to them", )}

    + />; } _renderPhaseWaitForPartnerToConfirm() { @@ -142,12 +140,12 @@ export default class IncomingSasDialog extends React.Component { _renderPhaseVerified() { const VerificationComplete = sdk.getComponent('views.verification.VerificationComplete'); - return + return ; } _renderPhaseCancelled() { const VerificationCancelled = sdk.getComponent('views.verification.VerificationCancelled'); - return + return ; } render() { diff --git a/src/components/views/elements/HexVerify.js b/src/components/views/elements/HexVerify.js index 667857a792..86ead3adc1 100644 --- a/src/components/views/elements/HexVerify.js +++ b/src/components/views/elements/HexVerify.js @@ -16,7 +16,6 @@ limitations under the License. import React from "react"; import PropTypes from "prop-types"; -import { _t } from '../../../languageHandler'; import classnames from 'classnames'; import sdk from '../../../index'; @@ -40,15 +39,15 @@ class HexVerifyPair extends React.Component { mx_HexVerify_pair_verified: this.props.verified, }; const AccessibleButton = sdk.getComponent('views.elements.AccessibleButton'); - return {this.props.text} - + ; } } -/** +/* * Helps a user verify a hexadecimal code matches one displayed * elsewhere (eg. on a different device) */ diff --git a/src/components/views/verification/VerificationCancelled.js b/src/components/views/verification/VerificationCancelled.js index 7c08d9eb07..b21153f2cc 100644 --- a/src/components/views/verification/VerificationCancelled.js +++ b/src/components/views/verification/VerificationCancelled.js @@ -37,4 +37,4 @@ export default class VerificationCancelled extends React.Component { />
    ; } -}; +} diff --git a/src/components/views/verification/VerificationComplete.js b/src/components/views/verification/VerificationComplete.js index 5153ae6650..59f7ff924a 100644 --- a/src/components/views/verification/VerificationComplete.js +++ b/src/components/views/verification/VerificationComplete.js @@ -39,4 +39,4 @@ export default class VerificationComplete extends React.Component { />
    ; } -}; +} diff --git a/src/components/views/verification/VerificationShowSas.js b/src/components/views/verification/VerificationShowSas.js index b9b5b27ac9..60f70e2748 100644 --- a/src/components/views/verification/VerificationShowSas.js +++ b/src/components/views/verification/VerificationShowSas.js @@ -42,11 +42,11 @@ export default class VerificationShowSas extends React.Component { const HexVerify = sdk.getComponent('views.elements.HexVerify'); return

    {_t( - "Verify this user by confirming the following number appears on their screen" + "Verify this user by confirming the following number appears on their screen", )}

    {_t( "For maximum security, we reccommend you do this in person or use another " + - "trusted means of communication" + "trusted means of communication", )}

    ; } -}; +} From 60a8d560d1b0e62e67d952338049fe12760a50a3 Mon Sep 17 00:00:00 2001 From: David Baker Date: Sat, 19 Jan 2019 11:54:01 +0000 Subject: [PATCH 0170/1528] Undo abortive first attempt at factoring out --- src/components/views/dialogs/DeviceVerifyDialog.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/components/views/dialogs/DeviceVerifyDialog.js b/src/components/views/dialogs/DeviceVerifyDialog.js index c2c754c715..68a2210814 100644 --- a/src/components/views/dialogs/DeviceVerifyDialog.js +++ b/src/components/views/dialogs/DeviceVerifyDialog.js @@ -24,7 +24,6 @@ import * as FormattingUtils from '../../../utils/FormattingUtils'; import { _t } from '../../../languageHandler'; import SettingsStore from '../../../settings/SettingsStore'; import {verificationMethods} from 'matrix-js-sdk/lib/crypto'; -import {renderSasWaitAccept} from '../../../sas_ui'; const MODE_LEGACY = 'legacy'; const MODE_SAS = 'sas'; @@ -128,7 +127,7 @@ export default class DeviceVerifyDialog extends React.Component { body = this._renderSasVerificationPhaseStart(); break; case PHASE_WAIT_FOR_PARTNER_TO_ACCEPT: - body = renderSasWaitAccept(this.props.userId); + body = this._renderSasVerificationPhaseWaitAccept(); break; case PHASE_SHOW_SAS: body = this._renderSasVerificationPhaseShowSas(); @@ -184,6 +183,17 @@ export default class DeviceVerifyDialog extends React.Component { ); } + _renderSasVerificationPhaseWaitAccept() { + const Spinner = sdk.getComponent("views.elements.Spinner"); + + return ( +
    + +

    {_t("Waiting for partner to accept...")}

    +
    + ); + } + _renderSasVerificationPhaseShowSas() { const VerificationShowSas = sdk.getComponent('views.verification.VerificationShowSas'); return Date: Sat, 19 Jan 2019 22:11:20 -0600 Subject: [PATCH 0171/1528] Add a form field component for the redesign The label moves into the border on focus and after being filled. A valid color is applied to the label and input border. Other states like invalid can be added later as needed. Adapted from @ara4n's experiment into a React component with a CSS only approach. --- res/css/_components.scss | 1 + res/css/views/elements/_Field.scss | 77 ++++++++++++++++++++++++++ res/themes/dharma/css/_dharma.scss | 7 ++- res/themes/light/css/_base.scss | 3 + src/components/views/elements/Field.js | 51 +++++++++++++++++ 5 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 res/css/views/elements/_Field.scss create mode 100644 src/components/views/elements/Field.js diff --git a/res/css/_components.scss b/res/css/_components.scss index 8f6f4d5936..6b353ba72b 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -59,6 +59,7 @@ @import "./views/elements/_DirectorySearchBox.scss"; @import "./views/elements/_Dropdown.scss"; @import "./views/elements/_EditableItemList.scss"; +@import "./views/elements/_Field.scss"; @import "./views/elements/_ImageView.scss"; @import "./views/elements/_InlineSpinner.scss"; @import "./views/elements/_MemberEventListSummary.scss"; diff --git a/res/css/views/elements/_Field.scss b/res/css/views/elements/_Field.scss new file mode 100644 index 0000000000..1b5b0b37c2 --- /dev/null +++ b/res/css/views/elements/_Field.scss @@ -0,0 +1,77 @@ +/* +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. +*/ + +/* TODO: Consider unifying with general input styles in _dharma.scss */ + +.mx_Field { + position: relative; + margin: 1em 0; +} + +.mx_Field input { + font-weight: normal; + border-radius: 4px; + transition: border-color 0.25s; + border: 1px solid $input-border-color; + padding: 8px 10px; +} + +.mx_Field input:focus { + outline: 0; + border-color: $input-valid-border-color; +} + +.mx_Field input::placeholder { + transition: color 0.25s ease-in 0s; + color: transparent; +} + +.mx_Field input:placeholder-shown:focus::placeholder { + transition: color 0.25s ease-in 0.1s; + color: $greyed-fg-color; +} + +.mx_Field label { + transition: + font-size 0.25s ease-out 0.1s, + color 0.25s ease-out 0.1s, + top 0.25s ease-out 0.1s, + background-color 0.25s ease-out 0.1s; + color: $primary-fg-color; + background-color: transparent; + font-size: 14px; + position: absolute; + left: 0px; + top: 0px; + margin: 6px 8px; + padding: 2px; +} + +.mx_Field input:focus + label, +.mx_Field input:not(:placeholder-shown) + label { + transition: + font-size 0.25s ease-out 0s, + color 0.25s ease-out 0s, + top 0.25s ease-out 0s, + background-color 0.25s ease-out 0s; + font-size: 10px; + top: -14px; + background-color: $field-focused-label-bg-color; +} + +.mx_Field input:focus + label { + color: $input-valid-border-color; +} diff --git a/res/themes/dharma/css/_dharma.scss b/res/themes/dharma/css/_dharma.scss index 7de20c1ed4..4a2bfec8e4 100644 --- a/res/themes/dharma/css/_dharma.scss +++ b/res/themes/dharma/css/_dharma.scss @@ -71,6 +71,9 @@ $input-darker-bg-color: rgba(193, 201, 214, 0.29); $input-darker-fg-color: #9fa9ba; $input-lighter-bg-color: #f2f5f8; $input-lighter-fg-color: $input-darker-fg-color; +$input-valid-border-color: #7ac9a1; + +$field-focused-label-bg-color: #ffffff; $button-bg-color: #7ac9a1; $button-fg-color: white; @@ -198,8 +201,8 @@ $memberstatus-placeholder-color: $roomtile-name-color; .mx_MatrixChat { - :not(.mx_textinput) > input[type=text], - :not(.mx_textinput) > input[type=search], + :not(.mx_textinput):not(.mx_Field) > input[type=text], + :not(.mx_textinput):not(.mx_Field) > input[type=search], .mx_textinput { display: block; margin: 9px; diff --git a/res/themes/light/css/_base.scss b/res/themes/light/css/_base.scss index 4b3501cbaf..9a3b3727a9 100644 --- a/res/themes/light/css/_base.scss +++ b/res/themes/light/css/_base.scss @@ -73,6 +73,9 @@ $button-bg-color: #7ac9a1; $button-fg-color: white; // apart from login forms, which have stronger border $strong-input-border-color: #c7c7c7; +$input-valid-border-color: #7ac9a1; + +$field-focused-label-bg-color: #ffffff; // used for UserSettings EditableText $input-underline-color: rgba(151, 151, 151, 0.5); diff --git a/src/components/views/elements/Field.js b/src/components/views/elements/Field.js new file mode 100644 index 0000000000..b74e28023d --- /dev/null +++ b/src/components/views/elements/Field.js @@ -0,0 +1,51 @@ +/* +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. +*/ + +import React from 'react'; +import PropTypes from 'prop-types'; + +export default class Field extends React.PureComponent { + static propTypes = { + // The field's id, which binds the input and label together. + id: PropTypes.string.isRequired, + // The field's type. Defaults to "text". + type: PropTypes.string, + // The field's label string. + label: PropTypes.string, + // The field's placeholder string. + placeholder: PropTypes.string, + // All other props pass through to the . + } + + render() { + const extraProps = Object.assign({}, this.props); + + // Remove explicit props + delete extraProps.id; + delete extraProps.type; + delete extraProps.placeholder; + delete extraProps.label; + + return
    + + +
    ; + } +} From 36ffbef010db6d60a4dbc9b6c4eab9ad4ebbcf7b Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Sat, 19 Jan 2019 22:29:57 -0600 Subject: [PATCH 0172/1528] Tweak comment about field ID Co-Authored-By: jryans --- src/components/views/elements/Field.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/elements/Field.js b/src/components/views/elements/Field.js index b74e28023d..428c7f1d6c 100644 --- a/src/components/views/elements/Field.js +++ b/src/components/views/elements/Field.js @@ -19,7 +19,7 @@ import PropTypes from 'prop-types'; export default class Field extends React.PureComponent { static propTypes = { - // The field's id, which binds the input and label together. + // The field's ID, which binds the input and label together. id: PropTypes.string.isRequired, // The field's type. Defaults to "text". type: PropTypes.string, From 728830e2fd19a66f8de6b8488bfc2211a7635af9 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Sat, 19 Jan 2019 20:31:06 -0600 Subject: [PATCH 0173/1528] Add rethemendex as script for easier access --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index dc46d437ec..aca3d433ad 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "scripts": { "reskindex": "node scripts/reskindex.js -h header", "reskindex:watch": "node scripts/reskindex.js -h header -w", + "rethemendex": "res/css/rethemendex.sh", "i18n": "matrix-gen-i18n", "prunei18n": "matrix-prune-i18n", "build": "npm run reskindex && npm run start:init", From efcfaed335bc66ceb6487f766bf832f667048b40 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 20 Jan 2019 14:31:06 +0000 Subject: [PATCH 0174/1528] switch to 35px high gradients --- res/css/structures/_RoomSubList.scss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/res/css/structures/_RoomSubList.scss b/res/css/structures/_RoomSubList.scss index 4a60650cef..faaf1cf462 100644 --- a/res/css/structures/_RoomSubList.scss +++ b/res/css/structures/_RoomSubList.scss @@ -155,7 +155,7 @@ limitations under the License. position: sticky; left: 0; right: 0; - height: 30px; + height: 35px; content: ""; display: block; z-index: 100; @@ -163,10 +163,10 @@ limitations under the License. } &.mx_IndicatorScrollbar_topOverflow > .mx_AutoHideScrollbar_offset { - margin-top: -30px; + margin-top: -35px; } &.mx_IndicatorScrollbar_bottomOverflow > .mx_AutoHideScrollbar_offset { - margin-bottom: -30px; + margin-bottom: -35px; } &.mx_IndicatorScrollbar_topOverflow::before { From 4c381c32ee43ba37dc475088e6ee4e3bd1c199ee Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 21 Jan 2019 11:34:13 +0000 Subject: [PATCH 0175/1528] Show verify button when we have a device to verify rather than when we don't --- src/components/views/settings/KeyBackupPanel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/settings/KeyBackupPanel.js b/src/components/views/settings/KeyBackupPanel.js index 473b52ff12..8dc817faad 100644 --- a/src/components/views/settings/KeyBackupPanel.js +++ b/src/components/views/settings/KeyBackupPanel.js @@ -234,7 +234,7 @@ export default class KeyBackupPanel extends React.PureComponent { } let verifyButton; - if (!sig.device || !sig.device.isVerified()) { + if (sig.device && !sig.device.isVerified()) { verifyButton =

    { _t("Verify...") } From 813ab4358f53484ff104992961037e3eecb114c9 Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Mon, 21 Jan 2019 13:08:52 +0000 Subject: [PATCH 0176/1528] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (1427 of 1427 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/zh_Hant/ --- src/i18n/strings/zh_Hant.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/zh_Hant.json b/src/i18n/strings/zh_Hant.json index d2c84d3c6f..f332f12bd6 100644 --- a/src/i18n/strings/zh_Hant.json +++ b/src/i18n/strings/zh_Hant.json @@ -1455,5 +1455,11 @@ "The following users may not exist": "以下的使用者可能不存在", "The following users may not exist - would you like to invite them anyways?": "以下的使用者可能不存在,您無論如何都想邀請他們嗎?", "Invite anyways and never warn me again": "總是邀請而且不要再警告我", - "Invite anyways": "總是邀請" + "Invite anyways": "總是邀請", + "Waiting for %(userId)s to accept...": "正在等待 %(userId)s 接受……", + "Waiting for %(userId)s to confirm...": "正在等待 %(userId)s 確認……", + "Prompt before sending invites to potentially invalid matrix IDs": "在傳送邀請給潛在的無效 matrix ID 前提示", + "Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "找不到下列 Matrix ID 的簡介,您無論如何都想邀請他們嗎?", + "Invite anyway and never warn me again": "無論如何都要邀請,而且不要再警告我", + "Invite anyway": "無論如何都要邀請" } From 7e0f60505e65377a216a1a1adf06d4f4f44fa8e3 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 21 Jan 2019 16:02:25 +0000 Subject: [PATCH 0177/1528] Fix settings direct chat We were expecting this function to return a string user ID, but it returned a user object Make it return a user ID and add jsdoc to say what it returns. Fixes https://github.com/vector-im/riot-web/issues/8180 --- src/Rooms.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Rooms.js b/src/Rooms.js index 6f73ea0659..c8f90ec39a 100644 --- a/src/Rooms.js +++ b/src/Rooms.js @@ -159,6 +159,10 @@ export function setDMRoom(roomId, userId) { /** * Given a room, estimate which of its members is likely to * be the target if the room were a DM room and return that user. + * + * @param {Object} room Target room + * @param {string} myUserId User ID of the current user + * @returns {string} User ID of the user that the room is probably a DM with */ function guessDMRoomTargetId(room, myUserId) { let oldestTs; @@ -173,7 +177,7 @@ function guessDMRoomTargetId(room, myUserId) { oldestTs = user.events.member.getTs(); } } - if (oldestUser) return oldestUser; + if (oldestUser) return oldestUser.userId; // if there are no joined members other than us, use the oldest member for (const user of room.currentState.getMembers()) { @@ -186,5 +190,5 @@ function guessDMRoomTargetId(room, myUserId) { } if (oldestUser === undefined) return myUserId; - return oldestUser; + return oldestUser.userId; } From 4248a2088580a3d68bd59a1a1824c3acd68f135b Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 21 Jan 2019 16:02:25 +0000 Subject: [PATCH 0178/1528] Fix settings direct chat We were expecting this function to return a string user ID, but it returned a user object Make it return a user ID and add jsdoc to say what it returns. Fixes https://github.com/vector-im/riot-web/issues/8180 --- src/Rooms.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Rooms.js b/src/Rooms.js index 6f73ea0659..c8f90ec39a 100644 --- a/src/Rooms.js +++ b/src/Rooms.js @@ -159,6 +159,10 @@ export function setDMRoom(roomId, userId) { /** * Given a room, estimate which of its members is likely to * be the target if the room were a DM room and return that user. + * + * @param {Object} room Target room + * @param {string} myUserId User ID of the current user + * @returns {string} User ID of the user that the room is probably a DM with */ function guessDMRoomTargetId(room, myUserId) { let oldestTs; @@ -173,7 +177,7 @@ function guessDMRoomTargetId(room, myUserId) { oldestTs = user.events.member.getTs(); } } - if (oldestUser) return oldestUser; + if (oldestUser) return oldestUser.userId; // if there are no joined members other than us, use the oldest member for (const user of room.currentState.getMembers()) { @@ -186,5 +190,5 @@ function guessDMRoomTargetId(room, myUserId) { } if (oldestUser === undefined) return myUserId; - return oldestUser; + return oldestUser.userId; } From 018f3d2a5ce7c501b61b1c5a9348ba437938b487 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 21 Jan 2019 17:30:02 +0100 Subject: [PATCH 0179/1528] use box-sizing: border-box to make clientHeight === actual height --- res/css/structures/_RoomView.scss | 4 ++++ src/components/structures/ScrollPanel.js | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index d8926c68e4..02d5cc67b0 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -171,6 +171,10 @@ limitations under the License. .mx_RoomView_MessageList { list-style-type: none; padding: 18px; + margin: 0; + /* needed as min-height is set to clientHeight in ScrollPanel + to prevent shrinking when WhoIsTypingTile is hidden */ + box-sizing: border-box; } .mx_RoomView_MessageList li { diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index 91a9f1ddfa..96318d64e1 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -689,7 +689,7 @@ module.exports = React.createClass({ blockShrinking: function() { const messageList = this.refs.itemlist; if (messageList) { - const currentHeight = messageList.clientHeight - 18; + const currentHeight = messageList.clientHeight; messageList.style.minHeight = `${currentHeight}px`; } }, From 25aa58f29f526baba9bb6b212fd1f67e2b385284 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 21 Jan 2019 17:35:40 +0100 Subject: [PATCH 0180/1528] increase/clear min-height on timeline on new message(s) depending on whether the typing bar is visible --- src/components/structures/MessagePanel.js | 16 +++++++++++++++- src/components/structures/TimelinePanel.js | 11 ++++++++--- src/components/views/rooms/WhoIsTypingTile.js | 4 ++++ 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index 5383cf15dc..fc3b421e89 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -640,6 +640,20 @@ module.exports = React.createClass({ } }, + updateTimelineMinHeight: function() { + const scrollPanel = this.refs.scrollPanel; + const whoIsTyping = this.refs.whoIsTyping; + const isTypingVisible = whoIsTyping && whoIsTyping.isVisible(); + + if (scrollPanel) { + if (isTypingVisible) { + scrollPanel.blockShrinking(); + } else { + scrollPanel.clearBlockShrinking(); + } + } + }, + onResize: function() { dis.dispatch({ action: 'timeline_resize' }, true); }, @@ -668,7 +682,7 @@ module.exports = React.createClass({ let whoIsTyping; if (this.props.room) { - whoIsTyping = (); + whoIsTyping = (); } return ( diff --git a/src/components/structures/TimelinePanel.js b/src/components/structures/TimelinePanel.js index ab10ec4aca..9fe83c2c2d 100644 --- a/src/components/structures/TimelinePanel.js +++ b/src/components/structures/TimelinePanel.js @@ -455,7 +455,7 @@ var TimelinePanel = React.createClass({ // const myUserId = MatrixClientPeg.get().credentials.userId; const sender = ev.sender ? ev.sender.userId : null; - var callback = null; + var callRMUpdated = false; if (sender != myUserId && !UserActivity.userCurrentlyActive()) { updatedState.readMarkerVisible = true; } else if (lastEv && this.getReadMarkerPosition() === 0) { @@ -465,11 +465,16 @@ var TimelinePanel = React.createClass({ this._setReadMarker(lastEv.getId(), lastEv.getTs(), true); updatedState.readMarkerVisible = false; updatedState.readMarkerEventId = lastEv.getId(); - callback = this.props.onReadMarkerUpdated; + callRMUpdated = true; } } - this.setState(updatedState, callback); + this.setState(updatedState, () => { + this.refs.messagePanel.updateTimelineMinHeight(); + if (callRMUpdated) { + this.props.onReadMarkerUpdated(); + } + }); }); }, diff --git a/src/components/views/rooms/WhoIsTypingTile.js b/src/components/views/rooms/WhoIsTypingTile.js index 5a2b6afc96..bef8aca0c4 100644 --- a/src/components/views/rooms/WhoIsTypingTile.js +++ b/src/components/views/rooms/WhoIsTypingTile.js @@ -77,6 +77,10 @@ module.exports = React.createClass({ Object.values(this.state.delayedStopTypingTimers).forEach((t) => t.abort()); }, + isVisible: function() { + return this.state.usersTyping.length !== 0 || Object.keys(this.state.delayedStopTypingTimers) !== 0; + }, + onRoomTimeline: function(event, room) { if (room.roomId === this.props.room.roomId) { const userId = event.getSender(); From 86357fde511fdae5158c38c749a1a8eba5e95499 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 21 Jan 2019 17:49:46 +0100 Subject: [PATCH 0181/1528] sort combined typing users by name so order is stable --- src/components/views/rooms/WhoIsTypingTile.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/views/rooms/WhoIsTypingTile.js b/src/components/views/rooms/WhoIsTypingTile.js index bef8aca0c4..4c97110797 100644 --- a/src/components/views/rooms/WhoIsTypingTile.js +++ b/src/components/views/rooms/WhoIsTypingTile.js @@ -191,6 +191,9 @@ module.exports = React.createClass({ // but have a timeout timer running so they can disappear // when a message comes in usersTyping = usersTyping.concat(stoppedUsersOnTimer); + // sort them so the typing members don't change order when + // moved to delayedStopTypingTimers + usersTyping.sort((a, b) => a.name.localeCompare(b.name)); const typingString = WhoIsTyping.whoIsTypingString( usersTyping, From 0a2b79b62d90376a9b1fd11d77a393a46498c980 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 21 Jan 2019 16:51:30 +0000 Subject: [PATCH 0182/1528] Error if no sessions decrypted Tell the user if they entered the wrong recovery key Fixes https://github.com/vector-im/riot-web/issues/8143 --- .../views/dialogs/keybackup/RestoreKeyBackupDialog.js | 11 ++++++++++- src/i18n/strings/en_EN.json | 4 ++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js b/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js index fba9f0b714..d614168eaa 100644 --- a/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js +++ b/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js @@ -1,5 +1,5 @@ /* -Copyright 2018 New Vector Ltd +Copyright 2018, 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. @@ -184,6 +184,15 @@ export default React.createClass({ } else if (this.state.backupInfo === null) { title = _t("Error"); content = _t("No backup found!"); + } else if (this.state.recoverInfo && this.state.recoverInfo.imported === 0) { + title = _t("Error Restoring Backup"); + let failedToDecrypt; + content =
    +

    {_t( + "Failed to decrypt any sessions: check that the recovery key " + + "used is the correct one for this backup." + )}

    +
    ; } else if (this.state.recoverInfo) { title = _t("Backup Restored"); let failedToDecrypt; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 19c6bf5d28..fd9d9b3eef 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -114,8 +114,6 @@ "Failed to invite": "Failed to invite", "Failed to invite users to the room:": "Failed to invite users to the room:", "Failed to invite the following users to the %(roomName)s room:": "Failed to invite the following users to the %(roomName)s room:", - "Waiting for %(userId)s to accept...": "Waiting for %(userId)s to accept...", - "Waiting for %(userId)s to confirm...": "Waiting for %(userId)s to confirm...", "You need to be logged in.": "You need to be logged in.", "You need to be able to invite users to do that.": "You need to be able to invite users to do that.", "Unable to create widget.": "Unable to create widget.", @@ -1048,6 +1046,8 @@ "Unable to load backup status": "Unable to load backup status", "Unable to restore backup": "Unable to restore backup", "No backup found!": "No backup found!", + "Error Restoring Backup": "Error Restoring Backup", + "Failed to decrypt any sessions: check that the recovery key used is the correct one for this backup.": "Failed to decrypt any sessions: check that the recovery key used is the correct one for this backup.", "Backup Restored": "Backup Restored", "Failed to decrypt %(failedCount)s sessions!": "Failed to decrypt %(failedCount)s sessions!", "Restored %(sessionCount)s session keys": "Restored %(sessionCount)s session keys", From 1a9c3f1ac7b8aeb39a5741bd6eaf535deeedc4b6 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 21 Jan 2019 17:41:55 +0000 Subject: [PATCH 0183/1528] Make error string less technical --- .../views/dialogs/keybackup/RestoreKeyBackupDialog.js | 3 +-- src/i18n/strings/en_EN.json | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js b/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js index d614168eaa..89d41803d5 100644 --- a/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js +++ b/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js @@ -189,8 +189,7 @@ export default React.createClass({ let failedToDecrypt; content =

    {_t( - "Failed to decrypt any sessions: check that the recovery key " + - "used is the correct one for this backup." + "Backup restore failed: please verify that you entered the correct recovery key.", )}

    ; } else if (this.state.recoverInfo) { diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index fd9d9b3eef..7b701cc863 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1047,7 +1047,7 @@ "Unable to restore backup": "Unable to restore backup", "No backup found!": "No backup found!", "Error Restoring Backup": "Error Restoring Backup", - "Failed to decrypt any sessions: check that the recovery key used is the correct one for this backup.": "Failed to decrypt any sessions: check that the recovery key used is the correct one for this backup.", + "Backup restore failed: please verify that you entered the correct recovery key.": "Backup restore failed: please verify that you entered the correct recovery key.", "Backup Restored": "Backup Restored", "Failed to decrypt %(failedCount)s sessions!": "Failed to decrypt %(failedCount)s sessions!", "Restored %(sessionCount)s session keys": "Restored %(sessionCount)s session keys", From bed765728a63c7eee0212eb7a735c6e7a8c738e0 Mon Sep 17 00:00:00 2001 From: Slavi Pantaleev Date: Mon, 21 Jan 2019 17:58:00 +0000 Subject: [PATCH 0184/1528] Translated using Weblate (Bulgarian) Currently translated at 100.0% (1427 of 1427 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/bg/ --- src/i18n/strings/bg.json | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/bg.json b/src/i18n/strings/bg.json index 1064fc8b91..edde264275 100644 --- a/src/i18n/strings/bg.json +++ b/src/i18n/strings/bg.json @@ -1444,5 +1444,15 @@ "Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "Настройката на Защитени Съобщения на това устройство ще зашифрова наново историята на съобщенията му посредством новия метод за възстановяване.", "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Ако не сте настройвали новия метод за възстановяване, вероятно някой се опитва да проникне в акаунта Ви. Веднага променете паролата на акаунта си и настройте нов метод за възстановяване от Настройки.", "Set up Secure Messages": "Настрой Защитени Съобщения", - "Go to Settings": "Отиди в Настройки" + "Go to Settings": "Отиди в Настройки", + "Waiting for %(userId)s to accept...": "Изкачване на %(userId)s да приеме...", + "Waiting for %(userId)s to confirm...": "Изчакване на %(userId)s да потвърди...", + "Unrecognised address": "Неразпознат адрес", + "User %(user_id)s may or may not exist": "Потребител %(user_id)s може да съществува или не", + "Prompt before sending invites to potentially invalid matrix IDs": "Питай преди изпращане на покани към потенциално невалидни Matrix идентификатори", + "To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "За да видите защитената история на съобщенията и да подсигурите, че ще можете да я гледате на бъдещи устройства, настройте Защитено Възстановяване на Съобщения.", + "The following users may not exist": "Следните потребители може да не съществуват", + "Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "Не бяга открити профили за изброените по-долу Matrix идентификатори. Желаете ли да ги поканите въпреки това?", + "Invite anyway and never warn me again": "Покани въпреки това и не питай отново", + "Invite anyway": "Покани въпреки това" } From e42b0a9972d870f29a54abe9d0942fc3c9355ae2 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 21 Jan 2019 18:02:09 +0000 Subject: [PATCH 0185/1528] Make error string less redundant --- .../views/dialogs/keybackup/RestoreKeyBackupDialog.js | 3 ++- src/i18n/strings/en_EN.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js b/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js index 89d41803d5..d47eca010f 100644 --- a/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js +++ b/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js @@ -189,7 +189,8 @@ export default React.createClass({ let failedToDecrypt; content =

    {_t( - "Backup restore failed: please verify that you entered the correct recovery key.", + "Backup could not be decrypted with this key: " + + "please verify that you entered the correct recovery key.", )}

    ; } else if (this.state.recoverInfo) { diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 7b701cc863..16c40460e2 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1047,7 +1047,7 @@ "Unable to restore backup": "Unable to restore backup", "No backup found!": "No backup found!", "Error Restoring Backup": "Error Restoring Backup", - "Backup restore failed: please verify that you entered the correct recovery key.": "Backup restore failed: please verify that you entered the correct recovery key.", + "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.": "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.", "Backup Restored": "Backup Restored", "Failed to decrypt %(failedCount)s sessions!": "Failed to decrypt %(failedCount)s sessions!", "Restored %(sessionCount)s session keys": "Restored %(sessionCount)s session keys", From 5aff76b49da5fe90b266d9ba4202af9d92479cb7 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 21 Jan 2019 19:01:18 +0100 Subject: [PATCH 0186/1528] use css scrollbar styles to make native scrollbars prettier --- res/css/structures/_AutoHideScrollbar.scss | 17 +++++++++++++++++ res/themes/dark/css/_dark.scss | 4 +++- res/themes/dharma/css/_dharma.scss | 4 +++- res/themes/light/css/_base.scss | 4 +++- src/components/structures/AutoHideScrollbar.js | 1 + 5 files changed, 27 insertions(+), 3 deletions(-) diff --git a/res/css/structures/_AutoHideScrollbar.scss b/res/css/structures/_AutoHideScrollbar.scss index 60aea7ce8f..cb0d6f7f09 100644 --- a/res/css/structures/_AutoHideScrollbar.scss +++ b/res/css/structures/_AutoHideScrollbar.scss @@ -64,3 +64,20 @@ body.mx_scrollbar_nooverlay { margin-right: calc(-1 * var(--scrollbar-width)); } } + +// style the native scrollbars ... +// ... standard css scrollbars (firefox at time of writing) +.mx_AutoHideScrollbar { + scrollbar-color: $scrollbar-thumb-color $scrollbar-track-color; + scrollbar-width: thin; +} +// or fallback for webkit browsers +::-webkit-scrollbar { + width: 6px; + background-color: $scrollbar-track-color; +} + +::-webkit-scrollbar-thumb { + background-color: $scrollbar-thumb-color; + border-radius: 3px; +} diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index 997a74e6aa..53d4b42ff4 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -74,7 +74,9 @@ $strong-input-border-color: #656565; // used for UserSettings EditableText $input-underline-color: $primary-fg-color; $input-fg-color: $primary-fg-color; - +// scrollbars +$scrollbar-thumb-color: rgba(255, 255, 255, 0.2); +$scrollbar-track-color: transparent; // context menus $menu-border-color: rgba(187, 187, 187, 0.5); $menu-bg-color: #373737; diff --git a/res/themes/dharma/css/_dharma.scss b/res/themes/dharma/css/_dharma.scss index c70d7f020a..01eaaed1bc 100644 --- a/res/themes/dharma/css/_dharma.scss +++ b/res/themes/dharma/css/_dharma.scss @@ -83,7 +83,9 @@ $strong-input-border-color: #c7c7c7; // used for UserSettings EditableText $input-underline-color: rgba(151, 151, 151, 0.5); $input-fg-color: rgba(74, 74, 74, 0.9); - +// scrollbars +$scrollbar-thumb-color: rgba(0, 0, 0, 0.2); +$scrollbar-track-color: transparent; // context menus $menu-border-color: #ebedf8; $menu-bg-color: #fff; diff --git a/res/themes/light/css/_base.scss b/res/themes/light/css/_base.scss index 96c179f6f5..bf453a6eb4 100644 --- a/res/themes/light/css/_base.scss +++ b/res/themes/light/css/_base.scss @@ -79,7 +79,9 @@ $strong-input-border-color: #c7c7c7; // used for UserSettings EditableText $input-underline-color: rgba(151, 151, 151, 0.5); $input-fg-color: rgba(74, 74, 74, 0.9); - +// scrollbars +$scrollbar-thumb-color: rgba(0, 0, 0, 0.2); +$scrollbar-track-color: transparent; // context menus $menu-border-color: rgba(187, 187, 187, 0.5); $menu-bg-color: #f6f6f6; diff --git a/src/components/structures/AutoHideScrollbar.js b/src/components/structures/AutoHideScrollbar.js index 47ae24ba0f..a8fccec08e 100644 --- a/src/components/structures/AutoHideScrollbar.js +++ b/src/components/structures/AutoHideScrollbar.js @@ -20,6 +20,7 @@ import React from "react"; // Copyright (c) Noel Delgado (pixelia.me) function getScrollbarWidth(alternativeOverflow) { const div = document.createElement('div'); + div.className = 'mx_AutoHideScrollbar'; //to get width of css scrollbar div.style.position = 'absolute'; div.style.top = '-9999px'; div.style.width = '100px'; From 31889ecfad6a92704590309201d6e1867a694f6f Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 21 Jan 2019 19:07:44 +0000 Subject: [PATCH 0187/1528] Lint --- src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js b/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js index d47eca010f..fdb4f0a226 100644 --- a/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js +++ b/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js @@ -186,7 +186,6 @@ export default React.createClass({ content = _t("No backup found!"); } else if (this.state.recoverInfo && this.state.recoverInfo.imported === 0) { title = _t("Error Restoring Backup"); - let failedToDecrypt; content =

    {_t( "Backup could not be decrypted with this key: " + From ce412280000659b6ea9e7f3a23a7b79c4d06fc96 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 21 Jan 2019 19:20:11 +0000 Subject: [PATCH 0188/1528] Token encouragement if zxcvbn gives no feedback zxcvbn is hardcoded to give no suggedtions if the score is greater than 2, but our threshold is 4, so give some generic feedback. Fixes https://github.com/vector-im/riot-web/issues/7860 --- .../views/dialogs/keybackup/CreateKeyBackupDialog.js | 2 +- src/i18n/strings/en_EN.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js b/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js index 4fb5df214b..fd3d6776eb 100644 --- a/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js +++ b/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js @@ -254,7 +254,7 @@ export default React.createClass({ } const suggestionBlock = suggestions.length > 0 ?

    {suggestions} -
    : null; +
    :
    {_t("Keep going...")}
    ; helpText =
    {this.state.zxcvbnResult.feedback.warning} diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 16c40460e2..1c4dbeea65 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1381,6 +1381,7 @@ "File to import": "File to import", "Import": "Import", "Great! This passphrase looks strong enough.": "Great! This passphrase looks strong enough.", + "Keep going...": "Keep going...", "Secure your encrypted message history with a Recovery Passphrase.": "Secure your encrypted message history with a Recovery Passphrase.", "You'll need it if you log out or lose access to this device.": "You'll need it if you log out or lose access to this device.", "Enter a passphrase...": "Enter a passphrase...", From bd011de1e5352041513c7895941437b1f07fa684 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 21 Jan 2019 19:32:57 +0000 Subject: [PATCH 0189/1528] De-lint CompatabilityPage & LoggedInView and remove from errorfiles --- .eslintignore.errorfiles | 2 - .../structures/CompatibilityPage.js | 16 ++++++-- src/components/structures/LoggedInView.js | 40 ++++++++++++------- 3 files changed, 38 insertions(+), 20 deletions(-) diff --git a/.eslintignore.errorfiles b/.eslintignore.errorfiles index 30cc55377c..4d4db0722d 100644 --- a/.eslintignore.errorfiles +++ b/.eslintignore.errorfiles @@ -2,9 +2,7 @@ src/component-index.js src/components/structures/BottomLeftMenu.js -src/components/structures/CompatibilityPage.js src/components/structures/CreateRoom.js -src/components/structures/LoggedInView.js src/components/structures/login/ForgotPassword.js src/components/structures/MessagePanel.js src/components/structures/NotificationPanel.js diff --git a/src/components/structures/CompatibilityPage.js b/src/components/structures/CompatibilityPage.js index 3c5005c053..28521cb1b7 100644 --- a/src/components/structures/CompatibilityPage.js +++ b/src/components/structures/CompatibilityPage.js @@ -41,10 +41,15 @@ module.exports = React.createClass({

    { _t("Sorry, your browser is not able to run Riot.", {}, { 'b': (sub) => {sub} }) }

    - { _t("Riot uses many advanced browser features, some of which are not available or experimental in your current browser.") } + { _t( + "Riot uses many advanced browser features, some of which are not available " + + "or experimental in your current browser.", + ) }

    - { _t('Please install Chrome or Firefox for the best experience.', + { _t( + 'Please install Chrome or Firefox ' + + 'for the best experience.', {}, { 'chromeLink': (sub) => {sub}, @@ -60,7 +65,12 @@ module.exports = React.createClass({ )}

    - { _t("With your current browser, the look and feel of the application may be completely incorrect, and some or all features may not function. If you want to try it anyway you can continue, but you are on your own in terms of any issues you may encounter!") } + { _t( + "With your current browser, the look and feel of the application may be " + + "completely incorrect, and some or all features may not function. " + + "If you want to try it anyway you can continue, but you are on your own in terms " + + "of any issues you may encounter!", + ) }

    From 1906cfd700a289d2045bea1adf031e3b40899aa2 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 21 Jan 2019 10:09:33 -0600 Subject: [PATCH 0190/1528] Tweak field label to be vertically centered --- res/css/views/elements/_Field.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/css/views/elements/_Field.scss b/res/css/views/elements/_Field.scss index 1b5b0b37c2..e28ae91761 100644 --- a/res/css/views/elements/_Field.scss +++ b/res/css/views/elements/_Field.scss @@ -56,7 +56,7 @@ limitations under the License. position: absolute; left: 0px; top: 0px; - margin: 6px 8px; + margin: 7px 8px; padding: 2px; } From 352107352edd46a63182c57e9a7cb539cb34fb2b Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 21 Jan 2019 10:16:20 -0600 Subject: [PATCH 0191/1528] Tweak field input padding to match label position --- res/css/views/elements/_Field.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/css/views/elements/_Field.scss b/res/css/views/elements/_Field.scss index e28ae91761..f8090eaaf7 100644 --- a/res/css/views/elements/_Field.scss +++ b/res/css/views/elements/_Field.scss @@ -26,7 +26,7 @@ limitations under the License. border-radius: 4px; transition: border-color 0.25s; border: 1px solid $input-border-color; - padding: 8px 10px; + padding: 8px 9px; } .mx_Field input:focus { From 23b3e74c1c3037e687620ea609dda8f95ce943cb Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 21 Jan 2019 10:24:04 -0600 Subject: [PATCH 0192/1528] Change to new field focused color --- res/css/views/elements/_Field.scss | 4 ++-- res/themes/dharma/css/_dharma.scss | 1 + res/themes/light/css/_base.scss | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/res/css/views/elements/_Field.scss b/res/css/views/elements/_Field.scss index f8090eaaf7..c728f4bcd4 100644 --- a/res/css/views/elements/_Field.scss +++ b/res/css/views/elements/_Field.scss @@ -31,7 +31,7 @@ limitations under the License. .mx_Field input:focus { outline: 0; - border-color: $input-valid-border-color; + border-color: $input-focused-border-color; } .mx_Field input::placeholder { @@ -73,5 +73,5 @@ limitations under the License. } .mx_Field input:focus + label { - color: $input-valid-border-color; + color: $input-focused-border-color; } diff --git a/res/themes/dharma/css/_dharma.scss b/res/themes/dharma/css/_dharma.scss index 4a2bfec8e4..5f6a69abe3 100644 --- a/res/themes/dharma/css/_dharma.scss +++ b/res/themes/dharma/css/_dharma.scss @@ -71,6 +71,7 @@ $input-darker-bg-color: rgba(193, 201, 214, 0.29); $input-darker-fg-color: #9fa9ba; $input-lighter-bg-color: #f2f5f8; $input-lighter-fg-color: $input-darker-fg-color; +$input-focused-border-color: #238cf5; $input-valid-border-color: #7ac9a1; $field-focused-label-bg-color: #ffffff; diff --git a/res/themes/light/css/_base.scss b/res/themes/light/css/_base.scss index 9a3b3727a9..dbab909f13 100644 --- a/res/themes/light/css/_base.scss +++ b/res/themes/light/css/_base.scss @@ -73,6 +73,7 @@ $button-bg-color: #7ac9a1; $button-fg-color: white; // apart from login forms, which have stronger border $strong-input-border-color: #c7c7c7; +$input-focused-border-color: #238cf5; $input-valid-border-color: #7ac9a1; $field-focused-label-bg-color: #ffffff; From 82dee37afeb045c511e6ad2748198164178929c4 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 21 Jan 2019 08:56:58 -0600 Subject: [PATCH 0193/1528] Fix styling regression in member list filter --- res/themes/dharma/css/_dharma.scss | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/res/themes/dharma/css/_dharma.scss b/res/themes/dharma/css/_dharma.scss index 5f6a69abe3..1436328047 100644 --- a/res/themes/dharma/css/_dharma.scss +++ b/res/themes/dharma/css/_dharma.scss @@ -247,8 +247,8 @@ input[type=password] { } .dark-panel { - :not(.mx_textinput) > input[type=text], - :not(.mx_textinput) > input[type=search], + :not(.mx_textinput):not(.mx_Field) > input[type=text], + :not(.mx_textinput):not(.mx_Field) > input[type=search], .mx_textinput { color: $input-darker-fg-color; background-color: $input-darker-bg-color; @@ -257,8 +257,8 @@ input[type=password] { } .light-panel { - :not(.mx_textinput) > input[type=text], - :not(.mx_textinput) > input[type=search], + :not(.mx_textinput):not(.mx_Field) > input[type=text], + :not(.mx_textinput):not(.mx_Field) > input[type=search], .mx_textinput { color: $input-lighter-fg-color; background-color: $input-lighter-bg-color; From e714b2aed2a000c0c159948a6e19290294d6ee5a Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 21 Jan 2019 12:05:07 -0600 Subject: [PATCH 0194/1528] Remove Status theme-specific hacks --- src/components/structures/login/Login.js | 14 +------ .../structures/login/Registration.js | 19 +++------ src/components/views/login/LoginPage.js | 39 +++---------------- 3 files changed, 13 insertions(+), 59 deletions(-) diff --git a/src/components/structures/login/Login.js b/src/components/structures/login/Login.js index 321084389b..6206b7660d 100644 --- a/src/components/structures/login/Login.js +++ b/src/components/structures/login/Login.js @@ -1,7 +1,7 @@ /* Copyright 2015, 2016 OpenMarket Ltd Copyright 2017 Vector Creations Ltd -Copyright 2018 New Vector Ltd +Copyright 2018, 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. @@ -24,7 +24,6 @@ import { _t, _td } from '../../../languageHandler'; import sdk from '../../../index'; import Login from '../../../Login'; import SdkConfig from '../../../SdkConfig'; -import SettingsStore from "../../../settings/SettingsStore"; import { messageForResourceLimitError } from '../../../utils/ErrorUtils'; import { AutoDiscovery } from "matrix-js-sdk"; @@ -533,7 +532,6 @@ module.exports = React.createClass({ } let serverConfig; - let header; if (!SdkConfig.get()['disable_custom_urls']) { serverConfig = ; } - // FIXME: remove status.im theme tweaks - const theme = SettingsStore.getValue("theme"); - if (theme !== "status") { - header =

    { _t('Sign in') } { loader }

    ; - } else { - if (!errorText) { - header =

    { _t('Sign in to get started') } { loader }

    ; - } - } + const header =

    { _t('Sign in') } { loader }

    ; let errorTextSection; if (errorText) { diff --git a/src/components/structures/login/Registration.js b/src/components/structures/login/Registration.js index fa5a02e881..74e3685bb5 100644 --- a/src/components/structures/login/Registration.js +++ b/src/components/structures/login/Registration.js @@ -1,7 +1,7 @@ /* Copyright 2015, 2016 OpenMarket Ltd Copyright 2017 Vector Creations Ltd -Copyright 2018 New Vector Ltd +Copyright 2018, 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. @@ -28,7 +28,6 @@ import RegistrationForm from '../../views/login/RegistrationForm'; import RtsClient from '../../../RtsClient'; import { _t, _td } from '../../../languageHandler'; import SdkConfig from '../../../SdkConfig'; -import SettingsStore from "../../../settings/SettingsStore"; import { messageForResourceLimitError } from '../../../utils/ErrorUtils'; const MIN_PASSWORD_LENGTH = 6; @@ -404,8 +403,6 @@ module.exports = React.createClass({ const Spinner = sdk.getComponent("elements.Spinner"); const ServerConfig = sdk.getComponent('views.login.ServerConfig'); - const theme = SettingsStore.getValue("theme"); - let registerBody; if (this.state.doingUIAuth) { registerBody = ( @@ -458,24 +455,18 @@ module.exports = React.createClass({ ); } - let header; let errorText; - // FIXME: remove hardcoded Status team tweaks at some point const err = this.state.errorText || this.props.defaultServerDiscoveryError; - if (theme === 'status' && err) { - header =
    { err }
    ; - } else { - header =

    { _t('Create an account') }

    ; - if (err) { - errorText =
    { err }
    ; - } + const header =

    { _t('Create an account') }

    ; + if (err) { + errorText =
    { err }
    ; } let signIn; if (!this.state.doingUIAuth) { signIn = ( - { theme === 'status' ? _t('Sign in') : _t('I already have an account') } + { _t('I already have an account') } ); } diff --git a/src/components/views/login/LoginPage.js b/src/components/views/login/LoginPage.js index 9eba53188e..83da8fa60b 100644 --- a/src/components/views/login/LoginPage.js +++ b/src/components/views/login/LoginPage.js @@ -1,5 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd +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. @@ -16,44 +17,16 @@ limitations under the License. 'use strict'; -import SettingsStore from "../../../settings/SettingsStore"; - const React = require('react'); module.exports = React.createClass({ displayName: 'LoginPage', render: function() { - // FIXME: this should be turned into a proper skin with a StatusLoginPage component - if (SettingsStore.getValue("theme") === 'status') { - return ( -
    -
    - Status -
    -
    -
    -

    Status Community Chat

    -
    - A safer, decentralised communication - platform powered by Riot -
    -
    - { this.props.children } -
    -

    This channel is for our development community.

    -

    Interested in SNT and discussions on the cryptocurrency market?

    -

    Join Telegram Chat

    -
    -
    -
    - ); - } else { - return ( -
    - { this.props.children } -
    - ); - } + return ( +
    + { this.props.children } +
    + ); }, }); From 31808c23a864991b0b6c9b6bd7d8944a58f03fd8 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 21 Jan 2019 14:31:51 -0600 Subject: [PATCH 0195/1528] Override Firefox UA style for placeholders --- res/themes/dharma/css/_dharma.scss | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/res/themes/dharma/css/_dharma.scss b/res/themes/dharma/css/_dharma.scss index 1436328047..c9f62fbe6b 100644 --- a/res/themes/dharma/css/_dharma.scss +++ b/res/themes/dharma/css/_dharma.scss @@ -295,6 +295,13 @@ input[type=search]::-webkit-search-results-decoration { .input[type=search]::-moz-placeholder { color: #a5aab2; } + +// Override Firefox's UA style so we get a consistent look across browsers +input::placeholder, +textarea::placeholder { + opacity: initial; +} + // ***** Mixins! ***** @define-mixin mx_DialogButton { From cd8c74a7c48014458405c35480bf0ceec826dca5 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 21 Jan 2019 15:03:55 -0600 Subject: [PATCH 0196/1528] Rebuild strings --- src/i18n/strings/en_EN.json | 1 - 1 file changed, 1 deletion(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 16c40460e2..cfd5168152 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1328,7 +1328,6 @@ "Can't connect to homeserver - please check your connectivity, ensure your homeserver's SSL certificate is trusted, and that a browser extension is not blocking requests.": "Can't connect to homeserver - please check your connectivity, ensure your homeserver's SSL certificate is trusted, and that a browser extension is not blocking requests.", "Sign in with single sign-on": "Sign in with single sign-on", "Try the app first": "Try the app first", - "Sign in to get started": "Sign in to get started", "Failed to fetch avatar URL": "Failed to fetch avatar URL", "Set a display name:": "Set a display name:", "Upload an avatar:": "Upload an avatar:", From c3adf4d3970663a0dcf50106f6a356727c7061be Mon Sep 17 00:00:00 2001 From: Osoitz Date: Mon, 21 Jan 2019 21:04:28 +0000 Subject: [PATCH 0197/1528] Translated using Weblate (Basque) Currently translated at 100.0% (1427 of 1427 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/eu/ --- src/i18n/strings/eu.json | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/eu.json b/src/i18n/strings/eu.json index bee6ef4668..0367393db8 100644 --- a/src/i18n/strings/eu.json +++ b/src/i18n/strings/eu.json @@ -1448,5 +1448,14 @@ "A new recovery passphrase and key for Secure Messages has been detected.": "Mezu seguruentzako berreskuratze pasa-esaldi eta gako berri bat antzeman dira.", "Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "Mezu seguruak gailu honetan ezartzeak, gailu honen mezuen historiala birzifratuko du berreskuratze metodo berriarekin.", "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Ez baduzu berreskuratze sistema berria ezarri, erasotzaile bat zure kontua atzitzen saiatzen egon daiteke. Aldatu zure kontuaren pasahitza eta ezarri berreskuratze metodo berria berehala ezarpenetan.", - "To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "Zure mezu seguruen historiala ikusteko eta etorkizunean erabiltzen dituzun gailuetan ere mezuak ikusi ahal izango dituzula ziurtatzeko, ezarri mezuen berreskuratze segurua." + "To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "Zure mezu seguruen historiala ikusteko eta etorkizunean erabiltzen dituzun gailuetan ere mezuak ikusi ahal izango dituzula ziurtatzeko, ezarri mezuen berreskuratze segurua.", + "Waiting for %(userId)s to accept...": "%(userId)s erabiltzaileak onartu dezan itxaroten...", + "Waiting for %(userId)s to confirm...": "%(userId)s erabiltzaileak berretsi dezan itxaroten...", + "User %(user_id)s may or may not exist": "%(user_id)s erabiltzailea existitu daiteke edo ez", + "Unrecognised address": "Helbide ezezaguna", + "Prompt before sending invites to potentially invalid matrix IDs": "Galdetu baliogabeak izan daitezkeen matrix ID-eetara gonbidapenak bidali aurretik", + "The following users may not exist": "Hurrengo erabiltzaileak agian ez dira existitzen", + "Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "Ezin izan dira behean zerrendatutako Matrix ID-een profilak, berdin gonbidatu nahi dituzu?", + "Invite anyway and never warn me again": "Gonbidatu edonola ere eta ez abisatu inoiz gehiago", + "Invite anyway": "Gonbidatu hala ere" } From 29be3ee4b5aa0fd7ddb10936545344d091dfe340 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 21 Jan 2019 16:11:10 -0600 Subject: [PATCH 0198/1528] Rename login directory to auth --- .eslintignore.errorfiles | 16 ++++++++-------- res/css/_components.scss | 6 +++--- res/css/structures/{login => auth}/_Login.scss | 0 .../_InteractiveAuthEntryComponents.scss | 0 res/css/views/{login => auth}/_ServerConfig.scss | 0 src/components/structures/InteractiveAuth.js | 2 +- src/components/structures/MatrixChat.js | 10 +++++----- .../structures/{login => auth}/ForgotPassword.js | 10 +++++----- .../{login => auth}/LanguageSelector.js | 0 .../structures/{login => auth}/Login.js | 12 ++++++------ .../{login => auth}/PostRegistration.js | 4 ++-- .../structures/{login => auth}/Registration.js | 12 ++++++------ .../views/{login => auth}/CaptchaForm.js | 0 .../views/{login => auth}/CountryDropdown.js | 0 .../views/{login => auth}/CustomServerDialog.js | 0 .../InteractiveAuthEntryComponents.js | 2 +- .../views/{login => auth}/LoginFooter.js | 0 .../views/{login => auth}/LoginHeader.js | 0 .../views/{login => auth}/LoginPage.js | 0 .../views/{login => auth}/PasswordLogin.js | 2 +- .../views/{login => auth}/RegistrationForm.js | 2 +- .../views/{login => auth}/ServerConfig.js | 2 +- src/components/views/settings/AddPhoneNumber.js | 2 +- src/stores/LifecycleStore.js | 4 ++-- .../{login => auth}/Registration-test.js | 2 +- .../{login => auth}/RegistrationForm-test.js | 2 +- 26 files changed, 45 insertions(+), 45 deletions(-) rename res/css/structures/{login => auth}/_Login.scss (100%) rename res/css/views/{login => auth}/_InteractiveAuthEntryComponents.scss (100%) rename res/css/views/{login => auth}/_ServerConfig.scss (100%) rename src/components/structures/{login => auth}/ForgotPassword.js (97%) rename src/components/structures/{login => auth}/LanguageSelector.js (100%) rename src/components/structures/{login => auth}/Login.js (98%) rename src/components/structures/{login => auth}/PostRegistration.js (95%) rename src/components/structures/{login => auth}/Registration.js (97%) rename src/components/views/{login => auth}/CaptchaForm.js (100%) rename src/components/views/{login => auth}/CountryDropdown.js (100%) rename src/components/views/{login => auth}/CustomServerDialog.js (100%) rename src/components/views/{login => auth}/InteractiveAuthEntryComponents.js (99%) rename src/components/views/{login => auth}/LoginFooter.js (100%) rename src/components/views/{login => auth}/LoginHeader.js (100%) rename src/components/views/{login => auth}/LoginPage.js (100%) rename src/components/views/{login => auth}/PasswordLogin.js (99%) rename src/components/views/{login => auth}/RegistrationForm.js (99%) rename src/components/views/{login => auth}/ServerConfig.js (98%) rename test/components/structures/{login => auth}/Registration-test.js (98%) rename test/components/views/{login => auth}/RegistrationForm-test.js (97%) diff --git a/.eslintignore.errorfiles b/.eslintignore.errorfiles index 30cc55377c..42dc3b4810 100644 --- a/.eslintignore.errorfiles +++ b/.eslintignore.errorfiles @@ -1,11 +1,11 @@ # autogenerated file: run scripts/generate-eslint-error-ignore-file to update. src/component-index.js +src/components/structures/auth/ForgotPassword.js src/components/structures/BottomLeftMenu.js src/components/structures/CompatibilityPage.js src/components/structures/CreateRoom.js src/components/structures/LoggedInView.js -src/components/structures/login/ForgotPassword.js src/components/structures/MessagePanel.js src/components/structures/NotificationPanel.js src/components/structures/RoomDirectory.js @@ -15,6 +15,11 @@ src/components/structures/ScrollPanel.js src/components/structures/SearchBox.js src/components/structures/TimelinePanel.js src/components/structures/UploadBar.js +src/components/views/auth/CountryDropdown.js +src/components/views/auth/InteractiveAuthEntryComponents.js +src/components/views/auth/PasswordLogin.js +src/components/views/auth/RegistrationForm.js +src/components/views/auth/ServerConfig.js src/components/views/avatars/BaseAvatar.js src/components/views/avatars/MemberAvatar.js src/components/views/create_room/RoomAlias.js @@ -31,11 +36,6 @@ src/components/views/elements/UserSelector.js src/components/views/globals/MatrixToolbar.js src/components/views/globals/NewVersionBar.js src/components/views/globals/UpdateCheckBar.js -src/components/views/login/CountryDropdown.js -src/components/views/login/InteractiveAuthEntryComponents.js -src/components/views/login/PasswordLogin.js -src/components/views/login/RegistrationForm.js -src/components/views/login/ServerConfig.js src/components/views/messages/MFileBody.js src/components/views/messages/RoomAvatarEvent.js src/components/views/messages/TextualBody.js @@ -98,12 +98,12 @@ src/VectorConferenceHandler.js src/Velociraptor.js src/WhoIsTyping.js src/wrappers/withMatrixClient.js -test/components/structures/login/Registration-test.js +test/components/structures/auth/Registration-test.js test/components/structures/MessagePanel-test.js test/components/structures/ScrollPanel-test.js test/components/structures/TimelinePanel-test.js +test/components/views/auth/RegistrationForm-test.js test/components/views/dialogs/InteractiveAuthDialog-test.js -test/components/views/login/RegistrationForm-test.js test/components/views/rooms/MessageComposerInput-test.js test/components/views/rooms/RoomSettings-test.js test/mock-clock.js diff --git a/res/css/_components.scss b/res/css/_components.scss index 6b353ba72b..a1b575a0a1 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -23,7 +23,9 @@ @import "./structures/_UploadBar.scss"; @import "./structures/_UserSettings.scss"; @import "./structures/_ViewSource.scss"; -@import "./structures/login/_Login.scss"; +@import "./structures/auth/_Login.scss"; +@import "./views/auth/_InteractiveAuthEntryComponents.scss"; +@import "./views/auth/_ServerConfig.scss"; @import "./views/avatars/_BaseAvatar.scss"; @import "./views/avatars/_MemberStatusMessageAvatar.scss"; @import "./views/context_menus/_MessageContextMenu.scss"; @@ -75,8 +77,6 @@ @import "./views/groups/_GroupPublicityToggle.scss"; @import "./views/groups/_GroupRoomList.scss"; @import "./views/groups/_GroupUserSettings.scss"; -@import "./views/login/_InteractiveAuthEntryComponents.scss"; -@import "./views/login/_ServerConfig.scss"; @import "./views/messages/_CreateEvent.scss"; @import "./views/messages/_DateSeparator.scss"; @import "./views/messages/_MEmoteBody.scss"; diff --git a/res/css/structures/login/_Login.scss b/res/css/structures/auth/_Login.scss similarity index 100% rename from res/css/structures/login/_Login.scss rename to res/css/structures/auth/_Login.scss diff --git a/res/css/views/login/_InteractiveAuthEntryComponents.scss b/res/css/views/auth/_InteractiveAuthEntryComponents.scss similarity index 100% rename from res/css/views/login/_InteractiveAuthEntryComponents.scss rename to res/css/views/auth/_InteractiveAuthEntryComponents.scss diff --git a/res/css/views/login/_ServerConfig.scss b/res/css/views/auth/_ServerConfig.scss similarity index 100% rename from res/css/views/login/_ServerConfig.scss rename to res/css/views/auth/_ServerConfig.scss diff --git a/src/components/structures/InteractiveAuth.js b/src/components/structures/InteractiveAuth.js index 2883c8cca4..89ff4d43a3 100644 --- a/src/components/structures/InteractiveAuth.js +++ b/src/components/structures/InteractiveAuth.js @@ -20,7 +20,7 @@ const InteractiveAuth = Matrix.InteractiveAuth; import React from 'react'; import PropTypes from 'prop-types'; -import {getEntryComponentForLoginType} from '../views/login/InteractiveAuthEntryComponents'; +import {getEntryComponentForLoginType} from '../views/auth/InteractiveAuthEntryComponents'; export default React.createClass({ displayName: 'InteractiveAuth', diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index e5cf6a986a..7acceb4bb7 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -183,7 +183,7 @@ export default React.createClass({ register_is_url: null, register_id_sid: null, - // Parameters used for setting up the login/registration views + // Parameters used for setting up the authentication views defaultServerName: this.props.config.default_server_name, defaultHsUrl: this.props.config.default_hs_url, defaultIsUrl: this.props.config.default_is_url, @@ -1851,7 +1851,7 @@ export default React.createClass({ // needs to be before normal PageTypes as you are logged in technically if (this.state.view === VIEWS.POST_REGISTRATION) { - const PostRegistration = sdk.getComponent('structures.login.PostRegistration'); + const PostRegistration = sdk.getComponent('structures.auth.PostRegistration'); return ( @@ -1906,7 +1906,7 @@ export default React.createClass({ } if (this.state.view === VIEWS.REGISTER) { - const Registration = sdk.getComponent('structures.login.Registration'); + const Registration = sdk.getComponent('structures.auth.Registration'); return ( { err }
    ; } - const LanguageSelector = sdk.getComponent('structures.login.LanguageSelector'); + const LanguageSelector = sdk.getComponent('structures.auth.LanguageSelector'); resetPasswordJsx = (
    diff --git a/src/components/structures/login/LanguageSelector.js b/src/components/structures/auth/LanguageSelector.js similarity index 100% rename from src/components/structures/login/LanguageSelector.js rename to src/components/structures/auth/LanguageSelector.js diff --git a/src/components/structures/login/Login.js b/src/components/structures/auth/Login.js similarity index 98% rename from src/components/structures/login/Login.js rename to src/components/structures/auth/Login.js index 6206b7660d..a1f0327835 100644 --- a/src/components/structures/login/Login.js +++ b/src/components/structures/auth/Login.js @@ -486,7 +486,7 @@ module.exports = React.createClass({ }, _renderPasswordStep: function() { - const PasswordLogin = sdk.getComponent('login.PasswordLogin'); + const PasswordLogin = sdk.getComponent('auth.PasswordLogin'); return (
    : null; const errorText = this.props.defaultServerDiscoveryError || this.state.discoveryError || this.state.errorText; @@ -555,7 +555,7 @@ module.exports = React.createClass({ ); } - const LanguageSelector = sdk.getComponent('structures.login.LanguageSelector'); + const LanguageSelector = sdk.getComponent('structures.auth.LanguageSelector'); return ( diff --git a/src/components/structures/login/PostRegistration.js b/src/components/structures/auth/PostRegistration.js similarity index 95% rename from src/components/structures/login/PostRegistration.js rename to src/components/structures/auth/PostRegistration.js index f6165348bd..826db89b93 100644 --- a/src/components/structures/login/PostRegistration.js +++ b/src/components/structures/auth/PostRegistration.js @@ -60,8 +60,8 @@ module.exports = React.createClass({ render: function() { const ChangeDisplayName = sdk.getComponent('settings.ChangeDisplayName'); const ChangeAvatar = sdk.getComponent('settings.ChangeAvatar'); - const LoginPage = sdk.getComponent('login.LoginPage'); - const LoginHeader = sdk.getComponent('login.LoginHeader'); + const LoginPage = sdk.getComponent('auth.LoginPage'); + const LoginHeader = sdk.getComponent('auth.LoginHeader'); return (
    diff --git a/src/components/structures/login/Registration.js b/src/components/structures/auth/Registration.js similarity index 97% rename from src/components/structures/login/Registration.js rename to src/components/structures/auth/Registration.js index 74e3685bb5..617c9d6983 100644 --- a/src/components/structures/login/Registration.js +++ b/src/components/structures/auth/Registration.js @@ -24,7 +24,7 @@ import PropTypes from 'prop-types'; import sdk from '../../../index'; import MatrixClientPeg from '../../../MatrixClientPeg'; -import RegistrationForm from '../../views/login/RegistrationForm'; +import RegistrationForm from '../../views/auth/RegistrationForm'; import RtsClient from '../../../RtsClient'; import { _t, _td } from '../../../languageHandler'; import SdkConfig from '../../../SdkConfig'; @@ -396,12 +396,12 @@ module.exports = React.createClass({ }, render: function() { - const LoginHeader = sdk.getComponent('login.LoginHeader'); - const LoginFooter = sdk.getComponent('login.LoginFooter'); - const LoginPage = sdk.getComponent('login.LoginPage'); + const LoginHeader = sdk.getComponent('auth.LoginHeader'); + const LoginFooter = sdk.getComponent('auth.LoginFooter'); + const LoginPage = sdk.getComponent('auth.LoginPage'); const InteractiveAuth = sdk.getComponent('structures.InteractiveAuth'); const Spinner = sdk.getComponent("elements.Spinner"); - const ServerConfig = sdk.getComponent('views.login.ServerConfig'); + const ServerConfig = sdk.getComponent('views.auth.ServerConfig'); let registerBody; if (this.state.doingUIAuth) { @@ -471,7 +471,7 @@ module.exports = React.createClass({ ); } - const LanguageSelector = sdk.getComponent('structures.login.LanguageSelector'); + const LanguageSelector = sdk.getComponent('structures.auth.LanguageSelector'); return ( diff --git a/src/components/views/login/CaptchaForm.js b/src/components/views/auth/CaptchaForm.js similarity index 100% rename from src/components/views/login/CaptchaForm.js rename to src/components/views/auth/CaptchaForm.js diff --git a/src/components/views/login/CountryDropdown.js b/src/components/views/auth/CountryDropdown.js similarity index 100% rename from src/components/views/login/CountryDropdown.js rename to src/components/views/auth/CountryDropdown.js diff --git a/src/components/views/login/CustomServerDialog.js b/src/components/views/auth/CustomServerDialog.js similarity index 100% rename from src/components/views/login/CustomServerDialog.js rename to src/components/views/auth/CustomServerDialog.js diff --git a/src/components/views/login/InteractiveAuthEntryComponents.js b/src/components/views/auth/InteractiveAuthEntryComponents.js similarity index 99% rename from src/components/views/login/InteractiveAuthEntryComponents.js rename to src/components/views/auth/InteractiveAuthEntryComponents.js index 73b46959b0..6a78898179 100644 --- a/src/components/views/login/InteractiveAuthEntryComponents.js +++ b/src/components/views/auth/InteractiveAuthEntryComponents.js @@ -187,7 +187,7 @@ export const RecaptchaAuthEntry = React.createClass({ return ; } - const CaptchaForm = sdk.getComponent("views.login.CaptchaForm"); + const CaptchaForm = sdk.getComponent("views.auth.CaptchaForm"); const sitePublicKey = this.props.stageParams.public_key; let errorSection; diff --git a/src/components/views/login/LoginFooter.js b/src/components/views/auth/LoginFooter.js similarity index 100% rename from src/components/views/login/LoginFooter.js rename to src/components/views/auth/LoginFooter.js diff --git a/src/components/views/login/LoginHeader.js b/src/components/views/auth/LoginHeader.js similarity index 100% rename from src/components/views/login/LoginHeader.js rename to src/components/views/auth/LoginHeader.js diff --git a/src/components/views/login/LoginPage.js b/src/components/views/auth/LoginPage.js similarity index 100% rename from src/components/views/login/LoginPage.js rename to src/components/views/auth/LoginPage.js diff --git a/src/components/views/login/PasswordLogin.js b/src/components/views/auth/PasswordLogin.js similarity index 99% rename from src/components/views/login/PasswordLogin.js rename to src/components/views/auth/PasswordLogin.js index 59d4db379c..1d36c52a24 100644 --- a/src/components/views/login/PasswordLogin.js +++ b/src/components/views/auth/PasswordLogin.js @@ -201,7 +201,7 @@ class PasswordLogin extends React.Component { disabled={disabled} />; case PasswordLogin.LOGIN_FIELD_PHONE: { - const CountryDropdown = sdk.getComponent('views.login.CountryDropdown'); + const CountryDropdown = sdk.getComponent('views.auth.CountryDropdown'); classes.mx_Login_phoneNumberField = true; classes.mx_Login_field_has_prefix = true; classes.error = this.props.loginIncorrect && !this.state.phoneNumber; diff --git a/src/components/views/login/RegistrationForm.js b/src/components/views/auth/RegistrationForm.js similarity index 99% rename from src/components/views/login/RegistrationForm.js rename to src/components/views/auth/RegistrationForm.js index 137aeada91..a0fc79b947 100644 --- a/src/components/views/login/RegistrationForm.js +++ b/src/components/views/auth/RegistrationForm.js @@ -323,7 +323,7 @@ module.exports = React.createClass({ } } - const CountryDropdown = sdk.getComponent('views.login.CountryDropdown'); + const CountryDropdown = sdk.getComponent('views.auth.CountryDropdown'); let phoneSection; if (!SdkConfig.get().disable_3pid_login) { const phonePlaceholder = this._authStepIsRequired('m.login.msisdn') ? _t("Mobile phone number") : _t("Mobile phone number (optional)"); diff --git a/src/components/views/login/ServerConfig.js b/src/components/views/auth/ServerConfig.js similarity index 98% rename from src/components/views/login/ServerConfig.js rename to src/components/views/auth/ServerConfig.js index 2f04011273..57535e80d8 100644 --- a/src/components/views/login/ServerConfig.js +++ b/src/components/views/auth/ServerConfig.js @@ -138,7 +138,7 @@ module.exports = React.createClass({ }, showHelpPopup: function() { - const CustomServerDialog = sdk.getComponent('login.CustomServerDialog'); + const CustomServerDialog = sdk.getComponent('auth.CustomServerDialog'); Modal.createTrackedDialog('Custom Server Dialog', '', CustomServerDialog); }, diff --git a/src/components/views/settings/AddPhoneNumber.js b/src/components/views/settings/AddPhoneNumber.js index 82169c9868..27164e6517 100644 --- a/src/components/views/settings/AddPhoneNumber.js +++ b/src/components/views/settings/AddPhoneNumber.js @@ -141,7 +141,7 @@ export default withMatrixClient(React.createClass({ return
    ; } - const CountryDropdown = sdk.getComponent('views.login.CountryDropdown'); + const CountryDropdown = sdk.getComponent('views.auth.CountryDropdown'); // XXX: This CSS relies on the CSS surrounding it in UserSettings as its in // a tabular format to align the submit buttons return ( diff --git a/src/stores/LifecycleStore.js b/src/stores/LifecycleStore.js index 2ce3be5a33..fcdfe93cf9 100644 --- a/src/stores/LifecycleStore.js +++ b/src/stores/LifecycleStore.js @@ -22,8 +22,8 @@ const INITIAL_STATE = { }; /** - * A class for storing application state to do with login/registration. This is a simple - * flux store that listens for actions and updates its state accordingly, informing any + * A class for storing application state to do with authentication. This is a simple flux + * store that listens for actions and updates its state accordingly, informing any * listeners (views) of state changes. */ class LifecycleStore extends Store { diff --git a/test/components/structures/login/Registration-test.js b/test/components/structures/auth/Registration-test.js similarity index 98% rename from test/components/structures/login/Registration-test.js rename to test/components/structures/auth/Registration-test.js index 7287bb0d95..4827bf4c12 100644 --- a/test/components/structures/login/Registration-test.js +++ b/test/components/structures/auth/Registration-test.js @@ -23,7 +23,7 @@ const expect = require('expect'); const testUtils = require('test-utils'); const sdk = require('matrix-react-sdk'); -const Registration = sdk.getComponent('structures.login.Registration'); +const Registration = sdk.getComponent('structures.auth.Registration'); let rtsClient; let client; diff --git a/test/components/views/login/RegistrationForm-test.js b/test/components/views/auth/RegistrationForm-test.js similarity index 97% rename from test/components/views/login/RegistrationForm-test.js rename to test/components/views/auth/RegistrationForm-test.js index 2d1c1be026..265f158bb9 100644 --- a/test/components/views/login/RegistrationForm-test.js +++ b/test/components/views/auth/RegistrationForm-test.js @@ -23,7 +23,7 @@ const expect = require('expect'); const testUtils = require('test-utils'); const sdk = require('matrix-react-sdk'); -const RegistrationForm = sdk.getComponent('views.login.RegistrationForm'); +const RegistrationForm = sdk.getComponent('views.auth.RegistrationForm'); const TEAM_CONFIG = { supportEmail: "support@some.domain", From 0e42c0892e046ce202871604eee3b546e247d026 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 18 Jan 2019 13:09:17 -0700 Subject: [PATCH 0199/1528] Early modalization of UserSettings Basically just shove it into a modal and call it good. --- src/components/structures/MatrixChat.js | 8 ++- .../views/dialogs/UserSettingsDialog.js | 49 +++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 src/components/views/dialogs/UserSettingsDialog.js diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 7acceb4bb7..25ba980bcf 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -611,8 +611,12 @@ export default React.createClass({ this._viewIndexedRoom(payload.roomIndex); break; case 'view_user_settings': - this._setPage(PageTypes.UserSettings); - this.notifyNewScreen('settings'); + const UserSettingsDialog = sdk.getComponent("dialogs.UserSettingsDialog"); + Modal.createTrackedDialog('User settings', '', UserSettingsDialog, { + title: _t("Settings"), + }); + //this._setPage(PageTypes.UserSettings); + //this.notifyNewScreen('settings'); break; case 'close_settings': this.setState({ diff --git a/src/components/views/dialogs/UserSettingsDialog.js b/src/components/views/dialogs/UserSettingsDialog.js new file mode 100644 index 0000000000..d12895010c --- /dev/null +++ b/src/components/views/dialogs/UserSettingsDialog.js @@ -0,0 +1,49 @@ +/* +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. +*/ + +import React from 'react'; +import PropTypes from 'prop-types'; +import sdk from '../../../index'; +import {_t} from '../../../languageHandler'; +import SdkConfig from "../../../SdkConfig"; + +export default React.createClass({ + propTypes: { + onFinished: PropTypes.func.isRequired, + }, + + render: function () { + const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); + const UserSettings = sdk.getComponent('structures.UserSettings'); + + return ( + +
    + +
    +
    + ); + }, +}); From 5adfc09237cb0eead02a8b2a9cf8fb2f2332a5fc Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 18 Jan 2019 13:43:17 -0700 Subject: [PATCH 0200/1528] Bring in TabbedView nearly verbatim from prior work Sourced from https://github.com/matrix-org/matrix-react-sdk/pull/1644 and related PRs. --- res/css/_components.scss | 1 + res/css/structures/_TabbedView.scss | 76 ++++++++ res/themes/dharma/css/_dharma.scss | 8 + res/themes/light/css/_base.scss | 9 + src/components/structures/MatrixChat.js | 4 +- src/components/structures/TabbedView.js | 165 ++++++++++++++++++ .../views/dialogs/UserSettingsDialog.js | 45 +++-- src/i18n/strings/en_EN.json | 4 +- 8 files changed, 284 insertions(+), 28 deletions(-) create mode 100644 res/css/structures/_TabbedView.scss create mode 100644 src/components/structures/TabbedView.js diff --git a/res/css/_components.scss b/res/css/_components.scss index a1b575a0a1..1b35332711 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -18,6 +18,7 @@ @import "./structures/_RoomSubList.scss"; @import "./structures/_RoomView.scss"; @import "./structures/_SearchBox.scss"; +@import "./structures/_TabbedView.scss"; @import "./structures/_TagPanel.scss"; @import "./structures/_TopLeftMenuButton.scss"; @import "./structures/_UploadBar.scss"; diff --git a/res/css/structures/_TabbedView.scss b/res/css/structures/_TabbedView.scss new file mode 100644 index 0000000000..7d42823d17 --- /dev/null +++ b/res/css/structures/_TabbedView.scss @@ -0,0 +1,76 @@ +/* +Copyright 2017 Travis Ralston + +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. +*/ + +.mx_TabbedView { + margin: 0; + padding: 0; + display: flex; + width: 100%; + height: 100%; + background-color: $tab-panel-bg-color; +} + +.mx_TabbedView_tabLabels { + width: 300px; + height: 100%; + background-color: $tab-list-bg-color; + color: $tab-list-fg-color; + border-right: 1px solid $tab-border-color; + border-left: 1px solid $tab-border-color; +} + +.mx_TabbedView_tabPanels { + width: calc(100% - 320px); + display: inline-block; + height: 100%; + padding-left: 20px; + scroll-snap-type: block; +} + +.mx_TabbedView_tabLabel { + text-align: center; + vertical-align: middle; + text-transform: uppercase; + cursor: pointer; + display: block; + padding: 20px; + width: calc(100% - 40px); + border-bottom: 1px solid $tab-border-color; +} + +.mx_TabbedView_exit { + padding-top: 10px; + padding-bottom: 10px; +} + +.mx_TabbedView_tabLabel:hover { + font-weight: 700; +} + +.mx_TabbedView_tabLabel_active { + font-weight: 700; + background-color: $tab-list-active-bg-color; + color: $tab-list-active-fg-color; +} + +.mx_TabbedView_tabPanel { + height: 100vh; // 100% of viewport height + scroll-snap-align: start; +} + +.mx_TabbedView_tabPanelContent { + width: 600px; +} \ No newline at end of file diff --git a/res/themes/dharma/css/_dharma.scss b/res/themes/dharma/css/_dharma.scss index c9f62fbe6b..8f369a3b33 100644 --- a/res/themes/dharma/css/_dharma.scss +++ b/res/themes/dharma/css/_dharma.scss @@ -186,6 +186,14 @@ $lightbox-bg-color: #454545; $lightbox-fg-color: #ffffff; $lightbox-border-color: #ffffff; +// Tabbed views +$tab-list-bg-color: $secondary-accent-color; +$tab-list-fg-color: $accent-color; +$tab-list-active-bg-color: $tertiary-accent-color; +$tab-list-active-fg-color: $accent-color; +$tab-border-color: $tertiary-accent-color; +$tab-panel-bg-color: #fff; + // unused? $progressbar-color: #000; diff --git a/res/themes/light/css/_base.scss b/res/themes/light/css/_base.scss index dbab909f13..996fe965cf 100644 --- a/res/themes/light/css/_base.scss +++ b/res/themes/light/css/_base.scss @@ -66,6 +66,7 @@ $primary-hairline-color: #e5e5e5; // used for the border of input text fields $input-border-color: #f0f0f0; +$input-border-dark-color: #b8b8b8; $input-darker-bg-color: #c1c9d6; $input-darker-fg-color: #9fa9ba; @@ -181,6 +182,14 @@ $imagebody-giflabel: rgba(0, 0, 0, 0.7); $imagebody-giflabel-border: rgba(0, 0, 0, 0.2); $imagebody-giflabel-color: rgba(255, 255, 255, 1); +// Tabbed views +$tab-list-bg-color: $secondary-accent-color; +$tab-list-fg-color: $accent-color; +$tab-list-active-bg-color: $tertiary-accent-color; +$tab-list-active-fg-color: $accent-color; +$tab-border-color: $tertiary-accent-color; +$tab-panel-bg-color: #fff; + // unused? $progressbar-color: #000; diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 25ba980bcf..9733576bd0 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -612,9 +612,7 @@ export default React.createClass({ break; case 'view_user_settings': const UserSettingsDialog = sdk.getComponent("dialogs.UserSettingsDialog"); - Modal.createTrackedDialog('User settings', '', UserSettingsDialog, { - title: _t("Settings"), - }); + Modal.createTrackedDialog('User settings', '', UserSettingsDialog, {}); //this._setPage(PageTypes.UserSettings); //this.notifyNewScreen('settings'); break; diff --git a/src/components/structures/TabbedView.js b/src/components/structures/TabbedView.js new file mode 100644 index 0000000000..44ecee7a95 --- /dev/null +++ b/src/components/structures/TabbedView.js @@ -0,0 +1,165 @@ +/* +Copyright 2017 Travis Ralston +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. +*/ + +import * as React from "react"; +import {_t, _td} from '../../languageHandler'; +import GeminiScrollbar from 'react-gemini-scrollbar'; +import PropTypes from "prop-types"; +//import scrollSnapPolyfill from 'css-scroll-snap-polyfill'; + +const DEFAULT_EXIT_STRING = _td("Return to app"); + +/** + * Represents a tab for the TabbedView + */ +export class Tab { + /** + * Creates a new tab + * @param {string} tabLabel The untranslated tab label + * @param {string} tabJsx The JSX for the tab container. + */ + constructor(tabLabel, tabJsx) { + this.label = tabLabel; + this.body = tabJsx; + } +} + +export class TabbedView extends React.Component { + constructor() { + super(); + + // This is used to track when the user has scrolled all the way up or down so we + // don't immediately start flipping between tabs. + this._reachedEndAt = 0; + } + + getInitialState() { + return { + activeTabIndex: 0, + }; + } + + _getActiveTabIndex() { + return this.state ? this.state.activeTabIndex : 0; + } + + /** + * Shows the given tab + * @param {Tab} tab the tab to show + * @private + */ + _setActiveTab(tab) { + const idx = this.props.tabs.indexOf(tab); + if (idx !== -1) { + this.setState({activeTabIndex: idx}); + this._reachedEndAt = 0; // reset scroll timer + } + else console.error("Could not find tab " + tab.label + " in tabs"); + } + + _nextTab() { + let targetIndex = this._getActiveTabIndex() + 1; + if (targetIndex < this.props.tabs.length) { + this.setState({activeTabIndex: targetIndex}); + this._reachedEndAt = 0; // reset scroll timer + } + } + + _previousTab() { + let targetIndex = this._getActiveTabIndex() - 1; + if (targetIndex >= 0) { + this.setState({activeTabIndex: targetIndex}); + this._reachedEndAt = 0; // reset scroll timer + } + } + + _getTabLabel(tab) { + let classes = "mx_TabbedView_tabLabel "; + + const idx = this.props.tabs.indexOf(tab); + if (idx === this._getActiveTabIndex()) classes += "mx_TabbedView_tabLabel_active"; + + return ( + this._setActiveTab(tab)}> + {_t(tab.label)} + + ); + } + + _getTabPanel(tab) { + return ( +
    + {tab.body} +
    + ); + } + + componentDidUpdate() { + window.requestAnimationFrame(() => { + console.log("SCROLL SNAP POLYFILL: UPDATE"); + //scrollSnapPolyfill(); + }); + } + + componentDidMount() { + window.requestAnimationFrame(() => { + console.log("SCROLL SNAP POLYFILL: MOUNT"); + //scrollSnapPolyfill(); + }); + } + + render() { + const labels = []; + const tabs = []; + + for (const tab of this.props.tabs) { + labels.push(this._getTabLabel(tab)); + tabs.push(this._getTabPanel(tab)); + } + + const returnToApp = ( + + {_t(this.props.exitLabel || DEFAULT_EXIT_STRING)} + + ); + + return ( +
    +
    + {returnToApp} + {labels} +
    +
    + {tabs} +
    +
    + ); + } +} + +TabbedView.PropTypes = { + // Called when the user clicks the "Exit" or "Return to app" button + onExit: PropTypes.func.isRequired, + + // The untranslated label for the "Return to app" button. + // Default: "Return to app" + exitLabel: PropTypes.string, + + // The tabs to show + tabs: PropTypes.arrayOf(Tab).isRequired, +}; \ No newline at end of file diff --git a/src/components/views/dialogs/UserSettingsDialog.js b/src/components/views/dialogs/UserSettingsDialog.js index d12895010c..f04b92b6cc 100644 --- a/src/components/views/dialogs/UserSettingsDialog.js +++ b/src/components/views/dialogs/UserSettingsDialog.js @@ -17,33 +17,30 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import sdk from '../../../index'; -import {_t} from '../../../languageHandler'; -import SdkConfig from "../../../SdkConfig"; +import {Tab, TabbedView} from "../../structures/TabbedView"; +import {_td} from "../../../languageHandler"; -export default React.createClass({ - propTypes: { +export default class UserSettingsDialog extends React.Component { + static propTypes = { onFinished: PropTypes.func.isRequired, - }, + }; - render: function () { - const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); - const UserSettings = sdk.getComponent('structures.UserSettings'); + _getTabs() { + return [ + new Tab(_td("General"),
    General Test
    ), + new Tab(_td("Account"),
    Account Test
    ), + ]; + } + render() { return ( - -
    - -
    -
    + + // ); - }, -}); + } +} diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index cfd5168152..cc18731ee0 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1043,6 +1043,8 @@ "Room contains unknown devices": "Room contains unknown devices", "\"%(RoomName)s\" contains devices that you haven't seen before.": "\"%(RoomName)s\" contains devices that you haven't seen before.", "Unknown devices": "Unknown devices", + "General": "General", + "Account": "Account", "Unable to load backup status": "Unable to load backup status", "Unable to restore backup": "Unable to restore backup", "No backup found!": "No backup found!", @@ -1222,6 +1224,7 @@ "Click to unmute audio": "Click to unmute audio", "Click to mute audio": "Click to mute audio", "Filter room names": "Filter room names", + "Return to app": "Return to app", "Clear filter": "Clear filter", "Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.": "Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.", "Tried to load a specific point in this room's timeline, but was unable to find it.": "Tried to load a specific point in this room's timeline, but was unable to find it.", @@ -1286,7 +1289,6 @@ "Add email address": "Add email address", "Profile": "Profile", "Display name": "Display name", - "Account": "Account", "To return to your account in future you need to set a password": "To return to your account in future you need to set a password", "Logged in as:": "Logged in as:", "Access Token:": "Access Token:", From 15709040e7b5c821ea04fdca76b4a4df05771a28 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 18 Jan 2019 15:07:11 -0700 Subject: [PATCH 0201/1528] Make tabs be their own panels --- res/css/structures/_TabbedView.scss | 42 +++---- res/themes/dharma/css/_dharma.scss | 10 +- res/themes/light/css/_base.scss | 10 +- src/components/structures/TabbedView.js | 103 ++++-------------- .../views/dialogs/UserSettingsDialog.js | 7 +- 5 files changed, 46 insertions(+), 126 deletions(-) diff --git a/res/css/structures/_TabbedView.scss b/res/css/structures/_TabbedView.scss index 7d42823d17..81a3af06a9 100644 --- a/res/css/structures/_TabbedView.scss +++ b/res/css/structures/_TabbedView.scss @@ -1,5 +1,6 @@ /* Copyright 2017 Travis Ralston +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. @@ -20,40 +21,22 @@ limitations under the License. display: flex; width: 100%; height: 100%; - background-color: $tab-panel-bg-color; } .mx_TabbedView_tabLabels { - width: 300px; + width: 136px; height: 100%; - background-color: $tab-list-bg-color; - color: $tab-list-fg-color; - border-right: 1px solid $tab-border-color; - border-left: 1px solid $tab-border-color; -} - -.mx_TabbedView_tabPanels { - width: calc(100% - 320px); - display: inline-block; - height: 100%; - padding-left: 20px; - scroll-snap-type: block; + color: $tab-label-fg-color; } .mx_TabbedView_tabLabel { - text-align: center; vertical-align: middle; - text-transform: uppercase; cursor: pointer; display: block; - padding: 20px; - width: calc(100% - 40px); - border-bottom: 1px solid $tab-border-color; -} - -.mx_TabbedView_exit { - padding-top: 10px; - padding-bottom: 10px; + border-radius: 3px; + font-size: 12px; + font-weight: 600; + height: 20px; } .mx_TabbedView_tabLabel:hover { @@ -61,16 +44,17 @@ limitations under the License. } .mx_TabbedView_tabLabel_active { - font-weight: 700; - background-color: $tab-list-active-bg-color; - color: $tab-list-active-fg-color; + background-color: $tab-label-active-bg-color; + color: $tab-label-active-fg-color; } .mx_TabbedView_tabPanel { + width: calc(100% - 320px); + display: inline-block; height: 100vh; // 100% of viewport height - scroll-snap-align: start; + margin-left: 20px; } .mx_TabbedView_tabPanelContent { - width: 600px; + flex-grow: 1; } \ No newline at end of file diff --git a/res/themes/dharma/css/_dharma.scss b/res/themes/dharma/css/_dharma.scss index 8f369a3b33..e95ad82daf 100644 --- a/res/themes/dharma/css/_dharma.scss +++ b/res/themes/dharma/css/_dharma.scss @@ -187,12 +187,10 @@ $lightbox-fg-color: #ffffff; $lightbox-border-color: #ffffff; // Tabbed views -$tab-list-bg-color: $secondary-accent-color; -$tab-list-fg-color: $accent-color; -$tab-list-active-bg-color: $tertiary-accent-color; -$tab-list-active-fg-color: $accent-color; -$tab-border-color: $tertiary-accent-color; -$tab-panel-bg-color: #fff; +$tab-label-fg-color: #45474a; +$tab-label-active-fg-color: #ffffff; +$tab-label-bg-color: transparent; +$tab-label-active-bg-color: #7ac9a1; // unused? $progressbar-color: #000; diff --git a/res/themes/light/css/_base.scss b/res/themes/light/css/_base.scss index 996fe965cf..852442c4d1 100644 --- a/res/themes/light/css/_base.scss +++ b/res/themes/light/css/_base.scss @@ -183,12 +183,10 @@ $imagebody-giflabel-border: rgba(0, 0, 0, 0.2); $imagebody-giflabel-color: rgba(255, 255, 255, 1); // Tabbed views -$tab-list-bg-color: $secondary-accent-color; -$tab-list-fg-color: $accent-color; -$tab-list-active-bg-color: $tertiary-accent-color; -$tab-list-active-fg-color: $accent-color; -$tab-border-color: $tertiary-accent-color; -$tab-panel-bg-color: #fff; +$tab-label-fg-color: #45474a; +$tab-label-active-fg-color: #ffffff; +$tab-label-bg-color: transparent; +$tab-label-active-bg-color: #7ac9a1; // unused? $progressbar-color: #000; diff --git a/src/components/structures/TabbedView.js b/src/components/structures/TabbedView.js index 44ecee7a95..047d48e808 100644 --- a/src/components/structures/TabbedView.js +++ b/src/components/structures/TabbedView.js @@ -16,45 +16,42 @@ limitations under the License. */ import * as React from "react"; -import {_t, _td} from '../../languageHandler'; -import GeminiScrollbar from 'react-gemini-scrollbar'; +import {_t} from '../../languageHandler'; import PropTypes from "prop-types"; -//import scrollSnapPolyfill from 'css-scroll-snap-polyfill'; - -const DEFAULT_EXIT_STRING = _td("Return to app"); /** - * Represents a tab for the TabbedView + * Represents a tab for the TabbedView. */ export class Tab { /** - * Creates a new tab - * @param {string} tabLabel The untranslated tab label + * Creates a new tab. + * @param {string} tabLabel The untranslated tab label. + * @param {string} tabIconRef The relative path to the tab's icon. * @param {string} tabJsx The JSX for the tab container. */ - constructor(tabLabel, tabJsx) { + constructor(tabLabel, tabIconRef, tabJsx) { this.label = tabLabel; this.body = tabJsx; } } export class TabbedView extends React.Component { + static propTypes = { + // The tabs to show + tabs: PropTypes.arrayOf(Tab).isRequired, + }; + constructor() { super(); - // This is used to track when the user has scrolled all the way up or down so we - // don't immediately start flipping between tabs. - this._reachedEndAt = 0; - } - - getInitialState() { - return { + this.state = { activeTabIndex: 0, }; } _getActiveTabIndex() { - return this.state ? this.state.activeTabIndex : 0; + if (!this.state || !this.state.activeTabIndex) return 0; + return this.state.activeTabIndex; } /** @@ -66,28 +63,12 @@ export class TabbedView extends React.Component { const idx = this.props.tabs.indexOf(tab); if (idx !== -1) { this.setState({activeTabIndex: idx}); - this._reachedEndAt = 0; // reset scroll timer - } - else console.error("Could not find tab " + tab.label + " in tabs"); - } - - _nextTab() { - let targetIndex = this._getActiveTabIndex() + 1; - if (targetIndex < this.props.tabs.length) { - this.setState({activeTabIndex: targetIndex}); - this._reachedEndAt = 0; // reset scroll timer + } else { + console.error("Could not find tab " + tab.label + " in tabs"); } } - _previousTab() { - let targetIndex = this._getActiveTabIndex() - 1; - if (targetIndex >= 0) { - this.setState({activeTabIndex: targetIndex}); - this._reachedEndAt = 0; // reset scroll timer - } - } - - _getTabLabel(tab) { + _renderTabLabel(tab) { let classes = "mx_TabbedView_tabLabel "; const idx = this.props.tabs.indexOf(tab); @@ -101,7 +82,7 @@ export class TabbedView extends React.Component { ); } - _getTabPanel(tab) { + _renderTabPanel(tab) { return (
    {tab.body} @@ -109,57 +90,17 @@ export class TabbedView extends React.Component { ); } - componentDidUpdate() { - window.requestAnimationFrame(() => { - console.log("SCROLL SNAP POLYFILL: UPDATE"); - //scrollSnapPolyfill(); - }); - } - - componentDidMount() { - window.requestAnimationFrame(() => { - console.log("SCROLL SNAP POLYFILL: MOUNT"); - //scrollSnapPolyfill(); - }); - } - render() { - const labels = []; - const tabs = []; - - for (const tab of this.props.tabs) { - labels.push(this._getTabLabel(tab)); - tabs.push(this._getTabPanel(tab)); - } - - const returnToApp = ( - - {_t(this.props.exitLabel || DEFAULT_EXIT_STRING)} - - ); + const labels = this.props.tabs.map(tab => this._renderTabLabel(tab)); + const panel = this._renderTabPanel(this.props.tabs[this._getActiveTabIndex()]); return (
    - {returnToApp} {labels}
    -
    - {tabs} -
    + {panel}
    ); } -} - -TabbedView.PropTypes = { - // Called when the user clicks the "Exit" or "Return to app" button - onExit: PropTypes.func.isRequired, - - // The untranslated label for the "Return to app" button. - // Default: "Return to app" - exitLabel: PropTypes.string, - - // The tabs to show - tabs: PropTypes.arrayOf(Tab).isRequired, -}; \ No newline at end of file +} \ No newline at end of file diff --git a/src/components/views/dialogs/UserSettingsDialog.js b/src/components/views/dialogs/UserSettingsDialog.js index f04b92b6cc..e54bc9c857 100644 --- a/src/components/views/dialogs/UserSettingsDialog.js +++ b/src/components/views/dialogs/UserSettingsDialog.js @@ -16,7 +16,6 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; -import sdk from '../../../index'; import {Tab, TabbedView} from "../../structures/TabbedView"; import {_td} from "../../../languageHandler"; @@ -27,14 +26,14 @@ export default class UserSettingsDialog extends React.Component { _getTabs() { return [ - new Tab(_td("General"),
    General Test
    ), - new Tab(_td("Account"),
    Account Test
    ), + new Tab(_td("General"), "",
    General Test
    ), + new Tab(_td("Account"), "",
    Account Test
    ), ]; } render() { return ( - + // Date: Fri, 18 Jan 2019 19:40:21 -0700 Subject: [PATCH 0202/1528] Make the tabs look like the design --- res/css/_components.scss | 1 + res/css/structures/_TabbedView.scss | 39 +++++++++++++++++-- .../views/dialogs/_UserSettingsDialog.scss | 26 +++++++++++++ res/themes/dharma/css/_dharma.scss | 2 + res/themes/light/css/_base.scss | 2 + src/components/structures/TabbedView.js | 15 +++++-- .../views/dialogs/UserSettingsDialog.js | 20 ++++++++-- src/i18n/strings/en_EN.json | 7 +++- 8 files changed, 99 insertions(+), 13 deletions(-) create mode 100644 res/css/views/dialogs/_UserSettingsDialog.scss diff --git a/res/css/_components.scss b/res/css/_components.scss index 1b35332711..e60e74383f 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -52,6 +52,7 @@ @import "./views/dialogs/_SetPasswordDialog.scss"; @import "./views/dialogs/_ShareDialog.scss"; @import "./views/dialogs/_UnknownDeviceDialog.scss"; +@import "./views/dialogs/_UserSettingsDialog.scss"; @import "./views/dialogs/keybackup/_CreateKeyBackupDialog.scss"; @import "./views/dialogs/keybackup/_KeyBackupFailedDialog.scss"; @import "./views/dialogs/keybackup/_RestoreKeyBackupDialog.scss"; diff --git a/res/css/structures/_TabbedView.scss b/res/css/structures/_TabbedView.scss index 81a3af06a9..32174a0ef5 100644 --- a/res/css/structures/_TabbedView.scss +++ b/res/css/structures/_TabbedView.scss @@ -39,15 +39,46 @@ limitations under the License. height: 20px; } -.mx_TabbedView_tabLabel:hover { - font-weight: 700; -} - .mx_TabbedView_tabLabel_active { background-color: $tab-label-active-bg-color; color: $tab-label-active-fg-color; } +.mx_TabbedView_tabLabel_icon { + width: 12px; + height: 12px; + margin-left: 6px; + margin-right: 9px; + position: relative; +} + +.mx_TabbedView_tabLabel_icon > .mx_TabbedView_maskedIcon { + width: 12px; + height: 12px; + display: inline-block; +} + +.mx_TabbedView_tabLabel_icon > .mx_TabbedView_maskedIcon:before { + background-color: $tab-label-icon-bg-color; + mask-repeat: no-repeat; + mask-size: 12px; + mask-position: center; + content: ''; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; +} + +.mx_TabbedView_tabLabel_active .mx_TabbedView_tabLabel_icon > .mx_TabbedView_maskedIcon:before { + background-color: $tab-label-active-icon-bg-color; +} + +.mx_TabbedView_tabLabel_text { + vertical-align: middle; +} + .mx_TabbedView_tabPanel { width: calc(100% - 320px); display: inline-block; diff --git a/res/css/views/dialogs/_UserSettingsDialog.scss b/res/css/views/dialogs/_UserSettingsDialog.scss new file mode 100644 index 0000000000..7d8c80e5bd --- /dev/null +++ b/res/css/views/dialogs/_UserSettingsDialog.scss @@ -0,0 +1,26 @@ +.mx_UserSettingsDialog_settingsIcon:before { + mask: url('$(res)/img/feather-icons/settings.svg'); +} + +.mx_UserSettingsDialog_voiceIcon:before { + mask: url('$(res)/img/feather-icons/phone.svg'); +} + +.mx_UserSettingsDialog_bellIcon:before { + mask: url('$(res)/img/feather-icons/notifications.svg'); +} + +.mx_UserSettingsDialog_preferencesIcon:before { + // TODO: Use real icon + mask: url('$(res)/img/feather-icons/paperclip.svg'); +} + +.mx_UserSettingsDialog_securityIcon:before { + // TODO: Use real icon + mask: url('$(res)/img/feather-icons/life-buoy.svg'); +} + +.mx_UserSettingsDialog_helpIcon:before { + // TODO: Use real icon + mask: url('$(res)/img/feather-icons/share.svg'); +} diff --git a/res/themes/dharma/css/_dharma.scss b/res/themes/dharma/css/_dharma.scss index e95ad82daf..5f405e49e9 100644 --- a/res/themes/dharma/css/_dharma.scss +++ b/res/themes/dharma/css/_dharma.scss @@ -191,6 +191,8 @@ $tab-label-fg-color: #45474a; $tab-label-active-fg-color: #ffffff; $tab-label-bg-color: transparent; $tab-label-active-bg-color: #7ac9a1; +$tab-label-icon-bg-color: #454545; +$tab-label-active-icon-bg-color: #ffffff; // unused? $progressbar-color: #000; diff --git a/res/themes/light/css/_base.scss b/res/themes/light/css/_base.scss index 852442c4d1..69f1b61f5f 100644 --- a/res/themes/light/css/_base.scss +++ b/res/themes/light/css/_base.scss @@ -187,6 +187,8 @@ $tab-label-fg-color: #45474a; $tab-label-active-fg-color: #ffffff; $tab-label-bg-color: transparent; $tab-label-active-bg-color: #7ac9a1; +$tab-label-icon-bg-color: #454545; +$tab-label-active-icon-bg-color: #ffffff; // unused? $progressbar-color: #000; diff --git a/src/components/structures/TabbedView.js b/src/components/structures/TabbedView.js index 047d48e808..48f8c7a4d8 100644 --- a/src/components/structures/TabbedView.js +++ b/src/components/structures/TabbedView.js @@ -26,11 +26,12 @@ export class Tab { /** * Creates a new tab. * @param {string} tabLabel The untranslated tab label. - * @param {string} tabIconRef The relative path to the tab's icon. + * @param {string} tabIconJsx The JSX for the tab icon. This should be a plain img element or null. * @param {string} tabJsx The JSX for the tab container. */ - constructor(tabLabel, tabIconRef, tabJsx) { + constructor(tabLabel, tabIconJsx, tabJsx) { this.label = tabLabel; + this.icon = tabIconJsx; this.body = tabJsx; } } @@ -74,10 +75,18 @@ export class TabbedView extends React.Component { const idx = this.props.tabs.indexOf(tab); if (idx === this._getActiveTabIndex()) classes += "mx_TabbedView_tabLabel_active"; + let tabIcon = null; + if (tab.icon) { + tabIcon = {tab.icon}; + } + return ( this._setActiveTab(tab)}> - {_t(tab.label)} + {tabIcon} + + {_t(tab.label)} + ); } diff --git a/src/components/views/dialogs/UserSettingsDialog.js b/src/components/views/dialogs/UserSettingsDialog.js index e54bc9c857..189d5871e3 100644 --- a/src/components/views/dialogs/UserSettingsDialog.js +++ b/src/components/views/dialogs/UserSettingsDialog.js @@ -17,7 +17,7 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import {Tab, TabbedView} from "../../structures/TabbedView"; -import {_td} from "../../../languageHandler"; +import {_t, _td} from "../../../languageHandler"; export default class UserSettingsDialog extends React.Component { static propTypes = { @@ -26,14 +26,26 @@ export default class UserSettingsDialog extends React.Component { _getTabs() { return [ - new Tab(_td("General"), "",
    General Test
    ), - new Tab(_td("Account"), "",
    Account Test
    ), + new Tab(_td("General"), ,
    General Test
    ), + new Tab(_td("Notifications"), ,
    Notifications Test
    ), + new Tab(_td("Preferences"), ,
    Preferences Test
    ), + new Tab(_td("Voice & Video"), ,
    Voice Test
    ), + new Tab(_td("Security & Privacy"), ,
    Security Test
    ), + new Tab(_td("Help & About"), ,
    Help Test
    ), ]; } render() { return ( - +
    +

    + {_t("Settings")} +

    + + X + + +
    // Date: Fri, 18 Jan 2019 20:09:23 -0700 Subject: [PATCH 0203/1528] Make the dialog look more like a new dialog --- res/css/_common.scss | 4 +- res/css/structures/_TabbedView.scss | 2 +- .../views/dialogs/_UserSettingsDialog.scss | 43 ++++++++++++++++++- res/themes/dharma/css/_dharma.scss | 5 +++ res/themes/light/css/_base.scss | 5 +++ .../views/dialogs/UserSettingsDialog.js | 11 ++--- 6 files changed, 61 insertions(+), 9 deletions(-) diff --git a/res/css/_common.scss b/res/css/_common.scss index bec4c02c18..306834bcde 100644 --- a/res/css/_common.scss +++ b/res/css/_common.scss @@ -160,7 +160,7 @@ textarea { padding: 0 58px 36px; width: 60%; max-width: 704px; - box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.2); + box-shadow: 2px 15px 30px 0 $dialog-shadow-color; max-height: 80%; overflow-y: auto; } @@ -171,7 +171,7 @@ textarea { left: 0; width: 100%; height: 100%; - background-color: $dialog-background-bg-color; + background-color: $dialog-backdrop-color; opacity: 0.8; } diff --git a/res/css/structures/_TabbedView.scss b/res/css/structures/_TabbedView.scss index 32174a0ef5..957e989f53 100644 --- a/res/css/structures/_TabbedView.scss +++ b/res/css/structures/_TabbedView.scss @@ -82,8 +82,8 @@ limitations under the License. .mx_TabbedView_tabPanel { width: calc(100% - 320px); display: inline-block; - height: 100vh; // 100% of viewport height margin-left: 20px; + flex-grow: 1; } .mx_TabbedView_tabPanelContent { diff --git a/res/css/views/dialogs/_UserSettingsDialog.scss b/res/css/views/dialogs/_UserSettingsDialog.scss index 7d8c80e5bd..e98001fea4 100644 --- a/res/css/views/dialogs/_UserSettingsDialog.scss +++ b/res/css/views/dialogs/_UserSettingsDialog.scss @@ -1,3 +1,44 @@ +.mx_UserSettingsDialog_header { + font-size: 24px; + display: block; + text-align: center; + color: $dialog-title-fg-color; + margin-top: 23px; + margin-bottom: 32px; + padding: 0; +} + +.mx_UserSettingsDialog_close { + position: absolute; + top: 23px; + right: 25px; +} + +.mx_UserSettingsDialog_closeIcon { + width: 14px; + height: 14px; + display: inline-block; +} + +.mx_UserSettingsDialog_closeIcon:before { + // TODO: Use real icon + mask: url('$(res)/img/feather-icons/video.svg'); + background-color: $dialog-close-fg-color; + mask-repeat: no-repeat; + mask-size: 14px; + mask-position: center; + content: ''; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; +} + + +// ICONS +// ========================================================== + .mx_UserSettingsDialog_settingsIcon:before { mask: url('$(res)/img/feather-icons/settings.svg'); } @@ -23,4 +64,4 @@ .mx_UserSettingsDialog_helpIcon:before { // TODO: Use real icon mask: url('$(res)/img/feather-icons/share.svg'); -} +} \ No newline at end of file diff --git a/res/themes/dharma/css/_dharma.scss b/res/themes/dharma/css/_dharma.scss index 5f405e49e9..cf3738a1bb 100644 --- a/res/themes/dharma/css/_dharma.scss +++ b/res/themes/dharma/css/_dharma.scss @@ -96,6 +96,11 @@ $avatar-bg-color: #ffffff; $h3-color: #3d3b39; +$dialog-title-fg-color: #454545; +$dialog-backdrop-color: rgba(46, 48, 51, 0.38); +$dialog-shadow-color: rgba(0, 0, 0, 0.48); +$dialog-close-fg-color: #9fa9ba; + $dialog-background-bg-color: #e9e9e9; $lightbox-background-bg-color: #000; diff --git a/res/themes/light/css/_base.scss b/res/themes/light/css/_base.scss index 69f1b61f5f..45b64243c6 100644 --- a/res/themes/light/css/_base.scss +++ b/res/themes/light/css/_base.scss @@ -93,6 +93,11 @@ $avatar-bg-color: #ffffff; $h3-color: #3d3b39; +$dialog-title-fg-color: #454545; +$dialog-backdrop-color: rgba(46, 48, 51, 0.38); +$dialog-shadow-color: rgba(0, 0, 0, 0.48); +$dialog-close-fg-color: #9fa9ba; + $dialog-background-bg-color: #e9e9e9; $lightbox-background-bg-color: #000; diff --git a/src/components/views/dialogs/UserSettingsDialog.js b/src/components/views/dialogs/UserSettingsDialog.js index 189d5871e3..1896bd38e0 100644 --- a/src/components/views/dialogs/UserSettingsDialog.js +++ b/src/components/views/dialogs/UserSettingsDialog.js @@ -18,6 +18,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import {Tab, TabbedView} from "../../structures/TabbedView"; import {_t, _td} from "../../../languageHandler"; +import AccessibleButton from "../elements/AccessibleButton"; export default class UserSettingsDialog extends React.Component { static propTypes = { @@ -38,12 +39,12 @@ export default class UserSettingsDialog extends React.Component { render() { return (
    -

    +
    {_t("Settings")} -

    - - X - + + + +
    // Date: Fri, 18 Jan 2019 20:22:36 -0700 Subject: [PATCH 0204/1528] Very early work on the "General" tab --- res/css/_components.scss | 2 + res/css/structures/_TabbedView.scss | 2 +- .../views/dialogs/_UserSettingsDialog.scss | 2 +- .../settings/tabs/_GeneralSettingsTab.scss | 6 +++ res/css/views/settings/tabs/_SettingsTab.scss | 13 +++++ .../views/dialogs/UserSettingsDialog.js | 3 +- .../views/settings/tabs/GeneralSettingsTab.js | 53 +++++++++++++++++++ 7 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 res/css/views/settings/tabs/_GeneralSettingsTab.scss create mode 100644 res/css/views/settings/tabs/_SettingsTab.scss create mode 100644 src/components/views/settings/tabs/GeneralSettingsTab.js diff --git a/res/css/_components.scss b/res/css/_components.scss index e60e74383f..c1e2cc29cd 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -124,6 +124,8 @@ @import "./views/settings/_IntegrationsManager.scss"; @import "./views/settings/_KeyBackupPanel.scss"; @import "./views/settings/_Notifications.scss"; +@import "./views/settings/tabs/_GeneralSettingsTab.scss"; +@import "./views/settings/tabs/_SettingsTab.scss"; @import "./views/voip/_CallView.scss"; @import "./views/voip/_IncomingCallbox.scss"; @import "./views/voip/_VideoView.scss"; diff --git a/res/css/structures/_TabbedView.scss b/res/css/structures/_TabbedView.scss index 957e989f53..322e763000 100644 --- a/res/css/structures/_TabbedView.scss +++ b/res/css/structures/_TabbedView.scss @@ -82,7 +82,7 @@ limitations under the License. .mx_TabbedView_tabPanel { width: calc(100% - 320px); display: inline-block; - margin-left: 20px; + margin-left: 70px; flex-grow: 1; } diff --git a/res/css/views/dialogs/_UserSettingsDialog.scss b/res/css/views/dialogs/_UserSettingsDialog.scss index e98001fea4..75d89a1d06 100644 --- a/res/css/views/dialogs/_UserSettingsDialog.scss +++ b/res/css/views/dialogs/_UserSettingsDialog.scss @@ -4,7 +4,7 @@ text-align: center; color: $dialog-title-fg-color; margin-top: 23px; - margin-bottom: 32px; + margin-bottom: 24px; padding: 0; } diff --git a/res/css/views/settings/tabs/_GeneralSettingsTab.scss b/res/css/views/settings/tabs/_GeneralSettingsTab.scss new file mode 100644 index 0000000000..b04975fc2d --- /dev/null +++ b/res/css/views/settings/tabs/_GeneralSettingsTab.scss @@ -0,0 +1,6 @@ +.mx_GeneralSettingsTab_profile input { + display: block; + font-size: 14px; + padding: 5px; + border-radius: 4px; +} \ No newline at end of file diff --git a/res/css/views/settings/tabs/_SettingsTab.scss b/res/css/views/settings/tabs/_SettingsTab.scss new file mode 100644 index 0000000000..13e8b0ab51 --- /dev/null +++ b/res/css/views/settings/tabs/_SettingsTab.scss @@ -0,0 +1,13 @@ +.mx_SettingsTab_heading { + font-size: 20px; + font-weight: 600; +} + +.mx_SettingsTab_subheading { + font-size: 14px; + display: block; +} + +.mx_SettingsTab_section { + margin-top: 10px; +} \ No newline at end of file diff --git a/src/components/views/dialogs/UserSettingsDialog.js b/src/components/views/dialogs/UserSettingsDialog.js index 1896bd38e0..b5450c01b5 100644 --- a/src/components/views/dialogs/UserSettingsDialog.js +++ b/src/components/views/dialogs/UserSettingsDialog.js @@ -19,6 +19,7 @@ import PropTypes from 'prop-types'; import {Tab, TabbedView} from "../../structures/TabbedView"; import {_t, _td} from "../../../languageHandler"; import AccessibleButton from "../elements/AccessibleButton"; +import GeneralSettingsTab from "../settings/tabs/GeneralSettingsTab"; export default class UserSettingsDialog extends React.Component { static propTypes = { @@ -27,7 +28,7 @@ export default class UserSettingsDialog extends React.Component { _getTabs() { return [ - new Tab(_td("General"), ,
    General Test
    ), + new Tab(_td("General"), , ), new Tab(_td("Notifications"), ,
    Notifications Test
    ), new Tab(_td("Preferences"), ,
    Preferences Test
    ), new Tab(_td("Voice & Video"), ,
    Voice Test
    ), diff --git a/src/components/views/settings/tabs/GeneralSettingsTab.js b/src/components/views/settings/tabs/GeneralSettingsTab.js new file mode 100644 index 0000000000..60f557d918 --- /dev/null +++ b/src/components/views/settings/tabs/GeneralSettingsTab.js @@ -0,0 +1,53 @@ +/* +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. +*/ + +import React from 'react'; +import PropTypes from 'prop-types'; +import {_t} from "../../../../languageHandler"; + +export default class GeneralSettingsTab extends React.Component { + static propTypes = { + onFinished: PropTypes.func.isRequired, + }; + + render() { + return ( +
    +
    {_t("General")}
    +
    + {_t("Profile")} + + +
    +
    + {_t("Profile")} + + +
    +
    + {_t("Profile")} + + +
    +
    + {_t("Profile")} + + +
    +
    + ); + } +} From d907647e61b8d3e5664c2a4c6a8eb6e8964edfbf Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 18 Jan 2019 20:25:44 -0700 Subject: [PATCH 0205/1528] Spread the tabs out a bit --- res/css/structures/_TabbedView.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/res/css/structures/_TabbedView.scss b/res/css/structures/_TabbedView.scss index 322e763000..ecb7193c18 100644 --- a/res/css/structures/_TabbedView.scss +++ b/res/css/structures/_TabbedView.scss @@ -37,6 +37,7 @@ limitations under the License. font-size: 12px; font-weight: 600; height: 20px; + margin-bottom: 6px; } .mx_TabbedView_tabLabel_active { From a8ec40a8b06f6e6472a24b49f6aedab3b5efa4ef Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 18 Jan 2019 20:36:02 -0700 Subject: [PATCH 0206/1528] Add a temporary tab for visiting the old settings For debugging purposes --- src/components/structures/MatrixChat.js | 4 ++++ .../views/dialogs/UserSettingsDialog.js | 18 ++++++++++++++++ .../views/settings/tabs/GeneralSettingsTab.js | 21 +++++++------------ src/i18n/strings/en_EN.json | 5 +++-- 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 9733576bd0..2b585506ae 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -616,6 +616,10 @@ export default React.createClass({ //this._setPage(PageTypes.UserSettings); //this.notifyNewScreen('settings'); break; + case 'view_old_user_settings': + this._setPage(PageTypes.UserSettings); + this.notifyNewScreen('settings'); + break; case 'close_settings': this.setState({ leftDisabled: false, diff --git a/src/components/views/dialogs/UserSettingsDialog.js b/src/components/views/dialogs/UserSettingsDialog.js index b5450c01b5..d355eb77bc 100644 --- a/src/components/views/dialogs/UserSettingsDialog.js +++ b/src/components/views/dialogs/UserSettingsDialog.js @@ -20,6 +20,23 @@ import {Tab, TabbedView} from "../../structures/TabbedView"; import {_t, _td} from "../../../languageHandler"; import AccessibleButton from "../elements/AccessibleButton"; import GeneralSettingsTab from "../settings/tabs/GeneralSettingsTab"; +import dis from '../../../dispatcher'; + +export class TempTab extends React.Component { + // TODO: Ditch this + static propTypes = { + onClose: PropTypes.func.isRequired, + }; + + componentDidMount(): void { + dis.dispatch({action: "view_old_user_settings"}); + this.props.onClose(); + } + + render() { + return
    Hello World
    ; + } +} export default class UserSettingsDialog extends React.Component { static propTypes = { @@ -34,6 +51,7 @@ export default class UserSettingsDialog extends React.Component { new Tab(_td("Voice & Video"), ,
    Voice Test
    ), new Tab(_td("Security & Privacy"), ,
    Security Test
    ), new Tab(_td("Help & About"), ,
    Help Test
    ), + new Tab(_td("Visit old settings"), , ), ]; } diff --git a/src/components/views/settings/tabs/GeneralSettingsTab.js b/src/components/views/settings/tabs/GeneralSettingsTab.js index 60f557d918..433b12a674 100644 --- a/src/components/views/settings/tabs/GeneralSettingsTab.js +++ b/src/components/views/settings/tabs/GeneralSettingsTab.js @@ -15,37 +15,32 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import {_t} from "../../../../languageHandler"; export default class GeneralSettingsTab extends React.Component { - static propTypes = { - onFinished: PropTypes.func.isRequired, - }; - render() { return (
    {_t("General")}
    {_t("Profile")} - - + +
    {_t("Profile")} - - + +
    {_t("Profile")} - - + +
    {_t("Profile")} - - + +
    ); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 2d547eda0c..6a06811fb3 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -401,6 +401,8 @@ "Off": "Off", "On": "On", "Noisy": "Noisy", + "General": "General", + "Profile": "Profile", "Cannot add any more widgets": "Cannot add any more widgets", "The maximum permitted number of widgets have already been added to this room.": "The maximum permitted number of widgets have already been added to this room.", "Add a widget": "Add a widget", @@ -1043,11 +1045,11 @@ "Room contains unknown devices": "Room contains unknown devices", "\"%(RoomName)s\" contains devices that you haven't seen before.": "\"%(RoomName)s\" contains devices that you haven't seen before.", "Unknown devices": "Unknown devices", - "General": "General", "Preferences": "Preferences", "Voice & Video": "Voice & Video", "Security & Privacy": "Security & Privacy", "Help & About": "Help & About", + "Visit old settings": "Visit old settings", "Unable to load backup status": "Unable to load backup status", "Unable to restore backup": "Unable to restore backup", "No backup found!": "No backup found!", @@ -1289,7 +1291,6 @@ "VoIP": "VoIP", "Email": "Email", "Add email address": "Add email address", - "Profile": "Profile", "Display name": "Display name", "Account": "Account", "To return to your account in future you need to set a password": "To return to your account in future you need to set a password", From c3692aa9ae7237c1366712c9ff7c58e70ef38681 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 21 Jan 2019 16:03:44 -0700 Subject: [PATCH 0207/1528] Use the right icons, sizing, and font families for things --- res/css/structures/_TabbedView.scss | 12 +++++------ .../views/dialogs/_UserSettingsDialog.scss | 21 ++++++++----------- res/css/views/settings/tabs/_SettingsTab.scss | 6 +++++- res/img/feather-icons/cancel.svg | 10 +++++++++ res/img/feather-icons/help-circle.svg | 6 ++++++ res/img/feather-icons/lock.svg | 6 ++++++ res/img/feather-icons/sliders.svg | 5 +++++ res/themes/dharma/css/_dharma.scss | 1 + res/themes/light/css/_base.scss | 1 + 9 files changed, 49 insertions(+), 19 deletions(-) create mode 100644 res/img/feather-icons/cancel.svg create mode 100644 res/img/feather-icons/help-circle.svg create mode 100644 res/img/feather-icons/lock.svg create mode 100644 res/img/feather-icons/sliders.svg diff --git a/res/css/structures/_TabbedView.scss b/res/css/structures/_TabbedView.scss index ecb7193c18..b888aa287b 100644 --- a/res/css/structures/_TabbedView.scss +++ b/res/css/structures/_TabbedView.scss @@ -30,7 +30,7 @@ limitations under the License. } .mx_TabbedView_tabLabel { - vertical-align: middle; + vertical-align: text-top; cursor: pointer; display: block; border-radius: 3px; @@ -46,23 +46,23 @@ limitations under the License. } .mx_TabbedView_tabLabel_icon { - width: 12px; - height: 12px; + width: 14px; + height: 14px; margin-left: 6px; margin-right: 9px; position: relative; } .mx_TabbedView_tabLabel_icon > .mx_TabbedView_maskedIcon { - width: 12px; - height: 12px; + width: 14px; + height: 14px; display: inline-block; } .mx_TabbedView_tabLabel_icon > .mx_TabbedView_maskedIcon:before { background-color: $tab-label-icon-bg-color; mask-repeat: no-repeat; - mask-size: 12px; + mask-size: 14px; mask-position: center; content: ''; position: absolute; diff --git a/res/css/views/dialogs/_UserSettingsDialog.scss b/res/css/views/dialogs/_UserSettingsDialog.scss index 75d89a1d06..25be25bd56 100644 --- a/res/css/views/dialogs/_UserSettingsDialog.scss +++ b/res/css/views/dialogs/_UserSettingsDialog.scss @@ -3,29 +3,29 @@ display: block; text-align: center; color: $dialog-title-fg-color; - margin-top: 23px; + margin-top: 16px; margin-bottom: 24px; padding: 0; } .mx_UserSettingsDialog_close { position: absolute; - top: 23px; + top: 16px; right: 25px; } .mx_UserSettingsDialog_closeIcon { - width: 14px; - height: 14px; + width: 16px; + height: 16px; display: inline-block; } .mx_UserSettingsDialog_closeIcon:before { // TODO: Use real icon - mask: url('$(res)/img/feather-icons/video.svg'); + mask: url('$(res)/img/feather-icons/cancel.svg'); background-color: $dialog-close-fg-color; mask-repeat: no-repeat; - mask-size: 14px; + mask-size: 16px; mask-position: center; content: ''; position: absolute; @@ -52,16 +52,13 @@ } .mx_UserSettingsDialog_preferencesIcon:before { - // TODO: Use real icon - mask: url('$(res)/img/feather-icons/paperclip.svg'); + mask: url('$(res)/img/feather-icons/sliders.svg'); } .mx_UserSettingsDialog_securityIcon:before { - // TODO: Use real icon - mask: url('$(res)/img/feather-icons/life-buoy.svg'); + mask: url('$(res)/img/feather-icons/lock.svg'); } .mx_UserSettingsDialog_helpIcon:before { - // TODO: Use real icon - mask: url('$(res)/img/feather-icons/share.svg'); + mask: url('$(res)/img/feather-icons/help-circle.svg'); } \ No newline at end of file diff --git a/res/css/views/settings/tabs/_SettingsTab.scss b/res/css/views/settings/tabs/_SettingsTab.scss index 13e8b0ab51..0753df56af 100644 --- a/res/css/views/settings/tabs/_SettingsTab.scss +++ b/res/css/views/settings/tabs/_SettingsTab.scss @@ -1,13 +1,17 @@ .mx_SettingsTab_heading { font-size: 20px; font-weight: 600; + color: $primary-fg-color; } .mx_SettingsTab_subheading { font-size: 14px; display: block; + font-family: $font-family-semibold; + color: $primary-fg-color; + margin-bottom: 10px; } .mx_SettingsTab_section { margin-top: 10px; -} \ No newline at end of file +} diff --git a/res/img/feather-icons/cancel.svg b/res/img/feather-icons/cancel.svg new file mode 100644 index 0000000000..6b734e4053 --- /dev/null +++ b/res/img/feather-icons/cancel.svg @@ -0,0 +1,10 @@ + + + + Slice 1 + Created with Sketch. + + + + + \ No newline at end of file diff --git a/res/img/feather-icons/help-circle.svg b/res/img/feather-icons/help-circle.svg new file mode 100644 index 0000000000..7ecb0a8f35 --- /dev/null +++ b/res/img/feather-icons/help-circle.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/res/img/feather-icons/lock.svg b/res/img/feather-icons/lock.svg new file mode 100644 index 0000000000..1330903b30 --- /dev/null +++ b/res/img/feather-icons/lock.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/res/img/feather-icons/sliders.svg b/res/img/feather-icons/sliders.svg new file mode 100644 index 0000000000..5b5ec8656c --- /dev/null +++ b/res/img/feather-icons/sliders.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/res/themes/dharma/css/_dharma.scss b/res/themes/dharma/css/_dharma.scss index cf3738a1bb..6d907d17be 100644 --- a/res/themes/dharma/css/_dharma.scss +++ b/res/themes/dharma/css/_dharma.scss @@ -5,6 +5,7 @@ horizontal mess. Arial empirically gets it right, hence prioritising Arial here. */ $font-family: 'Nunito', Arial, Helvetica, Sans-Serif; +$font-family-semibold: 'Nunito SemiBold', Arial, Helvetica, Sans-Serif; // typical text (dark-on-white in light skin) $primary-fg-color: #454545; diff --git a/res/themes/light/css/_base.scss b/res/themes/light/css/_base.scss index 45b64243c6..ec36f15b89 100644 --- a/res/themes/light/css/_base.scss +++ b/res/themes/light/css/_base.scss @@ -4,6 +4,7 @@ horizontal mess. Arial empirically gets it right, hence prioritising Arial here. */ $font-family: 'Open Sans', Arial, Helvetica, Sans-Serif; +$font-family-semibold: 'Open Sans', Arial, Helvetica, Sans-Serif; // typical text (dark-on-white in light skin) $primary-fg-color: #454545; From 15a56fa90b50ec3d3fb64f7cf203e4ee4e41376e Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 21 Jan 2019 17:27:43 -0700 Subject: [PATCH 0208/1528] Improve the profile section a bit and add a highlight to the temp tab --- res/css/structures/_TabbedView.scss | 6 ++ res/css/views/elements/_AccessibleButton.scss | 21 +++++ .../settings/tabs/_GeneralSettingsTab.scss | 25 +++++- res/themes/dharma/css/_dharma.scss | 6 ++ res/themes/light/css/_base.scss | 6 ++ src/components/structures/TabbedView.js | 3 +- .../views/elements/AccessibleButton.js | 83 ++++++++++------- .../views/settings/tabs/GeneralSettingsTab.js | 90 ++++++++++++++----- src/i18n/strings/en_EN.json | 1 + 9 files changed, 186 insertions(+), 55 deletions(-) diff --git a/res/css/structures/_TabbedView.scss b/res/css/structures/_TabbedView.scss index b888aa287b..86149020b8 100644 --- a/res/css/structures/_TabbedView.scss +++ b/res/css/structures/_TabbedView.scss @@ -45,6 +45,11 @@ limitations under the License. color: $tab-label-active-fg-color; } +// TODO: Remove temporary hack alongside "visit old settings" tab +.mx_TabbedView_tabLabel_TEMP_HACK { + background-color: orange; +} + .mx_TabbedView_tabLabel_icon { width: 14px; height: 14px; @@ -89,4 +94,5 @@ limitations under the License. .mx_TabbedView_tabPanelContent { flex-grow: 1; + min-width: 560px; } \ No newline at end of file diff --git a/res/css/views/elements/_AccessibleButton.scss b/res/css/views/elements/_AccessibleButton.scss index d6702a232c..23445f5f6f 100644 --- a/res/css/views/elements/_AccessibleButton.scss +++ b/res/css/views/elements/_AccessibleButton.scss @@ -21,3 +21,24 @@ limitations under the License. .mx_AccessibleButton { cursor: pointer; } + +.mx_AccessibleButton_disabled { + cursor: default; +} + +.mx_AccessibleButton_hasKind { + padding: 10px 25px; + text-align: center; + border-radius: 4px; + display: inline-block; +} + +.mx_AccessibleButton_kind_primary { + color: $button-primary-fg-color; + background-color: $button-primary-bg-color; +} + +.mx_AccessibleButton_kind_primary.mx_AccessibleButton_disabled { + color: $button-primary-disabled-fg-color; + background-color: $button-primary-disabled-bg-color; +} diff --git a/res/css/views/settings/tabs/_GeneralSettingsTab.scss b/res/css/views/settings/tabs/_GeneralSettingsTab.scss index b04975fc2d..8bc3de8689 100644 --- a/res/css/views/settings/tabs/_GeneralSettingsTab.scss +++ b/res/css/views/settings/tabs/_GeneralSettingsTab.scss @@ -1,6 +1,25 @@ -.mx_GeneralSettingsTab_profile input { +.mx_GeneralSettingsTab_profile { + display: flex; +} + +.mx_GeneralSettingsTab_profileControls { + flex-grow: 1; +} + +.mx_GeneralSettingsTab_profileControls .mx_Field #profileDisplayName { + width: calc(100% - 20px); // subtract 10px padding on left and right +} + +.mx_GeneralSettingsTab_profileAvatar { + width: 88px; + height: 88px; + margin-left: 13px; +} + +.mx_GeneralSettingsTab_profileAvatar div { display: block; - font-size: 14px; - padding: 5px; + width: 88px; + height: 88px; border-radius: 4px; + background-color: #ccc; } \ No newline at end of file diff --git a/res/themes/dharma/css/_dharma.scss b/res/themes/dharma/css/_dharma.scss index 6d907d17be..c3f7b661ab 100644 --- a/res/themes/dharma/css/_dharma.scss +++ b/res/themes/dharma/css/_dharma.scss @@ -200,6 +200,12 @@ $tab-label-active-bg-color: #7ac9a1; $tab-label-icon-bg-color: #454545; $tab-label-active-icon-bg-color: #ffffff; +// Buttons +$button-primary-fg-color: #ffffff; +$button-primary-bg-color: #7ac9a1; +$button-primary-disabled-fg-color: #ffffff; +$button-primary-disabled-bg-color: #bce4d0; + // unused? $progressbar-color: #000; diff --git a/res/themes/light/css/_base.scss b/res/themes/light/css/_base.scss index ec36f15b89..7f08b6d1c2 100644 --- a/res/themes/light/css/_base.scss +++ b/res/themes/light/css/_base.scss @@ -196,6 +196,12 @@ $tab-label-active-bg-color: #7ac9a1; $tab-label-icon-bg-color: #454545; $tab-label-active-icon-bg-color: #ffffff; +// Buttons +$button-primary-fg-color: #ffffff; +$button-primary-bg-color: #7ac9a1; +$button-primary-disabled-fg-color: #ffffff; +$button-primary-disabled-bg-color: #bce4d0; + // unused? $progressbar-color: #000; diff --git a/src/components/structures/TabbedView.js b/src/components/structures/TabbedView.js index 48f8c7a4d8..ab1f5d76de 100644 --- a/src/components/structures/TabbedView.js +++ b/src/components/structures/TabbedView.js @@ -39,7 +39,7 @@ export class Tab { export class TabbedView extends React.Component { static propTypes = { // The tabs to show - tabs: PropTypes.arrayOf(Tab).isRequired, + tabs: PropTypes.arrayOf(PropTypes.instanceOf(Tab)).isRequired, }; constructor() { @@ -74,6 +74,7 @@ export class TabbedView extends React.Component { const idx = this.props.tabs.indexOf(tab); if (idx === this._getActiveTabIndex()) classes += "mx_TabbedView_tabLabel_active"; + if (tab.label === "Visit old settings") classes += "mx_TabbedView_tabLabel_TEMP_HACK"; let tabIcon = null; if (tab.icon) { diff --git a/src/components/views/elements/AccessibleButton.js b/src/components/views/elements/AccessibleButton.js index e30ceb85fa..938426d5bc 100644 --- a/src/components/views/elements/AccessibleButton.js +++ b/src/components/views/elements/AccessibleButton.js @@ -28,41 +28,56 @@ import { KeyCode } from '../../../Keyboard'; * @returns {Object} rendered react */ export default function AccessibleButton(props) { - const {element, onClick, children, ...restProps} = props; - restProps.onClick = onClick; - // We need to consume enter onKeyDown and space onKeyUp - // otherwise we are risking also activating other keyboard focusable elements - // that might receive focus as a result of the AccessibleButtonClick action - // It's because we are using html buttons at a few places e.g. inside dialogs - // And divs which we report as role button to assistive technologies. - // Browsers handle space and enter keypresses differently and we are only adjusting to the - // inconsistencies here - restProps.onKeyDown = function(e) { - if (e.keyCode === KeyCode.ENTER) { - e.stopPropagation(); - e.preventDefault(); - return onClick(e); - } - if (e.keyCode === KeyCode.SPACE) { - e.stopPropagation(); - e.preventDefault(); - } - }; - restProps.onKeyUp = function(e) { - if (e.keyCode === KeyCode.SPACE) { - e.stopPropagation(); - e.preventDefault(); - return onClick(e); - } - if (e.keyCode === KeyCode.ENTER) { - e.stopPropagation(); - e.preventDefault(); - } - }; + const {element, onClick, children, kind, disabled, ...restProps} = props; + + if (!disabled) { + restProps.onClick = onClick; + // We need to consume enter onKeyDown and space onKeyUp + // otherwise we are risking also activating other keyboard focusable elements + // that might receive focus as a result of the AccessibleButtonClick action + // It's because we are using html buttons at a few places e.g. inside dialogs + // And divs which we report as role button to assistive technologies. + // Browsers handle space and enter keypresses differently and we are only adjusting to the + // inconsistencies here + restProps.onKeyDown = function (e) { + if (e.keyCode === KeyCode.ENTER) { + e.stopPropagation(); + e.preventDefault(); + return onClick(e); + } + if (e.keyCode === KeyCode.SPACE) { + e.stopPropagation(); + e.preventDefault(); + } + }; + restProps.onKeyUp = function (e) { + if (e.keyCode === KeyCode.SPACE) { + e.stopPropagation(); + e.preventDefault(); + return onClick(e); + } + if (e.keyCode === KeyCode.ENTER) { + e.stopPropagation(); + e.preventDefault(); + } + }; + } + restProps.tabIndex = restProps.tabIndex || "0"; restProps.role = "button"; restProps.className = (restProps.className ? restProps.className + " " : "") + "mx_AccessibleButton"; + + if (kind) { + // We apply a hasKind class to maintain backwards compatibility with + // buttons which might not know about kind and break + restProps.className += " mx_AccessibleButton_hasKind mx_AccessibleButton_kind_" + kind; + } + + if (disabled) { + restProps.className += " mx_AccessibleButton_disabled"; + } + return React.createElement(element, restProps, children); } @@ -76,6 +91,12 @@ AccessibleButton.propTypes = { children: PropTypes.node, element: PropTypes.string, onClick: PropTypes.func.isRequired, + + // The kind of button, similar to how Bootstrap works. + // See available classes for AccessibleButton for options. + kind: PropTypes.string, + + disabled: PropTypes.bool, }; AccessibleButton.defaultProps = { diff --git a/src/components/views/settings/tabs/GeneralSettingsTab.js b/src/components/views/settings/tabs/GeneralSettingsTab.js index 433b12a674..513d33fabe 100644 --- a/src/components/views/settings/tabs/GeneralSettingsTab.js +++ b/src/components/views/settings/tabs/GeneralSettingsTab.js @@ -16,32 +16,82 @@ limitations under the License. import React from 'react'; import {_t} from "../../../../languageHandler"; +import MatrixClientPeg from "../../../../MatrixClientPeg"; +import Field from "../../elements/Field"; +import AccessibleButton from "../../elements/AccessibleButton"; export default class GeneralSettingsTab extends React.Component { + + constructor() { + super(); + + const client = MatrixClientPeg.get(); + this.state = { + userId: client.getUserId(), + displayName: client.getUser(client.getUserId()).displayName, + enableProfileSave: false, + }; + } + + _saveProfile = async (e) => { + e.stopPropagation(); + e.preventDefault(); + + if (!this.state.enableProfileSave) return; + this.setState({enableProfileSave: false}); + + // TODO: What do we do about errors? + await MatrixClientPeg.get().setDisplayName(this.state.displayName); + + // TODO: Support avatars + + this.setState({enableProfileSave: true}); + }; + + _onDisplayNameChanged = (e) => { + this.setState({ + displayName: e.target.value, + enableProfileSave: true, + }); + }; + + _renderProfileSection() { + const form = ( +
    +
    +
    +

    {this.state.userId}

    + +
    +
    + {/*TODO: Ditch avatar placeholder and use the real thing*/} +
    +
    +
    + + {_t("Save")} + + + ); + + return ( +
    + {_t("Profile")} + {form} +
    + ); + } + render() { return (
    {_t("General")}
    -
    - {_t("Profile")} - - -
    -
    - {_t("Profile")} - - -
    -
    - {_t("Profile")} - - -
    -
    - {_t("Profile")} - - -
    + {this._renderProfileSection()}
    ); } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 6a06811fb3..defc77e3dd 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -403,6 +403,7 @@ "Noisy": "Noisy", "General": "General", "Profile": "Profile", + "Display Name": "Display Name", "Cannot add any more widgets": "Cannot add any more widgets", "The maximum permitted number of widgets have already been added to this room.": "The maximum permitted number of widgets have already been added to this room.", "Add a widget": "Add a widget", From b678e84272a2e0cbc0ca9a9098948046f6007827 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 21 Jan 2019 17:32:25 -0700 Subject: [PATCH 0209/1528] Remove extraneous TODO comment The thing it describes actually happened --- res/css/views/dialogs/_UserSettingsDialog.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/res/css/views/dialogs/_UserSettingsDialog.scss b/res/css/views/dialogs/_UserSettingsDialog.scss index 25be25bd56..def5d3f724 100644 --- a/res/css/views/dialogs/_UserSettingsDialog.scss +++ b/res/css/views/dialogs/_UserSettingsDialog.scss @@ -21,7 +21,6 @@ } .mx_UserSettingsDialog_closeIcon:before { - // TODO: Use real icon mask: url('$(res)/img/feather-icons/cancel.svg'); background-color: $dialog-close-fg-color; mask-repeat: no-repeat; From c7354f483b8d5260e752fad55e01d3482a9ffb72 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 21 Jan 2019 17:49:50 -0600 Subject: [PATCH 0210/1528] Rename LoginBox to AuthButtons This component displays login and register buttons. It's currently used in the composer when viewing a room as a guest. The name is confusing because the login flow uses are very similarly named `mx_Login_box` as a wrapping around forms, which is totally different than these buttons. Additionally, the components is moved to `views/auth` since it is very simple and auth related. --- res/css/_components.scss | 2 +- .../auth/_AuthButtons.scss} | 9 +++++---- src/components/structures/RoomView.js | 4 ++-- .../LoginBox.js => views/auth/AuthButtons.js} | 18 +++++++++--------- 4 files changed, 17 insertions(+), 16 deletions(-) rename res/css/{structures/_LoginBox.scss => views/auth/_AuthButtons.scss} (87%) rename src/components/{structures/LoginBox.js => views/auth/AuthButtons.js} (67%) diff --git a/res/css/_components.scss b/res/css/_components.scss index a1b575a0a1..998e1754c8 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -8,7 +8,6 @@ @import "./structures/_GroupView.scss"; @import "./structures/_HomePage.scss"; @import "./structures/_LeftPanel.scss"; -@import "./structures/_LoginBox.scss"; @import "./structures/_MatrixChat.scss"; @import "./structures/_MyGroups.scss"; @import "./structures/_NotificationPanel.scss"; @@ -24,6 +23,7 @@ @import "./structures/_UserSettings.scss"; @import "./structures/_ViewSource.scss"; @import "./structures/auth/_Login.scss"; +@import "./views/auth/_AuthButtons.scss"; @import "./views/auth/_InteractiveAuthEntryComponents.scss"; @import "./views/auth/_ServerConfig.scss"; @import "./views/avatars/_BaseAvatar.scss"; diff --git a/res/css/structures/_LoginBox.scss b/res/css/views/auth/_AuthButtons.scss similarity index 87% rename from res/css/structures/_LoginBox.scss rename to res/css/views/auth/_AuthButtons.scss index 0a3e21a980..553adeee14 100644 --- a/res/css/structures/_LoginBox.scss +++ b/res/css/views/auth/_AuthButtons.scss @@ -1,5 +1,6 @@ /* Copyright 2017 OpenMarket Ltd +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. @@ -14,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_LoginBox { +.mx_AuthButtons { min-height: 24px; height: unset !important; padding-top: 13px !important; @@ -22,13 +23,13 @@ limitations under the License. order: 4; } -.mx_LoginBox_loginButton_wrapper { +.mx_AuthButtons_loginButton_wrapper { text-align: center; width: 100%; } -.mx_LoginBox_loginButton, -.mx_LoginBox_registerButton { +.mx_AuthButtons_loginButton, +.mx_AuthButtons_registerButton { margin-top: 3px; height: 40px; border: 0px; diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index c34b618645..f63e5b3273 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -1757,8 +1757,8 @@ module.exports = React.createClass({ } if (MatrixClientPeg.get().isGuest()) { - const LoginBox = sdk.getComponent('structures.LoginBox'); - messageComposer = ; + const AuthButtons = sdk.getComponent('views.auth.AuthButtons'); + messageComposer = ; } // TODO: Why aren't we storing the term/scope/count in this format diff --git a/src/components/structures/LoginBox.js b/src/components/views/auth/AuthButtons.js similarity index 67% rename from src/components/structures/LoginBox.js rename to src/components/views/auth/AuthButtons.js index 168014daa5..35bfabbbca 100644 --- a/src/components/structures/LoginBox.js +++ b/src/components/views/auth/AuthButtons.js @@ -1,6 +1,6 @@ /* Copyright 2017 Vector Creations Ltd -Copyright 2018 New Vector Ltd +Copyright 2018, 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. @@ -18,12 +18,12 @@ limitations under the License. 'use strict'; const React = require('react'); -import { _t } from '../../languageHandler'; -const dis = require('../../dispatcher'); -const AccessibleButton = require('../../components/views/elements/AccessibleButton'); +import { _t } from '../../../languageHandler'; +const dis = require('../../../dispatcher'); +const AccessibleButton = require('../elements/AccessibleButton'); module.exports = React.createClass({ - displayName: 'LoginBox', + displayName: 'AuthButtons', propTypes: { }, @@ -38,18 +38,18 @@ module.exports = React.createClass({ render: function() { const loginButton = ( -
    - +
    + { _t("Login") } - + { _t("Register") }
    ); return ( -
    +
    { loginButton }
    ); From 3bd765f63f985862fe646b59bff597efcfdc547c Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 21 Jan 2019 18:33:17 -0600 Subject: [PATCH 0211/1528] Rename LoginPage, Header, Footer views to Auth* --- res/css/_components.scss | 3 ++ res/css/structures/auth/_Login.scss | 41 +------------------ res/css/views/auth/_AuthFooter.scss | 28 +++++++++++++ res/css/views/auth/_AuthHeader.scss | 25 +++++++++++ res/css/views/auth/_AuthPage.scss | 32 +++++++++++++++ .../structures/auth/ForgotPassword.js | 14 +++---- src/components/structures/auth/Login.js | 14 +++---- .../structures/auth/PostRegistration.js | 10 ++--- .../structures/auth/Registration.js | 14 +++---- .../auth/{LoginFooter.js => AuthFooter.js} | 5 ++- .../auth/{LoginHeader.js => AuthHeader.js} | 9 ++-- .../views/auth/{LoginPage.js => AuthPage.js} | 4 +- 12 files changed, 126 insertions(+), 73 deletions(-) create mode 100644 res/css/views/auth/_AuthFooter.scss create mode 100644 res/css/views/auth/_AuthHeader.scss create mode 100644 res/css/views/auth/_AuthPage.scss rename src/components/views/auth/{LoginFooter.js => AuthFooter.js} (89%) rename src/components/views/auth/{LoginHeader.js => AuthHeader.js} (77%) rename src/components/views/auth/{LoginPage.js => AuthPage.js} (91%) diff --git a/res/css/_components.scss b/res/css/_components.scss index 998e1754c8..92070483f5 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -24,6 +24,9 @@ @import "./structures/_ViewSource.scss"; @import "./structures/auth/_Login.scss"; @import "./views/auth/_AuthButtons.scss"; +@import "./views/auth/_AuthFooter.scss"; +@import "./views/auth/_AuthHeader.scss"; +@import "./views/auth/_AuthPage.scss"; @import "./views/auth/_InteractiveAuthEntryComponents.scss"; @import "./views/auth/_ServerConfig.scss"; @import "./views/avatars/_BaseAvatar.scss"; diff --git a/res/css/structures/auth/_Login.scss b/res/css/structures/auth/_Login.scss index 1264d2a30f..a5f62089d6 100644 --- a/res/css/structures/auth/_Login.scss +++ b/res/css/structures/auth/_Login.scss @@ -1,5 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd +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. @@ -14,23 +15,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_Login { - width: 100%; - height: 100%; - - display: flex; - align-items: center; - justify-content: center; - - overflow: auto; -} - -.mx_Login h2 { - font-weight: 300; - margin-top: 32px; - margin-bottom: 20px; -} - .mx_Login_box { width: 300px; min-height: 450px; @@ -39,16 +23,6 @@ limitations under the License. margin: auto; } -.mx_Login_logo { - text-align: center; - height: 150px; - margin-bottom: 45px; -} - -.mx_Login_logo img { - max-height: 100% -} - .mx_Login_support { text-align: center; font-size: 13px; @@ -115,19 +89,6 @@ limitations under the License. color: $primary-fg-color; } -.mx_Login_links { - display: block; - text-align: center; - margin-top: 15px; - width: 100%; - font-size: 13px; - opacity: 0.8; -} - -.mx_Login_links a:link { - color: $primary-fg-color; -} - .mx_Login_prompt { padding-top: 15px; padding-bottom: 15px; diff --git a/res/css/views/auth/_AuthFooter.scss b/res/css/views/auth/_AuthFooter.scss new file mode 100644 index 0000000000..4737513125 --- /dev/null +++ b/res/css/views/auth/_AuthFooter.scss @@ -0,0 +1,28 @@ +/* +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. +*/ + +.mx_AuthFooter { + display: block; + text-align: center; + margin-top: 15px; + width: 100%; + font-size: 13px; + opacity: 0.8; +} + +.mx_AuthFooter a:link { + color: $primary-fg-color; +} diff --git a/res/css/views/auth/_AuthHeader.scss b/res/css/views/auth/_AuthHeader.scss new file mode 100644 index 0000000000..58df178aa9 --- /dev/null +++ b/res/css/views/auth/_AuthHeader.scss @@ -0,0 +1,25 @@ +/* +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. +*/ + +.mx_AuthHeader_logo { + text-align: center; + height: 150px; + margin-bottom: 45px; +} + +.mx_AuthHeader_logo img { + max-height: 100% +} diff --git a/res/css/views/auth/_AuthPage.scss b/res/css/views/auth/_AuthPage.scss new file mode 100644 index 0000000000..d87a906275 --- /dev/null +++ b/res/css/views/auth/_AuthPage.scss @@ -0,0 +1,32 @@ +/* +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. +*/ + +.mx_AuthPage { + width: 100%; + height: 100%; + + display: flex; + align-items: center; + justify-content: center; + + overflow: auto; +} + +.mx_AuthPage h2 { + font-weight: 300; + margin-top: 32px; + margin-bottom: 20px; +} diff --git a/src/components/structures/auth/ForgotPassword.js b/src/components/structures/auth/ForgotPassword.js index 6d5da4f2b7..7c763b0c77 100644 --- a/src/components/structures/auth/ForgotPassword.js +++ b/src/components/structures/auth/ForgotPassword.js @@ -183,9 +183,9 @@ module.exports = React.createClass({ }, render: function() { - const LoginPage = sdk.getComponent("auth.LoginPage"); - const LoginHeader = sdk.getComponent("auth.LoginHeader"); - const LoginFooter = sdk.getComponent("auth.LoginFooter"); + const AuthPage = sdk.getComponent("auth.AuthPage"); + const AuthHeader = sdk.getComponent("auth.AuthHeader"); + const AuthFooter = sdk.getComponent("auth.AuthFooter"); const ServerConfig = sdk.getComponent("auth.ServerConfig"); const Spinner = sdk.getComponent("elements.Spinner"); @@ -272,7 +272,7 @@ module.exports = React.createClass({ { _t('Create an account') } - +
    ); @@ -280,12 +280,12 @@ module.exports = React.createClass({ return ( - +
    - + { resetPasswordJsx }
    -
    + ); }, }); diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js index a1f0327835..069e3aebb6 100644 --- a/src/components/structures/auth/Login.js +++ b/src/components/structures/auth/Login.js @@ -515,9 +515,9 @@ module.exports = React.createClass({ render: function() { const Loader = sdk.getComponent("elements.Spinner"); - const LoginPage = sdk.getComponent("auth.LoginPage"); - const LoginHeader = sdk.getComponent("auth.LoginHeader"); - const LoginFooter = sdk.getComponent("auth.LoginFooter"); + const AuthPage = sdk.getComponent("auth.AuthPage"); + const AuthHeader = sdk.getComponent("auth.AuthHeader"); + const AuthFooter = sdk.getComponent("auth.AuthFooter"); const ServerConfig = sdk.getComponent("auth.ServerConfig"); const loader = this.state.busy ?
    : null; @@ -558,9 +558,9 @@ module.exports = React.createClass({ const LanguageSelector = sdk.getComponent('structures.auth.LanguageSelector'); return ( - +
    - +
    { header } { errorTextSection } @@ -571,10 +571,10 @@ module.exports = React.createClass({ { loginAsGuestJsx } - +
    -
    + ); }, }); diff --git a/src/components/structures/auth/PostRegistration.js b/src/components/structures/auth/PostRegistration.js index 826db89b93..78622695cf 100644 --- a/src/components/structures/auth/PostRegistration.js +++ b/src/components/structures/auth/PostRegistration.js @@ -60,12 +60,12 @@ module.exports = React.createClass({ render: function() { const ChangeDisplayName = sdk.getComponent('settings.ChangeDisplayName'); const ChangeAvatar = sdk.getComponent('settings.ChangeAvatar'); - const LoginPage = sdk.getComponent('auth.LoginPage'); - const LoginHeader = sdk.getComponent('auth.LoginHeader'); + const AuthPage = sdk.getComponent('auth.AuthPage'); + const AuthHeader = sdk.getComponent('auth.AuthHeader'); return ( - +
    - +
    { _t('Set a display name:') } @@ -76,7 +76,7 @@ module.exports = React.createClass({ { this.state.errorString }
    -
    + ); }, }); diff --git a/src/components/structures/auth/Registration.js b/src/components/structures/auth/Registration.js index 617c9d6983..bd5a3a3fda 100644 --- a/src/components/structures/auth/Registration.js +++ b/src/components/structures/auth/Registration.js @@ -396,9 +396,9 @@ module.exports = React.createClass({ }, render: function() { - const LoginHeader = sdk.getComponent('auth.LoginHeader'); - const LoginFooter = sdk.getComponent('auth.LoginFooter'); - const LoginPage = sdk.getComponent('auth.LoginPage'); + const AuthHeader = sdk.getComponent('auth.AuthHeader'); + const AuthFooter = sdk.getComponent('auth.AuthFooter'); + const AuthPage = sdk.getComponent('auth.AuthPage'); const InteractiveAuth = sdk.getComponent('structures.InteractiveAuth'); const Spinner = sdk.getComponent("elements.Spinner"); const ServerConfig = sdk.getComponent('views.auth.ServerConfig'); @@ -474,9 +474,9 @@ module.exports = React.createClass({ const LanguageSelector = sdk.getComponent('structures.auth.LanguageSelector'); return ( - +
    - - +
    -
    + ); }, }); diff --git a/src/components/views/auth/LoginFooter.js b/src/components/views/auth/AuthFooter.js similarity index 89% rename from src/components/views/auth/LoginFooter.js rename to src/components/views/auth/AuthFooter.js index 392d36e288..ea43bf322c 100644 --- a/src/components/views/auth/LoginFooter.js +++ b/src/components/views/auth/AuthFooter.js @@ -1,5 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd +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. @@ -20,11 +21,11 @@ import { _t } from '../../../languageHandler'; import React from 'react'; module.exports = React.createClass({ - displayName: 'LoginFooter', + displayName: 'AuthFooter', render: function() { return ( -
    + ); diff --git a/src/components/views/auth/LoginHeader.js b/src/components/views/auth/AuthHeader.js similarity index 77% rename from src/components/views/auth/LoginHeader.js rename to src/components/views/auth/AuthHeader.js index cd1f9c6a28..08c9ad41c9 100644 --- a/src/components/views/auth/LoginHeader.js +++ b/src/components/views/auth/AuthHeader.js @@ -1,5 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd +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. @@ -19,12 +20,14 @@ limitations under the License. const React = require('react'); module.exports = React.createClass({ - displayName: 'LoginHeader', + displayName: 'AuthHeader', render: function() { return ( -
    - Matrix +
    +
    + Matrix +
    ); }, diff --git a/src/components/views/auth/LoginPage.js b/src/components/views/auth/AuthPage.js similarity index 91% rename from src/components/views/auth/LoginPage.js rename to src/components/views/auth/AuthPage.js index 83da8fa60b..09540885c6 100644 --- a/src/components/views/auth/LoginPage.js +++ b/src/components/views/auth/AuthPage.js @@ -20,11 +20,11 @@ limitations under the License. const React = require('react'); module.exports = React.createClass({ - displayName: 'LoginPage', + displayName: 'AuthPage', render: function() { return ( -
    +
    { this.props.children }
    ); From 1d01ac398c58fc2c0ebe05988f3aeca4c4fb72d4 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 21 Jan 2019 18:49:28 -0600 Subject: [PATCH 0212/1528] Rename `mx_Login_box` to `mx_AuthPage_modal` and fold into `AuthPage` --- res/css/structures/auth/_Login.scss | 8 ------ res/css/views/auth/_AuthPage.scss | 8 ++++++ .../structures/auth/ForgotPassword.js | 6 ++--- src/components/structures/auth/Login.js | 26 +++++++++---------- .../structures/auth/PostRegistration.js | 20 +++++++------- .../structures/auth/Registration.js | 26 +++++++++---------- src/components/views/auth/AuthPage.js | 4 ++- 7 files changed, 46 insertions(+), 52 deletions(-) diff --git a/res/css/structures/auth/_Login.scss b/res/css/structures/auth/_Login.scss index a5f62089d6..c4eebc48a1 100644 --- a/res/css/structures/auth/_Login.scss +++ b/res/css/structures/auth/_Login.scss @@ -15,14 +15,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_Login_box { - width: 300px; - min-height: 450px; - padding-top: 50px; - padding-bottom: 50px; - margin: auto; -} - .mx_Login_support { text-align: center; font-size: 13px; diff --git a/res/css/views/auth/_AuthPage.scss b/res/css/views/auth/_AuthPage.scss index d87a906275..6916f1d92a 100644 --- a/res/css/views/auth/_AuthPage.scss +++ b/res/css/views/auth/_AuthPage.scss @@ -30,3 +30,11 @@ limitations under the License. margin-top: 32px; margin-bottom: 20px; } + +.mx_AuthPage_modal { + width: 300px; + min-height: 450px; + padding-top: 50px; + padding-bottom: 50px; + margin: auto; +} diff --git a/src/components/structures/auth/ForgotPassword.js b/src/components/structures/auth/ForgotPassword.js index 7c763b0c77..ab0f660be0 100644 --- a/src/components/structures/auth/ForgotPassword.js +++ b/src/components/structures/auth/ForgotPassword.js @@ -281,10 +281,8 @@ module.exports = React.createClass({ return ( -
    - - { resetPasswordJsx } -
    + + { resetPasswordJsx }
    ); }, diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js index 069e3aebb6..c64223ba48 100644 --- a/src/components/structures/auth/Login.js +++ b/src/components/structures/auth/Login.js @@ -559,20 +559,18 @@ module.exports = React.createClass({ return ( -
    - -
    - { header } - { errorTextSection } - { this.componentForStep(this.state.currentFlow) } - { serverConfig } - - { _t('Create an account') } - - { loginAsGuestJsx } - - -
    + +
    + { header } + { errorTextSection } + { this.componentForStep(this.state.currentFlow) } + { serverConfig } + + { _t('Create an account') } + + { loginAsGuestJsx } + +
    ); diff --git a/src/components/structures/auth/PostRegistration.js b/src/components/structures/auth/PostRegistration.js index 78622695cf..fff326f6ac 100644 --- a/src/components/structures/auth/PostRegistration.js +++ b/src/components/structures/auth/PostRegistration.js @@ -64,17 +64,15 @@ module.exports = React.createClass({ const AuthHeader = sdk.getComponent('auth.AuthHeader'); return ( -
    - -
    - { _t('Set a display name:') } - - { _t('Upload an avatar:') } - - - { this.state.errorString } -
    + +
    + { _t('Set a display name:') } + + { _t('Upload an avatar:') } + + + { this.state.errorString }
    ); diff --git a/src/components/structures/auth/Registration.js b/src/components/structures/auth/Registration.js index bd5a3a3fda..39f7964281 100644 --- a/src/components/structures/auth/Registration.js +++ b/src/components/structures/auth/Registration.js @@ -475,20 +475,18 @@ module.exports = React.createClass({ return ( -
    - - { header } - { registerBody } - { signIn } - { errorText } - - -
    + + { header } + { registerBody } + { signIn } + { errorText } + +
    ); }, diff --git a/src/components/views/auth/AuthPage.js b/src/components/views/auth/AuthPage.js index 09540885c6..d5f82f7264 100644 --- a/src/components/views/auth/AuthPage.js +++ b/src/components/views/auth/AuthPage.js @@ -25,7 +25,9 @@ module.exports = React.createClass({ render: function() { return (
    - { this.props.children } +
    + { this.props.children } +
    ); }, From a488304410fc42fa5e6c30acf1c24d45db87a23b Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 21 Jan 2019 17:49:48 -0700 Subject: [PATCH 0213/1528] Appease the linter Appease the linter round 2 Appease the linter round 3 Appease the linter round 4 Appease the linter round 5 --- .eslintrc.js | 5 +- src/components/structures/MatrixChat.js | 3 +- src/components/structures/TabbedView.js | 8 +-- .../views/dialogs/UserSettingsDialog.js | 50 +++++++++++++------ .../views/elements/AccessibleButton.js | 4 +- .../views/settings/tabs/GeneralSettingsTab.js | 14 ++---- 6 files changed, 52 insertions(+), 32 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 971809f851..ec48f6b2ff 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -42,9 +42,8 @@ module.exports = { // bind or arrow function in props causes performance issues // (but we currently use them in some places) - "react/jsx-no-bind": ["warn", { - "ignoreRefs": true, - }], + // It's disabled here, but we should using it sparingly. + "react/jsx-no-bind": "off", "react/jsx-key": ["error"], // Components in JSX should always be defined. diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 2b585506ae..4e6ffbd2c8 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -610,12 +610,13 @@ export default React.createClass({ case 'view_indexed_room': this._viewIndexedRoom(payload.roomIndex); break; - case 'view_user_settings': + case 'view_user_settings': { const UserSettingsDialog = sdk.getComponent("dialogs.UserSettingsDialog"); Modal.createTrackedDialog('User settings', '', UserSettingsDialog, {}); //this._setPage(PageTypes.UserSettings); //this.notifyNewScreen('settings'); break; + } case 'view_old_user_settings': this._setPage(PageTypes.UserSettings); this.notifyNewScreen('settings'); diff --git a/src/components/structures/TabbedView.js b/src/components/structures/TabbedView.js index ab1f5d76de..43979140a8 100644 --- a/src/components/structures/TabbedView.js +++ b/src/components/structures/TabbedView.js @@ -81,9 +81,11 @@ export class TabbedView extends React.Component { tabIcon = {tab.icon}; } + const onClickHandler = () => this._setActiveTab(tab); + return ( - this._setActiveTab(tab)}> + {tabIcon} {_t(tab.label)} @@ -113,4 +115,4 @@ export class TabbedView extends React.Component {
    ); } -} \ No newline at end of file +} diff --git a/src/components/views/dialogs/UserSettingsDialog.js b/src/components/views/dialogs/UserSettingsDialog.js index d355eb77bc..d0b3f436b8 100644 --- a/src/components/views/dialogs/UserSettingsDialog.js +++ b/src/components/views/dialogs/UserSettingsDialog.js @@ -22,8 +22,8 @@ import AccessibleButton from "../elements/AccessibleButton"; import GeneralSettingsTab from "../settings/tabs/GeneralSettingsTab"; import dis from '../../../dispatcher'; +// TODO: Ditch this whole component export class TempTab extends React.Component { - // TODO: Ditch this static propTypes = { onClose: PropTypes.func.isRequired, }; @@ -45,13 +45,41 @@ export default class UserSettingsDialog extends React.Component { _getTabs() { return [ - new Tab(_td("General"), , ), - new Tab(_td("Notifications"), ,
    Notifications Test
    ), - new Tab(_td("Preferences"), ,
    Preferences Test
    ), - new Tab(_td("Voice & Video"), ,
    Voice Test
    ), - new Tab(_td("Security & Privacy"), ,
    Security Test
    ), - new Tab(_td("Help & About"), ,
    Help Test
    ), - new Tab(_td("Visit old settings"), , ), + new Tab( + _td("General"), + , + , + ), + new Tab( + _td("Notifications"), + , +
    Notifications Test
    , + ), + new Tab( + _td("Preferences"), + , +
    Preferences Test
    , + ), + new Tab( + _td("Voice & Video"), + , +
    Voice Test
    , + ), + new Tab( + _td("Security & Privacy"), + , +
    Security Test
    , + ), + new Tab( + _td("Help & About"), + , +
    Help Test
    , + ), + new Tab( + _td("Visit old settings"), + , + , + ), ]; } @@ -66,12 +94,6 @@ export default class UserSettingsDialog extends React.Component {
    - // ); } } diff --git a/src/components/views/elements/AccessibleButton.js b/src/components/views/elements/AccessibleButton.js index 938426d5bc..1c39ba4f49 100644 --- a/src/components/views/elements/AccessibleButton.js +++ b/src/components/views/elements/AccessibleButton.js @@ -39,7 +39,7 @@ export default function AccessibleButton(props) { // And divs which we report as role button to assistive technologies. // Browsers handle space and enter keypresses differently and we are only adjusting to the // inconsistencies here - restProps.onKeyDown = function (e) { + restProps.onKeyDown = function(e) { if (e.keyCode === KeyCode.ENTER) { e.stopPropagation(); e.preventDefault(); @@ -50,7 +50,7 @@ export default function AccessibleButton(props) { e.preventDefault(); } }; - restProps.onKeyUp = function (e) { + restProps.onKeyUp = function(e) { if (e.keyCode === KeyCode.SPACE) { e.stopPropagation(); e.preventDefault(); diff --git a/src/components/views/settings/tabs/GeneralSettingsTab.js b/src/components/views/settings/tabs/GeneralSettingsTab.js index 513d33fabe..81501033ec 100644 --- a/src/components/views/settings/tabs/GeneralSettingsTab.js +++ b/src/components/views/settings/tabs/GeneralSettingsTab.js @@ -21,7 +21,6 @@ import Field from "../../elements/Field"; import AccessibleButton from "../../elements/AccessibleButton"; export default class GeneralSettingsTab extends React.Component { - constructor() { super(); @@ -56,6 +55,7 @@ export default class GeneralSettingsTab extends React.Component { }; _renderProfileSection() { + // TODO: Ditch avatar placeholder and use the real thing const form = (
    @@ -63,24 +63,20 @@ export default class GeneralSettingsTab extends React.Component {

    {this.state.userId}

    + onChange={this._onDisplayNameChanged} />
    - {/*TODO: Ditch avatar placeholder and use the real thing*/} -
    +
    + disabled={!this.state.enableProfileSave}> {_t("Save")} ); - return ( -
    + return (
    {_t("Profile")} {form}
    From feed17d9acc54d5e4d130b68640c4a4eda4ab359 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 21 Jan 2019 20:55:40 -0700 Subject: [PATCH 0214/1528] Minor code style fix --- src/components/views/settings/tabs/GeneralSettingsTab.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/views/settings/tabs/GeneralSettingsTab.js b/src/components/views/settings/tabs/GeneralSettingsTab.js index 81501033ec..c8816325c0 100644 --- a/src/components/views/settings/tabs/GeneralSettingsTab.js +++ b/src/components/views/settings/tabs/GeneralSettingsTab.js @@ -76,7 +76,8 @@ export default class GeneralSettingsTab extends React.Component { ); - return (
    + return ( +
    {_t("Profile")} {form}
    From 9f5244fa8b646b7fec1d4da7781bd73714657540 Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 22 Jan 2019 10:16:31 +0000 Subject: [PATCH 0215/1528] Deduplicate
    tag --- .../views/dialogs/keybackup/CreateKeyBackupDialog.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js b/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js index fd3d6776eb..2c54344a30 100644 --- a/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js +++ b/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js @@ -252,9 +252,7 @@ export default React.createClass({ for (let i = 0; i < this.state.zxcvbnResult.feedback.suggestions.length; ++i) { suggestions.push(
    {this.state.zxcvbnResult.feedback.suggestions[i]}
    ); } - const suggestionBlock = suggestions.length > 0 ?
    - {suggestions} -
    :
    {_t("Keep going...")}
    ; + const suggestionBlock =
    {suggestions.length > 0 ? suggestions : _t("Keep going...")}
    ; helpText =
    {this.state.zxcvbnResult.feedback.warning} From 881353037e30767957f638a7a06521efe1424994 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 22 Jan 2019 10:34:54 +0000 Subject: [PATCH 0216/1528] forgot .length somehow Co-Authored-By: bwindels --- src/components/views/rooms/WhoIsTypingTile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/WhoIsTypingTile.js b/src/components/views/rooms/WhoIsTypingTile.js index 4c97110797..b540abf61e 100644 --- a/src/components/views/rooms/WhoIsTypingTile.js +++ b/src/components/views/rooms/WhoIsTypingTile.js @@ -78,7 +78,7 @@ module.exports = React.createClass({ }, isVisible: function() { - return this.state.usersTyping.length !== 0 || Object.keys(this.state.delayedStopTypingTimers) !== 0; + return this.state.usersTyping.length !== 0 || Object.keys(this.state.delayedStopTypingTimers).length !== 0; }, onRoomTimeline: function(event, room) { From 5d45d5dfac1dd0f166f7a6ae778dd36735401336 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 22 Jan 2019 11:37:09 +0100 Subject: [PATCH 0217/1528] formatting --- src/components/structures/ScrollPanel.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index 96318d64e1..be5f23c420 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -681,6 +681,7 @@ module.exports = React.createClass({ _collectGeminiScroll: function(gemScroll) { this._gemScroll = gemScroll; }, + /** * Set the current height as the min height for the message list * so the timeline cannot shrink. This is used to avoid @@ -693,6 +694,7 @@ module.exports = React.createClass({ messageList.style.minHeight = `${currentHeight}px`; } }, + /** * Clear the previously set min height */ From 0e0128c29749651ff733de7eeddad5e18ea46583 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 22 Jan 2019 11:37:18 +0100 Subject: [PATCH 0218/1528] if instead of short-circuit and for readability --- src/components/views/rooms/WhoIsTypingTile.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/views/rooms/WhoIsTypingTile.js b/src/components/views/rooms/WhoIsTypingTile.js index b540abf61e..e826380469 100644 --- a/src/components/views/rooms/WhoIsTypingTile.js +++ b/src/components/views/rooms/WhoIsTypingTile.js @@ -110,7 +110,9 @@ module.exports = React.createClass({ // abort all the timers for the users that started typing again usersThatStartedTyping.forEach((m) => { const timer = this.state.delayedStopTypingTimers[m.userId]; - timer && timer.abort(); + if (timer) { + timer.abort(); + } }); // prepare new delayedStopTypingTimers object to update state with let delayedStopTypingTimers = Object.assign({}, this.state.delayedStopTypingTimers); From f83411ea0b97b92bd73091f21451b55a95817087 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 22 Jan 2019 11:46:02 +0100 Subject: [PATCH 0219/1528] whitespace --- src/components/views/rooms/WhoIsTypingTile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/WhoIsTypingTile.js b/src/components/views/rooms/WhoIsTypingTile.js index e826380469..4ee11d77b2 100644 --- a/src/components/views/rooms/WhoIsTypingTile.js +++ b/src/components/views/rooms/WhoIsTypingTile.js @@ -128,7 +128,7 @@ module.exports = React.createClass({ delayedStopTypingTimers[m.userId] = timer; timer.start(); timer.finished().then( - () => this._removeUserTimer(m.userId), //on elapsed + () => this._removeUserTimer(m.userId), // on elapsed () => {/* aborted */}, ); } From 5cdc8486d38a0ecf2a28dc709cbbff483c04c23a Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 22 Jan 2019 11:14:00 +0000 Subject: [PATCH 0220/1528] Released js-sdk --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 26792463aa..1e14016683 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "linkifyjs": "^2.1.6", "lodash": "^4.13.1", "lolex": "2.3.2", - "matrix-js-sdk": "0.14.3-rc.1", + "matrix-js-sdk": "0.14.3", "optimist": "^0.6.1", "pako": "^1.0.5", "prop-types": "^15.5.8", From f6d15d652bae107875d886336d06e1bb12fd21c6 Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 22 Jan 2019 11:26:28 +0000 Subject: [PATCH 0221/1528] Prepare changelog for v0.14.8 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f192708dab..09ff79ae0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +Changes in [0.14.8](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.14.8) (2019-01-22) +===================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.14.8-rc.1...v0.14.8) + + * Fix settings direct chat + [\#2467](https://github.com/matrix-org/matrix-react-sdk/pull/2467) + Changes in [0.14.8-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.14.8-rc.1) (2019-01-17) =============================================================================================================== [Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.14.7...v0.14.8-rc.1) From 17e9a442e447db620908a1be908449c365a52218 Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 22 Jan 2019 11:26:29 +0000 Subject: [PATCH 0222/1528] v0.14.8 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1e14016683..5d765a5bb2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "0.14.8-rc.1", + "version": "0.14.8", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { From 67568222effe1ff0c84b7d97b74c82dc7c07d82a Mon Sep 17 00:00:00 2001 From: Osoitz Date: Mon, 21 Jan 2019 21:09:25 +0000 Subject: [PATCH 0223/1528] Translated using Weblate (Basque) Currently translated at 100.0% (1427 of 1427 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/eu/ --- src/i18n/strings/eu.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/i18n/strings/eu.json b/src/i18n/strings/eu.json index 0367393db8..d9f796c03f 100644 --- a/src/i18n/strings/eu.json +++ b/src/i18n/strings/eu.json @@ -972,7 +972,7 @@ "Code": "Kodea", "Debug Logs Submission": "Arazte-egunkarien bidalketak", "If you've submitted a bug via GitHub, debug logs can help us track down the problem. Debug logs contain application usage data including your username, the IDs or aliases of the rooms or groups you have visited and the usernames of other users. They do not contain messages.": "Akats bat bidali baduzu GitHub bidez, arazte-egunkariek arazoa aurkitzen lagundu gaitzakete. Arazte-egunkariek aplikazioak darabilen datuak dauzkate, zure erabiltzaile izena barne, bisitatu dituzun gelen ID-ak edo ezizenak eta beste erabiltzaileen izenak. Ez dute mezurik.", - "Submit debug logs": "Bidali arazte-txostenak", + "Submit debug logs": "Bidali arazte-egunkariak", "Opens the Developer Tools dialog": "Garatzailearen tresnen elkarrizketa-koadroa irekitzen du", "Seen by %(displayName)s (%(userName)s) at %(dateTime)s": "%(displayName)s (%(userName)s)(e)k ikusita %(dateTime)s(e)tan", "Unable to join community": "Ezinekoa komunitatera elkartzea", @@ -992,7 +992,7 @@ "Couldn't load home page": "Ezin izan da hasiera orria kargatu", "Send Account Data": "Bidali kontuaren datuak", "All notifications are currently disabled for all targets.": "Une honetan jakinarazpen guztiak helburu guztietarako desgaituta daude.", - "Uploading report": "Igoera txostena", + "Uploading report": "Txostena igotzen", "Sunday": "Igandea", "Notification targets": "Jakinarazpenen helburuak", "Today": "Gaur", From 510c7c2d9fe1c4ec2703f8f186425bfb0b5a7a92 Mon Sep 17 00:00:00 2001 From: Marco Date: Fri, 18 Jan 2019 10:27:57 +0000 Subject: [PATCH 0224/1528] Translated using Weblate (German) Currently translated at 100.0% (1427 of 1427 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/de/ --- src/i18n/strings/de_DE.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/de_DE.json b/src/i18n/strings/de_DE.json index 1fdb424442..e2abc2f991 100644 --- a/src/i18n/strings/de_DE.json +++ b/src/i18n/strings/de_DE.json @@ -1174,7 +1174,7 @@ "Deactivating your account does not by default cause us to forget messages you have sent. If you would like us to forget your messages, please tick the box below.": "Standardmäßig werden die von dir gesendeten Nachrichten beim Deaktiveren nicht gelöscht. Wenn du dies von uns möchtest, aktivere das Auswalfeld unten.", "Message visibility in Matrix is similar to email. Our forgetting your messages means that messages you have sent will not be shared with any new or unregistered users, but registered users who already have access to these messages will still have access to their copy.": "Sie Sichtbarkeit der Nachrichten in Matrix ist vergleichbar mit E-Mails: Wenn wir deine Nachrichten vergessen heißt das, dass diese nicht mit neuen oder nicht registrierten Nutzern teilen werden, aber registrierte Nutzer, die bereits zugriff haben, werden Zugriff auf ihre Kopie behalten.", "Please forget all messages I have sent when my account is deactivated (Warning: this will cause future users to see an incomplete view of conversations)": "Bitte vergesst alle Nachrichten, die ich gesendet habe, wenn mein Account deaktiviert wird. (Warnung: Zukünftige Nutzer werden eine unvollständige Konversation sehen)", - "To continue, please enter your password:": "Um fortzufahren, bitte Password eingeben:", + "To continue, please enter your password:": "Um fortzufahren, bitte Passwort eingeben:", "password": "Passwort", "Can't leave Server Notices room": "Du kannst den Raum für Server-Notizen nicht verlassen", "This room is used for important messages from the Homeserver, so you cannot leave it.": "Du kannst diesen Raum nicht verlassen, da dieser Raum für wichtige Nachrichten vom Heimserver verwendet wird.", From dcbc8e103ca0b841785b849e5d2a014603c38270 Mon Sep 17 00:00:00 2001 From: Yusuke Watanabe Date: Thu, 17 Jan 2019 13:53:40 +0000 Subject: [PATCH 0225/1528] Translated using Weblate (Japanese) Currently translated at 90.8% (1296 of 1427 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/ja/ --- src/i18n/strings/ja.json | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/ja.json b/src/i18n/strings/ja.json index fb4e384819..b1ed91e9ab 100644 --- a/src/i18n/strings/ja.json +++ b/src/i18n/strings/ja.json @@ -1275,5 +1275,28 @@ "Status.im theme": "Status.im テーマ", "Unignore": "無視しない", "If you would like to create a Matrix account you can register now.": "Matrixアカウントを作成したい場合は、今すぐ登録することができます。", - "You are currently using Riot anonymously as a guest.": "現在、Riotをゲストとして匿名で使用しています。" + "You are currently using Riot anonymously as a guest.": "現在、Riotをゲストとして匿名で使用しています。", + "Unable to load! Check your network connectivity and try again.": "ロードできません! ネットワーク通信を確認の上もう一度お試しください。", + "Failed to invite users to the room:": "部屋にユーザーを招待できませんでした:", + "Waiting for %(userId)s to accept...": "%(userId)s の承認を待っています...", + "Waiting for %(userId)s to confirm...": "%(userId)s の確認を待っています...", + "You do not have permission to invite people to this room.": "この部屋にユーザーを招待する権限がありません。", + "Unknown server error": "不明なサーバーエラー", + "No need for symbols, digits, or uppercase letters": "記号、数字、大文字を含む必要はありません", + "Use a longer keyboard pattern with more turns": "キーボードの上でもっと長くて複雑な図形になるものを使ってください", + "Avoid repeated words and characters": "単語や文字の繰り返しは避けましょう", + "Avoid sequences": "規則的な文字列は避けましょう", + "Avoid recent years": "最近の年号は避けましょう", + "Avoid years that are associated with you": "あなたに関係のある年号は避けましょう", + "Avoid dates and years that are associated with you": "あなたに関係のある日付や年号は避けましょう", + "Capitalization doesn't help very much": "大文字を入れれば良いというものではありません", + "All-uppercase is almost as easy to guess as all-lowercase": "すべて大文字というのは、すべて小文字と同じくらい推測されやすいです", + "Reversed words aren't much harder to guess": "逆さ言葉は推測されやすいです", + "Predictable substitutions like '@' instead of 'a' don't help very much": "a を @ に替えるような安易な変換は、やってもやらなくても一緒です", + "Add another word or two. Uncommon words are better.": "単語をあとひとつかふたつ付け足しましょう。めったに使わない単語がよいです。", + "Repeats like \"aaa\" are easy to guess": "\"aaa\" のような繰り返しは推測されやすいです", + "Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "\"abcabcabc\" のような繰り返しは \"abc\" とほとんど変わらないくらい推測されやすいです", + "Sequences like abc or 6543 are easy to guess": "abc や 6543 のような規則的な文字列は推測されやすいです", + "Recent years are easy to guess": "最近の年号は推測されやすいです", + "Dates are often easy to guess": "たいていの日付は推測されやすいです" } From 3d9f937a6fc8ea7220f1f17ca85dca466a4282c9 Mon Sep 17 00:00:00 2001 From: Paulo Miranda Date: Mon, 21 Jan 2019 16:52:28 +0000 Subject: [PATCH 0226/1528] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (1427 of 1427 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/pt_BR/ --- src/i18n/strings/pt_BR.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/i18n/strings/pt_BR.json b/src/i18n/strings/pt_BR.json index 8a40801f42..9b50873ffd 100644 --- a/src/i18n/strings/pt_BR.json +++ b/src/i18n/strings/pt_BR.json @@ -573,9 +573,9 @@ "Encrypted by a verified device": "Criptografado por um dispositivo verificado", "Encrypted by an unverified device": "Criptografado por um dispositivo não verificado", "Failed to upload profile picture!": "Falha ao enviar a imagem de perfil!", - "Incoming call from %(name)s": "Chamada de %(name)s recebida", - "Incoming video call from %(name)s": "Chamada de vídeo de %(name)s recebida", - "Incoming voice call from %(name)s": "Chamada de voz de %(name)s recebida", + "Incoming call from %(name)s": "Recebendo chamada de %(name)s", + "Incoming video call from %(name)s": "Recebendo chamada de vídeo de %(name)s", + "Incoming voice call from %(name)s": "Recebendo chamada de voz de %(name)s", "Join as voice or video.": "Participar por voz ou por vídeo.", "Last seen": "Último uso", "Level:": "Nível:", From 367cda20b11db0fb3fd547f01ab3353bff83106d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20V=C3=A1gner?= Date: Thu, 17 Jan 2019 15:04:54 +0000 Subject: [PATCH 0227/1528] Translated using Weblate (Slovak) Currently translated at 100.0% (1427 of 1427 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/sk/ --- src/i18n/strings/sk.json | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/i18n/strings/sk.json b/src/i18n/strings/sk.json index a5e8f5e9fa..e332027dbb 100644 --- a/src/i18n/strings/sk.json +++ b/src/i18n/strings/sk.json @@ -248,8 +248,8 @@ "Make Moderator": "Udeliť stav moderátor", "Admin Tools": "Nástroje správcu", "Level:": "Úroveň:", - "and %(count)s others...|other": "a ďalších %(count)s...", - "and %(count)s others...|one": "a jeden ďalší...", + "and %(count)s others...|other": "a ďalších %(count)s…", + "and %(count)s others...|one": "a jeden ďalší…", "Invited": "Pozvaní", "Filter room members": "Filtrovať členov v miestnosti", "%(userName)s (power %(powerLevelNumber)s)": "%(userName)s (moc %(powerLevelNumber)s)", @@ -283,7 +283,7 @@ "Unpin Message": "Zrušiť pripnutie správy", "Jump to message": "Preskočiť na správu", "No pinned messages.": "Žiadne pripnuté správy.", - "Loading...": "Načítanie...", + "Loading...": "Načítavanie…", "Pinned Messages": "Pripnuté správy", "Online": "Pripojený", "Idle": "Nečinný", @@ -496,7 +496,7 @@ "Unblacklist": "Odstrániť z čiernej listiny", "Blacklist": "Pridať na čiernu listinu", "Unverify": "Zrušiť overenie", - "Verify...": "Overiť...", + "Verify...": "Overiť…", "No results": "Žiadne výsledky", "Home": "Domov", "Integrations Error": "Chyba integrácií", @@ -557,7 +557,7 @@ "Custom level": "Vlastná úroveň", "Room directory": "Adresár miestností", "Start chat": "Začať konverzáciu", - "And %(count)s more...|other": "A %(count)s ďalších...", + "And %(count)s more...|other": "A %(count)s ďalších…", "ex. @bob:example.com": "pr. @jan:priklad.sk", "Add User": "Pridať používateľa", "Matrix ID": "Matrix ID", @@ -603,7 +603,7 @@ "Start verification": "Spustiť overenie", "Share without verifying": "Zdieľať bez overenia", "Ignore request": "Ignorovať žiadosť", - "Loading device info...": "Načítanie informácií o zariadení...", + "Loading device info...": "Načítanie informácií o zariadení…", "Encryption key request": "Žiadosť o šifrovacie kľúče", "Unable to restore session": "Nie je možné obnoviť reláciu", "If you have previously used a more recent version of Riot, your session may be incompatible with this version. Close this window and return to the more recent version.": "Ak ste sa v minulosti prihlásili s novšou verziou programu Riot, vaša relácia nemusí byť kompatibilná s touto verziou. Zatvorte prosím toto okno a vráťte sa cez najnovšiu verziu Riot.", @@ -736,8 +736,8 @@ "Mirror local video feed": "Zrkadliť lokálne video", "Disable Peer-to-Peer for 1:1 calls": "Zakázať P2P počas priamych volaní", "Never send encrypted messages to unverified devices from this device": "Z tohoto zariadenia nikdy neposielať šifrované správy neovereným zariadeniam", - "Light theme": "Svetlá téma", - "Dark theme": "Tmavá téma", + "Light theme": "Svetlý vzhľad", + "Dark theme": "Tmavý vzhľad", "Can't load user settings": "Nie je možné načítať používateľské nastavenia", "Server may be unavailable or overloaded": "Server môže byť nedostupný alebo preťažený", "Sign out": "Odhlásiť sa", @@ -882,7 +882,7 @@ "Import": "Importovať", "Show these rooms to non-members on the community page and room list?": "Zobrazovať tieto miestnosti na domovskej stránke komunity a v zozname miestností aj pre nečlenov?", "Sign in to get started": "Začnite prihlásením sa", - "Status.im theme": "Téma status.im", + "Status.im theme": "Vzhľad status.im", "Please note you are logging into the %(hs)s server, not matrix.org.": "Všimnite si: Práve sa prihlasujete na server %(hs)s, nie na server matrix.org.", "Username on %(hs)s": "Meno používateľa na serveri %(hs)s", "Restricted": "Obmedzené", @@ -1022,7 +1022,7 @@ "The Home Server may be too old to support third party networks": "Domovský server môže byť natoľko zastaralý, že nepodporuje siete tretíh strán", "Resend": "Poslať znovu", "Room not found": "Miestnosť nenájdená", - "Downloading update...": "Sťahovanie aktualizácie...", + "Downloading update...": "Sťahovanie aktualizácie…", "Messages in one-to-one chats": "Správy v priamych konverzáciách", "Unavailable": "Nedostupné", "View Decrypted Source": "Zobraziť dešifrovaný zdroj", @@ -1137,7 +1137,7 @@ "#example": "#príklad", "Collapse panel": "Zbaliť panel", "With your current browser, the look and feel of the application may be completely incorrect, and some or all features may not function. If you want to try it anyway you can continue, but you are on your own in terms of any issues you may encounter!": "Vo vašom súčasnom prehliadači nemusí Riot vizerať ani fungovať správne a niektoré alebo všetky vlastnosti môžu chýbať. Ak to chcete vyskúšať, môžete pokračovať, no pri riešení problémov s tým spojených si budete musieť poradiť na vlastnú päsť!", - "Checking for an update...": "Kontrola dostupnosti aktualizácie...", + "Checking for an update...": "Kontrola dostupnosti aktualizácie…", "There are advanced notifications which are not shown here": "Niektoré pokročilé oznámenia nemôžu byť zobrazené", "Every page you use in the app": "Každú stránku v aplikácii, ktorú navštívite", "e.g. ": "príklad ", @@ -1268,7 +1268,7 @@ "%(senderName)s added %(addedAddresses)s and removed %(removedAddresses)s as addresses for this room.": "%(senderName)s pridal %(addedAddresses)s a odstránil %(removedAddresses)s z tejto miestnosti.", "%(senderName)s set the main address for this room to %(address)s.": "%(senderName)s nastavil hlavnú adresu tejto miestnosti %(address)s.", "%(senderName)s removed the main address for this room.": "%(senderName)s odstránil hlavnú adresu tejto miestnosti.", - "Unable to connect to Homeserver. Retrying...": "Nie je možné sa pripojiť k domovskému serveru. Prebieha pokus o opetovné pripojenie...", + "Unable to connect to Homeserver. Retrying...": "Nie je možné sa pripojiť k domovskému serveru. Prebieha pokus o opetovné pripojenie…", "Before submitting logs, you must create a GitHub issue to describe your problem.": "Pred tým, než odošlete záznamy, musíte nahlásiť váš problém na GitHub. Uvedte prosím podrobný popis.", "What GitHub issue are these logs for?": "Pre ktoré hlásenie GitHub sú tieto záznamy?", "Riot now uses 3-5x less memory, by only loading information about other users when needed. Please wait whilst we resynchronise with the server!": "Riot teraz vyžaduje 3-5× menej pamäte, pretože informácie o ostatných používateľoch načítava len podľa potreby. Prosím počkajte na dokončenie synchronizácie so serverom!", @@ -1342,7 +1342,7 @@ "No backup is present": "Nemáte žiadnu zálohu", "Start a new backup": "Vytvoriť zálohu", "The following files cannot be uploaded:": "Nie je možné nahrať nasledujúce súbory:", - "Joining room...": "Vstup do miestnosti...", + "Joining room...": "Vstup do miestnosti…", "To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "Aby ste mohli čítať históriu zašifrovaných konverzácií a čítať šifrované správy aj na vašich nových zariadeniach v budúcnosti, nastavte si Bezpečnú obnovu správ.", "If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.": "Keď sa odhlásite alebo použijete iné zariadenie, stratíte prístup k histórii šifrovaných konverzácií. Predísť tomu môžete, ak si nastavíte Bezpečnú obnovu správ.", "Secure Message Recovery": "Bezpečná obnova správ", From 5dd5f4f1dc4e00c95a4403e2318d2adf31754e28 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 22 Jan 2019 14:39:03 +0100 Subject: [PATCH 0228/1528] add JumpToBottomButtom component --- res/css/_components.scss | 1 + res/css/views/rooms/_JumpToBottomButton.scss | 69 +++++++++++++++++++ res/img/icon-jump-to-bottom.svg | 32 +++++++++ .../views/rooms/JumpToBottomButton.js | 32 +++++++++ 4 files changed, 134 insertions(+) create mode 100644 res/css/views/rooms/_JumpToBottomButton.scss create mode 100644 res/img/icon-jump-to-bottom.svg create mode 100644 src/components/views/rooms/JumpToBottomButton.js diff --git a/res/css/_components.scss b/res/css/_components.scss index 92070483f5..6532fcd74c 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -98,6 +98,7 @@ @import "./views/rooms/_AuxPanel.scss"; @import "./views/rooms/_EntityTile.scss"; @import "./views/rooms/_EventTile.scss"; +@import "./views/rooms/_JumpToBottomButton.scss"; @import "./views/rooms/_LinkPreviewWidget.scss"; @import "./views/rooms/_MemberDeviceInfo.scss"; @import "./views/rooms/_MemberInfo.scss"; diff --git a/res/css/views/rooms/_JumpToBottomButton.scss b/res/css/views/rooms/_JumpToBottomButton.scss new file mode 100644 index 0000000000..968139671f --- /dev/null +++ b/res/css/views/rooms/_JumpToBottomButton.scss @@ -0,0 +1,69 @@ +/* +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. +*/ + +@charset "utf-8"; + +.mx_JumpToBottomButton { + z-index: 1000; + position: absolute; + // 12 because height is 50 but button is only 38 = 12+(50-38) = 24 + bottom: 12px; + right: 24px; + width: 38px; + // give it a fixed height so the badge doesn't make + // it taller and pop upwards when visible + height: 50px; + text-align: center; +} + +.mx_JumpToBottomButton_badge { + position: relative; + top: -12px; + border-radius: 16px; + font-weight: bold; + font-size: 12px; + line-height: 14px; + text-align: center; + // to be able to get it centered + // with text-align in parent + display: inline-block; + padding: 0 4px; + color: $secondary-accent-color; + background-color: $warning-color; +} + +.mx_JumpToBottomButton_scrollDown { + position: relative; + height: 38px; + border-radius: 19px; + box-sizing: border-box; + background: $primary-bg-color; + border: 1.3px solid $roomtile-name-color; + cursor: pointer; +} + +.mx_JumpToBottomButton_scrollDown:before { + content: ""; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + mask: url('$(res)/img/icon-jump-to-bottom.svg'); + mask-repeat: no-repeat; + mask-position: 9px 14px; + background: $roomtile-name-color; +} diff --git a/res/img/icon-jump-to-bottom.svg b/res/img/icon-jump-to-bottom.svg new file mode 100644 index 0000000000..c4210b4ebe --- /dev/null +++ b/res/img/icon-jump-to-bottom.svg @@ -0,0 +1,32 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/src/components/views/rooms/JumpToBottomButton.js b/src/components/views/rooms/JumpToBottomButton.js new file mode 100644 index 0000000000..d68af07317 --- /dev/null +++ b/src/components/views/rooms/JumpToBottomButton.js @@ -0,0 +1,32 @@ +/* +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. +*/ + +import { _t } from '../../../languageHandler'; +import AccessibleButton from '../elements/AccessibleButton'; + +export default (props) => { + let badge; + if (props.numUnreadMessages) { + badge =
    {props.numUnreadMessages}
    + } + return (
    + + + { badge } +
    ); +}; From de4cda4572dc04e243382566e18ace33110dc71a Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 22 Jan 2019 14:49:41 +0100 Subject: [PATCH 0229/1528] remove unread messages and jump to bottom from RoomStatusBar --- src/components/structures/RoomStatusBar.js | 53 +--------------------- src/components/structures/RoomView.js | 3 -- 2 files changed, 1 insertion(+), 55 deletions(-) diff --git a/src/components/structures/RoomStatusBar.js b/src/components/structures/RoomStatusBar.js index 12888769ff..b57bac805e 100644 --- a/src/components/structures/RoomStatusBar.js +++ b/src/components/structures/RoomStatusBar.js @@ -45,14 +45,6 @@ module.exports = React.createClass({ propTypes: { // the room this statusbar is representing. room: PropTypes.object.isRequired, - - // the number of messages which have arrived since we've been scrolled up - numUnreadMessages: PropTypes.number, - - // this is true if we are fully scrolled-down, and are looking at - // the end of the live timeline. - atEndOfLiveTimeline: PropTypes.bool, - // This is true when the user is alone in the room, but has also sent a message. // Used to suggest to the user to invite someone sentMessageAndIsAlone: PropTypes.bool, @@ -82,9 +74,6 @@ module.exports = React.createClass({ // 'you are alone' bar onStopWarningClick: PropTypes.func, - // callback for when the user clicks on the 'scroll to bottom' button - onScrollToBottomClick: PropTypes.func, - // callback for when we do something that changes the size of the // status bar. This is used to trigger a re-layout in the parent // component. @@ -180,8 +169,6 @@ module.exports = React.createClass({ // indicate other sizes. _getSize: function() { if (this._shouldShowConnectionError() || - this.props.numUnreadMessages || - !this.props.atEndOfLiveTimeline || this.props.hasActiveCall || this.props.sentMessageAndIsAlone ) { @@ -194,28 +181,6 @@ module.exports = React.createClass({ // return suitable content for the image on the left of the status bar. _getIndicator: function() { - if (this.props.numUnreadMessages) { - return ( -
    - -
    - ); - } - - const AccessibleButton = sdk.getComponent("elements.AccessibleButton"); - if (!this.props.atEndOfLiveTimeline) { - return ( - - {_t("Scroll - - ); - } - if (this.props.hasActiveCall) { const TintableSvg = sdk.getComponent("elements.TintableSvg"); return ( @@ -231,9 +196,7 @@ module.exports = React.createClass({ }, _shouldShowConnectionError: function() { - // no conn bar trumps unread count since you can't get unread messages - // without a connection! (technically may already have some but meh) - // It also trumps the "some not sent" msg since you can't resend without + // no conn bar trumps the "some not sent" msg since you can't resend without // a connection! // There's one situation in which we don't show this 'no connection' bar, and that's // if it's a resource limit exceeded error: those are shown in the top bar. @@ -363,20 +326,6 @@ module.exports = React.createClass({ return this._getUnsentMessageContent(); } - // unread count trumps who is typing since the unread count is only - // set when you've scrolled up - if (this.props.numUnreadMessages) { - // MUST use var name "count" for pluralization to kick in - const unreadMsgs = _t("%(count)s new messages", {count: this.props.numUnreadMessages}); - - return ( -
    - { unreadMsgs } -
    - ); - } - if (this.props.hasActiveCall) { return (
    diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index f63e5b3273..eb530be1a1 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -1651,14 +1651,11 @@ module.exports = React.createClass({ isStatusAreaExpanded = this.state.statusBarVisible; statusBar = Date: Tue, 22 Jan 2019 14:50:16 +0100 Subject: [PATCH 0230/1528] use JumpToBottomButton in RoomView --- src/components/structures/RoomView.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index eb530be1a1..53eae5467c 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -1861,6 +1861,14 @@ module.exports = React.createClass({ onCloseClick={this.forgetReadMarker} />); } + let jumpToBottom; + if (!this.state.atEndOfLiveTimeline) { + const JumpToBottomButton = sdk.getComponent('rooms.JumpToBottomButton'); + jumpToBottom = (); + } const statusBarAreaClass = classNames( "mx_RoomView_statusArea", { @@ -1898,6 +1906,7 @@ module.exports = React.createClass({ { auxPanel }
    { topUnreadMessagesBar } + { jumpToBottom } { messagePanel } { searchResultsPanel }
    From e5de33ab77a78267059518740269114e76072069 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 22 Jan 2019 14:50:31 +0100 Subject: [PATCH 0231/1528] hide RoomStatusBar when not needed again as it will be shown a lot less now, having the layout jump up and down won't be so much of a problem. --- src/components/structures/RoomView.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 53eae5467c..ea01c9bcae 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -1473,11 +1473,10 @@ module.exports = React.createClass({ onStatusBarHidden: function() { // This is currently not desired as it is annoying if it keeps expanding and collapsing - // TODO: Find a less annoying way of hiding the status bar - /*if (this.unmounted) return; + if (this.unmounted) return; this.setState({ statusBarVisible: false, - });*/ + }); }, /** From 689df1b50616eb0961e2bf0cd11cab70bb36531a Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 22 Jan 2019 14:51:11 +0100 Subject: [PATCH 0232/1528] copyright --- src/components/views/rooms/TopUnreadMessagesBar.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/views/rooms/TopUnreadMessagesBar.js b/src/components/views/rooms/TopUnreadMessagesBar.js index ed04ce594d..99f3b7fb23 100644 --- a/src/components/views/rooms/TopUnreadMessagesBar.js +++ b/src/components/views/rooms/TopUnreadMessagesBar.js @@ -1,6 +1,7 @@ /* Copyright 2016 OpenMarket Ltd Copyright 2017 Vector Creations Ltd +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. From 85b55847e10e19cfdc09ef0226d66361f8be1c50 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 22 Jan 2019 14:52:22 +0100 Subject: [PATCH 0233/1528] missing semicolon --- src/components/views/rooms/JumpToBottomButton.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/JumpToBottomButton.js b/src/components/views/rooms/JumpToBottomButton.js index d68af07317..487071855f 100644 --- a/src/components/views/rooms/JumpToBottomButton.js +++ b/src/components/views/rooms/JumpToBottomButton.js @@ -20,7 +20,7 @@ import AccessibleButton from '../elements/AccessibleButton'; export default (props) => { let badge; if (props.numUnreadMessages) { - badge =
    {props.numUnreadMessages}
    + badge = (
    {props.numUnreadMessages}
    ); } return (
    Date: Tue, 22 Jan 2019 16:40:11 +0100 Subject: [PATCH 0234/1528] set default size of 350px for left panel --- src/components/structures/LoggedInView.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index 409988842f..6f2e1f3989 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -183,10 +183,13 @@ const LoggedInView = React.createClass({ }, _loadResizerPreferences() { - const lhsSize = window.localStorage.getItem("mx_lhs_size"); + let lhsSize = window.localStorage.getItem("mx_lhs_size"); if (lhsSize !== null) { - this.resizer.forHandleAt(0).resize(parseInt(lhsSize, 10)); + lhsSize = parseInt(lhsSize, 10); + } else { + lhsSize = 350; } + this.resizer.forHandleAt(0).resize(lhsSize); }, onAccountData: function(event) { From 1373b2f5e27600677165569b0d5790f38378e856 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 22 Jan 2019 17:34:48 +0100 Subject: [PATCH 0235/1528] apparently room can be null here --- src/components/views/rooms/WhoIsTypingTile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/WhoIsTypingTile.js b/src/components/views/rooms/WhoIsTypingTile.js index 4ee11d77b2..dba40f033a 100644 --- a/src/components/views/rooms/WhoIsTypingTile.js +++ b/src/components/views/rooms/WhoIsTypingTile.js @@ -82,7 +82,7 @@ module.exports = React.createClass({ }, onRoomTimeline: function(event, room) { - if (room.roomId === this.props.room.roomId) { + if (room && room.roomId === this.props.room.roomId) { const userId = event.getSender(); // remove user from usersTyping const usersTyping = this.state.usersTyping.filter((m) => m.userId !== userId); From 7d4165802cc08dbc1e9b849911c6a1bdf52fa2b9 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 22 Jan 2019 17:54:04 +0100 Subject: [PATCH 0236/1528] show rooms and people section when empty while filtering --- src/components/views/rooms/RoomList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 1a714e3a84..01e6d280c6 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -593,7 +593,7 @@ module.exports = React.createClass({ subListsProps = subListsProps.filter((props => { const len = props.list.length + (props.extraTiles ? props.extraTiles.length : 0); - return len !== 0 || (props.onAddRoom && !this.props.searchFilter); + return len !== 0 || props.onAddRoom; })); return subListsProps.reduce((components, props, i) => { From 0deb210fd89b91b41d147c4a08969ea9acc1b480 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 22 Jan 2019 09:54:35 -0700 Subject: [PATCH 0237/1528] Collapse DOM around tab label icon --- res/css/structures/_TabbedView.scss | 22 +++++++------------ .../views/dialogs/_UserSettingsDialog.scss | 12 +++++----- src/components/structures/TabbedView.js | 8 +++---- .../views/dialogs/UserSettingsDialog.js | 14 ++++++------ 4 files changed, 25 insertions(+), 31 deletions(-) diff --git a/res/css/structures/_TabbedView.scss b/res/css/structures/_TabbedView.scss index 86149020b8..0f4b67ad71 100644 --- a/res/css/structures/_TabbedView.scss +++ b/res/css/structures/_TabbedView.scss @@ -38,6 +38,7 @@ limitations under the License. font-weight: 600; height: 20px; margin-bottom: 6px; + position: relative; } .mx_TabbedView_tabLabel_active { @@ -50,34 +51,27 @@ limitations under the License. background-color: orange; } -.mx_TabbedView_tabLabel_icon { - width: 14px; - height: 14px; +.mx_TabbedView_maskedIcon {; margin-left: 6px; margin-right: 9px; - position: relative; -} - -.mx_TabbedView_tabLabel_icon > .mx_TabbedView_maskedIcon { width: 14px; height: 14px; display: inline-block; } -.mx_TabbedView_tabLabel_icon > .mx_TabbedView_maskedIcon:before { +.mx_TabbedView_maskedIcon:before { + display: inline-block; background-color: $tab-label-icon-bg-color; mask-repeat: no-repeat; mask-size: 14px; + width: 14px; + height: 14px; mask-position: center; content: ''; - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; + vertical-align: middle; } -.mx_TabbedView_tabLabel_active .mx_TabbedView_tabLabel_icon > .mx_TabbedView_maskedIcon:before { +.mx_TabbedView_tabLabel_active .mx_TabbedView_maskedIcon:before { background-color: $tab-label-active-icon-bg-color; } diff --git a/res/css/views/dialogs/_UserSettingsDialog.scss b/res/css/views/dialogs/_UserSettingsDialog.scss index def5d3f724..c4bd8a5110 100644 --- a/res/css/views/dialogs/_UserSettingsDialog.scss +++ b/res/css/views/dialogs/_UserSettingsDialog.scss @@ -39,25 +39,25 @@ // ========================================================== .mx_UserSettingsDialog_settingsIcon:before { - mask: url('$(res)/img/feather-icons/settings.svg'); + mask-image: url('$(res)/img/feather-icons/settings.svg'); } .mx_UserSettingsDialog_voiceIcon:before { - mask: url('$(res)/img/feather-icons/phone.svg'); + mask-image: url('$(res)/img/feather-icons/phone.svg'); } .mx_UserSettingsDialog_bellIcon:before { - mask: url('$(res)/img/feather-icons/notifications.svg'); + mask-image: url('$(res)/img/feather-icons/notifications.svg'); } .mx_UserSettingsDialog_preferencesIcon:before { - mask: url('$(res)/img/feather-icons/sliders.svg'); + mask-image: url('$(res)/img/feather-icons/sliders.svg'); } .mx_UserSettingsDialog_securityIcon:before { - mask: url('$(res)/img/feather-icons/lock.svg'); + mask-image: url('$(res)/img/feather-icons/lock.svg'); } .mx_UserSettingsDialog_helpIcon:before { - mask: url('$(res)/img/feather-icons/help-circle.svg'); + mask-image: url('$(res)/img/feather-icons/help-circle.svg'); } \ No newline at end of file diff --git a/src/components/structures/TabbedView.js b/src/components/structures/TabbedView.js index 43979140a8..2b136128f3 100644 --- a/src/components/structures/TabbedView.js +++ b/src/components/structures/TabbedView.js @@ -26,12 +26,12 @@ export class Tab { /** * Creates a new tab. * @param {string} tabLabel The untranslated tab label. - * @param {string} tabIconJsx The JSX for the tab icon. This should be a plain img element or null. + * @param {string} tabIconClass The class for the tab icon. This should be a simple mask. * @param {string} tabJsx The JSX for the tab container. */ - constructor(tabLabel, tabIconJsx, tabJsx) { + constructor(tabLabel, tabIconClass, tabJsx) { this.label = tabLabel; - this.icon = tabIconJsx; + this.icon = tabIconClass; this.body = tabJsx; } } @@ -78,7 +78,7 @@ export class TabbedView extends React.Component { let tabIcon = null; if (tab.icon) { - tabIcon = {tab.icon}; + tabIcon = ; } const onClickHandler = () => this._setActiveTab(tab); diff --git a/src/components/views/dialogs/UserSettingsDialog.js b/src/components/views/dialogs/UserSettingsDialog.js index d0b3f436b8..dd404ce280 100644 --- a/src/components/views/dialogs/UserSettingsDialog.js +++ b/src/components/views/dialogs/UserSettingsDialog.js @@ -47,37 +47,37 @@ export default class UserSettingsDialog extends React.Component { return [ new Tab( _td("General"), - , + "mx_UserSettingsDialog_settingsIcon", , ), new Tab( _td("Notifications"), - , + "mx_UserSettingsDialog_bellIcon",
    Notifications Test
    , ), new Tab( _td("Preferences"), - , + "mx_UserSettingsDialog_preferencesIcon",
    Preferences Test
    , ), new Tab( _td("Voice & Video"), - , + "mx_UserSettingsDialog_voiceIcon",
    Voice Test
    , ), new Tab( _td("Security & Privacy"), - , + "mx_UserSettingsDialog_securityIcon",
    Security Test
    , ), new Tab( _td("Help & About"), - , + "mx_UserSettingsDialog_helpIcon",
    Help Test
    , ), new Tab( _td("Visit old settings"), - , + "mx_UserSettingsDialog_helpIcon", , ), ]; From 5ef901513313d985ada89b8ec622c4a8c2732145 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 22 Jan 2019 10:28:33 -0700 Subject: [PATCH 0238/1528] Add labs flag for tabbed settings --- src/components/structures/MatrixChat.js | 11 ++-- src/i18n/strings/en_EN.json | 87 +++++++++++++------------ src/settings/Settings.js | 6 ++ 3 files changed, 57 insertions(+), 47 deletions(-) diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 4e6ffbd2c8..4c783eedac 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -611,10 +611,13 @@ export default React.createClass({ this._viewIndexedRoom(payload.roomIndex); break; case 'view_user_settings': { - const UserSettingsDialog = sdk.getComponent("dialogs.UserSettingsDialog"); - Modal.createTrackedDialog('User settings', '', UserSettingsDialog, {}); - //this._setPage(PageTypes.UserSettings); - //this.notifyNewScreen('settings'); + if (SettingsStore.isFeatureEnabled("feature_tabbed_settings")) { + const UserSettingsDialog = sdk.getComponent("dialogs.UserSettingsDialog"); + Modal.createTrackedDialog('User settings', '', UserSettingsDialog, {}); + } else { + this._setPage(PageTypes.UserSettings); + this.notifyNewScreen('settings'); + } break; } case 'view_old_user_settings': diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index defc77e3dd..ae9eb2e9b4 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -262,6 +262,7 @@ "Please contact your homeserver administrator.": "Please contact your homeserver administrator.", "Failed to join room": "Failed to join room", "Message Pinning": "Message Pinning", + "Tabbed settings": "Tabbed settings", "Custom user status messages": "Custom user status messages", "Increase performance by only loading room members on first view": "Increase performance by only loading room members on first view", "Backup of encryption keys to server": "Backup of encryption keys to server", @@ -401,9 +402,10 @@ "Off": "Off", "On": "On", "Noisy": "Noisy", - "General": "General", - "Profile": "Profile", "Display Name": "Display Name", + "Save": "Save", + "Profile": "Profile", + "General": "General", "Cannot add any more widgets": "Cannot add any more widgets", "The maximum permitted number of widgets have already been added to this room.": "The maximum permitted number of widgets have already been added to this room.", "Add a widget": "Add a widget", @@ -536,7 +538,6 @@ "World readable": "World readable", "Guests can join": "Guests can join", "Failed to set avatar.": "Failed to set avatar.", - "Save": "Save", "(~%(count)s results)|other": "(~%(count)s results)", "(~%(count)s results)|one": "(~%(count)s result)", "Join Room": "Join Room", @@ -713,46 +714,6 @@ "Removed or unknown message type": "Removed or unknown message type", "Message removed by %(userId)s": "Message removed by %(userId)s", "Message removed": "Message removed", - "Robot check is currently unavailable on desktop - please use a web browser": "Robot check is currently unavailable on desktop - please use a web browser", - "This Home Server would like to make sure you are not a robot": "This Home Server would like to make sure you are not a robot", - "Custom Server Options": "Custom Server Options", - "You can use the custom server options to sign into other Matrix servers by specifying a different Home server URL.": "You can use the custom server options to sign into other Matrix servers by specifying a different Home server URL.", - "This allows you to use this app with an existing Matrix account on a different home server.": "This allows you to use this app with an existing Matrix account on a different home server.", - "You can also set a custom identity server but this will typically prevent interaction with users based on email address.": "You can also set a custom identity server but this will typically prevent interaction with users based on email address.", - "To continue, please enter your password.": "To continue, please enter your password.", - "Password:": "Password:", - "Please review and accept all of the homeserver's policies": "Please review and accept all of the homeserver's policies", - "Please review and accept the policies of this homeserver:": "Please review and accept the policies of this homeserver:", - "An email has been sent to %(emailAddress)s": "An email has been sent to %(emailAddress)s", - "Please check your email to continue registration.": "Please check your email to continue registration.", - "Token incorrect": "Token incorrect", - "A text message has been sent to %(msisdn)s": "A text message has been sent to %(msisdn)s", - "Please enter the code it contains:": "Please enter the code it contains:", - "Code": "Code", - "Start authentication": "Start authentication", - "powered by Matrix": "powered by Matrix", - "The email field must not be blank.": "The email field must not be blank.", - "The user name field must not be blank.": "The user name field must not be blank.", - "The phone number field must not be blank.": "The phone number field must not be blank.", - "The password field must not be blank.": "The password field must not be blank.", - "Username on %(hs)s": "Username on %(hs)s", - "User name": "User name", - "Mobile phone number": "Mobile phone number", - "Forgot your password?": "Forgot your password?", - "Matrix ID": "Matrix ID", - "%(serverName)s Matrix ID": "%(serverName)s Matrix ID", - "Sign in with": "Sign in with", - "Email address": "Email address", - "Sign in": "Sign in", - "If you don't specify an email address, you won't be able to reset your password. Are you sure?": "If you don't specify an email address, you won't be able to reset your password. Are you sure?", - "Email address (optional)": "Email address (optional)", - "You are registering with %(SelectedTeamName)s": "You are registering with %(SelectedTeamName)s", - "Mobile phone number (optional)": "Mobile phone number (optional)", - "Default server": "Default server", - "Custom server": "Custom server", - "Home server URL": "Home server URL", - "Identity server URL": "Identity server URL", - "What does this mean?": "What does this mean?", "Remove from community": "Remove from community", "Disinvite this user from community?": "Disinvite this user from community?", "Remove this user from community?": "Remove this user from community?", @@ -889,6 +850,7 @@ "And %(count)s more...|other": "And %(count)s more...", "ex. @bob:example.com": "ex. @bob:example.com", "Add User": "Add User", + "Matrix ID": "Matrix ID", "Matrix Room ID": "Matrix Room ID", "email address": "email address", "That doesn't look like a valid email address": "That doesn't look like a valid email address", @@ -1015,6 +977,7 @@ "Please check your email and click on the link it contains. Once this is done, click continue.": "Please check your email and click on the link it contains. Once this is done, click continue.", "Unable to add email address": "Unable to add email address", "Unable to verify email address.": "Unable to verify email address.", + "Email address": "Email address", "This will allow you to reset your password and receive notifications.": "This will allow you to reset your password and receive notifications.", "Skip": "Skip", "Only use lower case letters, numbers and '=_-./'": "Only use lower case letters, numbers and '=_-./'", @@ -1102,6 +1065,44 @@ "Set status": "Set status", "Set a new status...": "Set a new status...", "View Community": "View Community", + "Robot check is currently unavailable on desktop - please use a web browser": "Robot check is currently unavailable on desktop - please use a web browser", + "This Home Server would like to make sure you are not a robot": "This Home Server would like to make sure you are not a robot", + "Custom Server Options": "Custom Server Options", + "You can use the custom server options to sign into other Matrix servers by specifying a different Home server URL.": "You can use the custom server options to sign into other Matrix servers by specifying a different Home server URL.", + "This allows you to use this app with an existing Matrix account on a different home server.": "This allows you to use this app with an existing Matrix account on a different home server.", + "You can also set a custom identity server but this will typically prevent interaction with users based on email address.": "You can also set a custom identity server but this will typically prevent interaction with users based on email address.", + "To continue, please enter your password.": "To continue, please enter your password.", + "Password:": "Password:", + "Please review and accept all of the homeserver's policies": "Please review and accept all of the homeserver's policies", + "Please review and accept the policies of this homeserver:": "Please review and accept the policies of this homeserver:", + "An email has been sent to %(emailAddress)s": "An email has been sent to %(emailAddress)s", + "Please check your email to continue registration.": "Please check your email to continue registration.", + "Token incorrect": "Token incorrect", + "A text message has been sent to %(msisdn)s": "A text message has been sent to %(msisdn)s", + "Please enter the code it contains:": "Please enter the code it contains:", + "Code": "Code", + "Start authentication": "Start authentication", + "powered by Matrix": "powered by Matrix", + "The email field must not be blank.": "The email field must not be blank.", + "The user name field must not be blank.": "The user name field must not be blank.", + "The phone number field must not be blank.": "The phone number field must not be blank.", + "The password field must not be blank.": "The password field must not be blank.", + "Username on %(hs)s": "Username on %(hs)s", + "User name": "User name", + "Mobile phone number": "Mobile phone number", + "Forgot your password?": "Forgot your password?", + "%(serverName)s Matrix ID": "%(serverName)s Matrix ID", + "Sign in with": "Sign in with", + "Sign in": "Sign in", + "If you don't specify an email address, you won't be able to reset your password. Are you sure?": "If you don't specify an email address, you won't be able to reset your password. Are you sure?", + "Email address (optional)": "Email address (optional)", + "You are registering with %(SelectedTeamName)s": "You are registering with %(SelectedTeamName)s", + "Mobile phone number (optional)": "Mobile phone number (optional)", + "Default server": "Default server", + "Custom server": "Custom server", + "Home server URL": "Home server URL", + "Identity server URL": "Identity server URL", + "What does this mean?": "What does this mean?", "Sorry, your browser is not able to run Riot.": "Sorry, your browser is not able to run Riot.", "Riot uses many advanced browser features, some of which are not available or experimental in your current browser.": "Riot uses many advanced browser features, some of which are not available or experimental in your current browser.", "Please install Chrome or Firefox for the best experience.": "Please install Chrome or Firefox for the best experience.", diff --git a/src/settings/Settings.js b/src/settings/Settings.js index 5a9bd9e455..4871ee92f9 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -84,6 +84,12 @@ export const SETTINGS = { supportedLevels: LEVELS_FEATURE, default: false, }, + "feature_tabbed_settings": { + isFeature: true, + displayName: _td("Tabbed settings"), + supportedLevels: LEVELS_FEATURE, + default: false, + }, "feature_custom_status": { isFeature: true, displayName: _td("Custom user status messages"), From be94e1aebc915b31b02328040f0c674f446ec1fb Mon Sep 17 00:00:00 2001 From: Christopher Medlin Date: Tue, 22 Jan 2019 11:39:26 -0800 Subject: [PATCH 0239/1528] Fix integrations error popup Signed-off-by: Christopher Medlin --- res/css/views/rooms/_RoomSettings.scss | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/res/css/views/rooms/_RoomSettings.scss b/res/css/views/rooms/_RoomSettings.scss index 4454cd479c..5ed9168aab 100644 --- a/res/css/views/rooms/_RoomSettings.scss +++ b/res/css/views/rooms/_RoomSettings.scss @@ -66,15 +66,16 @@ limitations under the License. .mx_RoomSettings_integrationsButton_errorPopup { position: absolute; top: 110%; - left: -125%; - width: 348%; - padding: 2%; + left: -275%; + width: 550%; + padding: 30%; font-size: 10pt; line-height: 1.5em; border-radius: 5px; background-color: $accent-color; color: $accent-fg-color; text-align: center; + z-index: 1000; } .mx_RoomSettings_unbanButton { display: inline; From f0e8182ff362c6f4352b6baabd081fb66126a550 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 22 Jan 2019 19:25:09 -0700 Subject: [PATCH 0240/1528] Support selects on Field Luckily, the styling is copy/paste capable. --- res/css/views/elements/_Field.scss | 19 +++++++++++++------ src/components/views/elements/Field.js | 13 ++++++++----- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/res/css/views/elements/_Field.scss b/res/css/views/elements/_Field.scss index c728f4bcd4..1fcd238c23 100644 --- a/res/css/views/elements/_Field.scss +++ b/res/css/views/elements/_Field.scss @@ -21,7 +21,8 @@ limitations under the License. margin: 1em 0; } -.mx_Field input { +.mx_Field input, +.mx_Field select { font-weight: normal; border-radius: 4px; transition: border-color 0.25s; @@ -29,17 +30,20 @@ limitations under the License. padding: 8px 9px; } -.mx_Field input:focus { +.mx_Field input:focus, +.mx_Field select:focus { outline: 0; border-color: $input-focused-border-color; } -.mx_Field input::placeholder { +.mx_Field input::placeholder, +.mx_Field select::placeholder { transition: color 0.25s ease-in 0s; color: transparent; } -.mx_Field input:placeholder-shown:focus::placeholder { +.mx_Field input:placeholder-shown:focus::placeholder, +.mx_Field select:placeholder-shown:focus::placeholder { transition: color 0.25s ease-in 0.1s; color: $greyed-fg-color; } @@ -61,7 +65,9 @@ limitations under the License. } .mx_Field input:focus + label, -.mx_Field input:not(:placeholder-shown) + label { +.mx_Field input:not(:placeholder-shown) + label, +.mx_Field select:focus + label, +.mx_Field select:not(:placeholder-shown) + label { transition: font-size 0.25s ease-out 0s, color 0.25s ease-out 0s, @@ -72,6 +78,7 @@ limitations under the License. background-color: $field-focused-label-bg-color; } -.mx_Field input:focus + label { +.mx_Field input:focus + label, +.mx_Field select:focus + label { color: $input-focused-border-color; } diff --git a/src/components/views/elements/Field.js b/src/components/views/elements/Field.js index 428c7f1d6c..896eff5918 100644 --- a/src/components/views/elements/Field.js +++ b/src/components/views/elements/Field.js @@ -27,6 +27,9 @@ export default class Field extends React.PureComponent { label: PropTypes.string, // The field's placeholder string. placeholder: PropTypes.string, + // The type of field to create. Defaults to "input". Should be "input" or "select". + // To define options for a select, use + element: PropTypes.string, // All other props pass through to the . } @@ -38,13 +41,13 @@ export default class Field extends React.PureComponent { delete extraProps.type; delete extraProps.placeholder; delete extraProps.label; + delete extraProps.element; + + const element = this.props.element || "input"; + const fieldInput = React.createElement(element, extraProps, this.props.children); return
    - + {fieldInput}
    ; } From 9d2bfdc0c0d49d7b4ee259024814d55f8faf7a8e Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Tue, 22 Jan 2019 11:50:11 -0600 Subject: [PATCH 0241/1528] Fix CSS indentation level --- res/css/views/auth/_AuthFooter.scss | 14 +++++++------- res/css/views/auth/_AuthHeader.scss | 8 ++++---- res/css/views/auth/_AuthPage.scss | 28 ++++++++++++++-------------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/res/css/views/auth/_AuthFooter.scss b/res/css/views/auth/_AuthFooter.scss index 4737513125..0d9e59e7df 100644 --- a/res/css/views/auth/_AuthFooter.scss +++ b/res/css/views/auth/_AuthFooter.scss @@ -15,14 +15,14 @@ limitations under the License. */ .mx_AuthFooter { - display: block; - text-align: center; - margin-top: 15px; - width: 100%; - font-size: 13px; - opacity: 0.8; + display: block; + text-align: center; + margin-top: 15px; + width: 100%; + font-size: 13px; + opacity: 0.8; } .mx_AuthFooter a:link { - color: $primary-fg-color; + color: $primary-fg-color; } diff --git a/res/css/views/auth/_AuthHeader.scss b/res/css/views/auth/_AuthHeader.scss index 58df178aa9..426215dc62 100644 --- a/res/css/views/auth/_AuthHeader.scss +++ b/res/css/views/auth/_AuthHeader.scss @@ -15,11 +15,11 @@ limitations under the License. */ .mx_AuthHeader_logo { - text-align: center; - height: 150px; - margin-bottom: 45px; + text-align: center; + height: 150px; + margin-bottom: 45px; } .mx_AuthHeader_logo img { - max-height: 100% + max-height: 100% } diff --git a/res/css/views/auth/_AuthPage.scss b/res/css/views/auth/_AuthPage.scss index 6916f1d92a..8dae4ca64e 100644 --- a/res/css/views/auth/_AuthPage.scss +++ b/res/css/views/auth/_AuthPage.scss @@ -15,26 +15,26 @@ limitations under the License. */ .mx_AuthPage { - width: 100%; - height: 100%; + width: 100%; + height: 100%; - display: flex; - align-items: center; - justify-content: center; + display: flex; + align-items: center; + justify-content: center; - overflow: auto; + overflow: auto; } .mx_AuthPage h2 { - font-weight: 300; - margin-top: 32px; - margin-bottom: 20px; + font-weight: 300; + margin-top: 32px; + margin-bottom: 20px; } .mx_AuthPage_modal { - width: 300px; - min-height: 450px; - padding-top: 50px; - padding-bottom: 50px; - margin: auto; + width: 300px; + min-height: 450px; + padding-top: 50px; + padding-bottom: 50px; + margin: auto; } From 575cd1e37b73e47487726a038e85f4967a6c5e0a Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Tue, 22 Jan 2019 19:28:23 -0600 Subject: [PATCH 0242/1528] Add modal look to authentication flows This changes the auth screens to use the modal-like style of the redesign. This does not attempt to style the actual body content of each screen. Instead, it covers the header area with logo, footer links, and overall modal container only. --- res/css/_components.scss | 1 + res/css/views/auth/_AuthBody.scss | 23 ++++++++++++++++ res/css/views/auth/_AuthFooter.scss | 12 ++++----- res/css/views/auth/_AuthHeader.scss | 12 ++++++--- res/css/views/auth/_AuthPage.scss | 18 ++++++------- res/themes/dharma/css/_dharma.scss | 4 +++ res/themes/light/css/_base.scss | 4 +++ .../structures/auth/ForgotPassword.js | 7 ++--- src/components/structures/auth/Login.js | 7 +++-- .../structures/auth/PostRegistration.js | 21 ++++++++------- .../structures/auth/Registration.js | 15 ++++++----- src/components/views/auth/AuthBody.js | 27 +++++++++++++++++++ src/components/views/auth/AuthPage.js | 4 +++ 13 files changed, 113 insertions(+), 42 deletions(-) create mode 100644 res/css/views/auth/_AuthBody.scss create mode 100644 src/components/views/auth/AuthBody.js diff --git a/res/css/_components.scss b/res/css/_components.scss index 6532fcd74c..be36ea7a5f 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -23,6 +23,7 @@ @import "./structures/_UserSettings.scss"; @import "./structures/_ViewSource.scss"; @import "./structures/auth/_Login.scss"; +@import "./views/auth/_AuthBody.scss"; @import "./views/auth/_AuthButtons.scss"; @import "./views/auth/_AuthFooter.scss"; @import "./views/auth/_AuthHeader.scss"; diff --git a/res/css/views/auth/_AuthBody.scss b/res/css/views/auth/_AuthBody.scss new file mode 100644 index 0000000000..97632c2e3f --- /dev/null +++ b/res/css/views/auth/_AuthBody.scss @@ -0,0 +1,23 @@ +/* +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. +*/ + +.mx_AuthBody { + width: 500px; + background-color: $authpage-body-bg-color; + border-radius: 0 4px 4px 0; + padding: 25px 60px; + box-sizing: border-box; +} diff --git a/res/css/views/auth/_AuthFooter.scss b/res/css/views/auth/_AuthFooter.scss index 0d9e59e7df..6ad5b0a459 100644 --- a/res/css/views/auth/_AuthFooter.scss +++ b/res/css/views/auth/_AuthFooter.scss @@ -15,14 +15,14 @@ limitations under the License. */ .mx_AuthFooter { - display: block; text-align: center; - margin-top: 15px; width: 100%; - font-size: 13px; - opacity: 0.8; + font-size: 14px; + opacity: 0.72; + margin: 20px 0; } -.mx_AuthFooter a:link { - color: $primary-fg-color; +.mx_AuthFooter a:link, a:hover, a:visited { + color: $accent-fg-color; + margin: 0 22px; } diff --git a/res/css/views/auth/_AuthHeader.scss b/res/css/views/auth/_AuthHeader.scss index 426215dc62..fb0b3e666b 100644 --- a/res/css/views/auth/_AuthHeader.scss +++ b/res/css/views/auth/_AuthHeader.scss @@ -14,12 +14,16 @@ See the License for the specific language governing permissions and limitations under the License. */ +.mx_AuthHeader { + width: 206px; + padding: 25px 50px; + box-sizing: border-box; +} + .mx_AuthHeader_logo { - text-align: center; - height: 150px; - margin-bottom: 45px; + margin-top: 15px; } .mx_AuthHeader_logo img { - max-height: 100% + width: 100%; } diff --git a/res/css/views/auth/_AuthPage.scss b/res/css/views/auth/_AuthPage.scss index 8dae4ca64e..9e32750771 100644 --- a/res/css/views/auth/_AuthPage.scss +++ b/res/css/views/auth/_AuthPage.scss @@ -17,12 +17,10 @@ limitations under the License. .mx_AuthPage { width: 100%; height: 100%; - display: flex; - align-items: center; - justify-content: center; - + flex-direction: column; overflow: auto; + background-color: $authpage-bg-color; } .mx_AuthPage h2 { @@ -32,9 +30,11 @@ limitations under the License. } .mx_AuthPage_modal { - width: 300px; - min-height: 450px; - padding-top: 50px; - padding-bottom: 50px; - margin: auto; + display: flex; + margin: 100px auto auto; + border-radius: 4px; + // Not currently supported in Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=1178765 + backdrop-filter: blur(10px); + box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.33); + background-color: $authpage-modal-bg-color; } diff --git a/res/themes/dharma/css/_dharma.scss b/res/themes/dharma/css/_dharma.scss index c9f62fbe6b..1678c9b586 100644 --- a/res/themes/dharma/css/_dharma.scss +++ b/res/themes/dharma/css/_dharma.scss @@ -193,6 +193,10 @@ $room-warning-bg-color: #fff8e3; $memberstatus-placeholder-color: $roomtile-name-color; +$authpage-bg-color: #2e3649; +$authpage-modal-bg-color: rgba(255, 255, 255, 0.59); +$authpage-body-bg-color: #ffffff; + /*** form elements ***/ // .mx_textinput is a container for a text input diff --git a/res/themes/light/css/_base.scss b/res/themes/light/css/_base.scss index dbab909f13..c03db23930 100644 --- a/res/themes/light/css/_base.scss +++ b/res/themes/light/css/_base.scss @@ -188,6 +188,10 @@ $room-warning-bg-color: #fff8e3; $memberstatus-placeholder-color: $roomtile-name-color; +$authpage-bg-color: #2e3649; +$authpage-modal-bg-color: rgba(255, 255, 255, 0.59); +$authpage-body-bg-color: #ffffff; + // ***** Mixins! ***** @define-mixin mx_DialogButton { diff --git a/src/components/structures/auth/ForgotPassword.js b/src/components/structures/auth/ForgotPassword.js index ab0f660be0..87e8c7d131 100644 --- a/src/components/structures/auth/ForgotPassword.js +++ b/src/components/structures/auth/ForgotPassword.js @@ -185,7 +185,7 @@ module.exports = React.createClass({ render: function() { const AuthPage = sdk.getComponent("auth.AuthPage"); const AuthHeader = sdk.getComponent("auth.AuthHeader"); - const AuthFooter = sdk.getComponent("auth.AuthFooter"); + const AuthBody = sdk.getComponent("auth.AuthBody"); const ServerConfig = sdk.getComponent("auth.ServerConfig"); const Spinner = sdk.getComponent("elements.Spinner"); @@ -272,7 +272,6 @@ module.exports = React.createClass({ { _t('Create an account') } -
    ); @@ -282,7 +281,9 @@ module.exports = React.createClass({ return ( - { resetPasswordJsx } + + {resetPasswordJsx} + ); }, diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js index c64223ba48..28bed9af05 100644 --- a/src/components/structures/auth/Login.js +++ b/src/components/structures/auth/Login.js @@ -517,7 +517,7 @@ module.exports = React.createClass({ const Loader = sdk.getComponent("elements.Spinner"); const AuthPage = sdk.getComponent("auth.AuthPage"); const AuthHeader = sdk.getComponent("auth.AuthHeader"); - const AuthFooter = sdk.getComponent("auth.AuthFooter"); + const AuthBody = sdk.getComponent("auth.AuthBody"); const ServerConfig = sdk.getComponent("auth.ServerConfig"); const loader = this.state.busy ?
    : null; @@ -560,7 +560,7 @@ module.exports = React.createClass({ return ( -
    + { header } { errorTextSection } { this.componentForStep(this.state.currentFlow) } @@ -570,8 +570,7 @@ module.exports = React.createClass({ { loginAsGuestJsx } - -
    +
    ); }, diff --git a/src/components/structures/auth/PostRegistration.js b/src/components/structures/auth/PostRegistration.js index fff326f6ac..1e24d0920a 100644 --- a/src/components/structures/auth/PostRegistration.js +++ b/src/components/structures/auth/PostRegistration.js @@ -62,18 +62,21 @@ module.exports = React.createClass({ const ChangeAvatar = sdk.getComponent('settings.ChangeAvatar'); const AuthPage = sdk.getComponent('auth.AuthPage'); const AuthHeader = sdk.getComponent('auth.AuthHeader'); + const AuthBody = sdk.getComponent("auth.AuthBody"); return ( -
    - { _t('Set a display name:') } - - { _t('Upload an avatar:') } - - - { this.state.errorString } -
    + +
    + { _t('Set a display name:') } + + { _t('Upload an avatar:') } + + + { this.state.errorString } +
    +
    ); }, diff --git a/src/components/structures/auth/Registration.js b/src/components/structures/auth/Registration.js index 39f7964281..fe6fb078e3 100644 --- a/src/components/structures/auth/Registration.js +++ b/src/components/structures/auth/Registration.js @@ -397,7 +397,7 @@ module.exports = React.createClass({ render: function() { const AuthHeader = sdk.getComponent('auth.AuthHeader'); - const AuthFooter = sdk.getComponent('auth.AuthFooter'); + const AuthBody = sdk.getComponent("auth.AuthBody"); const AuthPage = sdk.getComponent('auth.AuthPage'); const InteractiveAuth = sdk.getComponent('structures.InteractiveAuth'); const Spinner = sdk.getComponent("elements.Spinner"); @@ -481,12 +481,13 @@ module.exports = React.createClass({ this.state.teamSelected.domain + "/icon.png" : null} /> - { header } - { registerBody } - { signIn } - { errorText } - - + + { header } + { registerBody } + { signIn } + { errorText } + + ); }, diff --git a/src/components/views/auth/AuthBody.js b/src/components/views/auth/AuthBody.js new file mode 100644 index 0000000000..9a078efb52 --- /dev/null +++ b/src/components/views/auth/AuthBody.js @@ -0,0 +1,27 @@ +/* +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. +*/ + +'use strict'; + +import React from 'react'; + +export default class AuthBody extends React.PureComponent { + render() { + return
    + { this.props.children } +
    ; + } +} diff --git a/src/components/views/auth/AuthPage.js b/src/components/views/auth/AuthPage.js index d5f82f7264..8cb8cf7d53 100644 --- a/src/components/views/auth/AuthPage.js +++ b/src/components/views/auth/AuthPage.js @@ -18,16 +18,20 @@ limitations under the License. 'use strict'; const React = require('react'); +import sdk from '../../../index'; module.exports = React.createClass({ displayName: 'AuthPage', render: function() { + const AuthFooter = sdk.getComponent('auth.AuthFooter'); + return (
    { this.props.children }
    +
    ); }, From 2b3c8c44503c03fbc3557e8b5c26587dafb8e313 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 22 Jan 2019 20:03:59 -0700 Subject: [PATCH 0243/1528] Correctly form a select/input element --- res/css/views/elements/_Field.scss | 9 +++------ src/components/views/elements/Field.js | 10 +++++----- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/res/css/views/elements/_Field.scss b/res/css/views/elements/_Field.scss index 1fcd238c23..4f6e868249 100644 --- a/res/css/views/elements/_Field.scss +++ b/res/css/views/elements/_Field.scss @@ -36,14 +36,12 @@ limitations under the License. border-color: $input-focused-border-color; } -.mx_Field input::placeholder, -.mx_Field select::placeholder { +.mx_Field input::placeholder { transition: color 0.25s ease-in 0s; color: transparent; } -.mx_Field input:placeholder-shown:focus::placeholder, -.mx_Field select:placeholder-shown:focus::placeholder { +.mx_Field input:placeholder-shown:focus::placeholder { transition: color 0.25s ease-in 0.1s; color: $greyed-fg-color; } @@ -66,8 +64,7 @@ limitations under the License. .mx_Field input:focus + label, .mx_Field input:not(:placeholder-shown) + label, -.mx_Field select:focus + label, -.mx_Field select:not(:placeholder-shown) + label { +.mx_Field select:focus + label { transition: font-size 0.25s ease-out 0s, color 0.25s ease-out 0s, diff --git a/src/components/views/elements/Field.js b/src/components/views/elements/Field.js index 896eff5918..69b890b911 100644 --- a/src/components/views/elements/Field.js +++ b/src/components/views/elements/Field.js @@ -36,12 +36,12 @@ export default class Field extends React.PureComponent { render() { const extraProps = Object.assign({}, this.props); - // Remove explicit props - delete extraProps.id; - delete extraProps.type; - delete extraProps.placeholder; - delete extraProps.label; + // Remove explicit properties that shouldn't be copied delete extraProps.element; + delete extraProps.children; + + // Set some defaults for the element + extraProps.type = extraProps.type || "text"; const element = this.props.element || "input"; const fieldInput = React.createElement(element, extraProps, this.props.children); From 7ccf64584e990872a93de3778ba83a194d2155f7 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 22 Jan 2019 21:35:36 -0700 Subject: [PATCH 0244/1528] Fix AuthFooter CSS rules conflicting with anchors all over the app Fixes https://github.com/vector-im/riot-web/issues/8227 --- res/css/views/auth/_AuthFooter.scss | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/res/css/views/auth/_AuthFooter.scss b/res/css/views/auth/_AuthFooter.scss index 6ad5b0a459..741be49a69 100644 --- a/res/css/views/auth/_AuthFooter.scss +++ b/res/css/views/auth/_AuthFooter.scss @@ -22,7 +22,9 @@ limitations under the License. margin: 20px 0; } -.mx_AuthFooter a:link, a:hover, a:visited { +.mx_AuthFooter a:link, +.mx_AuthFooter a:hover, +.mx_AuthFooter a:visited { color: $accent-fg-color; margin: 0 22px; } From 0f3ee9c786d7f8f37ca6a7ff4077cbd45b2214c7 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Tue, 22 Jan 2019 21:51:42 -0600 Subject: [PATCH 0245/1528] Extract auth header logo to new component This will allow `riot-web` to replace only the logo, rather than the whole header. --- res/css/_components.scss | 1 + res/css/views/auth/_AuthHeader.scss | 8 ------ res/css/views/auth/_AuthHeaderLogo.scss | 23 ++++++++++++++++++ src/components/views/auth/AuthHeader.js | 7 +++--- src/components/views/auth/AuthHeaderLogo.js | 27 +++++++++++++++++++++ 5 files changed, 55 insertions(+), 11 deletions(-) create mode 100644 res/css/views/auth/_AuthHeaderLogo.scss create mode 100644 src/components/views/auth/AuthHeaderLogo.js diff --git a/res/css/_components.scss b/res/css/_components.scss index be36ea7a5f..9a5e390933 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -27,6 +27,7 @@ @import "./views/auth/_AuthButtons.scss"; @import "./views/auth/_AuthFooter.scss"; @import "./views/auth/_AuthHeader.scss"; +@import "./views/auth/_AuthHeaderLogo.scss"; @import "./views/auth/_AuthPage.scss"; @import "./views/auth/_InteractiveAuthEntryComponents.scss"; @import "./views/auth/_ServerConfig.scss"; diff --git a/res/css/views/auth/_AuthHeader.scss b/res/css/views/auth/_AuthHeader.scss index fb0b3e666b..376864d268 100644 --- a/res/css/views/auth/_AuthHeader.scss +++ b/res/css/views/auth/_AuthHeader.scss @@ -19,11 +19,3 @@ limitations under the License. padding: 25px 50px; box-sizing: border-box; } - -.mx_AuthHeader_logo { - margin-top: 15px; -} - -.mx_AuthHeader_logo img { - width: 100%; -} diff --git a/res/css/views/auth/_AuthHeaderLogo.scss b/res/css/views/auth/_AuthHeaderLogo.scss new file mode 100644 index 0000000000..3d8ab29325 --- /dev/null +++ b/res/css/views/auth/_AuthHeaderLogo.scss @@ -0,0 +1,23 @@ +/* +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. +*/ + +.mx_AuthHeaderLogo { + margin-top: 15px; +} + +.mx_AuthHeaderLogo img { + width: 100%; +} diff --git a/src/components/views/auth/AuthHeader.js b/src/components/views/auth/AuthHeader.js index 08c9ad41c9..c1d831a70a 100644 --- a/src/components/views/auth/AuthHeader.js +++ b/src/components/views/auth/AuthHeader.js @@ -18,16 +18,17 @@ limitations under the License. 'use strict'; const React = require('react'); +import sdk from '../../../index'; module.exports = React.createClass({ displayName: 'AuthHeader', render: function() { + const AuthHeaderLogo = sdk.getComponent('auth.AuthHeaderLogo'); + return (
    -
    - Matrix -
    +
    ); }, diff --git a/src/components/views/auth/AuthHeaderLogo.js b/src/components/views/auth/AuthHeaderLogo.js new file mode 100644 index 0000000000..9edf149a83 --- /dev/null +++ b/src/components/views/auth/AuthHeaderLogo.js @@ -0,0 +1,27 @@ +/* +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. +*/ + +'use strict'; + +import React from 'react'; + +export default class AuthHeaderLogo extends React.PureComponent { + render() { + return
    + Matrix +
    ; + } +} From 6d7e88a84a125a7e52d0fcc1d80493fe5252697e Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 23 Jan 2019 15:06:49 +0000 Subject: [PATCH 0246/1528] Fix desktop captcha check Change gnarly hardcoded protocol to detect running in the electron app Fixes https://github.com/vector-im/riot-web/issues/8236 --- src/components/views/auth/CaptchaForm.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/auth/CaptchaForm.js b/src/components/views/auth/CaptchaForm.js index ab1bfbd393..eba1682b03 100644 --- a/src/components/views/auth/CaptchaForm.js +++ b/src/components/views/auth/CaptchaForm.js @@ -62,7 +62,7 @@ module.exports = React.createClass({ console.log("Loading recaptcha script..."); window.mx_on_recaptcha_loaded = () => {this._onCaptchaLoaded();}; const protocol = global.location.protocol; - if (protocol === "file:") { + if (protocol === "vector:") { const warning = document.createElement('div'); // XXX: fix hardcoded app URL. Better solutions include: // * jumping straight to a hosted captcha page (but we don't support that yet) From 36ebd91f07352f7e533cbdfad73c256e9e1dfb58 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 23 Jan 2019 09:10:49 -0600 Subject: [PATCH 0247/1528] Move language selector to auth header --- src/components/structures/auth/ForgotPassword.js | 3 --- src/components/structures/auth/Login.js | 3 --- src/components/structures/auth/Registration.js | 3 --- src/components/views/auth/AuthHeader.js | 2 ++ 4 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/components/structures/auth/ForgotPassword.js b/src/components/structures/auth/ForgotPassword.js index 87e8c7d131..b2dc2a47eb 100644 --- a/src/components/structures/auth/ForgotPassword.js +++ b/src/components/structures/auth/ForgotPassword.js @@ -234,8 +234,6 @@ module.exports = React.createClass({ errorText =
    { err }
    ; } - const LanguageSelector = sdk.getComponent('structures.auth.LanguageSelector'); - resetPasswordJsx = (
    @@ -271,7 +269,6 @@ module.exports = React.createClass({ { _t('Create an account') } -
    ); diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js index 28bed9af05..28c4a3e960 100644 --- a/src/components/structures/auth/Login.js +++ b/src/components/structures/auth/Login.js @@ -555,8 +555,6 @@ module.exports = React.createClass({ ); } - const LanguageSelector = sdk.getComponent('structures.auth.LanguageSelector'); - return ( @@ -569,7 +567,6 @@ module.exports = React.createClass({ { _t('Create an account') } { loginAsGuestJsx } - ); diff --git a/src/components/structures/auth/Registration.js b/src/components/structures/auth/Registration.js index fe6fb078e3..fb913b22e1 100644 --- a/src/components/structures/auth/Registration.js +++ b/src/components/structures/auth/Registration.js @@ -471,8 +471,6 @@ module.exports = React.createClass({ ); } - const LanguageSelector = sdk.getComponent('structures.auth.LanguageSelector'); - return ( ); diff --git a/src/components/views/auth/AuthHeader.js b/src/components/views/auth/AuthHeader.js index c1d831a70a..cc70d126e8 100644 --- a/src/components/views/auth/AuthHeader.js +++ b/src/components/views/auth/AuthHeader.js @@ -25,10 +25,12 @@ module.exports = React.createClass({ render: function() { const AuthHeaderLogo = sdk.getComponent('auth.AuthHeaderLogo'); + const LanguageSelector = sdk.getComponent('structures.auth.LanguageSelector'); return (
    +
    ); }, From f9793fa5676001a6dea37a6f605df12f9581bc2e Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 23 Jan 2019 09:11:37 -0600 Subject: [PATCH 0248/1528] Extract language selector styles --- .../structures/auth/_LanguageSelector.scss | 27 +++++++++++++++++++ res/css/structures/auth/_Login.scss | 13 --------- .../structures/auth/LanguageSelector.js | 4 +-- 3 files changed, 29 insertions(+), 15 deletions(-) create mode 100644 res/css/structures/auth/_LanguageSelector.scss diff --git a/res/css/structures/auth/_LanguageSelector.scss b/res/css/structures/auth/_LanguageSelector.scss new file mode 100644 index 0000000000..26a8207b20 --- /dev/null +++ b/res/css/structures/auth/_LanguageSelector.scss @@ -0,0 +1,27 @@ +/* +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. +*/ + +.mx_Auth_language { + margin-left: auto; + margin-right: auto; + min-width: 60%; +} + +.mx_Auth_language_div { + display: flex; + margin-top: 12px; + margin-bottom: 12px; +} diff --git a/res/css/structures/auth/_Login.scss b/res/css/structures/auth/_Login.scss index c4eebc48a1..09af69183b 100644 --- a/res/css/structures/auth/_Login.scss +++ b/res/css/structures/auth/_Login.scss @@ -233,16 +233,3 @@ limitations under the License. margin: 3px; vertical-align: top; } - -.mx_Login_language { - margin-left: auto; - margin-right: auto; - min-width: 60%; -} - -.mx_Login_language_div { - display: flex; - margin-top: 12px; - margin-bottom: 12px; -} - diff --git a/src/components/structures/auth/LanguageSelector.js b/src/components/structures/auth/LanguageSelector.js index 965d8334d9..60b369c303 100644 --- a/src/components/structures/auth/LanguageSelector.js +++ b/src/components/structures/auth/LanguageSelector.js @@ -32,7 +32,7 @@ export default function LanguageSelector() { if (SdkConfig.get()['disable_login_language_selector']) return
    ; const LanguageDropdown = sdk.getComponent('views.elements.LanguageDropdown'); - return
    - + return
    +
    ; } From 05254f0e8284bfed770c8422c3f2e317ee88029e Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 23 Jan 2019 09:57:31 -0600 Subject: [PATCH 0249/1528] Tweak language selector to match design --- res/css/_components.scss | 1 + res/css/structures/auth/_LanguageSelector.scss | 13 ++++++------- res/css/views/auth/_AuthHeader.scss | 2 ++ res/css/views/auth/_AuthHeaderLogo.scss | 1 + res/themes/dharma/css/_dharma.scss | 1 + res/themes/light/css/_base.scss | 1 + src/components/structures/auth/LanguageSelector.js | 7 ++++--- 7 files changed, 16 insertions(+), 10 deletions(-) diff --git a/res/css/_components.scss b/res/css/_components.scss index 2617cd7c4c..133324529b 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -23,6 +23,7 @@ @import "./structures/_UploadBar.scss"; @import "./structures/_UserSettings.scss"; @import "./structures/_ViewSource.scss"; +@import "./structures/auth/_LanguageSelector.scss"; @import "./structures/auth/_Login.scss"; @import "./views/auth/_AuthBody.scss"; @import "./views/auth/_AuthButtons.scss"; diff --git a/res/css/structures/auth/_LanguageSelector.scss b/res/css/structures/auth/_LanguageSelector.scss index 26a8207b20..5193fa98ed 100644 --- a/res/css/structures/auth/_LanguageSelector.scss +++ b/res/css/structures/auth/_LanguageSelector.scss @@ -15,13 +15,12 @@ limitations under the License. */ .mx_Auth_language { - margin-left: auto; - margin-right: auto; - min-width: 60%; + width: 100%; } -.mx_Auth_language_div { - display: flex; - margin-top: 12px; - margin-bottom: 12px; +.mx_Auth_language .mx_Dropdown_input { + border: none; + font-size: 14px; + font-weight: 600; + color: $authpage-lang-color; } diff --git a/res/css/views/auth/_AuthHeader.scss b/res/css/views/auth/_AuthHeader.scss index 376864d268..e1e8802437 100644 --- a/res/css/views/auth/_AuthHeader.scss +++ b/res/css/views/auth/_AuthHeader.scss @@ -15,6 +15,8 @@ limitations under the License. */ .mx_AuthHeader { + display: flex; + flex-direction: column; width: 206px; padding: 25px 50px; box-sizing: border-box; diff --git a/res/css/views/auth/_AuthHeaderLogo.scss b/res/css/views/auth/_AuthHeaderLogo.scss index 3d8ab29325..b6f107d9c4 100644 --- a/res/css/views/auth/_AuthHeaderLogo.scss +++ b/res/css/views/auth/_AuthHeaderLogo.scss @@ -16,6 +16,7 @@ limitations under the License. .mx_AuthHeaderLogo { margin-top: 15px; + flex: 1; } .mx_AuthHeaderLogo img { diff --git a/res/themes/dharma/css/_dharma.scss b/res/themes/dharma/css/_dharma.scss index 235eb02e3c..22aa018b5e 100644 --- a/res/themes/dharma/css/_dharma.scss +++ b/res/themes/dharma/css/_dharma.scss @@ -216,6 +216,7 @@ $memberstatus-placeholder-color: $roomtile-name-color; $authpage-bg-color: #2e3649; $authpage-modal-bg-color: rgba(255, 255, 255, 0.59); $authpage-body-bg-color: #ffffff; +$authpage-lang-color: #4e5054; /*** form elements ***/ diff --git a/res/themes/light/css/_base.scss b/res/themes/light/css/_base.scss index 1522ee82a0..438ab69856 100644 --- a/res/themes/light/css/_base.scss +++ b/res/themes/light/css/_base.scss @@ -212,6 +212,7 @@ $memberstatus-placeholder-color: $roomtile-name-color; $authpage-bg-color: #2e3649; $authpage-modal-bg-color: rgba(255, 255, 255, 0.59); $authpage-body-bg-color: #ffffff; +$authpage-lang-color: #4e5054; // ***** Mixins! ***** diff --git a/src/components/structures/auth/LanguageSelector.js b/src/components/structures/auth/LanguageSelector.js index 60b369c303..d964af184c 100644 --- a/src/components/structures/auth/LanguageSelector.js +++ b/src/components/structures/auth/LanguageSelector.js @@ -32,7 +32,8 @@ export default function LanguageSelector() { if (SdkConfig.get()['disable_login_language_selector']) return
    ; const LanguageDropdown = sdk.getComponent('views.elements.LanguageDropdown'); - return
    - -
    ; + return ; } From 523d910c6618ff4225260217732cd0422efb6838 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 23 Jan 2019 10:14:45 -0600 Subject: [PATCH 0250/1528] Use new dropdown arrow for language selector --- .../structures/auth/_LanguageSelector.scss | 20 +++++++++++++++++++ res/img/feather-icons/dropdown-arrow.svg | 6 ++++++ 2 files changed, 26 insertions(+) create mode 100644 res/img/feather-icons/dropdown-arrow.svg diff --git a/res/css/structures/auth/_LanguageSelector.scss b/res/css/structures/auth/_LanguageSelector.scss index 5193fa98ed..e73dd4ac64 100644 --- a/res/css/structures/auth/_LanguageSelector.scss +++ b/res/css/structures/auth/_LanguageSelector.scss @@ -24,3 +24,23 @@ limitations under the License. font-weight: 600; color: $authpage-lang-color; } + +/* TODO: Consider using this new arrow for all dropdowns */ +.mx_Auth_language .mx_Dropdown_arrow { + width: 10px; + height: 6px; + border: none; + right: 6px; +} + +.mx_Auth_language .mx_Dropdown_arrow::before { + content: ""; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + mask: url('$(res)/img/feather-icons/dropdown-arrow.svg'); + mask-repeat: no-repeat; + background: $authpage-lang-color; +} diff --git a/res/img/feather-icons/dropdown-arrow.svg b/res/img/feather-icons/dropdown-arrow.svg new file mode 100644 index 0000000000..a1d46fa61a --- /dev/null +++ b/res/img/feather-icons/dropdown-arrow.svg @@ -0,0 +1,6 @@ + + + + + + From de81c8d768b9d5e8cdd0e68190a502b0b5e84ce1 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 22 Jan 2019 10:36:47 -0700 Subject: [PATCH 0251/1528] Template out remaining sections --- .../views/settings/tabs/GeneralSettingsTab.js | 41 +++++++++++++++++++ src/i18n/strings/en_EN.json | 13 +++--- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/components/views/settings/tabs/GeneralSettingsTab.js b/src/components/views/settings/tabs/GeneralSettingsTab.js index c8816325c0..c248ba23dd 100644 --- a/src/components/views/settings/tabs/GeneralSettingsTab.js +++ b/src/components/views/settings/tabs/GeneralSettingsTab.js @@ -73,6 +73,7 @@ export default class GeneralSettingsTab extends React.Component { disabled={!this.state.enableProfileSave}> {_t("Save")} +
    FLAIR
    ); @@ -84,11 +85,51 @@ export default class GeneralSettingsTab extends React.Component { ); } + _renderAccountSection() { + return ( +
    + {_t("Account")} +

    ACCOUNT SECTION

    +
    + ); + } + + _renderLanguageSection() { + return ( +
    + {_t("Language and region")} +

    LANGUAGE SECTION

    +
    + ); + } + + _renderThemeSection() { + return ( +
    + {_t("Theme")} +

    THEME SECTION

    +
    + ); + } + + _renderManagementSection() { + return ( +
    + {_t("Account management")} +

    MANAGEMENT SECTION

    +
    + ); + } + render() { return (
    {_t("General")}
    {this._renderProfileSection()} + {this._renderAccountSection()} + {this._renderLanguageSection()} + {this._renderThemeSection()} + {this._renderManagementSection()}
    ); } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 6bf857be07..5a85f8c4f3 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -405,6 +405,10 @@ "Display Name": "Display Name", "Save": "Save", "Profile": "Profile", + "Account": "Account", + "Language and region": "Language and region", + "Theme": "Theme", + "Account management": "Account management", "General": "General", "Cannot add any more widgets": "Cannot add any more widgets", "The maximum permitted number of widgets have already been added to this room.": "The maximum permitted number of widgets have already been added to this room.", @@ -431,6 +435,7 @@ "Encrypted by an unverified device": "Encrypted by an unverified device", "Unencrypted message": "Unencrypted message", "Please select the destination room for this message": "Please select the destination room for this message", + "Scroll to bottom of page": "Scroll to bottom of page", "Blacklisted": "Blacklisted", "Verified": "Verified", "Unverified": "Unverified", @@ -1065,6 +1070,8 @@ "Set status": "Set status", "Set a new status...": "Set a new status...", "View Community": "View Community", + "Login": "Login", + "powered by Matrix": "powered by Matrix", "Robot check is currently unavailable on desktop - please use a web browser": "Robot check is currently unavailable on desktop - please use a web browser", "This Home Server would like to make sure you are not a robot": "This Home Server would like to make sure you are not a robot", "Custom Server Options": "Custom Server Options", @@ -1082,7 +1089,6 @@ "Please enter the code it contains:": "Please enter the code it contains:", "Code": "Code", "Start authentication": "Start authentication", - "powered by Matrix": "powered by Matrix", "The email field must not be blank.": "The email field must not be blank.", "The user name field must not be blank.": "The user name field must not be blank.", "The phone number field must not be blank.": "The phone number field must not be blank.", @@ -1155,7 +1161,6 @@ "Couldn't load home page": "Couldn't load home page", "You are currently using Riot anonymously as a guest.": "You are currently using Riot anonymously as a guest.", "If you would like to create a Matrix account you can register now.": "If you would like to create a Matrix account you can register now.", - "Login": "Login", "Invalid configuration: Cannot supply a default homeserver URL and a default server name": "Invalid configuration: Cannot supply a default homeserver URL and a default server name", "Failed to reject invitation": "Failed to reject invitation", "This room is not public. You will not be able to rejoin without an invite.": "This room is not public. You will not be able to rejoin without an invite.", @@ -1197,7 +1202,6 @@ "Directory": "Directory", "Search for a room": "Search for a room", "#example": "#example", - "Scroll to bottom of page": "Scroll to bottom of page", "Message not sent due to unknown devices being present": "Message not sent due to unknown devices being present", "Show devices, send anyway or cancel.": "Show devices, send anyway or cancel.", "You can't send any messages until you review and agree to our terms and conditions.": "You can't send any messages until you review and agree to our terms and conditions.", @@ -1209,8 +1213,6 @@ "%(count)s Resend all or cancel all now. You can also select individual messages to resend or cancel.|one": "Resend message or cancel message now.", "Connectivity to the server has been lost.": "Connectivity to the server has been lost.", "Sent messages will be stored until your connection has returned.": "Sent messages will be stored until your connection has returned.", - "%(count)s new messages|other": "%(count)s new messages", - "%(count)s new messages|one": "%(count)s new message", "Active call": "Active call", "There's no one else here! Would you like to invite others or stop warning about the empty room?": "There's no one else here! Would you like to invite others or stop warning about the empty room?", "You seem to be uploading files, are you sure you want to quit?": "You seem to be uploading files, are you sure you want to quit?", @@ -1294,7 +1296,6 @@ "Email": "Email", "Add email address": "Add email address", "Display name": "Display name", - "Account": "Account", "To return to your account in future you need to set a password": "To return to your account in future you need to set a password", "Logged in as:": "Logged in as:", "Access Token:": "Access Token:", From f643d7a143ce1ba5e1a26c4666b3fe2b23fad9dc Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 21 Jan 2019 22:39:49 -0700 Subject: [PATCH 0252/1528] Finish the box for displayname/avatar changes --- .../settings/tabs/_GeneralSettingsTab.scss | 70 +++++++++++++- res/img/feather-icons/upload.svg | 5 + res/themes/dharma/css/_dharma.scss | 5 + res/themes/light/css/_base.scss | 5 + .../views/settings/tabs/GeneralSettingsTab.js | 92 +++++++++++++++++-- src/i18n/strings/en_EN.json | 3 + 6 files changed, 170 insertions(+), 10 deletions(-) create mode 100644 res/img/feather-icons/upload.svg diff --git a/res/css/views/settings/tabs/_GeneralSettingsTab.scss b/res/css/views/settings/tabs/_GeneralSettingsTab.scss index 8bc3de8689..caacd0d3c7 100644 --- a/res/css/views/settings/tabs/_GeneralSettingsTab.scss +++ b/res/css/views/settings/tabs/_GeneralSettingsTab.scss @@ -14,12 +14,78 @@ width: 88px; height: 88px; margin-left: 13px; + position: relative; + cursor: pointer; } -.mx_GeneralSettingsTab_profileAvatar div { +.mx_GeneralSettingsTab_profileAvatar > * { display: block; width: 88px; height: 88px; border-radius: 4px; - background-color: #ccc; +} + +.mx_GeneralSettingsTab_profileAvatar .mx_GeneralSettingsTab_profileAvatarPlaceholder { + background-color: $settings-profile-placeholder-bg-color; +} + +.mx_GeneralSettingsTab_profileAvatarOverlay { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + display: none; + text-align: center; + vertical-align: middle; + font-size: 10px; +} + +.mx_GeneralSettingsTab_profileAvatar:hover .mx_GeneralSettingsTab_profileAvatarOverlay { + display: inline-block; + opacity: 0.5 !important; + color: $settings-profile-overlay-fg-color !important; + background-color: $settings-profile-overlay-bg-color !important; +} + +.mx_GeneralSettingsTab_profileAvatarOverlay_show { + display: inline-block; + opacity: 1; + color: $settings-profile-overlay-placeholder-fg-color; + background-color: $settings-profile-overlay-placeholder-bg-color; +} + +.mx_GeneralSettingsTab_profileAvatarOverlayText { + display: block; + margin-top: 17px; + margin-bottom: 8px; +} + +.mx_GeneralSettingsTab_profileAvatarOverlayImgContainer { + position: relative; + width: 14px; + height: 14px; + margin: auto; +} + +.mx_GeneralSettingsTab_profileAvatarOverlayImg:before { + background-color: $settings-profile-overlay-placeholder-fg-color; + mask: url("$(res)/img/feather-icons/upload.svg"); + mask-repeat: no-repeat; + mask-size: 14px; + mask-position: center; + content: ''; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; +} + +.mx_GeneralSettingsTab_profileAvatar:hover .mx_GeneralSettingsTab_profileAvatarOverlayImg:before { + background-color: $settings-profile-overlay-fg-color !important; +} + +.mx_GeneralSettingsTab_profileAvatarUpload { + display: none; } \ No newline at end of file diff --git a/res/img/feather-icons/upload.svg b/res/img/feather-icons/upload.svg new file mode 100644 index 0000000000..8ec5d95c2c --- /dev/null +++ b/res/img/feather-icons/upload.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/res/themes/dharma/css/_dharma.scss b/res/themes/dharma/css/_dharma.scss index 235eb02e3c..ed5620d30f 100644 --- a/res/themes/dharma/css/_dharma.scss +++ b/res/themes/dharma/css/_dharma.scss @@ -120,6 +120,11 @@ $blockquote-bar-color: #ddd; $blockquote-fg-color: #777; $settings-grey-fg-color: #a2a2a2; +$settings-profile-placeholder-bg-color: #e7e7e7; +$settings-profile-overlay-bg-color: #000; +$settings-profile-overlay-placeholder-bg-color: transparent; +$settings-profile-overlay-fg-color: #fff; +$settings-profile-overlay-placeholder-fg-color: #454545; $voip-decline-color: #f48080; $voip-accept-color: #80f480; diff --git a/res/themes/light/css/_base.scss b/res/themes/light/css/_base.scss index 1522ee82a0..d7b135a74e 100644 --- a/res/themes/light/css/_base.scss +++ b/res/themes/light/css/_base.scss @@ -113,6 +113,11 @@ $blockquote-bar-color: #ddd; $blockquote-fg-color: #777; $settings-grey-fg-color: #a2a2a2; +$settings-profile-placeholder-bg-color: #e7e7e7; +$settings-profile-overlay-bg-color: #000; +$settings-profile-overlay-placeholder-bg-color: transparent; +$settings-profile-overlay-fg-color: #fff; +$settings-profile-overlay-placeholder-fg-color: #454545; $voip-decline-color: #f48080; $voip-accept-color: #80f480; diff --git a/src/components/views/settings/tabs/GeneralSettingsTab.js b/src/components/views/settings/tabs/GeneralSettingsTab.js index c248ba23dd..993061eaa0 100644 --- a/src/components/views/settings/tabs/GeneralSettingsTab.js +++ b/src/components/views/settings/tabs/GeneralSettingsTab.js @@ -19,19 +19,34 @@ import {_t} from "../../../../languageHandler"; import MatrixClientPeg from "../../../../MatrixClientPeg"; import Field from "../../elements/Field"; import AccessibleButton from "../../elements/AccessibleButton"; +import classNames from 'classnames'; export default class GeneralSettingsTab extends React.Component { constructor() { super(); const client = MatrixClientPeg.get(); + const user = client.getUser(client.getUserId()); + let avatarUrl = user.avatarUrl; + if (avatarUrl) avatarUrl = client.mxcUrlToHttp(avatarUrl, 96, 96, 'crop', false); this.state = { - userId: client.getUserId(), - displayName: client.getUser(client.getUserId()).displayName, + userId: user.userId, + originalDisplayName: user.displayName, + displayName: user.displayName, + originalAvatarUrl: avatarUrl, + avatarUrl: avatarUrl, + avatarFile: null, enableProfileSave: false, }; } + _uploadAvatar = (e) => { + e.stopPropagation(); + e.preventDefault(); + + this.refs.avatarUpload.click(); + }; + _saveProfile = async (e) => { e.stopPropagation(); e.preventDefault(); @@ -39,12 +54,26 @@ export default class GeneralSettingsTab extends React.Component { if (!this.state.enableProfileSave) return; this.setState({enableProfileSave: false}); + const client = MatrixClientPeg.get(); + const newState = {}; + // TODO: What do we do about errors? - await MatrixClientPeg.get().setDisplayName(this.state.displayName); - // TODO: Support avatars + if (this.state.originalDisplayName !== this.state.displayName) { + await client.setDisplayName(this.state.displayName); + newState.originalDisplayName = this.state.displayName; + } - this.setState({enableProfileSave: true}); + if (this.state.avatarFile) { + const uri = await client.uploadContent(this.state.avatarFile); + await client.setAvatarUrl(uri); + newState.avatarUrl = client.mxcUrlToHttp(uri, 96, 96, 'crop', false); + newState.originalAvatarUrl = newState.avatarUrl; + newState.avatarFile = null; + } + + newState.enableProfileSave = true; + this.setState(newState); }; _onDisplayNameChanged = (e) => { @@ -54,19 +83,66 @@ export default class GeneralSettingsTab extends React.Component { }); }; + _onAvatarChanged = (e) => { + if (!e.target.files || !e.target.files.length) { + this.setState({ + avatarUrl: this.state.originalAvatarUrl, + avatarFile: null, + enableProfileSave: false, + }); + return; + } + + const file = e.target.files[0]; + const reader = new FileReader(); + reader.onload = (ev) => { + this.setState({ + avatarUrl: ev.target.result, + avatarFile: file, + enableProfileSave: true, + }); + }; + reader.readAsDataURL(file); + }; + _renderProfileSection() { - // TODO: Ditch avatar placeholder and use the real thing + // TODO: Why is rendering a box with an overlay so complicated? Can the DOM be reduced? + + let showOverlayAnyways = true; + let avatarElement =
    ; + if (this.state.avatarUrl) { + showOverlayAnyways = false; + avatarElement = {_t("Profile + } + + const avatarOverlayClasses = classNames({ + "mx_GeneralSettingsTab_profileAvatarOverlay": true, + "mx_GeneralSettingsTab_profileAvatarOverlay_show": showOverlayAnyways, + }); + let avatarHoverElement = ( +
    + {_t("Upload profile picture")} +
    +
    +
    +
    + ); + const form = (
    +

    {this.state.userId}

    -
    + {avatarElement} + {avatarHoverElement}
    Date: Mon, 21 Jan 2019 23:08:01 -0700 Subject: [PATCH 0253/1528] Bring flair into the new settings Makes the flair options in old settings look broken (cosmetic issues), but it's fine because we're ripping that out in due time. --- res/css/views/groups/_GroupUserSettings.scss | 1 - res/css/views/settings/tabs/_SettingsTab.scss | 11 +++++++--- res/themes/dharma/css/_dharma.scss | 1 + res/themes/light/css/_base.scss | 1 + .../views/groups/GroupUserSettings.js | 11 ++++------ .../views/settings/tabs/GeneralSettingsTab.js | 21 ++++++++++++++++++- src/i18n/strings/en_EN.json | 3 +-- 7 files changed, 35 insertions(+), 14 deletions(-) diff --git a/res/css/views/groups/_GroupUserSettings.scss b/res/css/views/groups/_GroupUserSettings.scss index 0c909b7cf7..b207aa2958 100644 --- a/res/css/views/groups/_GroupUserSettings.scss +++ b/res/css/views/groups/_GroupUserSettings.scss @@ -18,6 +18,5 @@ limitations under the License. height: 200px; border: 1px solid $primary-hairline-color; border-radius: 3px; - margin-right: 32px; overflow: hidden; } diff --git a/res/css/views/settings/tabs/_SettingsTab.scss b/res/css/views/settings/tabs/_SettingsTab.scss index 0753df56af..c86fb1f41e 100644 --- a/res/css/views/settings/tabs/_SettingsTab.scss +++ b/res/css/views/settings/tabs/_SettingsTab.scss @@ -10,8 +10,13 @@ font-family: $font-family-semibold; color: $primary-fg-color; margin-bottom: 10px; -} - -.mx_SettingsTab_section { margin-top: 10px; } + +.mx_SettingsTab_subsectionText { + color: $settings-subsection-fg-color; + font-size: 12px; + padding-bottom: 12px; + margin: 0; + display: block; +} diff --git a/res/themes/dharma/css/_dharma.scss b/res/themes/dharma/css/_dharma.scss index ed5620d30f..f54c058220 100644 --- a/res/themes/dharma/css/_dharma.scss +++ b/res/themes/dharma/css/_dharma.scss @@ -125,6 +125,7 @@ $settings-profile-overlay-bg-color: #000; $settings-profile-overlay-placeholder-bg-color: transparent; $settings-profile-overlay-fg-color: #fff; $settings-profile-overlay-placeholder-fg-color: #454545; +$settings-subsection-fg-color: #61708b; $voip-decline-color: #f48080; $voip-accept-color: #80f480; diff --git a/res/themes/light/css/_base.scss b/res/themes/light/css/_base.scss index d7b135a74e..fce4e93112 100644 --- a/res/themes/light/css/_base.scss +++ b/res/themes/light/css/_base.scss @@ -118,6 +118,7 @@ $settings-profile-overlay-bg-color: #000; $settings-profile-overlay-placeholder-bg-color: transparent; $settings-profile-overlay-fg-color: #fff; $settings-profile-overlay-placeholder-fg-color: #454545; +$settings-subsection-fg-color: #61708b; $voip-decline-color: #f48080; $voip-accept-color: #80f480; diff --git a/src/components/views/groups/GroupUserSettings.js b/src/components/views/groups/GroupUserSettings.js index 0405d411d2..a349a34caf 100644 --- a/src/components/views/groups/GroupUserSettings.js +++ b/src/components/views/groups/GroupUserSettings.js @@ -68,15 +68,12 @@ export default React.createClass({ text = _t("You're not currently a member of any communities."); } - return
    -

    { _t('Flair') }

    -
    -

    - { text } -

    + return ( +
    +

    { text }

    { scrollbox }
    -
    ; + ); }, render() { diff --git a/src/components/views/settings/tabs/GeneralSettingsTab.js b/src/components/views/settings/tabs/GeneralSettingsTab.js index 993061eaa0..f57609625f 100644 --- a/src/components/views/settings/tabs/GeneralSettingsTab.js +++ b/src/components/views/settings/tabs/GeneralSettingsTab.js @@ -20,8 +20,16 @@ import MatrixClientPeg from "../../../../MatrixClientPeg"; import Field from "../../elements/Field"; import AccessibleButton from "../../elements/AccessibleButton"; import classNames from 'classnames'; +import GroupUserSettings from "../../groups/GroupUserSettings"; +import PropTypes from "prop-types"; +import {MatrixClient} from "matrix-js-sdk"; +import { DragDropContext } from 'react-beautiful-dnd'; export default class GeneralSettingsTab extends React.Component { + static childContextTypes = { + matrixClient: PropTypes.instanceOf(MatrixClient), + }; + constructor() { super(); @@ -40,6 +48,12 @@ export default class GeneralSettingsTab extends React.Component { }; } + getChildContext() { + return { + matrixClient: MatrixClientPeg.get(), + }; + } + _uploadAvatar = (e) => { e.stopPropagation(); e.preventDefault(); @@ -149,14 +163,19 @@ export default class GeneralSettingsTab extends React.Component { disabled={!this.state.enableProfileSave}> {_t("Save")} -
    FLAIR
    ); + // HACK/TODO: Using DragDropContext feels wrong, but we need it. return (
    {_t("Profile")} {form} + + {_t("Flair")} + + +
    ); } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index c61c806830..42046cba19 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -404,10 +404,10 @@ "Noisy": "Noisy", "Profile picture": "Profile picture", "Upload profile picture": "Upload profile picture", - "Upload": "Upload", "Display Name": "Display Name", "Save": "Save", "Profile": "Profile", + "Flair": "Flair", "Account": "Account", "Language and region": "Language and region", "Theme": "Theme", @@ -680,7 +680,6 @@ "New address (e.g. #foo:%(localDomain)s)": "New address (e.g. #foo:%(localDomain)s)", "Invalid community ID": "Invalid community ID", "'%(groupId)s' is not a valid community ID": "'%(groupId)s' is not a valid community ID", - "Flair": "Flair", "Showing flair for these communities:": "Showing flair for these communities:", "This room is not showing flair for any communities": "This room is not showing flair for any communities", "New community ID (e.g. +foo:%(localDomain)s)": "New community ID (e.g. +foo:%(localDomain)s)", From 19de6694ca642f6d066c077ca5df3744585619bd Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 22 Jan 2019 13:09:40 -0700 Subject: [PATCH 0254/1528] Bring in the change password section This also changes the layout slightly in the user settings, but nothing detrimental. --- .../settings/tabs/_GeneralSettingsTab.scss | 18 +++++++ src/components/structures/UserSettings.js | 4 +- .../views/dialogs/SetPasswordDialog.js | 5 +- src/components/views/elements/Field.js | 5 ++ .../views/settings/ChangePassword.js | 39 +++++--------- .../views/settings/tabs/GeneralSettingsTab.js | 52 ++++++++++++++++++- src/i18n/strings/en_EN.json | 7 +-- 7 files changed, 94 insertions(+), 36 deletions(-) diff --git a/res/css/views/settings/tabs/_GeneralSettingsTab.scss b/res/css/views/settings/tabs/_GeneralSettingsTab.scss index caacd0d3c7..097d81dab4 100644 --- a/res/css/views/settings/tabs/_GeneralSettingsTab.scss +++ b/res/css/views/settings/tabs/_GeneralSettingsTab.scss @@ -88,4 +88,22 @@ .mx_GeneralSettingsTab_profileAvatarUpload { display: none; +} + +.mx_GeneralSettingsTab_changePassword { + display: block; +} + +.mx_GeneralSettingsTab_changePassword .mx_Field { + display: block; + margin-right: 100px; // Align with the other fields on the page +} + +.mx_GeneralSettingsTab_changePassword .mx_Field input { + display: block; + width: calc(100% - 20px); // subtract 10px padding on left and right +} + +.mx_GeneralSettingsTab_changePassword .mx_Field:first-child { + margin-top: 0; } \ No newline at end of file diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index 65e1897137..f8d9e2dd84 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -1268,9 +1268,7 @@ module.exports = React.createClass({ ); diff --git a/src/components/views/dialogs/SetPasswordDialog.js b/src/components/views/dialogs/SetPasswordDialog.js index 42c35ad187..fe3a2216f4 100644 --- a/src/components/views/dialogs/SetPasswordDialog.js +++ b/src/components/views/dialogs/SetPasswordDialog.js @@ -116,9 +116,8 @@ export default React.createClass({