From e53801957c30d286736aeb0ab18489adf5649b22 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 19 Feb 2021 13:36:39 +0000 Subject: [PATCH 01/95] Add subscribeToChanges/unsubscribeToChanges to VectorPreferences --- .../app/features/settings/VectorPreferences.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt index d3ef36a80b..a0fe525d3e 100755 --- a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt @@ -239,6 +239,20 @@ class VectorPreferences @Inject constructor(private val context: Context) { } private val defaultPrefs = DefaultSharedPreferences.getInstance(context) + + /** + * Allow subscribing and unsubscribing to configuration changes. This is + * particularly useful when you need to be notified of a configuration change + * in a background service, e.g. for the P2P demos. + */ + + public fun subscribeToChanges(listener: SharedPreferences.OnSharedPreferenceChangeListener) { + defaultPrefs.registerOnSharedPreferenceChangeListener(listener) + } + + public fun unsubscribeToChanges(listener: SharedPreferences.OnSharedPreferenceChangeListener) { + defaultPrefs.unregisterOnSharedPreferenceChangeListener(listener) + } /** * Clear the preferences. From adc461d2f3c28bf95957caba357995561b6e30b8 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 19 Feb 2021 14:23:38 +0000 Subject: [PATCH 02/95] Update VectorPreferences.kt --- .../im/vector/app/features/settings/VectorPreferences.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt index a0fe525d3e..fbd53f09c5 100755 --- a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt @@ -16,6 +16,7 @@ package im.vector.app.features.settings import android.content.Context +import android.content.SharedPreferences import android.media.RingtoneManager import android.net.Uri import android.provider.MediaStore @@ -246,11 +247,11 @@ class VectorPreferences @Inject constructor(private val context: Context) { * in a background service, e.g. for the P2P demos. */ - public fun subscribeToChanges(listener: SharedPreferences.OnSharedPreferenceChangeListener) { + fun subscribeToChanges(listener: SharedPreferences.OnSharedPreferenceChangeListener) { defaultPrefs.registerOnSharedPreferenceChangeListener(listener) } - public fun unsubscribeToChanges(listener: SharedPreferences.OnSharedPreferenceChangeListener) { + fun unsubscribeToChanges(listener: SharedPreferences.OnSharedPreferenceChangeListener) { defaultPrefs.unregisterOnSharedPreferenceChangeListener(listener) } From 2b403371a3370b073908581ebb09d9528c045722 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 19 Feb 2021 15:17:42 +0000 Subject: [PATCH 03/95] Update VectorPreferences.kt --- .../java/im/vector/app/features/settings/VectorPreferences.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt index fbd53f09c5..eba7403a05 100755 --- a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt @@ -246,11 +246,9 @@ class VectorPreferences @Inject constructor(private val context: Context) { * particularly useful when you need to be notified of a configuration change * in a background service, e.g. for the P2P demos. */ - fun subscribeToChanges(listener: SharedPreferences.OnSharedPreferenceChangeListener) { defaultPrefs.registerOnSharedPreferenceChangeListener(listener) } - fun unsubscribeToChanges(listener: SharedPreferences.OnSharedPreferenceChangeListener) { defaultPrefs.unregisterOnSharedPreferenceChangeListener(listener) } From f6ac57ec9359229e452f7f87252221dc6a549114 Mon Sep 17 00:00:00 2001 From: lvre <7uu3qrbvm@relay.firefox.com> Date: Thu, 17 Jun 2021 21:11:06 +0000 Subject: [PATCH 04/95] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2490 of 2490 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/pt_BR/ --- vector/src/main/res/values-pt-rBR/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vector/src/main/res/values-pt-rBR/strings.xml b/vector/src/main/res/values-pt-rBR/strings.xml index db7f940e38..3d5fada807 100644 --- a/vector/src/main/res/values-pt-rBR/strings.xml +++ b/vector/src/main/res/values-pt-rBR/strings.xml @@ -2876,4 +2876,9 @@ Enviar vídeo com o tamanho original Enviar vídeos com o tamanho original + No momento pessoas podem não ser capaz de se juntar a quaisquer salas privadas que você fizer. +\n +\nNós vamos melhorar isto como parte da beta, mas só queríamos deixar você saber. + Espaços de colegas de trabalho não estão bem prontos mas você ainda pode dar-lhes uma tentativa + Continuar Mesmo Assim \ No newline at end of file From 51119ceec4b990caf8d812a2f1e1f4edb3903f54 Mon Sep 17 00:00:00 2001 From: lvre <7uu3qrbvm@relay.firefox.com> Date: Thu, 17 Jun 2021 21:36:51 +0000 Subject: [PATCH 05/95] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2490 of 2490 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/pt_BR/ --- vector/src/main/res/values-pt-rBR/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/res/values-pt-rBR/strings.xml b/vector/src/main/res/values-pt-rBR/strings.xml index 3d5fada807..6a86e58d11 100644 --- a/vector/src/main/res/values-pt-rBR/strings.xml +++ b/vector/src/main/res/values-pt-rBR/strings.xml @@ -429,7 +429,7 @@ Falha para verificar endereço de email: assegure-se que clicou no link no email Sua senha tem sido resettada. \n -\nVocê tem sido feito logout de todas as sessões e não vai mais receber notificações push. Para reativar notificações, faça re-login em cada dispositivo. +\nVocê tem sido feito logout de todas as sessões e não vai mais receber notificações push. Para re-ativar notificações, re-faça login em cada dispositivo. URL deve começar com http[s]:// Incapaz de fazer login: Erro de rede From 861d652d88a3331ba2093dd98fa85486289a85f0 Mon Sep 17 00:00:00 2001 From: lvre <7uu3qrbvm@relay.firefox.com> Date: Thu, 17 Jun 2021 21:45:05 +0000 Subject: [PATCH 06/95] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2490 of 2490 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/pt_BR/ --- vector/src/main/res/values-pt-rBR/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/res/values-pt-rBR/strings.xml b/vector/src/main/res/values-pt-rBR/strings.xml index 6a86e58d11..0f684d145c 100644 --- a/vector/src/main/res/values-pt-rBR/strings.xml +++ b/vector/src/main/res/values-pt-rBR/strings.xml @@ -1995,7 +1995,7 @@ Eles correspondem Eles não correspondem Verifique esta(e) usuária(o) ao confirmar que os seguintes emoji únicos aparecem na tela dela(e), na mesma ordem. - Para máxima segurança, use um outro meio de comunicação confiado ou faça isto em pessoa. + Para segurança ótima, use um outro meio de comunicação confiado ou faça isto em pessoa. Procure pelo escudo verde para assegurar que um/uma usuário(a) é confiado. Confie em todos(as) os/as usuários(as) numa sala para assegurar que a sala é segura. Não seguro Um dos seguintes pode estar comprometido: From 1ea48f89b4bf44bf5e6492de18f7d15b66b6fb43 Mon Sep 17 00:00:00 2001 From: lvre <7uu3qrbvm@relay.firefox.com> Date: Thu, 17 Jun 2021 21:56:35 +0000 Subject: [PATCH 07/95] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2490 of 2490 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/pt_BR/ --- vector/src/main/res/values-pt-rBR/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/res/values-pt-rBR/strings.xml b/vector/src/main/res/values-pt-rBR/strings.xml index 0f684d145c..458d8243b7 100644 --- a/vector/src/main/res/values-pt-rBR/strings.xml +++ b/vector/src/main/res/values-pt-rBR/strings.xml @@ -1358,7 +1358,7 @@ Desbanir usuária(o) Desbanir usuária(o) vai permitir-lhe se juntar à sala de novo. Confirme sua senha - Você não pode fazer isto de ${app_name} celular + Você não pode fazer isto desde ${app_name} mobile Autenticação é requerida O app não precisa de se conectar ao ServidorCasa no background, isto deveria reduzir uso de bateria Modo Sinc no Background From de0b745eb980883002430af04cfa2e2e412ebba3 Mon Sep 17 00:00:00 2001 From: lvre <7uu3qrbvm@relay.firefox.com> Date: Thu, 17 Jun 2021 22:10:33 +0000 Subject: [PATCH 08/95] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2490 of 2490 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/pt_BR/ --- vector/src/main/res/values-pt-rBR/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/res/values-pt-rBR/strings.xml b/vector/src/main/res/values-pt-rBR/strings.xml index 458d8243b7..cf45cbf5ee 100644 --- a/vector/src/main/res/values-pt-rBR/strings.xml +++ b/vector/src/main/res/values-pt-rBR/strings.xml @@ -1602,7 +1602,7 @@ Esperando por parceira(o) confirmar… Verificada! Você tem confirmado esta sessão com sucesso. - Mensagens seguras com esta(e) usuária(o) estão encriptadas ponta-a-ponta e não são capazes de ser lidas por terceiros. + Mensagens seguras com esta(e) usuária(o) são encriptadas ponta-a-ponta e não são capazes de ser lidas por terceiros. Entendido Nada aparecendo\? Não todos os clientes suportam verificação interativa ainda. Use verificação legado. Usar verificação legado. From e6e7f82eb625b54f62fd07bcd02f40230614197a Mon Sep 17 00:00:00 2001 From: lvre <7uu3qrbvm@relay.firefox.com> Date: Thu, 17 Jun 2021 22:36:15 +0000 Subject: [PATCH 09/95] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2490 of 2490 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/pt_BR/ --- vector/src/main/res/values-pt-rBR/strings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vector/src/main/res/values-pt-rBR/strings.xml b/vector/src/main/res/values-pt-rBR/strings.xml index cf45cbf5ee..ce235e3b8a 100644 --- a/vector/src/main/res/values-pt-rBR/strings.xml +++ b/vector/src/main/res/values-pt-rBR/strings.xml @@ -1943,7 +1943,7 @@ Este não é um identificador de usuária(o) válido. Formato esperado: \'@usuarix:servidorcasa.org\' Incapaz de encontrar um servidorcasa válido. Por favor cheque seu identificador Vista por - Você fez signout + Você está com signout feito Pode ser devido a várias razões: \n \n• Você tem mudado sua senha numa outra sessão. @@ -1952,7 +1952,7 @@ \n \n• O/a administrador(a) de seu servidor tem invalidado seu acesso por razão de segurança. Fazer signin de novo - Você fez signout + Você está com signout feito Fazer signin A/o admin de seu servidorcasa (%1$s) fez seu signout de sua conta %2$s (%3$s). Faça signin para recuperar chaves de encriptação armazenadas exclusivamente neste dispositivo. Você precisa delas para ler todas suas mensagens seguras em qualquer dispositivo. @@ -2361,7 +2361,7 @@ Você não pode acessar esta mensagem porque o/a enviador(a) propositalmente não enviou as chaves Esperando por histórico de encriptação Riot agora é Element! - Nós estamos animados em anunciar que nós mudamos de nome! Seu app está atualizado e o signin está feito a sua conta. + Nós estamos animados em anunciar que nós mudamos de nome! Seu app está atualizado e você está com signin feito a sua conta. ENTENDI SABER MAIS Salvar chave de recuperação em From 7a12d29d3977e04fcc96288652f7bc61fbe672ef Mon Sep 17 00:00:00 2001 From: lvre <7uu3qrbvm@relay.firefox.com> Date: Thu, 17 Jun 2021 22:37:07 +0000 Subject: [PATCH 10/95] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2490 of 2490 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/pt_BR/ --- vector/src/main/res/values-pt-rBR/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/res/values-pt-rBR/strings.xml b/vector/src/main/res/values-pt-rBR/strings.xml index ce235e3b8a..617ceb8fb8 100644 --- a/vector/src/main/res/values-pt-rBR/strings.xml +++ b/vector/src/main/res/values-pt-rBR/strings.xml @@ -2361,7 +2361,7 @@ Você não pode acessar esta mensagem porque o/a enviador(a) propositalmente não enviou as chaves Esperando por histórico de encriptação Riot agora é Element! - Nós estamos animados em anunciar que nós mudamos de nome! Seu app está atualizado e você está com signin feito a sua conta. + Nós estamos animados em anunciar que nós temos mudado de nome! Seu app está atualizado e você está com signin feito a sua conta. ENTENDI SABER MAIS Salvar chave de recuperação em From e826900bd3c3d0de122295551907d72581594b60 Mon Sep 17 00:00:00 2001 From: lvre <7uu3qrbvm@relay.firefox.com> Date: Thu, 17 Jun 2021 22:38:38 +0000 Subject: [PATCH 11/95] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2490 of 2490 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/pt_BR/ --- vector/src/main/res/values-pt-rBR/strings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vector/src/main/res/values-pt-rBR/strings.xml b/vector/src/main/res/values-pt-rBR/strings.xml index 617ceb8fb8..e85ef28212 100644 --- a/vector/src/main/res/values-pt-rBR/strings.xml +++ b/vector/src/main/res/values-pt-rBR/strings.xml @@ -1637,7 +1637,7 @@ Convidada(o) por %s Você está em dia! Você não tem mais nenhuma mensagem não-lida - Boas-vindas! + Boas vindas a casa! Fique em dia com suas mensagens não-lidas aqui Conversas Suas conversas de mensagem direta vai ser exibidas aqui. Toque no + à direita fundo para começar algumas. @@ -2790,7 +2790,7 @@ Convidar por nome de usuária(o) Convidar por email Convidar pessoas - Boas-vindas a %1$s, %2$s. + Boas vindas a %1$s, %2$s. Você está convidada(o) Aviso requer suporte de servidor e versão de sala experimental %s convida você @@ -2810,7 +2810,7 @@ Procurando por alguém que não está em %s\? Espaço Experimental - Sala Restringida. Espaços são uma nova forma de agrupar salas e pessoas. - Boas-vindas a Espaços! + Boas vindas a Espaços! Adicionar salas Adicionar salas e espaços existentes Você é admin deste espaço, assegure-se que você tem transferido direito de admin a um outro membro antes de sair. From 08af370600090cd5c3663df676eebf96b15133bb Mon Sep 17 00:00:00 2001 From: lvre <7uu3qrbvm@relay.firefox.com> Date: Thu, 17 Jun 2021 22:50:45 +0000 Subject: [PATCH 12/95] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2490 of 2490 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/pt_BR/ --- vector/src/main/res/values-pt-rBR/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/res/values-pt-rBR/strings.xml b/vector/src/main/res/values-pt-rBR/strings.xml index e85ef28212..191b9846ad 100644 --- a/vector/src/main/res/values-pt-rBR/strings.xml +++ b/vector/src/main/res/values-pt-rBR/strings.xml @@ -2510,7 +2510,7 @@ Rotar e recortar Configurações de sala Tópico - Tópico da sala (opcional) + Tópico de sala (opcional) Nome de sala Enviar histórico de requisições de compartilhamento de chaves Mais nenhum resultado From a1bfe099adb9ffb702113e60254ec27d8cc1f2e6 Mon Sep 17 00:00:00 2001 From: lvre <7uu3qrbvm@relay.firefox.com> Date: Thu, 17 Jun 2021 22:56:50 +0000 Subject: [PATCH 13/95] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2490 of 2490 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/pt_BR/ --- vector/src/main/res/values-pt-rBR/strings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vector/src/main/res/values-pt-rBR/strings.xml b/vector/src/main/res/values-pt-rBR/strings.xml index 191b9846ad..f5a9635a48 100644 --- a/vector/src/main/res/values-pt-rBR/strings.xml +++ b/vector/src/main/res/values-pt-rBR/strings.xml @@ -1077,7 +1077,7 @@ Privacidade de Notificação ${app_name} pode rodar no background para gerenciar suas notificações seguramente e privadamente. Isto pode afetar uso de bateria. Conceder permissão - Escolha um outra opção + Escolher uma outra opção Enviar dados de analítica ${app_name} coleta analítica anônima para nos permitir melhorar o aplicativo. Por favor ative analítica para nos ajudar a melhorar ${app_name}. @@ -1846,7 +1846,7 @@ Junte-se a milhões de graça no maior servidor público Hospedagem premium para organizações Saiba mais - Outros + Outro Configurações personalizadas & avançadas Continuar Conectar-se a %1$s @@ -2010,7 +2010,7 @@ Arquivo Sticker Esperando… - %s cancelado + %s cancelou Você cancelou %s aceitou Você aceitou From d4c8c645d1fa1148645b14be677252190317f69e Mon Sep 17 00:00:00 2001 From: lvre <7uu3qrbvm@relay.firefox.com> Date: Thu, 17 Jun 2021 23:04:15 +0000 Subject: [PATCH 14/95] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2490 of 2490 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/pt_BR/ --- vector/src/main/res/values-pt-rBR/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/res/values-pt-rBR/strings.xml b/vector/src/main/res/values-pt-rBR/strings.xml index f5a9635a48..eaec973570 100644 --- a/vector/src/main/res/values-pt-rBR/strings.xml +++ b/vector/src/main/res/values-pt-rBR/strings.xml @@ -2519,7 +2519,7 @@ Mostrar avançadas Esconder avançadas Link Matrix - %s para deixar pessoas sabendo do que esta sala se trata. + %s para deixar pessoas saberem do que esta sala se trata. Por favor proveja um endereço de sala Recente QR code não scannado! From e0a5241cafe9c5a99d2dea1646519fe8fc2dbf1b Mon Sep 17 00:00:00 2001 From: lvre <7uu3qrbvm@relay.firefox.com> Date: Sun, 20 Jun 2021 00:02:59 +0000 Subject: [PATCH 15/95] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (2490 of 2490 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/pt_BR/ --- vector/src/main/res/values-pt-rBR/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/res/values-pt-rBR/strings.xml b/vector/src/main/res/values-pt-rBR/strings.xml index eaec973570..7fe24cbb4b 100644 --- a/vector/src/main/res/values-pt-rBR/strings.xml +++ b/vector/src/main/res/values-pt-rBR/strings.xml @@ -359,7 +359,7 @@ Enviar crash logs Enviar screenshot Reportar bug - Por favor descreva o bug. O que você fez\? O que você esperava que acontecese\? O que aconteceu na verdade\? + Por favor descreva o bug. O que você fez\? O que você esperava que acontecesse\? O que na verdade aconteceu\? Descreva seu problema aqui A fim de diagnosticar problemas, logs deste cliente vão ser enviados com este reporte de bug. Este reporte de bug, incluindo os logs e o screenshot, não será visível publicamente. Se você prefere somente enviar o texto acima, por favor desmarque: Você parece estar agitando o telefone em frustração. Você gostaria de abrir a tela de reporte de bug\? From a64c7e5df2bf11d53d2ad42ceb710dc442e0e154 Mon Sep 17 00:00:00 2001 From: waclaw66 Date: Fri, 18 Jun 2021 05:09:31 +0000 Subject: [PATCH 16/95] Translated using Weblate (Czech) Currently translated at 100.0% (2490 of 2490 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/cs/ --- vector/src/main/res/values-cs/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vector/src/main/res/values-cs/strings.xml b/vector/src/main/res/values-cs/strings.xml index 7523be029e..0b37b4e046 100644 --- a/vector/src/main/res/values-cs/strings.xml +++ b/vector/src/main/res/values-cs/strings.xml @@ -2859,4 +2859,9 @@ Zadejte název nového serveru, který chcete prozkoumat. Přidat nový server Váš server + Přesto pokračovat + V současné době se lidé nemohou připojit k soukromým místnostem, které jste vytvořili. +\n +\nV rámci beta verze to zlepšíme, ale jen jsme vás chtěli informovat. + Prostory pro spolupracovníky nejsou ještě zcela připravené, ale přesto je můžete vyzkoušet \ No newline at end of file From b0c23426df27b23a998c9c0d09d885ab38908048 Mon Sep 17 00:00:00 2001 From: libexus Date: Fri, 18 Jun 2021 16:09:31 +0000 Subject: [PATCH 17/95] Translated using Weblate (German) Currently translated at 99.7% (2485 of 2490 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/de/ --- vector/src/main/res/values-de/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vector/src/main/res/values-de/strings.xml b/vector/src/main/res/values-de/strings.xml index fa6d20d007..faff212373 100644 --- a/vector/src/main/res/values-de/strings.xml +++ b/vector/src/main/res/values-de/strings.xml @@ -2866,4 +2866,9 @@ Spaces Feedback Dieser Server ist schon in der Liste vorhanden Server oder Raumliste kann nicht gefunden werden + Momentan kann es sein, dass einige Leute deinen privaten Räumen nicht beitreten können. +\n +\nDies werden wir demnächst als Teil der Beta verbessern, wir wollten aber sicherstellen, dass du bescheid weißt. + Team-Spaces sind noch nicht fertig entwickelt, du kannst sie aber schon testen + Trotzdem fortfahren \ No newline at end of file From 5555b0dbb7247ce828b3401a1105f18389447d49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20J=C3=B5er=C3=BC=C3=BCt?= Date: Thu, 17 Jun 2021 18:47:43 +0000 Subject: [PATCH 18/95] Translated using Weblate (Estonian) Currently translated at 100.0% (2490 of 2490 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/et/ --- vector/src/main/res/values-et/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vector/src/main/res/values-et/strings.xml b/vector/src/main/res/values-et/strings.xml index 88081c59c5..49761f6d88 100644 --- a/vector/src/main/res/values-et/strings.xml +++ b/vector/src/main/res/values-et/strings.xml @@ -2806,4 +2806,9 @@ Sisesta serveri nimi, mille sisu sa soovid uurida. Lisa uus server Sinu server + Kaasteeliste kogukonnakeskused pole veel päris valmis, aga sa võid neid juba proovida + Jätka ikkagi + Hetkel teiste kasutajate liitumine sinu poolt tehtud privaatsete jututubadega ei pruugi õnnestuda. +\n +\nKuna tegemist on beetaversiooniga, siis me veel parandame seda funktsionaalsust, aga lihtsalt tahtsime sind teavitada. \ No newline at end of file From f6dd07eb64738431143c7a77ff47bcc17312ff85 Mon Sep 17 00:00:00 2001 From: Vancha Date: Fri, 18 Jun 2021 22:22:40 +0000 Subject: [PATCH 19/95] Translated using Weblate (Frisian) Currently translated at 25.7% (641 of 2490 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/fy/ --- vector/src/main/res/values-fy/strings.xml | 35 +++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/vector/src/main/res/values-fy/strings.xml b/vector/src/main/res/values-fy/strings.xml index 12a1df9012..5bdcc26d1f 100644 --- a/vector/src/main/res/values-fy/strings.xml +++ b/vector/src/main/res/values-fy/strings.xml @@ -630,4 +630,39 @@ Iepenbier Eltsenien kin by disse keamer oankopje, leden kinne don akseptearje as ôfslaan Eltsenien dyt in link nei disse keamer hat, sels gasten + Do hast gjin brûkers negearre + Negearre brûkers + Stim & Fideo + Avansearre ynstellingen + Oanpaste en avansearre ynstellingen + Akkount Tafoegje + Oanpaste Ynstellingen. + Ynskeakelje + Ynskeakelje + Notifikaasjes binne ynskeakele foar dyn akkount. + Akkount Ynstellingen. + Ynstellingen Iepenje + Notifikaasjes binne ynskeakele yn de systeem ynstellingen. + Systeem Ynstellingen. + Tests Útfiere + Telefoannûmers + E-mailadressen + Wachtwurd befêstigje + Applikaasje informaasje yn de systeem ynstellingen sjen litte. + Applikaasje informaasje + Telefoannûmer tafoegje + Der is gjin telefoannûmer tafoege oan syn akkount + E-mailadres tafoegje + Email + Ynstellingen + Petear Ferlitte + Direkt Petear + Alle berjochten + Alle berjochten (lûd) + Ynstellingen + Ynstellingen feroarje + Keamer rjochten + Do hast de tsjinner ACLs foar dizze keamer feroare. + %s hat de tsjinner ACLs foar dizze keamer feroare. + Do hast dyn profyl ôfbylding feroare \ No newline at end of file From e77cca4495b2c9d27aaf85d9d8800ff2b6936d41 Mon Sep 17 00:00:00 2001 From: Szimszon Date: Fri, 18 Jun 2021 06:50:19 +0000 Subject: [PATCH 20/95] Translated using Weblate (Hungarian) Currently translated at 100.0% (2490 of 2490 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/hu/ --- vector/src/main/res/values-hu/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vector/src/main/res/values-hu/strings.xml b/vector/src/main/res/values-hu/strings.xml index 797ea4f036..ba1e3a9e8e 100644 --- a/vector/src/main/res/values-hu/strings.xml +++ b/vector/src/main/res/values-hu/strings.xml @@ -2811,4 +2811,9 @@ Ha nem te állítottad be a visszaállítási metódust, akkor egy támadó pró Add meg a felfedezni kívánt új szerver nevét. Új szerver hozzáadása Matrix szervered + Az emberek jelen pillanatban nem fognak tudni csatlakozni egyetlen olyan privát szobához sem amit készítettél. +\n +\nEzt folyamatosan fejlesztjük a béta program keretében, csak szerettünk volna tájékoztatni róla. + A csoporttárs terek még nem igazán vannak készen de már tehetsz velük egy próbát + Mindenképpen folytatás \ No newline at end of file From b5ff31b84ea29633b062b2ca0eb6ac256990657e Mon Sep 17 00:00:00 2001 From: Besnik Bleta Date: Fri, 18 Jun 2021 09:28:16 +0000 Subject: [PATCH 21/95] Translated using Weblate (Albanian) Currently translated at 99.5% (2479 of 2490 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/sq/ --- vector/src/main/res/values-sq/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vector/src/main/res/values-sq/strings.xml b/vector/src/main/res/values-sq/strings.xml index 73512f103c..167d4a6354 100644 --- a/vector/src/main/res/values-sq/strings.xml +++ b/vector/src/main/res/values-sq/strings.xml @@ -2796,4 +2796,9 @@ Jepni emrin e e një shërbyesi të ri që doni të eksploroni. Shtoni shërbyes të ri Shërbyesi juaj + Hëpërhë, personat mund të mos jenë në gjendje të hyjnë në çfarëdo dhome private që krijoni. +\n +\nDo ta përmirësojmë këtë punë, si pjesë e versionit beta, thjesht donim t’ua bënim të ditur. + Hapësirat për anëtarë ekipi ende s’janë tërësisht gati, por mund t’i provoni + Vazhdo, Sido Qoftë \ No newline at end of file From 8e595a7605b4971a82f4475d311e751c2a5ecfa2 Mon Sep 17 00:00:00 2001 From: LinAGKar Date: Sat, 19 Jun 2021 10:10:16 +0000 Subject: [PATCH 22/95] Translated using Weblate (Swedish) Currently translated at 100.0% (2490 of 2490 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/sv/ --- vector/src/main/res/values-sv/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vector/src/main/res/values-sv/strings.xml b/vector/src/main/res/values-sv/strings.xml index ce65fd9a5a..d9b58bb605 100644 --- a/vector/src/main/res/values-sv/strings.xml +++ b/vector/src/main/res/values-sv/strings.xml @@ -2806,4 +2806,9 @@ Ange namnet för en ny server du vill utforska. Lägg till en ny server Din server + För tillfället så kan folk kanske inte gå med i privata rum som du skapar. +\n +\nVi kommer att förbättra detta som en del av betan, men ville låta dig veta. + Lagkamratsutrymmen är inte riktigt färdiga men du kan ändå testa dem + Fortsätt ändå \ No newline at end of file From 061ab76c21ca97edcde165e324a6362d06d1f203 Mon Sep 17 00:00:00 2001 From: sr093906 Date: Fri, 18 Jun 2021 02:58:54 +0000 Subject: [PATCH 23/95] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (2490 of 2490 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/zh_Hans/ --- vector/src/main/res/values-zh-rCN/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vector/src/main/res/values-zh-rCN/strings.xml b/vector/src/main/res/values-zh-rCN/strings.xml index d3cc148943..190ea00a1e 100644 --- a/vector/src/main/res/values-zh-rCN/strings.xml +++ b/vector/src/main/res/values-zh-rCN/strings.xml @@ -2763,4 +2763,9 @@ 输入你想要探索的新服务器的名称。 添加一个新的服务器 你的服务器 + 眼下,人们可能无法加入您设置的任何私人房间。 +\n +\n作为测试版的一部分,我们将对此进行改进,只是想让你知道。 + 队友空间还没有完全准备好,但你仍然可以尝试一下 + 不论如何继续 \ No newline at end of file From efe0a1737eea55897ac732cdfbf921630c6e2464 Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Fri, 18 Jun 2021 03:00:53 +0000 Subject: [PATCH 24/95] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (2490 of 2490 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/zh_Hant/ --- vector/src/main/res/values-zh-rTW/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vector/src/main/res/values-zh-rTW/strings.xml b/vector/src/main/res/values-zh-rTW/strings.xml index 1c67fdbbcd..e6577580b5 100644 --- a/vector/src/main/res/values-zh-rTW/strings.xml +++ b/vector/src/main/res/values-zh-rTW/strings.xml @@ -2753,4 +2753,9 @@ 輸入您想要探索的新伺服器名稱。 加入新的伺服器 您的伺服器 + 目前,人們可能無法加入您開啟的任何私人聊天室。 +\n +\n作為測試版的一部分,我們會對此進行改善,但想先讓您知道。 + 隊友空間還沒有完全準備好,但您仍可以試試看 + 無論如何都要繼續 \ No newline at end of file From f7be5996e5cfbd7a7e6a03c4f1e240214c6e4dc7 Mon Sep 17 00:00:00 2001 From: zeritti Date: Sun, 20 Jun 2021 08:33:40 +0000 Subject: [PATCH 25/95] Translated using Weblate (Czech) Currently translated at 100.0% (21 of 21 strings) Translation: Element Android/Element Android Store Translate-URL: https://translate.element.io/projects/element-android/element-store/cs/ --- fastlane/metadata/android/cs-CZ/changelogs/40101070.txt | 2 ++ fastlane/metadata/android/cs-CZ/changelogs/40101080.txt | 2 ++ fastlane/metadata/android/cs-CZ/changelogs/40101090.txt | 2 ++ 3 files changed, 6 insertions(+) create mode 100644 fastlane/metadata/android/cs-CZ/changelogs/40101070.txt create mode 100644 fastlane/metadata/android/cs-CZ/changelogs/40101080.txt create mode 100644 fastlane/metadata/android/cs-CZ/changelogs/40101090.txt diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40101070.txt b/fastlane/metadata/android/cs-CZ/changelogs/40101070.txt new file mode 100644 index 0000000000..2a6afb21a5 --- /dev/null +++ b/fastlane/metadata/android/cs-CZ/changelogs/40101070.txt @@ -0,0 +1,2 @@ +Hlavní změny v této verzi: beta podpora pro Spaces. Komprimace videa před odesláním. +Úplný záznam změn: https://github.com/vector-im/element-android/releases/tag/v1.1.7 diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40101080.txt b/fastlane/metadata/android/cs-CZ/changelogs/40101080.txt new file mode 100644 index 0000000000..5ec173ebea --- /dev/null +++ b/fastlane/metadata/android/cs-CZ/changelogs/40101080.txt @@ -0,0 +1,2 @@ +Hlavní změny v této verzi: vylepšení pro Spaces +Úplný záznam změn: https://github.com/vector-im/element-android/releases/tag/v1.1.8 diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40101090.txt b/fastlane/metadata/android/cs-CZ/changelogs/40101090.txt new file mode 100644 index 0000000000..782a2fa8c5 --- /dev/null +++ b/fastlane/metadata/android/cs-CZ/changelogs/40101090.txt @@ -0,0 +1,2 @@ +Hlavní změny v této verzi: doplněna podpora pro síť gitter.im +Úplný záznam změn: https://github.com/vector-im/element-android/releases/tag/v1.1.9 From 171793d19017275b3daf64d5152d8254903604b2 Mon Sep 17 00:00:00 2001 From: Valere Date: Tue, 22 Jun 2021 17:35:39 +0200 Subject: [PATCH 26/95] room version cap support + room upgrade --- .../homeserver/HomeServerCapabilities.kt | 6 +- .../session/homeserver/RoomVersionModel.kt | 32 +++++ .../android/sdk/api/session/room/Room.kt | 4 +- .../room/version/RoomVersionService.kt | 32 +++++ .../android/sdk/api/session/space/Space.kt | 3 + .../database/RealmSessionStoreMigration.kt | 9 +- .../mapper/HomeServerCapabilitiesMapper.kt | 23 ++- .../model/HomeServerCapabilitiesEntity.kt | 3 +- .../homeserver/GetCapabilitiesResult.kt | 22 ++- .../GetHomeServerCapabilitiesTask.kt | 5 + .../sdk/internal/session/room/DefaultRoom.kt | 7 +- .../sdk/internal/session/room/RoomAPI.kt | 11 ++ .../sdk/internal/session/room/RoomFactory.kt | 5 +- .../sdk/internal/session/room/RoomModule.kt | 5 + .../internal/session/room/RoomUpgradeBody.kt | 26 ++++ .../session/room/RoomUpgradeResponse.kt | 26 ++++ .../room/summary/RoomSummaryUpdater.kt | 2 +- .../room/version/DefaultRoomVersionService.kt | 85 +++++++++++ .../room/version/RoomVersionUpgradeTask.kt | 66 +++++++++ .../internal/session/space/DefaultSpace.kt | 6 + .../java/im/vector/app/VectorApplication.kt | 1 - .../im/vector/app/core/di/ScreenComponent.kt | 4 + .../VectorBaseBottomSheetDialogFragment.kt | 6 +- .../core/ui/list/GenericProgressBarItem.kt | 53 +++++++ .../app/core/ui/views/NotificationAreaView.kt | 6 +- .../im/vector/app/features/command/Command.kt | 3 +- .../app/features/command/CommandParser.kt | 10 +- .../app/features/command/ParsedCommand.kt | 1 + .../detail/JoinReplacementRoomBottomSheet.kt | 87 +++++++++++ .../home/room/detail/RoomDetailAction.kt | 1 + .../home/room/detail/RoomDetailFragment.kt | 32 ++++- .../home/room/detail/RoomDetailViewEvents.kt | 2 + .../home/room/detail/RoomDetailViewModel.kt | 27 ++++ .../room/detail/upgrade/MigrateRoomAction.kt | 25 ++++ .../detail/upgrade/MigrateRoomBottomSheet.kt | 126 ++++++++++++++++ .../detail/upgrade/MigrateRoomController.kt | 135 ++++++++++++++++++ .../detail/upgrade/MigrateRoomViewModel.kt | 116 +++++++++++++++ .../detail/upgrade/MigrateRoomViewState.kt | 41 ++++++ .../upgrade/UpgradeRoomViewModelTask.kt | 99 +++++++++++++ .../HomeserverSettingsController.kt | 37 ++++- .../layout/bottom_sheet_tombstone_join.xml | 48 +++++++ .../main/res/layout/item_generic_progress.xml | 6 + .../res/layout/item_timeline_event_create.xml | 4 +- .../res/layout/view_notification_area.xml | 28 ++-- vector/src/main/res/values/strings.xml | 27 +++- 45 files changed, 1257 insertions(+), 46 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/RoomVersionModel.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/version/RoomVersionService.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomUpgradeBody.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomUpgradeResponse.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/version/DefaultRoomVersionService.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/version/RoomVersionUpgradeTask.kt create mode 100644 vector/src/main/java/im/vector/app/core/ui/list/GenericProgressBarItem.kt create mode 100644 vector/src/main/java/im/vector/app/features/home/room/detail/JoinReplacementRoomBottomSheet.kt create mode 100644 vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomAction.kt create mode 100644 vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomBottomSheet.kt create mode 100644 vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomController.kt create mode 100644 vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewModel.kt create mode 100644 vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewState.kt create mode 100644 vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/UpgradeRoomViewModelTask.kt create mode 100644 vector/src/main/res/layout/bottom_sheet_tombstone_join.xml create mode 100644 vector/src/main/res/layout/item_generic_progress.xml diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt index da99ab8d54..fc3d09d91d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt @@ -16,6 +16,8 @@ package org.matrix.android.sdk.api.session.homeserver +import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities.Companion.MAX_UPLOAD_FILE_SIZE_UNKNOWN + data class HomeServerCapabilities( /** * True if it is possible to change the password of the account. @@ -32,7 +34,9 @@ data class HomeServerCapabilities( /** * Default identity server url, provided in Wellknown */ - val defaultIdentityServerUrl: String? = null + val defaultIdentityServerUrl: String? = null, + + val roomVersions: RoomVersionCapabilities? = null ) { companion object { const val MAX_UPLOAD_FILE_SIZE_UNKNOWN = -1L diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/RoomVersionModel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/RoomVersionModel.kt new file mode 100644 index 0000000000..5997df035e --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/RoomVersionModel.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.session.homeserver + +data class RoomVersionCapabilities( + val defaultRoomVersion: String, + val supportedVersion: List +) + +data class RoomVersionInfo( + val version: String, + val status: RoomVersionStatus +) + +enum class RoomVersionStatus { + STABLE, + UNSTABLE +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt index cb04b05a74..ebe96b6382 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt @@ -34,6 +34,7 @@ import org.matrix.android.sdk.api.session.room.tags.TagsService import org.matrix.android.sdk.api.session.room.timeline.TimelineService import org.matrix.android.sdk.api.session.room.typing.TypingService import org.matrix.android.sdk.api.session.room.uploads.UploadsService +import org.matrix.android.sdk.api.session.room.version.RoomVersionService import org.matrix.android.sdk.api.session.search.SearchResult import org.matrix.android.sdk.api.session.space.Space import org.matrix.android.sdk.api.util.Optional @@ -57,7 +58,8 @@ interface Room : RelationService, RoomCryptoService, RoomPushRuleService, - RoomAccountDataService { + RoomAccountDataService, + RoomVersionService { /** * The roomId of this room diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/version/RoomVersionService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/version/RoomVersionService.kt new file mode 100644 index 0000000000..a90e1343f2 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/version/RoomVersionService.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.session.room.version + +interface RoomVersionService { + + fun getRoomVersion(): String + + /** + * Upgrade to the given room version + * @return the replacement room id + */ + suspend fun upgradeToVersion(version: String): String + + suspend fun getRecommendedVersion() : String + + fun userMayUpgradeRoom(userId: String): Boolean +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/Space.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/Space.kt index db25762c2f..3bae6126e0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/Space.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/Space.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.api.session.space import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.model.RoomSummary +import org.matrix.android.sdk.api.session.space.model.SpaceChildContent interface Space { @@ -38,6 +39,8 @@ interface Space { autoJoin: Boolean = false, suggested: Boolean? = false) + fun getChildInfo(roomId: String): SpaceChildContent? + suspend fun removeChildren(roomId: String) @Throws diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt index 2b3c3b28ee..864aa13cc2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt @@ -46,7 +46,7 @@ import javax.inject.Inject class RealmSessionStoreMigration @Inject constructor() : RealmMigration { companion object { - const val SESSION_STORE_SCHEMA_VERSION = 14L + const val SESSION_STORE_SCHEMA_VERSION = 15L } override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) { @@ -66,6 +66,7 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration { if (oldVersion <= 11) migrateTo12(realm) if (oldVersion <= 12) migrateTo13(realm) if (oldVersion <= 13) migrateTo14(realm) + if (oldVersion <= 14) migrateTo15(realm) } private fun migrateTo1(realm: DynamicRealm) { @@ -306,4 +307,10 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration { roomAccountDataSchema.isEmbedded = true } + + private fun migrateTo15(realm: DynamicRealm) { + Timber.d("Step 14 -> 15") + realm.schema.get("HomeServerCapabilitiesEntity") + ?.addField(HomeServerCapabilitiesEntityFields.ROOM_VERSION_JSON, String::class.java) + } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt index b18c67294f..566df97105 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt @@ -16,8 +16,15 @@ package org.matrix.android.sdk.internal.database.mapper +import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities +import org.matrix.android.sdk.api.session.homeserver.RoomVersionCapabilities +import org.matrix.android.sdk.api.session.homeserver.RoomVersionInfo +import org.matrix.android.sdk.api.session.homeserver.RoomVersionStatus import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity +import org.matrix.android.sdk.internal.di.MoshiProvider +import org.matrix.android.sdk.internal.session.homeserver.RoomVersions +import org.matrix.android.sdk.internal.session.room.version.DefaultRoomVersionService /** * HomeServerCapabilitiesEntity -> HomeSeverCapabilities @@ -29,7 +36,21 @@ internal object HomeServerCapabilitiesMapper { canChangePassword = entity.canChangePassword, maxUploadFileSize = entity.maxUploadFileSize, lastVersionIdentityServerSupported = entity.lastVersionIdentityServerSupported, - defaultIdentityServerUrl = entity.defaultIdentityServerUrl + defaultIdentityServerUrl = entity.defaultIdentityServerUrl, + roomVersions = entity.roomVersionJson?.let { + tryOrNull { + MoshiProvider.providesMoshi().adapter(RoomVersions::class.java).fromJson(it)?.let { + RoomVersionCapabilities( + defaultRoomVersion = it.default ?: DefaultRoomVersionService.DEFAULT_ROOM_VERSION, + supportedVersion = it.available.entries.map { entry -> + RoomVersionInfo(entry.key, RoomVersionStatus.STABLE + .takeIf { entry.value == "stable" } + ?: RoomVersionStatus.UNSTABLE) + } + ) + } + } + } ) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/HomeServerCapabilitiesEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/HomeServerCapabilitiesEntity.kt index 763dcf80a2..0af2fc4cc5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/HomeServerCapabilitiesEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/HomeServerCapabilitiesEntity.kt @@ -24,7 +24,8 @@ internal open class HomeServerCapabilitiesEntity( var maxUploadFileSize: Long = HomeServerCapabilities.MAX_UPLOAD_FILE_SIZE_UNKNOWN, var lastVersionIdentityServerSupported: Boolean = false, var defaultIdentityServerUrl: String? = null, - var lastUpdatedTimestamp: Long = 0L + var lastUpdatedTimestamp: Long = 0L, + var roomVersionJson: String? = null ) : RealmObject() { companion object diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetCapabilitiesResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetCapabilitiesResult.kt index ab029a0fce..014b1b17da 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetCapabilitiesResult.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetCapabilitiesResult.kt @@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.session.homeserver import com.squareup.moshi.Json import com.squareup.moshi.JsonClass import org.matrix.android.sdk.api.extensions.orTrue +import org.matrix.android.sdk.api.util.JsonDict /** * Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-capabilities @@ -38,9 +39,14 @@ internal data class Capabilities( * Capability to indicate if the user can change their password. */ @Json(name = "m.change_password") - val changePassword: ChangePassword? = null + val changePassword: ChangePassword? = null, - // No need for m.room_versions for the moment + /** + * This capability describes the default and available room versions a server supports, and at what level of stability. + * Clients should make use of this capability to determine if users need to be encouraged to upgrade their rooms. + */ + @Json(name = "m.room_versions") + val roomVersions: RoomVersions? = null ) @JsonClass(generateAdapter = true) @@ -52,6 +58,18 @@ internal data class ChangePassword( val enabled: Boolean? ) +@JsonClass(generateAdapter = true) +internal data class RoomVersions( + /** + * Required. True if the user can change their password, false otherwise. + */ + @Json(name = "default") + val default: String?, + + @Json(name = "available") + val available: JsonDict +) + // The spec says: If not present, the client should assume that password changes are possible via the API internal fun GetCapabilitiesResult.canChangePassword(): Boolean { return capabilities?.changePassword?.enabled.orTrue() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt index 740370123f..82eb03afe6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt @@ -24,6 +24,7 @@ import org.matrix.android.sdk.internal.auth.version.Versions import org.matrix.android.sdk.internal.auth.version.isLoginAndRegistrationSupportedBySdk import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity import org.matrix.android.sdk.internal.database.query.getOrCreate +import org.matrix.android.sdk.internal.di.MoshiProvider import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.network.GlobalErrorReceiver @@ -104,6 +105,10 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( if (getCapabilitiesResult != null) { homeServerCapabilitiesEntity.canChangePassword = getCapabilitiesResult.canChangePassword() + + homeServerCapabilitiesEntity.roomVersionJson = getCapabilitiesResult.capabilities?.roomVersions?.let { + MoshiProvider.providesMoshi().adapter(RoomVersions::class.java).toJson(it) + } } if (getMediaConfigResult != null) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt index 0d9c106d41..1a95996024 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt @@ -37,6 +37,7 @@ import org.matrix.android.sdk.api.session.room.tags.TagsService import org.matrix.android.sdk.api.session.room.timeline.TimelineService import org.matrix.android.sdk.api.session.room.typing.TypingService import org.matrix.android.sdk.api.session.room.uploads.UploadsService +import org.matrix.android.sdk.api.session.room.version.RoomVersionService import org.matrix.android.sdk.api.session.search.SearchResult import org.matrix.android.sdk.api.session.space.Space import org.matrix.android.sdk.api.util.Optional @@ -69,7 +70,8 @@ internal class DefaultRoom(override val roomId: String, private val roomAccountDataService: RoomAccountDataService, private val sendStateTask: SendStateTask, private val viaParameterFinder: ViaParameterFinder, - private val searchTask: SearchTask) : + private val searchTask: SearchTask, + private val roomVersionService: RoomVersionService) : Room, TimelineService by timelineService, SendService by sendService, @@ -85,7 +87,8 @@ internal class DefaultRoom(override val roomId: String, RelationService by relationService, MembershipService by roomMembersService, RoomPushRuleService by roomPushRuleService, - RoomAccountDataService by roomAccountDataService { + RoomAccountDataService by roomAccountDataService, + RoomVersionService by roomVersionService { override fun getRoomSummaryLive(): LiveData> { return roomSummaryDataSource.getRoomSummaryLive(roomId) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt index 4f12604039..18ece60629 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt @@ -369,4 +369,15 @@ internal interface RoomAPI { @Path("roomId") roomId: String, @Path("type") type: String, @Body content: JsonDict) + + /** + * Upgrades the given room to a particular room version. + * Errors: + * 400, The request was invalid. One way this can happen is if the room version requested is not supported by the homeserver + * (M_UNSUPPORTED_ROOM_VERSION) + * 403: The user is not permitted to upgrade the room.(M_FORBIDDEN) + */ + @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/upgrade") + suspend fun upgradeRoom(@Path("roomId") roomId: String, + @Body body: RoomUpgradeBody): RoomUpgradeResponse } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt index 9ddb8f1177..6b5565fa50 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt @@ -37,6 +37,7 @@ import org.matrix.android.sdk.internal.session.room.tags.DefaultTagsService import org.matrix.android.sdk.internal.session.room.timeline.DefaultTimelineService import org.matrix.android.sdk.internal.session.room.typing.DefaultTypingService import org.matrix.android.sdk.internal.session.room.uploads.DefaultUploadsService +import org.matrix.android.sdk.internal.session.room.version.DefaultRoomVersionService import org.matrix.android.sdk.internal.session.search.SearchTask import javax.inject.Inject @@ -61,6 +62,7 @@ internal class DefaultRoomFactory @Inject constructor(private val cryptoService: private val relationServiceFactory: DefaultRelationService.Factory, private val membershipServiceFactory: DefaultMembershipService.Factory, private val roomPushRuleServiceFactory: DefaultRoomPushRuleService.Factory, + private val roomVersionServiceFactory: DefaultRoomVersionService.Factory, private val roomAccountDataServiceFactory: DefaultRoomAccountDataService.Factory, private val sendStateTask: SendStateTask, private val viaParameterFinder: ViaParameterFinder, @@ -89,7 +91,8 @@ internal class DefaultRoomFactory @Inject constructor(private val cryptoService: roomAccountDataService = roomAccountDataServiceFactory.create(roomId), sendStateTask = sendStateTask, searchTask = searchTask, - viaParameterFinder = viaParameterFinder + viaParameterFinder = viaParameterFinder, + roomVersionService = roomVersionServiceFactory.create(roomId) ) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt index d88c195056..c04c899e18 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt @@ -92,6 +92,8 @@ import org.matrix.android.sdk.internal.session.room.typing.DefaultSendTypingTask import org.matrix.android.sdk.internal.session.room.typing.SendTypingTask import org.matrix.android.sdk.internal.session.room.uploads.DefaultGetUploadsTask import org.matrix.android.sdk.internal.session.room.uploads.GetUploadsTask +import org.matrix.android.sdk.internal.session.room.version.DefaultRoomVersionUpgradeTask +import org.matrix.android.sdk.internal.session.room.version.RoomVersionUpgradeTask import org.matrix.android.sdk.internal.session.space.DefaultSpaceService import retrofit2.Retrofit @@ -243,4 +245,7 @@ internal abstract class RoomModule { @Binds abstract fun bindGetEventTask(task: DefaultGetEventTask): GetEventTask + + @Binds + abstract fun bindRoomVersionUpgradeTask(task: DefaultRoomVersionUpgradeTask): RoomVersionUpgradeTask } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomUpgradeBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomUpgradeBody.kt new file mode 100644 index 0000000000..feefbe5f66 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomUpgradeBody.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.room + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +internal data class RoomUpgradeBody( + @Json(name = "new_version") + val newVersion: String +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomUpgradeResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomUpgradeResponse.kt new file mode 100644 index 0000000000..16e95194a3 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomUpgradeResponse.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.room + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +internal data class RoomUpgradeResponse( + @Json(name = "replacement_room") + val replacementRoomId: String +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt index 7cbcfee713..7ad6d06b1e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt @@ -354,7 +354,7 @@ internal class RoomSummaryUpdater @Inject constructor( // we keep real m.child/m.parent relations and add the one for common memberships dmRoom.flattenParentIds += "|${flattenRelated.joinToString("|")}|" } -// Timber.v("## SPACES: flatten of ${dmRoom.otherMemberIds.joinToString(",")} is ${dmRoom.flattenParentIds}") + Timber.v("## SPACES: flatten of ${dmRoom.otherMemberIds.joinToString(",")} is ${dmRoom.flattenParentIds}") } // Maybe a good place to count the number of notifications for spaces? diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/version/DefaultRoomVersionService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/version/DefaultRoomVersionService.kt new file mode 100644 index 0000000000..1b5d62926e --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/version/DefaultRoomVersionService.kt @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.room.version + +import com.zhuinden.monarchy.Monarchy +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import io.realm.Realm +import org.matrix.android.sdk.api.query.QueryStringValue +import org.matrix.android.sdk.api.session.events.model.EventType +import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent +import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent +import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper +import org.matrix.android.sdk.api.session.room.version.RoomVersionService +import org.matrix.android.sdk.internal.database.mapper.HomeServerCapabilitiesMapper +import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity +import org.matrix.android.sdk.internal.database.query.get +import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.session.room.state.StateEventDataSource + +internal class DefaultRoomVersionService @AssistedInject constructor( + @Assisted private val roomId: String, + @SessionDatabase private val monarchy: Monarchy, + private val stateEventDataSource: StateEventDataSource, + private val roomVersionUpgradeTask: RoomVersionUpgradeTask +) : RoomVersionService { + + @AssistedFactory + interface Factory { + fun create(roomId: String): DefaultRoomVersionService + } + + override fun getRoomVersion(): String { + return stateEventDataSource.getStateEvent(roomId, EventType.STATE_ROOM_CREATE, QueryStringValue.IsEmpty) + ?.content + ?.toModel() + ?.roomVersion + // as per spec -> Defaults to "1" if the key does not exist. + ?: DEFAULT_ROOM_VERSION + } + + override suspend fun upgradeToVersion(version: String): String { + return roomVersionUpgradeTask.execute( + RoomVersionUpgradeTask.Params( + roomId, version + ) + ) + } + + override suspend fun getRecommendedVersion(): String { + return Realm.getInstance(monarchy.realmConfiguration).use { realm -> + HomeServerCapabilitiesEntity.get(realm)?.let { + HomeServerCapabilitiesMapper.map(it) + }?.roomVersions?.defaultRoomVersion ?: DEFAULT_ROOM_VERSION + } + } + + override fun userMayUpgradeRoom(userId: String): Boolean { + val powerLevelsHelper = stateEventDataSource.getStateEvent(roomId, EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition) + ?.content?.toModel() + ?.let { PowerLevelsHelper(it) } + + return powerLevelsHelper?.isUserAllowedToSend(userId, true, EventType.STATE_ROOM_TOMBSTONE) ?: false + } + + companion object { + const val DEFAULT_ROOM_VERSION = "1" + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/version/RoomVersionUpgradeTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/version/RoomVersionUpgradeTask.kt new file mode 100644 index 0000000000..444795b5a9 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/version/RoomVersionUpgradeTask.kt @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.room.version + +import io.realm.RealmConfiguration +import org.matrix.android.sdk.api.extensions.tryOrNull +import org.matrix.android.sdk.api.session.room.model.Membership +import org.matrix.android.sdk.internal.database.awaitNotEmptyResult +import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity +import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields +import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.network.GlobalErrorReceiver +import org.matrix.android.sdk.internal.network.executeRequest +import org.matrix.android.sdk.internal.session.room.RoomAPI +import org.matrix.android.sdk.internal.session.room.RoomUpgradeBody +import org.matrix.android.sdk.internal.task.Task +import java.util.concurrent.TimeUnit +import javax.inject.Inject + +internal interface RoomVersionUpgradeTask : Task { + data class Params( + val roomId: String, + val newVersion: String + ) +} + +internal class DefaultRoomVersionUpgradeTask @Inject constructor( + private val roomAPI: RoomAPI, + private val globalErrorReceiver: GlobalErrorReceiver, + @SessionDatabase + private val realmConfiguration: RealmConfiguration +) : RoomVersionUpgradeTask { + + override suspend fun execute(params: RoomVersionUpgradeTask.Params): String { + val replacementRoomId = executeRequest(globalErrorReceiver) { + roomAPI.upgradeRoom( + roomId = params.roomId, + body = RoomUpgradeBody(params.newVersion) + ) + }.replacementRoomId + + // Wait for room to come back from the sync (but it can maybe be in the DB if the sync response is received before) + tryOrNull { + awaitNotEmptyResult(realmConfiguration, TimeUnit.MINUTES.toMillis(1L)) { realm -> + realm.where(RoomSummaryEntity::class.java) + .equalTo(RoomSummaryEntityFields.ROOM_ID, replacementRoomId) + .equalTo(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.JOIN.name) + } + } + return replacementRoomId + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpace.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpace.kt index 70c52bf4ae..233eef45f8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpace.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpace.kt @@ -86,6 +86,12 @@ internal class DefaultSpace( ) } + override fun getChildInfo(roomId: String): SpaceChildContent? { + return room.getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId)) + .firstOrNull() + ?.content.toModel() + } + override suspend fun setChildrenOrder(roomId: String, order: String?) { val existing = room.getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId)) .firstOrNull() diff --git a/vector/src/main/java/im/vector/app/VectorApplication.kt b/vector/src/main/java/im/vector/app/VectorApplication.kt index f3e2f8740e..37a9dc36b4 100644 --- a/vector/src/main/java/im/vector/app/VectorApplication.kt +++ b/vector/src/main/java/im/vector/app/VectorApplication.kt @@ -159,7 +159,6 @@ class VectorApplication : // Do not display the name change popup doNotShowDisclaimerDialog(this) } - if (authenticationService.hasAuthenticatedSessions() && !activeSessionHolder.hasActiveSession()) { val lastAuthenticatedSession = authenticationService.getLastAuthenticatedSession()!! activeSessionHolder.setActiveSession(lastAuthenticatedSession) diff --git a/vector/src/main/java/im/vector/app/core/di/ScreenComponent.kt b/vector/src/main/java/im/vector/app/core/di/ScreenComponent.kt index 3c11bfcd13..7784a2bd1c 100644 --- a/vector/src/main/java/im/vector/app/core/di/ScreenComponent.kt +++ b/vector/src/main/java/im/vector/app/core/di/ScreenComponent.kt @@ -40,12 +40,14 @@ import im.vector.app.features.debug.DebugMenuActivity import im.vector.app.features.devtools.RoomDevToolActivity import im.vector.app.features.home.HomeActivity import im.vector.app.features.home.HomeModule +import im.vector.app.features.home.room.detail.JoinReplacementRoomBottomSheet import im.vector.app.features.home.room.detail.RoomDetailActivity import im.vector.app.features.home.room.detail.readreceipts.DisplayReadReceiptsBottomSheet import im.vector.app.features.home.room.detail.search.SearchActivity import im.vector.app.features.home.room.detail.timeline.action.MessageActionsBottomSheet import im.vector.app.features.home.room.detail.timeline.edithistory.ViewEditHistoryBottomSheet import im.vector.app.features.home.room.detail.timeline.reactions.ViewReactionsBottomSheet +import im.vector.app.features.home.room.detail.upgrade.MigrateRoomBottomSheet import im.vector.app.features.home.room.detail.widget.RoomWidgetsBottomSheet import im.vector.app.features.home.room.filtered.FilteredRoomsActivity import im.vector.app.features.home.room.list.RoomListModule @@ -191,6 +193,8 @@ interface ScreenComponent { fun inject(bottomSheet: SpaceSettingsMenuBottomSheet) fun inject(bottomSheet: InviteRoomSpaceChooserBottomSheet) fun inject(bottomSheet: SpaceInviteBottomSheet) + fun inject(bottomSheet: JoinReplacementRoomBottomSheet) + fun inject(bottomSheet: MigrateRoomBottomSheet) /* ========================================================================================== * Others diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseBottomSheetDialogFragment.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseBottomSheetDialogFragment.kt index d6d4d07500..b9b5bc8ca5 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseBottomSheetDialogFragment.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseBottomSheetDialogFragment.kt @@ -46,7 +46,7 @@ import java.util.concurrent.TimeUnit /** * Add MvRx capabilities to bottomsheetdialog (like BaseMvRxFragment) */ -abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment(), MvRxView { +abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment(), MvRxView { private val mvrxViewIdProperty = MvRxViewId() final override val mvrxViewId: String by mvrxViewIdProperty @@ -168,6 +168,10 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomShee @CallSuper override fun invalidate() { + forceExpandState() + } + + protected fun forceExpandState() { if (showExpanded) { // Force the bottom sheet to be expanded bottomSheetBehavior?.state = BottomSheetBehavior.STATE_EXPANDED diff --git a/vector/src/main/java/im/vector/app/core/ui/list/GenericProgressBarItem.kt b/vector/src/main/java/im/vector/app/core/ui/list/GenericProgressBarItem.kt new file mode 100644 index 0000000000..48a267ec12 --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/ui/list/GenericProgressBarItem.kt @@ -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. + */ +package im.vector.app.core.ui.list + +import android.widget.ProgressBar +import com.airbnb.epoxy.EpoxyAttribute +import com.airbnb.epoxy.EpoxyModelClass +import im.vector.app.R +import im.vector.app.core.epoxy.VectorEpoxyHolder +import im.vector.app.core.epoxy.VectorEpoxyModel + +/** + * A generic list item. + * Displays an item with a title, and optional description. + * Can display an accessory on the right, that can be an image or an indeterminate progress. + * If provided with an action, will display a button at the bottom of the list item. + */ +@EpoxyModelClass(layout = R.layout.item_generic_progress) +abstract class GenericProgressBarItem : VectorEpoxyModel() { + + @EpoxyAttribute + var progress: Int = 0 + + @EpoxyAttribute + var total: Int = 100 + + @EpoxyAttribute + var indeterminate: Boolean = false + + override fun bind(holder: Holder) { + super.bind(holder) + holder.progressbar.progress = progress + holder.progressbar.max = total + holder.progressbar.isIndeterminate = indeterminate + } + + class Holder : VectorEpoxyHolder() { + val progressbar by bind(R.id.genericProgressBar) + } +} diff --git a/vector/src/main/java/im/vector/app/core/ui/views/NotificationAreaView.kt b/vector/src/main/java/im/vector/app/core/ui/views/NotificationAreaView.kt index ad2a4b8e0c..9e9fe9b8a0 100644 --- a/vector/src/main/java/im/vector/app/core/ui/views/NotificationAreaView.kt +++ b/vector/src/main/java/im/vector/app/core/ui/views/NotificationAreaView.kt @@ -21,7 +21,7 @@ import android.graphics.Color import android.text.method.LinkMovementMethod import android.util.AttributeSet import android.view.View -import android.widget.RelativeLayout +import android.widget.LinearLayout import androidx.core.content.ContextCompat import androidx.core.text.italic import im.vector.app.R @@ -44,7 +44,7 @@ class NotificationAreaView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 -) : RelativeLayout(context, attrs, defStyleAttr) { +) : LinearLayout(context, attrs, defStyleAttr) { var delegate: Delegate? = null private var state: State = State.Initial @@ -127,7 +127,7 @@ class NotificationAreaView @JvmOverloads constructor( private fun renderTombstone(state: State.Tombstone) { visibility = View.VISIBLE - views.roomNotificationIcon.setImageResource(R.drawable.error) + views.roomNotificationIcon.setImageResource(R.drawable.ic_warning_badge) val message = span { +resources.getString(R.string.room_tombstone_versioned_description) +"\n" diff --git a/vector/src/main/java/im/vector/app/features/command/Command.kt b/vector/src/main/java/im/vector/app/features/command/Command.kt index 61d39857cc..3719618d31 100644 --- a/vector/src/main/java/im/vector/app/features/command/Command.kt +++ b/vector/src/main/java/im/vector/app/features/command/Command.kt @@ -50,7 +50,8 @@ enum class Command(val command: String, val parameters: String, @StringRes val d CREATE_SPACE("/createspace", " *", R.string.command_description_create_space, true), ADD_TO_SPACE("/addToSpace", "spaceId", R.string.command_description_create_space, true), JOIN_SPACE("/joinSpace", "spaceId", R.string.command_description_join_space, true), - LEAVE_ROOM("/leave", "", R.string.command_description_leave_room, true); + LEAVE_ROOM("/leave", "", R.string.command_description_leave_room, true), + UPGRADE_ROOM("/upgraderoom", "newVersion", R.string.command_description_upgrade_room, true); val length get() = command.length + 1 diff --git a/vector/src/main/java/im/vector/app/features/command/CommandParser.kt b/vector/src/main/java/im/vector/app/features/command/CommandParser.kt index 3de00f4d0c..224956049c 100644 --- a/vector/src/main/java/im/vector/app/features/command/CommandParser.kt +++ b/vector/src/main/java/im/vector/app/features/command/CommandParser.kt @@ -312,24 +312,28 @@ object CommandParser { ) } } - Command.ADD_TO_SPACE.command -> { + Command.ADD_TO_SPACE.command -> { val rawCommand = textMessage.substring(Command.ADD_TO_SPACE.command.length).trim() ParsedCommand.AddToSpace( rawCommand ) } - Command.JOIN_SPACE.command -> { + Command.JOIN_SPACE.command -> { val spaceIdOrAlias = textMessage.substring(Command.JOIN_SPACE.command.length).trim() ParsedCommand.JoinSpace( spaceIdOrAlias ) } - Command.LEAVE_ROOM.command -> { + Command.LEAVE_ROOM.command -> { val spaceIdOrAlias = textMessage.substring(Command.LEAVE_ROOM.command.length).trim() ParsedCommand.LeaveRoom( spaceIdOrAlias ) } + Command.UPGRADE_ROOM.command -> { + val newVersion = textMessage.substring(Command.UPGRADE_ROOM.command.length).trim() + ParsedCommand.UpgradeRoom(newVersion) + } else -> { // Unknown command ParsedCommand.ErrorUnknownSlashCommand(slashCommand) diff --git a/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt b/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt index d67caac60a..123f1d3a36 100644 --- a/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt +++ b/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt @@ -61,4 +61,5 @@ sealed class ParsedCommand { class AddToSpace(val spaceId: String) : ParsedCommand() class JoinSpace(val spaceIdOrAlias: String) : ParsedCommand() class LeaveRoom(val roomId: String) : ParsedCommand() + class UpgradeRoom(val newVersion: String) : ParsedCommand() } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/JoinReplacementRoomBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/JoinReplacementRoomBottomSheet.kt new file mode 100644 index 0000000000..972162645d --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/JoinReplacementRoomBottomSheet.kt @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.home.room.detail + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.airbnb.mvrx.Fail +import com.airbnb.mvrx.Loading +import com.airbnb.mvrx.Success +import com.airbnb.mvrx.Uninitialized +import com.airbnb.mvrx.parentFragmentViewModel +import com.airbnb.mvrx.withState +import im.vector.app.R +import im.vector.app.core.di.ScreenComponent +import im.vector.app.core.epoxy.ClickListener +import im.vector.app.core.error.ErrorFormatter +import im.vector.app.core.platform.ButtonStateView +import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment +import im.vector.app.databinding.BottomSheetTombstoneJoinBinding +import javax.inject.Inject + +class JoinReplacementRoomBottomSheet : + VectorBaseBottomSheetDialogFragment() { + + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?) = + BottomSheetTombstoneJoinBinding.inflate(inflater, container, false) + + @Inject + lateinit var errorFormatter: ErrorFormatter + + override fun injectWith(injector: ScreenComponent) { + injector.inject(this) + } + + private val viewModel: RoomDetailViewModel by parentFragmentViewModel() + + override val showExpanded: Boolean + get() = true + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + views.roomUpgradeButton.retryClicked = object : ClickListener { + override fun invoke(view: View) { + withState(viewModel) { it.tombstoneEvent }?.let { + viewModel.handle(RoomDetailAction.HandleTombstoneEvent(it)) + } + } + } + + viewModel.selectSubscribe(this, RoomDetailViewState::tombstoneEventHandling) { joinState -> + when (joinState) { + // it should never be Uninitialized + Uninitialized -> views.roomUpgradeButton.render(ButtonStateView.State.Loaded) + is Loading -> { + views.roomUpgradeButton.render(ButtonStateView.State.Loading) + views.descriptionText.setText(R.string.it_may_take_some_time) + } + is Success -> { + views.roomUpgradeButton.render(ButtonStateView.State.Loaded) + dismiss() + } + is Fail -> { + // display the error message + views.descriptionText.text = errorFormatter.toHumanReadable(joinState.error) + views.roomUpgradeButton.render(ButtonStateView.State.Error) + } + } + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailAction.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailAction.kt index c0e73823e4..0e090256d3 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailAction.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailAction.kt @@ -108,4 +108,5 @@ sealed class RoomDetailAction : VectorViewModelAction { // Failed messages object RemoveAllFailedMessages : RoomDetailAction() + data class RoomUpgradeSuccess(val replacementRoom: String): RoomDetailAction() } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt index 8307e93576..156d3f713f 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt @@ -51,6 +51,7 @@ import androidx.core.view.ViewCompat import androidx.core.view.forEach import androidx.core.view.isInvisible import androidx.core.view.isVisible +import androidx.fragment.app.setFragmentResultListener import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager @@ -147,6 +148,7 @@ import im.vector.app.features.home.room.detail.timeline.item.MessageTextItem import im.vector.app.features.home.room.detail.timeline.item.ReadReceiptData import im.vector.app.features.home.room.detail.timeline.reactions.ViewReactionsBottomSheet import im.vector.app.features.home.room.detail.timeline.url.PreviewUrlRetriever +import im.vector.app.features.home.room.detail.upgrade.MigrateRoomBottomSheet import im.vector.app.features.home.room.detail.widget.RoomWidgetsBottomSheet import im.vector.app.features.html.EventHtmlRenderer import im.vector.app.features.html.PillImageSpan @@ -306,6 +308,15 @@ class RoomDetailFragment @Inject constructor( private lateinit var emojiPopup: EmojiPopup + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setFragmentResultListener(MigrateRoomBottomSheet.REQUEST_KEY) { _, bundle -> + bundle.getString(MigrateRoomBottomSheet.BUNDLE_KEY_REPLACEMENT_ROOM)?.let { replacementRoomId -> + roomDetailViewModel.handle(RoomDetailAction.RoomUpgradeSuccess(replacementRoomId)) + } + } + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java) @@ -405,6 +416,8 @@ class RoomDetailFragment @Inject constructor( is RoomDetailViewEvents.StartChatEffect -> handleChatEffect(it.type) RoomDetailViewEvents.StopChatEffects -> handleStopChatEffects() is RoomDetailViewEvents.DisplayAndAcceptCall -> acceptIncomingCall(it) + RoomDetailViewEvents.RoomReplacementStarted -> handleRoomReplacement() + is RoomDetailViewEvents.ShowRoomUpgradeDialog -> handleShowRoomUpgradeDialog(it) }.exhaustive } @@ -423,6 +436,19 @@ class RoomDetailFragment @Inject constructor( startActivity(intent) } + private fun handleRoomReplacement() { + // this will join a new room, it can take time and might fail + // so we need to report progress and retry + val tag = JoinReplacementRoomBottomSheet::javaClass.name + JoinReplacementRoomBottomSheet().show(childFragmentManager, tag) + } + + private fun handleShowRoomUpgradeDialog(roomDetailViewEvents: RoomDetailViewEvents.ShowRoomUpgradeDialog) { + val tag = MigrateRoomBottomSheet::javaClass.name + MigrateRoomBottomSheet.newInstance(roomDetailArgs.roomId, roomDetailViewEvents.newVersion) + .show(parentFragmentManager, tag) + } + private fun handleChatEffect(chatEffect: ChatEffect) { when (chatEffect) { ChatEffect.CONFETTI -> { @@ -1306,16 +1332,14 @@ class RoomDetailFragment @Inject constructor( private fun renderTombstoneEventHandling(async: Async) { when (async) { is Loading -> { - // TODO Better handling progress - vectorBaseActivity.showWaitingView(getString(R.string.joining_room)) + // shown in bottom sheet } is Success -> { navigator.openRoom(vectorBaseActivity, async()) vectorBaseActivity.finish() } is Fail -> { - vectorBaseActivity.hideWaitingView() - vectorBaseActivity.toast(errorFormatter.toHumanReadable(async.error)) + // shown in bottom sheet } } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewEvents.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewEvents.kt index 4d1e62da7e..458549bbac 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewEvents.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewEvents.kt @@ -94,4 +94,6 @@ sealed class RoomDetailViewEvents : VectorViewEvents { data class StartChatEffect(val type: ChatEffect) : RoomDetailViewEvents() object StopChatEffects : RoomDetailViewEvents() + object RoomReplacementStarted : RoomDetailViewEvents() + data class ShowRoomUpgradeDialog(val newVersion: String, val isPublic: Boolean): RoomDetailViewEvents() } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt index 751114c2d9..08e1d215c2 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt @@ -321,6 +321,11 @@ class RoomDetailViewModel @AssistedInject constructor( is RoomDetailAction.DoNotShowPreviewUrlFor -> handleDoNotShowPreviewUrlFor(action) RoomDetailAction.RemoveAllFailedMessages -> handleRemoveAllFailedMessages() RoomDetailAction.ResendAll -> handleResendAll() + is RoomDetailAction.RoomUpgradeSuccess -> { + setState { + copy(tombstoneEventHandling = Success(action.replacementRoom)) + } + } }.exhaustive } @@ -585,6 +590,11 @@ class RoomDetailViewModel @AssistedInject constructor( val viaServers = MatrixPatterns.extractServerNameFromId(action.event.senderId) ?.let { listOf(it) } .orEmpty() + // need to provide feedback as joining could take some time + _viewEvents.post(RoomDetailViewEvents.RoomReplacementStarted) + setState { + copy(tombstoneEventHandling = Loading()) + } viewModelScope.launch { val result = runCatchingToAsync { session.joinRoom(roomId, viaServers = viaServers) @@ -817,6 +827,23 @@ class RoomDetailViewModel @AssistedInject constructor( _viewEvents.post(RoomDetailViewEvents.SlashCommandHandled()) popDraft() } + is ParsedCommand.UpgradeRoom -> { + _viewEvents.post( + RoomDetailViewEvents.ShowRoomUpgradeDialog( + slashCommandResult.newVersion, + room.roomSummary()?.isPublic ?: false + ) + ) +// session.coroutineScope.launch { +// try { +// room.upgradeToVersion(slashCommandResult.newVersion) +// } catch (failure: Throwable) { +// _viewEvents.post(RoomDetailViewEvents.SlashCommandResultError(failure)) +// } +// } + _viewEvents.post(RoomDetailViewEvents.SlashCommandHandled()) + popDraft() + } }.exhaustive } is SendMode.EDIT -> { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomAction.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomAction.kt new file mode 100644 index 0000000000..cb65be7e28 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomAction.kt @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.home.room.detail.upgrade + +import im.vector.app.core.platform.VectorViewModelAction + +sealed class MigrateRoomAction : VectorViewModelAction { + data class SetAutoInvite(val autoInvite: Boolean) : MigrateRoomAction() + data class SetUpdateKnownParentSpace(val update: Boolean) : MigrateRoomAction() + object UpgradeRoom : MigrateRoomAction() +} diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomBottomSheet.kt new file mode 100644 index 0000000000..12a0fb222b --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomBottomSheet.kt @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.home.room.detail.upgrade + +import android.os.Bundle +import android.os.Parcelable +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.setFragmentResult +import com.airbnb.epoxy.OnModelBuildFinishedListener +import com.airbnb.mvrx.Success +import com.airbnb.mvrx.fragmentViewModel +import com.airbnb.mvrx.withState +import im.vector.app.core.di.ScreenComponent +import im.vector.app.core.extensions.cleanup +import im.vector.app.core.extensions.configureWith +import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment +import im.vector.app.databinding.BottomSheetGenericListBinding +import kotlinx.parcelize.Parcelize +import javax.inject.Inject + +class MigrateRoomBottomSheet : + VectorBaseBottomSheetDialogFragment(), + MigrateRoomViewModel.Factory, MigrateRoomController.InteractionListener { + + @Parcelize + data class Args( + val roomId: String, + val newVersion: String + ) : Parcelable + + @Inject + lateinit var viewModelFactory: MigrateRoomViewModel.Factory + + override val showExpanded = true + + @Inject + lateinit var epoxyController: MigrateRoomController + + val viewModel: MigrateRoomViewModel by fragmentViewModel() + + override fun injectWith(injector: ScreenComponent) { + injector.inject(this) + } + + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?) = + BottomSheetGenericListBinding.inflate(inflater, container, false) + + override fun invalidate() = withState(viewModel) { state -> + epoxyController.setData(state) + super.invalidate() + + when (val result = state.upgradingStatus) { + is Success -> { + val result = result.invoke() + if (result is UpgradeRoomViewModelTask.Result.Success) { + setFragmentResult(REQUEST_KEY, Bundle().apply { + putString(BUNDLE_KEY_REPLACEMENT_ROOM, result.replacementRoomId) + }) + dismiss() + } + } + } + } + + val postBuild = OnModelBuildFinishedListener { + view?.post { forceExpandState() } + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + epoxyController.callback = this + views.bottomSheetRecyclerView.configureWith(epoxyController) + epoxyController.addModelBuildListener(postBuild) + } + + override fun onDestroyView() { + views.bottomSheetRecyclerView.cleanup() + epoxyController.removeModelBuildListener(postBuild) + super.onDestroyView() + } + + override fun create(initialState: MigrateRoomViewState): MigrateRoomViewModel { + return viewModelFactory.create(initialState) + } + + companion object { + + const val REQUEST_KEY = "MigrateRoomBottomSheetRequest" + const val BUNDLE_KEY_REPLACEMENT_ROOM = "BUNDLE_KEY_REPLACEMENT_ROOM" + + fun newInstance(roomId: String, newVersion: String) + : MigrateRoomBottomSheet { + return MigrateRoomBottomSheet().apply { + setArguments(Args(roomId, newVersion)) + } + } + } + + override fun onAutoInvite(autoInvite: Boolean) { + viewModel.handle(MigrateRoomAction.SetAutoInvite(autoInvite)) + } + + override fun onAutoUpdateParent(update: Boolean) { + viewModel.handle(MigrateRoomAction.SetUpdateKnownParentSpace(update)) + } + + override fun onConfirmUpgrade() { + viewModel.handle(MigrateRoomAction.UpgradeRoom) + } +} diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomController.kt new file mode 100644 index 0000000000..8d037860d2 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomController.kt @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.home.room.detail.upgrade + +import com.airbnb.epoxy.TypedEpoxyController +import com.airbnb.mvrx.Loading +import com.airbnb.mvrx.Success +import im.vector.app.R +import im.vector.app.core.epoxy.errorWithRetryItem +import im.vector.app.core.error.ErrorFormatter +import im.vector.app.core.resources.StringProvider +import im.vector.app.core.ui.bottomsheet.bottomSheetTitleItem +import im.vector.app.core.ui.list.ItemStyle +import im.vector.app.core.ui.list.genericFooterItem +import im.vector.app.core.ui.list.genericProgressBarItem +import im.vector.app.features.form.formSubmitButtonItem +import im.vector.app.features.form.formSwitchItem +import javax.inject.Inject + +class MigrateRoomController @Inject constructor( + private val stringProvider: StringProvider, + private val errorFormatter: ErrorFormatter +) : TypedEpoxyController() { + + interface InteractionListener { + fun onAutoInvite(autoInvite: Boolean) + fun onAutoUpdateParent(update: Boolean) + fun onConfirmUpgrade() + } + + var callback: InteractionListener? = null + + override fun buildModels(data: MigrateRoomViewState?) { + data ?: return + + val host = this@MigrateRoomController + + bottomSheetTitleItem { + id("title") + title( + host.stringProvider.getString(if (data.isPublic) R.string.upgrade_public_room else R.string.upgrade_private_room) + ) + } + + genericFooterItem { + id("warning_text") + centered(false) + style(ItemStyle.NORMAL_TEXT) + text(host.stringProvider.getString(R.string.upgrade_room_warning)) + } + + genericFooterItem { + id("from_to_room") + centered(false) + style(ItemStyle.NORMAL_TEXT) + text(host.stringProvider.getString(R.string.upgrade_public_room_from_to, data.currentVersion, data.newVersion)) + } + + if (!data.isPublic && data.otherMemberCount > 0) { + formSwitchItem { + id("auto_invite") + switchChecked(data.shouldIssueInvites) + title(host.stringProvider.getString(R.string.upgrade_room_auto_invite)) + listener { switch -> host.callback?.onAutoInvite(switch) } + } + } + + if (data.knownParents.isNotEmpty()) { + formSwitchItem { + id("update_parent") + switchChecked(data.shouldUpdateKnownParents) + title(host.stringProvider.getString(R.string.upgrade_room_update_parent)) + listener { switch -> host.callback?.onAutoUpdateParent(switch) } + } + } + when (data.upgradingStatus) { + is Loading -> { + genericProgressBarItem { + id("upgrade_progress") + indeterminate(data.upgradingProgressIndeterminate) + progress(data.upgradingProgress) + total(data.upgradingProgressTotal) + } + } + is Success -> { + when (val result = data.upgradingStatus.invoke()) { + is UpgradeRoomViewModelTask.Result.Failure -> { + val errorText = when (result) { + is UpgradeRoomViewModelTask.Result.UnknownRoom -> { + // should not happen + host.stringProvider.getString(R.string.unknown_error) + } + is UpgradeRoomViewModelTask.Result.NotAllowed -> { + host.stringProvider.getString(R.string.upgrade_room_no_power_to_manage) + } + is UpgradeRoomViewModelTask.Result.ErrorFailure -> { + host.errorFormatter.toHumanReadable(result.throwable) + } + else -> null + } + errorWithRetryItem { + id("error") + text(errorText) + listener { host.callback?.onConfirmUpgrade() } + } + } + is UpgradeRoomViewModelTask.Result.Success -> { + // nop, dismisses + } + } + } + else -> { + formSubmitButtonItem { + id("migrate") + buttonTitleId(R.string.upgrade) + buttonClickListener { host.callback?.onConfirmUpgrade() } + } + } + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewModel.kt new file mode 100644 index 0000000000..be9dc1bc52 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewModel.kt @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.home.room.detail.upgrade + +import com.airbnb.mvrx.ActivityViewModelContext +import com.airbnb.mvrx.FragmentViewModelContext +import com.airbnb.mvrx.Loading +import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.Success +import com.airbnb.mvrx.ViewModelContext +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import im.vector.app.core.platform.EmptyViewEvents +import im.vector.app.core.platform.VectorViewModel +import im.vector.app.features.session.coroutineScope +import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.session.Session + +class MigrateRoomViewModel @AssistedInject constructor( + @Assisted initialState: MigrateRoomViewState, + private val session: Session, + private val upgradeRoomViewModelTask: UpgradeRoomViewModelTask) + : VectorViewModel(initialState) { + + init { + val room = session.getRoom(initialState.roomId) + val summary = session.getRoomSummary(initialState.roomId) + setState { + copy( + currentVersion = room?.getRoomVersion(), + isPublic = summary?.isPublic ?: false, + otherMemberCount = summary?.otherMemberIds?.count() ?: 0, + knownParents = summary?.flattenParentIds ?: emptyList() + ) + } + } + + @AssistedFactory + interface Factory { + fun create(initialState: MigrateRoomViewState): MigrateRoomViewModel + } + + companion object : MvRxViewModelFactory { + + override fun create(viewModelContext: ViewModelContext, state: MigrateRoomViewState): MigrateRoomViewModel? { + val factory = when (viewModelContext) { + is FragmentViewModelContext -> viewModelContext.fragment as? Factory + is ActivityViewModelContext -> viewModelContext.activity as? Factory + } + return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface") + } + } + + override fun handle(action: MigrateRoomAction) { + when (action) { + is MigrateRoomAction.SetAutoInvite -> { + setState { + copy(shouldIssueInvites = action.autoInvite) + } + } + is MigrateRoomAction.SetUpdateKnownParentSpace -> { + setState { + copy(shouldUpdateKnownParents = action.update) + } + } + MigrateRoomAction.UpgradeRoom -> { + handleUpgradeRoom(action) + } + } + } + + val upgradingProgress: ((indeterminate: Boolean, progress: Int, total: Int) -> Unit) = { indeterminate, progress, total -> + setState { + copy( + upgradingProgress = progress, + upgradingProgressTotal = total, + upgradingProgressIndeterminate = indeterminate + ) + } + } + + private fun handleUpgradeRoom(action: MigrateRoomAction) = withState { state -> + val summary = session.getRoomSummary(state.roomId) + setState { + copy(upgradingStatus = Loading()) + } + session.coroutineScope.launch { + val result = upgradeRoomViewModelTask.execute(UpgradeRoomViewModelTask.Params( + roomId = state.roomId, + newVersion = state.newVersion, + userIdsToAutoInvite = summary?.otherMemberIds?.takeIf { state.shouldIssueInvites } ?: emptyList(), + parentSpaceToUpdate = summary?.flattenParentIds?.takeIf { state.shouldUpdateKnownParents } ?: emptyList(), + progressReporter = upgradingProgress + )) + + setState { + copy(upgradingStatus = Success(result)) + } + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewState.kt new file mode 100644 index 0000000000..78c280fb10 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewState.kt @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.home.room.detail.upgrade + +import com.airbnb.mvrx.Async +import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.Uninitialized + +data class MigrateRoomViewState( + val roomId: String, + val newVersion: String, + val currentVersion: String? = null, + val isPublic: Boolean = false, + val shouldIssueInvites: Boolean = false, + val shouldUpdateKnownParents: Boolean = false, + val otherMemberCount: Int = 0, + val knownParents: List = emptyList(), + val upgradingStatus: Async = Uninitialized, + val upgradingProgress: Int = 0, + val upgradingProgressTotal: Int = 0, + val upgradingProgressIndeterminate: Boolean = true +) : MvRxState { + constructor(args: MigrateRoomBottomSheet.Args) : this( + roomId = args.roomId, + newVersion = args.newVersion + ) +} diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/UpgradeRoomViewModelTask.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/UpgradeRoomViewModelTask.kt new file mode 100644 index 0000000000..32c8e6ee92 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/UpgradeRoomViewModelTask.kt @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.home.room.detail.upgrade + +import im.vector.app.core.platform.ViewModelTask +import im.vector.app.core.resources.StringProvider +import org.matrix.android.sdk.api.extensions.tryOrNull +import org.matrix.android.sdk.api.session.Session +import timber.log.Timber +import javax.inject.Inject + +class UpgradeRoomViewModelTask @Inject constructor( + val session: Session, + val stringProvider: StringProvider +) : ViewModelTask { + + sealed class Result { + data class Success(val replacementRoomId: String) : Result() + abstract class Failure(val throwable: Throwable?) : Result() + object UnknownRoom : Failure(null) + object NotAllowed : Failure(null) + class ErrorFailure(throwable: Throwable) : Failure(throwable) + } + + data class Params( + val roomId: String, + val newVersion: String, + val userIdsToAutoInvite: List = emptyList(), + val parentSpaceToUpdate: List = emptyList(), + val progressReporter: ((indeterminate: Boolean, progress: Int, total: Int) -> Unit)? = null + ) + + override suspend fun execute(params: Params): Result { + params.progressReporter?.invoke(true, 0, 0) + + val room = session.getRoom(params.roomId) + ?: return Result.UnknownRoom + if (!room.userMayUpgradeRoom(session.myUserId)) { + return Result.NotAllowed + } + + val updatedRoomId = try { + room.upgradeToVersion(params.newVersion) + } catch (failure: Throwable) { + return Result.ErrorFailure(failure) + } + + val totalStep = params.userIdsToAutoInvite.size + params.parentSpaceToUpdate.size + var currentStep = 0 + params.userIdsToAutoInvite.forEach { + params.progressReporter?.invoke(false, currentStep, totalStep) + tryOrNull { + session.getRoom(updatedRoomId)?.invite(it) + } + currentStep++ + } + + params.parentSpaceToUpdate.forEach { parentId -> + params.progressReporter?.invoke(false, currentStep, totalStep) + // we try and silently fail + try { + session.getRoom(parentId)?.asSpace()?.let { parentSpace -> + val currentInfo = parentSpace.getChildInfo(params.roomId) + if (currentInfo != null) { + parentSpace.addChildren( + roomId = updatedRoomId, + viaServers = currentInfo.via, + order = currentInfo.order, + autoJoin = currentInfo.autoJoin ?: false, + suggested = currentInfo.suggested + ) + + parentSpace.removeChildren(params.roomId) + } + } + } catch (failure: Throwable) { + Timber.d("## Migrate: Failed to update space parent. cause: ${failure.localizedMessage}") + } finally { + currentStep++ + } + } + + return Result.Success(updatedRoomId) + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/homeserver/HomeserverSettingsController.kt b/vector/src/main/java/im/vector/app/features/settings/homeserver/HomeserverSettingsController.kt index 3217756a82..37f95b184e 100644 --- a/vector/src/main/java/im/vector/app/features/settings/homeserver/HomeserverSettingsController.kt +++ b/vector/src/main/java/im/vector/app/features/settings/homeserver/HomeserverSettingsController.kt @@ -26,16 +26,20 @@ import im.vector.app.core.epoxy.errorWithRetryItem import im.vector.app.core.epoxy.loadingItem import im.vector.app.core.error.ErrorFormatter import im.vector.app.core.resources.StringProvider +import im.vector.app.core.ui.list.genericWithValueItem import im.vector.app.features.discovery.settingsCenteredImageItem import im.vector.app.features.discovery.settingsInfoItem import im.vector.app.features.discovery.settingsSectionTitleItem +import im.vector.app.features.settings.VectorPreferences import org.matrix.android.sdk.api.federation.FederationVersion import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities +import org.matrix.android.sdk.api.session.homeserver.RoomVersionStatus import javax.inject.Inject class HomeserverSettingsController @Inject constructor( private val stringProvider: StringProvider, - private val errorFormatter: ErrorFormatter + private val errorFormatter: ErrorFormatter, + private val vectorPreferences: VectorPreferences ) : TypedEpoxyController() { var callback: Callback? = null @@ -118,5 +122,36 @@ class HomeserverSettingsController @Inject constructor( helperText(host.stringProvider.getString(R.string.settings_server_upload_size_content, "${limit / 1048576L} MB")) } } + + if (vectorPreferences.developerMode()) { + val roomCapabilities = data.homeServerCapabilities.roomVersions + if (roomCapabilities != null) { + settingsSectionTitleItem { + id("room_versions") + titleResId(R.string.settings_server_room_versions) + } + + genericWithValueItem { + id("room_version_default") + title(host.stringProvider.getString(R.string.settings_server_default_room_version)) + value(roomCapabilities.defaultRoomVersion) + } + + roomCapabilities.supportedVersion.forEach { + genericWithValueItem { + id("room_version_${it.version}") + title(it.version) + value( + host.stringProvider.getString( + when (it.status) { + RoomVersionStatus.STABLE -> R.string.settings_server_room_version_stable + RoomVersionStatus.UNSTABLE -> R.string.settings_server_room_version_unstable + } + ) + ) + } + } + } + } } } diff --git a/vector/src/main/res/layout/bottom_sheet_tombstone_join.xml b/vector/src/main/res/layout/bottom_sheet_tombstone_join.xml new file mode 100644 index 0000000000..3e7fd495a9 --- /dev/null +++ b/vector/src/main/res/layout/bottom_sheet_tombstone_join.xml @@ -0,0 +1,48 @@ + + + + + + + + + + diff --git a/vector/src/main/res/layout/item_generic_progress.xml b/vector/src/main/res/layout/item_generic_progress.xml new file mode 100644 index 0000000000..29ad67efa0 --- /dev/null +++ b/vector/src/main/res/layout/item_generic_progress.xml @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/vector/src/main/res/layout/item_timeline_event_create.xml b/vector/src/main/res/layout/item_timeline_event_create.xml index ea881ccdd0..51da203d10 100644 --- a/vector/src/main/res/layout/item_timeline_event_create.xml +++ b/vector/src/main/res/layout/item_timeline_event_create.xml @@ -10,7 +10,7 @@ style="@style/Widget.Vector.TextView.Body" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginStart="16dp" + android:layout_marginStart="0dp" android:layout_marginTop="16dp" android:layout_marginBottom="16dp" android:background="?vctr_keys_backup_banner_accent_color" @@ -18,7 +18,7 @@ android:gravity="center|start" android:minHeight="80dp" android:padding="16dp" - app:drawableStartCompat="@drawable/error" + app:drawableStartCompat="@drawable/ic_warning_badge" tools:text="This room is continuation…" /> \ No newline at end of file diff --git a/vector/src/main/res/layout/view_notification_area.xml b/vector/src/main/res/layout/view_notification_area.xml index 5e3a79291c..1d30b87aa4 100644 --- a/vector/src/main/res/layout/view_notification_area.xml +++ b/vector/src/main/res/layout/view_notification_area.xml @@ -1,38 +1,34 @@ - - - + android:orientation="horizontal" + android:padding="16dp"> + tools:src="@drawable/ic_warning_badge" /> - \ No newline at end of file + \ No newline at end of file diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 54356db664..9305deb752 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -926,7 +926,7 @@ Resend unsent messages Delete unsent messages File not found - You do not have permission to post to this room + You do not have permission to post to this room. %d new message %d new messages @@ -1820,7 +1820,7 @@ Please enter a username. Please enter your password. - This room has been replaced and is no longer active + This room has been replaced and is no longer active. The conversation continues here This room is a continuation of another conversation Click here to see older messages @@ -2735,6 +2735,11 @@ Server file upload limit Your homeserver accepts attachments (files, media, etc.) with a size up to %s. The limit is unknown. + + Room Versions 🕶 + Default Version + stable + unstable No cryptographic information available @@ -3295,6 +3300,7 @@ Create a Space Join the Space with the given id Leave room with given id (or current room if null) + Upgrades a room to a new version Sending Sent @@ -3406,4 +3412,19 @@ "Teammate spaces aren’t quite ready but you can still give them a try" "At the moment people might not be able to join any private rooms you make.\n\nWe’ll be improving this as part of the beta, but just wanted to let you know." - + + Join replacement room + Please be patient, it may take some time. + + + Upgrade + Upgrade public room + Upgrade private room + Upgrading a room is an advanced action and is usually recommended when a room is unstable due to bugs, missing features or security vulnerabilities.\nThis usually only affects how the room is processed on the server. + You\'ll upgrade this room from %s to %s. + Automatically invite users + Automatically update space parent + Automatically update parent space + You need permission to upgrade a room + + From 13ec7a500a4468ff4bf38beb17b6cf43ffaa65a4 Mon Sep 17 00:00:00 2001 From: Ridhubharan Date: Tue, 22 Jun 2021 17:31:49 +0000 Subject: [PATCH 27/95] Added translation using Weblate (Tamil) --- vector/src/main/res/values-ta/strings.xml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 vector/src/main/res/values-ta/strings.xml diff --git a/vector/src/main/res/values-ta/strings.xml b/vector/src/main/res/values-ta/strings.xml new file mode 100644 index 0000000000..a6b3daec93 --- /dev/null +++ b/vector/src/main/res/values-ta/strings.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file From 3b31f3956c3cb2cfa04c0bc49c64f8a948db33b0 Mon Sep 17 00:00:00 2001 From: libexus Date: Mon, 21 Jun 2021 18:01:18 +0000 Subject: [PATCH 28/95] Translated using Weblate (German) Currently translated at 99.9% (2488 of 2490 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/de/ --- vector/src/main/res/values-de/strings.xml | 66 ++++++++++++----------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/vector/src/main/res/values-de/strings.xml b/vector/src/main/res/values-de/strings.xml index faff212373..6b8aa1c07e 100644 --- a/vector/src/main/res/values-de/strings.xml +++ b/vector/src/main/res/values-de/strings.xml @@ -511,7 +511,7 @@ Vorschau Ablehnen - Zur ersten ungelesenen Nachricht springen. + Zur ersten ungelesenen Nachricht Du wurdest von %s in diesen Raum eingeladen Diese Einladung wurde an %s gesendet, welche nicht mit diesem Konto verknüpft ist. @@ -650,9 +650,9 @@ Benachrichtigungen für diesen Account aktivieren Benachrichtigungen für diese Sitzung aktivieren Bildschirm für 3 Sekunden aktivieren - Nachrichten in direkten Chats - Nachrichten in Gruppen-Chats - Wenn ich in einen Raum eingeladen werde + Direktnachrichten + Gruppenchats + Einladungen Anrufe Nachrichten von Bots Hintergrundsynchronisierung @@ -797,7 +797,7 @@ Sitzungsschlüssel Verifizierungsstatus Ed25519-Fingerabdruck - Ende-zu-Ende-Verschlüsselungs-Raumschlüssel exportieren + Ende-zu-Ende-Raumschlüssel exportieren Raumschlüssel exportieren Schlüssel in lokale Datei exportieren Exportieren @@ -877,7 +877,7 @@ Du hast keine Berechtigung, diese Aktion in diesem Raum auszuführen. Anfrage beinhaltet keine Raum-ID. Raum %s ist nicht sichtbar. - Matrix-Apps hinzufügen + Integrationen hinzufügen Benachrichtigungston Anfrage konnte nicht gesendet werden. Anfrage enthält keine user_id. @@ -887,7 +887,7 @@ Synchronisiere… Auf Ereignisse lauschen Nachrichten mit meinem Anzeigenamen - Nachrichten, die meinen Benutzernamen enthalten + Nachrichten mit meinen Benutzernamen Du hast die neue Sitzung \'%s\' hinzugefügt, die jetzt Verschlüsselungs-Schlüssel anfordert. Deine bislang nicht verifiziertes Sitzung \'%s\' fordert Verschlüsselungs-Schlüssel an. Verifizierung beginnen @@ -1028,7 +1028,7 @@ \n \nMöchtest du welche hinzufügen\? Account deaktivieren - Deaktiviere meinen Account + Meinen Account deaktivieren Sende Analysedaten ${app_name} sammelt anonyme Analysedaten um uns zu helfen, die App zu verbessern. Bitte aktive Analysedaten um uns zu helfen ${app_name} zu verbessern. @@ -1150,11 +1150,11 @@ Entfernen Grund Linkvorschau im Chat aktivieren, falls dein Home-Server diese Funktion unterstützt. - Sende Schreibbenachrichtigungen + Schreibbenachrichtigungen senden Lasse andere Benutzer wissen, dass du tippst. Markdown-Formatierung Formatiere Nachrichten mittels Markdown-Syntax, bevor sie gesendet werden. Dies erlaubt erweiterte Formatierungen, etwa Sternchen (*) um kursiven Text anzuzeigen. - Zeige Lesebestätigungen + Lesebestätigungen zeigen Klicke auf die Lesebestätigungen für eine detailliertere Liste. Einladungen, Kicks und Banns bleiben unberührt. Passwort @@ -1223,7 +1223,7 @@ Einschränkungen deaktivieren Batterieoptimierung ${app_name} wird nicht von Batterieoptimierungen beeinflusst. - Fehler bei Benachrichtigungen finden + Benachrichtigungsprobleme finden Diagnose von Fehlern Basisdiagnose ist OK. Wenn du immer noch keine Benachrichtigungen bekommst, sende bitte einen Fehlerbericht, um uns beim Nachforschen zu helfen. Prüfung der Play-Dienste @@ -1254,8 +1254,8 @@ Konto hinzufügen Laute Benachrichtigungen einstellen Anrufbenachrichtigung einstellen - Lautlose Benachrichtigungen einstellen - Wähle LED-Farbe, Vibration, Ton… + Stumme Benachrichtigungen einstellen + LED-Farbe, Vibration und Ton wählen Stumm Bitte eine Passphrase eingeben Passphrase ist zu schwach @@ -1391,7 +1391,7 @@ Mit Single-Sign-On anmelden Diese URL ist nicht erreichbar, bitte prüfen Dein Gerät nutzt eine veraltetes TLS-Sicherheitsprotokoll, das anfällig für Angriffe ist. Zu deiner Sicherheit wirst du nicht in der Lage sein, dich zu verbinden - Schicke Nachricht mit Eingabetaste + Nachricht mit Eingabetaste senden Eingabetaste der Bildschirmtastatur schickt die Nachricht ab, statt einen Zeilenumbruch zu erzeugen Passwort aktualisieren Das Passwort ist ungültig @@ -1569,7 +1569,7 @@ Kannst du nicht finden, wonach du suchst\? Erstelle einen neuen Raum Name oder ID (#beispiel:matrix.org) - Aktiviere Wischen, um in der Zeitleiste zu antworten + Wischen, um in der Zeitleiste zu antworten Kein Ergebnis gefunden. Verwende \'Mit Matrix-ID hinzufügen\', um auf dem Server zu suchen. Beginne mit der Eingabe, um Ergebnisse zu erhalten Filtern nach Benutzername oder ID… @@ -1638,7 +1638,7 @@ Integrationen Benutze einen Integrations-Manager um Bots, Brücken, Widgets und Sticker-Pakete zu verwalten. \nIntegrations-Manager erhalten Konfigurationsdaten und können Widgets verändern, Raum-Einladungen senden und in deinem Namen Berechtigungslevel setzen. - Erlaube Integrationen + Integrationen erlauben Widget Widget laden Dieses Widget wurde hinzugefügt von: @@ -1659,7 +1659,7 @@ Mikrofon benutzen Lese DRM-geschützte Medien Du wirst nicht über eingehende Nachrichten benachrichtigt, wenn die App im Hintergrund ist. - Verwalte deine Erkennungseinstellungen. + Erkennungseinstellungen verwalten. Zugriff für mich zurückziehen Sitzungsname: Format: @@ -2101,8 +2101,8 @@ Speichere ihn auf einem USB-Stick oder auf einem Sicherungslaufwerk Import der Schlüssel fehlgeschlagen Benachrichtigungskonfiguration - Nachrichten, die @raum enthalten - Verschlüsselte Nachrichten in Gruppenchats + Nachrichten mit \"@room\" + Verschlüsselte Gruppenchats Setze die Benachrichtigungspräferenz abhängig vom Ereignistyp Sendet eine Nachricht als einfachen Text, ohne sie als Markdown zu interpretieren Inkorrekter Benutzername und/oder Passwort. Das eingegebene Passwort beginnt oder endet mit Leerzeichen, bitte kontrolliere es. @@ -2113,7 +2113,7 @@ Kopier es in deinen persönlichen Cloud-Speicher Verschlüsselung ist nicht aktiviert Dies kann nicht von einem mobilen Gerät erfolgen - Wenn Räume verbessert werden + Raumupgrades Verschlüsselung aktiviert Nachrichten in diesem Raum sind Ende-zu-Ende-verschlüsselt. Erfahre mehr & verifiziere Benutzer in deren Profil. Die Verschlüsselung in diesem Raum wird nicht unterstützt @@ -2123,7 +2123,7 @@ %s hat den Raum erstellt und konfiguriert. Fast geschafft! Zeigt das andere Gerät das gleiche Schild an\? Fast geschafft! Warte auf Bestätigung… - Verschlüsselte Nachrichten in 1:1 Chats + Verschlüsselte Direktnachrichten Nachricht… Verifiziere dich & andere, um eure Chats zu schützen Gib zum Fortfahren deinen %s ein @@ -2150,7 +2150,7 @@ nutze deinen Schlüsselbackup-Wiederherstellungsschlüssel Wenn du dein Schlüsselbackup-Passwort nicht weißt, kannst du %s. Schlüsselbackup-Wiederherstellungsschlüssel - Verhindere Screenshots innerhalb der Anwendung + Screenshots innerhalb der Anwendung verhindern Das Aktivieren dieser Einstellung setzt das FLAG_SECURE in allen Aktivitäten. Starte die Anwendung neu, damit die Änderung wirksam wird. Datei wurde der Galerie hinzugefügt Datei konnte nicht zur Galerie hinzugefügt werden @@ -2381,7 +2381,7 @@ Aktiviere PIN Wenn du deine PIN zurücksetzen möchtest, tippe \"PIN vergessen\" um dich abzumelden und sie anschließend zurückzusetzen. Bestätige PIN um die PIN zu deaktivieren - Verhindere versehentliche Anrufe + Versehentliche Anrufe verhindern Bitte um Bestätigung, bevor du einen Anruf tätigst Einrichten Dir fehlt die Berechtigung in diesem Raum eine Konferenz zu starten @@ -2397,7 +2397,7 @@ %1$d/%2$d Schlüssel erfolgreich importiert. %1$d/%2$d Schlüssel erfolgreich importiert. - Verwalte Integrationen + Integrationen verwalten Keine aktiven Widgets Der Raum wurde erstellt, aber manche Einladungen wurden aus folgendem Grund nicht versendet: \n @@ -2456,7 +2456,7 @@ Aktiviere Gerät-spezifische Biometrie wie Fingerabdrücke und Gesichtserkennung. Biometrie aktivieren Schutz konfigurieren - Zugriff schützen + Zugriffsschutz Schütze den Zugriff mit PIN und Biometrie. Zeigen das Gerät, mit dem du jetzt überprüfen kannst @@ -2556,7 +2556,7 @@ Hey, schreibe mit mir auf ${app_name}: %s Freunde einladen Leute hinzufügen - "Thema " + "Thema: " Füge ein Thema hinzu %s, um zu zeigen um was es in diesem Raum geht. Das ist der Anfang deiner Direktnachrichten mit %s. @@ -2629,7 +2629,7 @@ Knopf zum Nachrichteneditor hinzufügen, der die Emoji-Tastatur öffnet Emoji-Tastatur anzeigen Nutze /confetti Kommando oder sende Nachrichten, die ❄️ oder 🎉 enthalten - Chat-Effekte zeigen + Chateffekte Thema ändern Raum aktualisieren Rollen, die zum Ändern verschiedener Teile des Raums erforderlich sind, auswählen @@ -2642,8 +2642,8 @@ Cross-Signing konnte nicht eingerichtet werden Nicht autorisierte, fehlende gültige Authentifizierungsdaten Nutzer - Beim Übertragen des Anrufs ist ein Fehler aufgetreten - Übertragen + Beim Weiterleiten des Anrufs ist ein Fehler aufgetreten + Weiterleiten Verbinden 1 aktiver Anruf (%1$s) · 1 pausierter Anruf @@ -2735,7 +2735,7 @@ Senden der Nachricht gescheitert Wird gesendet Nachricht gesendet - Zuerst nachfragen + Zuerst anfragen Privat Öffentlich Du kannst dies später ändern @@ -2755,9 +2755,9 @@ Diese werden kein Teil von %s sein Tritt meinem Space %1$s %2$s bei Willkommen zu %1$s, %2$s. - Warnung benötigt Server Unterstützung und eine experimentelle Raumversion + Warnung: benötigt Server-Unterstützung und eine experimentelle Raumversion Experimenteller Space - Zugangsbeschränkter Raum. - Mit Spaces hast du die Möglichkeit Personen und Räume zu gruppieren. + Mit Spaces kannst du Personen und Räume zu gruppieren. Sag hallo zu Spaces! Füge bereits existierende Räume und Spaces hinzu Vorübergehend überspringen @@ -2871,4 +2871,6 @@ \nDies werden wir demnächst als Teil der Beta verbessern, wir wollten aber sicherstellen, dass du bescheid weißt. Team-Spaces sind noch nicht fertig entwickelt, du kannst sie aber schon testen Trotzdem fortfahren + Bei %1$s anfragen + Zu %1$s weiterleiten \ No newline at end of file From 25b954767830c546ab712af6ed5101b96a698537 Mon Sep 17 00:00:00 2001 From: Thor Arne Johansen Date: Tue, 22 Jun 2021 13:35:05 +0000 Subject: [PATCH 29/95] =?UTF-8?q?Translated=20using=20Weblate=20(Norwegian?= =?UTF-8?q?=20Bokm=C3=A5l)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 62.8% (1564 of 2490 strings) Translation: Element Android/Element Android App Translate-URL: https://translate.element.io/projects/element-android/element-app/nb_NO/ --- vector/src/main/res/values-nb-rNO/strings.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/vector/src/main/res/values-nb-rNO/strings.xml b/vector/src/main/res/values-nb-rNO/strings.xml index 827c7ceaae..bf220237da 100644 --- a/vector/src/main/res/values-nb-rNO/strings.xml +++ b/vector/src/main/res/values-nb-rNO/strings.xml @@ -140,7 +140,7 @@ Ignorer Folk Filer - Instillinger + Innstillinger BLE MED Avbryt opplastning Avbryt nedlasting @@ -318,7 +318,7 @@ Lyd Galleri Demp - Instillinger + Innstillinger Lær mer Annet Fortsett @@ -349,7 +349,7 @@ Logg på Logg på Passord - Instillinger + Innstillinger Gjeldende økt Føyer til ¯\\_(ツ)_/¯ på en råtekstmelding Video. @@ -897,13 +897,13 @@ Denne hjemmetjeneren vil vite om du er en robot Registrering med e-post og telefonummer samtidig fungerer ikke enda. Bare telefonummeret kommer til å bli registrert. \n -\nDu kan legge e-postadressen din til i instillinger. - Bruk egendefinerte tjenerinstillinger (avansert) +\nDu kan legge e-postadressen din til i innstillinger. + Bruk egendefinerte tjenerinnstillinger (avansert) Klarte ikke å starte en sanntidskopling. \nVennligst be hjemmetjeneradministratoren din om å sette opp en TURN server så samtaler blir mer stabile. Vennligst be administratoren for hjemmetjeneren din (%1$s) til å sette opp en TURN tjener for at telefonsamtaler skal fungere ordentlig. \n -\nAlternativt kan du prøve å bruke den offentlige tjeneren på %2$s, men dette vil ikke være like stabilt, og det vil dele IP-adressen din med den serveren. Du kan styre dette i instillinger. +\nAlternativt kan du prøve å bruke den offentlige tjeneren på %2$s, men dette vil ikke være like stabilt, og det vil dele IP-adressen din med den serveren. Du kan styre dette i innstillinger. E-postkoblingen som ikke er klikket på ennå Dette brukernavnet er allerede brukt Inneholdt ikke gyldig JSON From 57c75f80399e0f4bb1ba24c9b08c0eede3fc5b26 Mon Sep 17 00:00:00 2001 From: Valere Date: Thu, 24 Jun 2021 09:38:20 +0200 Subject: [PATCH 30/95] Ugrade unstable room notice in settings default update parent, clean migrate bottomsheet layout --- .../room/version/RoomVersionService.kt | 5 +- .../internal/session/room/RoomUpgradeBody.kt | 2 +- .../session/room/RoomUpgradeResponse.kt | 2 +- .../room/version/DefaultRoomVersionService.kt | 17 ++- .../room/version/RoomVersionUpgradeTask.kt | 2 +- tools/check/forbidden_strings_in_code.txt | 2 +- .../app/features/command/CommandParser.kt | 6 +- .../detail/upgrade/MigrateRoomBottomSheet.kt | 112 +++++++++------ .../detail/upgrade/MigrateRoomController.kt | 135 ------------------ .../detail/upgrade/MigrateRoomViewState.kt | 2 +- .../roomprofile/RoomProfileController.kt | 28 +++- .../roomprofile/RoomProfileFragment.kt | 6 + .../roomprofile/RoomProfileViewModel.kt | 12 +- .../roomprofile/RoomProfileViewState.kt | 6 +- .../res/layout/bottom_sheet_generic_list.xml | 1 + .../res/layout/bottom_sheet_room_upgrade.xml | 90 ++++++++++++ vector/src/main/res/values/strings.xml | 3 + 17 files changed, 239 insertions(+), 192 deletions(-) delete mode 100644 vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomController.kt create mode 100644 vector/src/main/res/layout/bottom_sheet_room_upgrade.xml diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/version/RoomVersionService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/version/RoomVersionService.kt index a90e1343f2..08dd955394 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/version/RoomVersionService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/version/RoomVersionService.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 New Vector Ltd + * Copyright 2021 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,7 +26,8 @@ interface RoomVersionService { */ suspend fun upgradeToVersion(version: String): String - suspend fun getRecommendedVersion() : String + fun getRecommendedVersion() : String fun userMayUpgradeRoom(userId: String): Boolean + fun isUsingUnstableRoomVersion(): Boolean } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomUpgradeBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomUpgradeBody.kt index feefbe5f66..4629f6e409 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomUpgradeBody.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomUpgradeBody.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 New Vector Ltd + * Copyright 2021 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomUpgradeResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomUpgradeResponse.kt index 16e95194a3..1cca2c572b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomUpgradeResponse.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomUpgradeResponse.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 New Vector Ltd + * Copyright 2021 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/version/DefaultRoomVersionService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/version/DefaultRoomVersionService.kt index 1b5d62926e..9d253e8b1c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/version/DefaultRoomVersionService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/version/DefaultRoomVersionService.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 New Vector Ltd + * Copyright 2021 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import io.realm.Realm import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.homeserver.RoomVersionStatus import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper @@ -63,7 +64,7 @@ internal class DefaultRoomVersionService @AssistedInject constructor( ) } - override suspend fun getRecommendedVersion(): String { + override fun getRecommendedVersion(): String { return Realm.getInstance(monarchy.realmConfiguration).use { realm -> HomeServerCapabilitiesEntity.get(realm)?.let { HomeServerCapabilitiesMapper.map(it) @@ -71,6 +72,18 @@ internal class DefaultRoomVersionService @AssistedInject constructor( } } + override fun isUsingUnstableRoomVersion(): Boolean { + var isUsingUnstable: Boolean + Realm.getInstance(monarchy.realmConfiguration).use { realm -> + val versionCaps = HomeServerCapabilitiesEntity.get(realm)?.let { + HomeServerCapabilitiesMapper.map(it) + }?.roomVersions + val currentVersion = getRoomVersion() + isUsingUnstable = versionCaps?.supportedVersion?.firstOrNull { it.version == currentVersion }?.status == RoomVersionStatus.UNSTABLE + } + return isUsingUnstable + } + override fun userMayUpgradeRoom(userId: String): Boolean { val powerLevelsHelper = stateEventDataSource.getStateEvent(roomId, EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition) ?.content?.toModel() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/version/RoomVersionUpgradeTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/version/RoomVersionUpgradeTask.kt index 444795b5a9..457bb3e948 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/version/RoomVersionUpgradeTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/version/RoomVersionUpgradeTask.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 New Vector Ltd + * Copyright 2021 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/tools/check/forbidden_strings_in_code.txt b/tools/check/forbidden_strings_in_code.txt index e0645e00b3..ba9dec0877 100644 --- a/tools/check/forbidden_strings_in_code.txt +++ b/tools/check/forbidden_strings_in_code.txt @@ -162,7 +162,7 @@ Formatter\.formatShortFileSize===1 # android\.text\.TextUtils ### This is not a rule, but a warning: the number of "enum class" has changed. For Json classes, it is mandatory that they have `@JsonClass(generateAdapter = false)`. If the enum is not used as a Json class, change the value in file forbidden_strings_in_code.txt -enum class===101 +enum class===102 ### Do not import temporary legacy classes import org.matrix.android.sdk.internal.legacy.riot===3 diff --git a/vector/src/main/java/im/vector/app/features/command/CommandParser.kt b/vector/src/main/java/im/vector/app/features/command/CommandParser.kt index 224956049c..adba6e4a18 100644 --- a/vector/src/main/java/im/vector/app/features/command/CommandParser.kt +++ b/vector/src/main/java/im/vector/app/features/command/CommandParser.kt @@ -332,7 +332,11 @@ object CommandParser { } Command.UPGRADE_ROOM.command -> { val newVersion = textMessage.substring(Command.UPGRADE_ROOM.command.length).trim() - ParsedCommand.UpgradeRoom(newVersion) + if (newVersion.isEmpty()) { + ParsedCommand.ErrorSyntax(Command.UPGRADE_ROOM) + } else { + ParsedCommand.UpgradeRoom(newVersion) + } } else -> { // Unknown command diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomBottomSheet.kt index 12a0fb222b..0de905d059 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomBottomSheet.kt @@ -21,22 +21,24 @@ import android.os.Parcelable import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.view.isVisible import androidx.fragment.app.setFragmentResult -import com.airbnb.epoxy.OnModelBuildFinishedListener +import com.airbnb.mvrx.Loading import com.airbnb.mvrx.Success import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState +import im.vector.app.R import im.vector.app.core.di.ScreenComponent -import im.vector.app.core.extensions.cleanup -import im.vector.app.core.extensions.configureWith +import im.vector.app.core.error.ErrorFormatter +import im.vector.app.core.extensions.setTextOrHide import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment -import im.vector.app.databinding.BottomSheetGenericListBinding +import im.vector.app.databinding.BottomSheetRoomUpgradeBinding import kotlinx.parcelize.Parcelize import javax.inject.Inject class MigrateRoomBottomSheet : - VectorBaseBottomSheetDialogFragment(), - MigrateRoomViewModel.Factory, MigrateRoomController.InteractionListener { + VectorBaseBottomSheetDialogFragment(), + MigrateRoomViewModel.Factory { @Parcelize data class Args( @@ -50,7 +52,7 @@ class MigrateRoomBottomSheet : override val showExpanded = true @Inject - lateinit var epoxyController: MigrateRoomController + lateinit var errorFormatter: ErrorFormatter val viewModel: MigrateRoomViewModel by fragmentViewModel() @@ -58,41 +60,79 @@ class MigrateRoomBottomSheet : injector.inject(this) } - override fun getBinding(inflater: LayoutInflater, container: ViewGroup?) = - BottomSheetGenericListBinding.inflate(inflater, container, false) - override fun invalidate() = withState(viewModel) { state -> - epoxyController.setData(state) - super.invalidate() - when (val result = state.upgradingStatus) { + views.headerText.setText(if (state.isPublic) R.string.upgrade_public_room else R.string.upgrade_private_room) + views.upgradeFromTo.text = getString(R.string.upgrade_public_room_from_to, state.currentVersion, state.newVersion) + + views.autoInviteSwitch.isVisible = !state.isPublic && state.otherMemberCount > 0 + + views.autoUpdateParent.isVisible = state.knownParents.isNotEmpty() + + when (state.upgradingStatus) { + is Loading -> { + views.progressBar.isVisible = true + views.progressBar.isIndeterminate = state.upgradingProgressIndeterminate + views.progressBar.progress = state.upgradingProgress + views.progressBar.max = state.upgradingProgressTotal + views.inlineError.setTextOrHide(null) + views.button.isVisible = false + } is Success -> { - val result = result.invoke() - if (result is UpgradeRoomViewModelTask.Result.Success) { - setFragmentResult(REQUEST_KEY, Bundle().apply { - putString(BUNDLE_KEY_REPLACEMENT_ROOM, result.replacementRoomId) - }) - dismiss() + views.progressBar.isVisible = false + when (val result = state.upgradingStatus.invoke()) { + is UpgradeRoomViewModelTask.Result.Failure -> { + val errorText = when (result) { + is UpgradeRoomViewModelTask.Result.UnknownRoom -> { + // should not happen + getString(R.string.unknown_error) + } + is UpgradeRoomViewModelTask.Result.NotAllowed -> { + getString(R.string.upgrade_room_no_power_to_manage) + } + is UpgradeRoomViewModelTask.Result.ErrorFailure -> { + errorFormatter.toHumanReadable(result.throwable) + } + else -> null + } + views.inlineError.setTextOrHide(errorText) + views.button.isVisible = true + views.button.text = getString(R.string.global_retry) + } + is UpgradeRoomViewModelTask.Result.Success -> { + setFragmentResult(REQUEST_KEY, Bundle().apply { + putString(BUNDLE_KEY_REPLACEMENT_ROOM, result.replacementRoomId) + }) + dismiss() + } } } + else -> { + views.button.isVisible = true + views.button.text = getString(R.string.upgrade) + } } + + super.invalidate() } - val postBuild = OnModelBuildFinishedListener { - view?.post { forceExpandState() } - } + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?) = + BottomSheetRoomUpgradeBinding.inflate(inflater, container, false) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - epoxyController.callback = this - views.bottomSheetRecyclerView.configureWith(epoxyController) - epoxyController.addModelBuildListener(postBuild) - } - override fun onDestroyView() { - views.bottomSheetRecyclerView.cleanup() - epoxyController.removeModelBuildListener(postBuild) - super.onDestroyView() + views.button.debouncedClicks { + viewModel.handle(MigrateRoomAction.UpgradeRoom) + } + + views.autoInviteSwitch.setOnCheckedChangeListener { _, isChecked -> + viewModel.handle(MigrateRoomAction.SetAutoInvite(isChecked)) + } + + views.autoUpdateParent.setOnCheckedChangeListener { _, isChecked -> + viewModel.handle(MigrateRoomAction.SetUpdateKnownParentSpace(isChecked)) + } } override fun create(initialState: MigrateRoomViewState): MigrateRoomViewModel { @@ -111,16 +151,4 @@ class MigrateRoomBottomSheet : } } } - - override fun onAutoInvite(autoInvite: Boolean) { - viewModel.handle(MigrateRoomAction.SetAutoInvite(autoInvite)) - } - - override fun onAutoUpdateParent(update: Boolean) { - viewModel.handle(MigrateRoomAction.SetUpdateKnownParentSpace(update)) - } - - override fun onConfirmUpgrade() { - viewModel.handle(MigrateRoomAction.UpgradeRoom) - } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomController.kt deleted file mode 100644 index 8d037860d2..0000000000 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomController.kt +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2021 New Vector Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package im.vector.app.features.home.room.detail.upgrade - -import com.airbnb.epoxy.TypedEpoxyController -import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.Success -import im.vector.app.R -import im.vector.app.core.epoxy.errorWithRetryItem -import im.vector.app.core.error.ErrorFormatter -import im.vector.app.core.resources.StringProvider -import im.vector.app.core.ui.bottomsheet.bottomSheetTitleItem -import im.vector.app.core.ui.list.ItemStyle -import im.vector.app.core.ui.list.genericFooterItem -import im.vector.app.core.ui.list.genericProgressBarItem -import im.vector.app.features.form.formSubmitButtonItem -import im.vector.app.features.form.formSwitchItem -import javax.inject.Inject - -class MigrateRoomController @Inject constructor( - private val stringProvider: StringProvider, - private val errorFormatter: ErrorFormatter -) : TypedEpoxyController() { - - interface InteractionListener { - fun onAutoInvite(autoInvite: Boolean) - fun onAutoUpdateParent(update: Boolean) - fun onConfirmUpgrade() - } - - var callback: InteractionListener? = null - - override fun buildModels(data: MigrateRoomViewState?) { - data ?: return - - val host = this@MigrateRoomController - - bottomSheetTitleItem { - id("title") - title( - host.stringProvider.getString(if (data.isPublic) R.string.upgrade_public_room else R.string.upgrade_private_room) - ) - } - - genericFooterItem { - id("warning_text") - centered(false) - style(ItemStyle.NORMAL_TEXT) - text(host.stringProvider.getString(R.string.upgrade_room_warning)) - } - - genericFooterItem { - id("from_to_room") - centered(false) - style(ItemStyle.NORMAL_TEXT) - text(host.stringProvider.getString(R.string.upgrade_public_room_from_to, data.currentVersion, data.newVersion)) - } - - if (!data.isPublic && data.otherMemberCount > 0) { - formSwitchItem { - id("auto_invite") - switchChecked(data.shouldIssueInvites) - title(host.stringProvider.getString(R.string.upgrade_room_auto_invite)) - listener { switch -> host.callback?.onAutoInvite(switch) } - } - } - - if (data.knownParents.isNotEmpty()) { - formSwitchItem { - id("update_parent") - switchChecked(data.shouldUpdateKnownParents) - title(host.stringProvider.getString(R.string.upgrade_room_update_parent)) - listener { switch -> host.callback?.onAutoUpdateParent(switch) } - } - } - when (data.upgradingStatus) { - is Loading -> { - genericProgressBarItem { - id("upgrade_progress") - indeterminate(data.upgradingProgressIndeterminate) - progress(data.upgradingProgress) - total(data.upgradingProgressTotal) - } - } - is Success -> { - when (val result = data.upgradingStatus.invoke()) { - is UpgradeRoomViewModelTask.Result.Failure -> { - val errorText = when (result) { - is UpgradeRoomViewModelTask.Result.UnknownRoom -> { - // should not happen - host.stringProvider.getString(R.string.unknown_error) - } - is UpgradeRoomViewModelTask.Result.NotAllowed -> { - host.stringProvider.getString(R.string.upgrade_room_no_power_to_manage) - } - is UpgradeRoomViewModelTask.Result.ErrorFailure -> { - host.errorFormatter.toHumanReadable(result.throwable) - } - else -> null - } - errorWithRetryItem { - id("error") - text(errorText) - listener { host.callback?.onConfirmUpgrade() } - } - } - is UpgradeRoomViewModelTask.Result.Success -> { - // nop, dismisses - } - } - } - else -> { - formSubmitButtonItem { - id("migrate") - buttonTitleId(R.string.upgrade) - buttonClickListener { host.callback?.onConfirmUpgrade() } - } - } - } - } -} diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewState.kt index 78c280fb10..e3936de42f 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewState.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewState.kt @@ -26,7 +26,7 @@ data class MigrateRoomViewState( val currentVersion: String? = null, val isPublic: Boolean = false, val shouldIssueInvites: Boolean = false, - val shouldUpdateKnownParents: Boolean = false, + val shouldUpdateKnownParents: Boolean = true, val otherMemberCount: Int = 0, val knownParents: List = emptyList(), val upgradingStatus: Async = Uninitialized, diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileController.kt index aa2db348c8..106062f7b3 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileController.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileController.kt @@ -22,8 +22,10 @@ import im.vector.app.R import im.vector.app.core.epoxy.expandableTextItem import im.vector.app.core.epoxy.profiles.buildProfileAction import im.vector.app.core.epoxy.profiles.buildProfileSection +import im.vector.app.core.resources.ColorProvider import im.vector.app.core.resources.StringProvider import im.vector.app.core.ui.list.genericFooterItem +import im.vector.app.core.ui.list.genericPositiveButtonItem import im.vector.app.features.home.ShortcutCreator import im.vector.app.features.home.room.detail.timeline.TimelineEventController import im.vector.app.features.home.room.detail.timeline.tools.createLinkMovementMethod @@ -34,6 +36,7 @@ import javax.inject.Inject class RoomProfileController @Inject constructor( private val stringProvider: StringProvider, + private val colorProvider: ColorProvider, private val vectorPreferences: VectorPreferences, private val shortcutCreator: ShortcutCreator ) : TypedEpoxyController() { @@ -55,6 +58,7 @@ class RoomProfileController @Inject constructor( fun onRoomIdClicked() fun onRoomDevToolsClicked() fun onUrlInTopicLongClicked(url: String) + fun doMigrateToVersion(newVersion: String) } override fun buildModels(data: RoomProfileViewState?) { @@ -87,6 +91,28 @@ class RoomProfileController @Inject constructor( // Security buildProfileSection(stringProvider.getString(R.string.room_profile_section_security)) + + // Upgrade warning + val roomVersion = data.roomCreateContent()?.roomVersion + if (data.canUpgradeRoom + && !data.isTombstoned + && roomVersion != null + && data.isUsingUnstableRoomVersion + && data.recommendedRoomVersion != null) { + genericFooterItem { + id("version_warning") + text(host.stringProvider.getString(R.string.room_using_unstable_room_version, roomVersion)) + textColor(host.colorProvider.getColorFromAttribute(R.attr.colorError)) + centered(false) + } + + genericPositiveButtonItem { + id("migrate_button") + text(host.stringProvider.getString(R.string.room_upgrade_to_recommened_version)) + buttonClickAction { host.callback?.doMigrateToVersion(data.recommendedRoomVersion) } + } + } + val learnMoreSubtitle = if (roomSummary.isEncrypted) { if (roomSummary.isDirect) R.string.direct_room_profile_encrypted_subtitle else R.string.room_profile_encrypted_subtitle } else { @@ -194,7 +220,7 @@ class RoomProfileController @Inject constructor( editable = false, action = { callback?.onRoomIdClicked() } ) - data.roomCreateContent()?.roomVersion?.let { + roomVersion?.let { buildProfileAction( id = "roomVersion", title = stringProvider.getString(R.string.room_settings_room_version_title), diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt index f9324ad3e2..8a10bcc842 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt @@ -45,6 +45,7 @@ import im.vector.app.core.utils.startSharePlainTextIntent import im.vector.app.databinding.FragmentMatrixProfileBinding import im.vector.app.databinding.ViewStubRoomProfileHeaderBinding import im.vector.app.features.home.AvatarRenderer +import im.vector.app.features.home.room.detail.upgrade.MigrateRoomBottomSheet import im.vector.app.features.home.room.list.actions.RoomListActionsArgs import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedAction @@ -303,6 +304,11 @@ class RoomProfileFragment @Inject constructor( copyToClipboard(requireContext(), url, true) } + override fun doMigrateToVersion(newVersion: String) { + MigrateRoomBottomSheet.newInstance(roomProfileArgs.roomId, newVersion) + .show(parentFragmentManager, "migrate") + } + private fun onShareRoomProfile(permalink: String) { startSharePlainTextIntent( fragment = this, diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt index 209ebcc35b..9fee87880a 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt @@ -22,8 +22,8 @@ import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted -import dagger.assisted.AssistedInject import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject import im.vector.app.R import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel @@ -81,8 +81,14 @@ class RoomProfileViewModel @AssistedInject constructor( rxRoom.liveStateEvent(EventType.STATE_ROOM_CREATE, QueryStringValue.NoCondition) .mapOptional { it.content.toModel() } .unwrap() - .execute { - copy(roomCreateContent = it) + .execute { async -> + copy( + roomCreateContent = async, + recommendedRoomVersion = room.getRecommendedVersion(), + isUsingUnstableRoomVersion = room.isUsingUnstableRoomVersion(), + canUpgradeRoom = room.userMayUpgradeRoom(session.myUserId), + isTombstoned = room.getStateEvent(EventType.STATE_ROOM_TOMBSTONE) != null + ) } } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewState.kt index bf7cd732ef..999b6540bd 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewState.kt @@ -30,7 +30,11 @@ data class RoomProfileViewState( val roomCreateContent: Async = Uninitialized, val bannedMembership: Async> = Uninitialized, val actionPermissions: ActionPermissions = ActionPermissions(), - val isLoading: Boolean = false + val isLoading: Boolean = false, + val isUsingUnstableRoomVersion: Boolean = false, + val recommendedRoomVersion: String? = null, + val canUpgradeRoom: Boolean = false, + val isTombstoned: Boolean = false ) : MvRxState { constructor(args: RoomProfileArgs) : this(roomId = args.roomId) diff --git a/vector/src/main/res/layout/bottom_sheet_generic_list.xml b/vector/src/main/res/layout/bottom_sheet_generic_list.xml index 87a2cb54fc..966ad48b25 100644 --- a/vector/src/main/res/layout/bottom_sheet_generic_list.xml +++ b/vector/src/main/res/layout/bottom_sheet_generic_list.xml @@ -6,6 +6,7 @@ android:layout_height="match_parent" android:background="?colorSurface" android:fadeScrollbars="false" + android:nestedScrollingEnabled="false" android:scrollbars="vertical" tools:itemCount="5" tools:listitem="@layout/item_bottom_sheet_action" /> diff --git a/vector/src/main/res/layout/bottom_sheet_room_upgrade.xml b/vector/src/main/res/layout/bottom_sheet_room_upgrade.xml new file mode 100644 index 0000000000..3cb1daffad --- /dev/null +++ b/vector/src/main/res/layout/bottom_sheet_room_upgrade.xml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + +