diff --git a/CHANGES.md b/CHANGES.md
index 37779cca96..b1b0deee2c 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,15 @@
+Changes in Element v1.3.17 (2022-01-31)
+=======================================
+
+Bugfixes 🐛
+----------
+ - Display static map images in the timeline and improve Location sharing feature ([#5084](https://github.com/vector-im/element-android/issues/5084))
+ - Show the legal mention of mapbox when sharing location ([#5062](https://github.com/vector-im/element-android/issues/5062))
+ - Poll cannot end in some unencrypted rooms ([#5067](https://github.com/vector-im/element-android/issues/5067))
+ - Selecting Transfer in a call should immediately put the other person on hold until the call connects or the Transfer is cancelled. ([#5081](https://github.com/vector-im/element-android/issues/5081))
+ - Fixing crashes when quickly scrolling or restoring the room timeline ([#5091](https://github.com/vector-im/element-android/issues/5091))
+
+
Changes in Element 1.3.16 (2022-01-25)
======================================
@@ -47,6 +59,11 @@ Other changes
- Exclude dependabot upgrade for @github-script@v3 ([#4988](https://github.com/vector-im/element-android/issues/4988))
- Small iteration on command parser and unit test it. ([#4998](https://github.com/vector-im/element-android/issues/4998))
+SDK API changes ⚠️
+------------------
+ - `StateService.sendStateEvent()` now takes a non-nullable String for the parameter `stateKey`. If null was used, just now use an empty string. ([#4895](https://github.com/vector-im/element-android/issues/4895))
+ - 429 are not automatically retried anymore in case of too long retry delay ([#4995](https://github.com/vector-im/element-android/issues/4995))
+
Changes in Element v1.3.15 (2022-01-18)
=======================================
diff --git a/changelog.d/4895.removal b/changelog.d/4895.removal
deleted file mode 100644
index 8b3e3adba4..0000000000
--- a/changelog.d/4895.removal
+++ /dev/null
@@ -1 +0,0 @@
-`StateService.sendStateEvent()` now takes a non-nullable String for the parameter `stateKey`. If null was used, just now use an empty string.
\ No newline at end of file
diff --git a/changelog.d/4995.removal b/changelog.d/4995.removal
deleted file mode 100644
index 9eacff87cd..0000000000
--- a/changelog.d/4995.removal
+++ /dev/null
@@ -1 +0,0 @@
-429 are not automatically retried anymore in case of too long retry delay
\ No newline at end of file
diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40103130.txt b/fastlane/metadata/android/cs-CZ/changelogs/40103130.txt
new file mode 100644
index 0000000000..dab96ddd72
--- /dev/null
+++ b/fastlane/metadata/android/cs-CZ/changelogs/40103130.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: Změna na úvodních obrazovkách, včetně přihlášení do služby Analytics. V experimentálních funkcích byla přidána podpora pro události s matematikou.
+Úplný seznam změn: https://github.com/vector-im/element-android/releases/tag/v1.3.13
diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40103140.txt b/fastlane/metadata/android/cs-CZ/changelogs/40103140.txt
new file mode 100644
index 0000000000..8d07600bc1
--- /dev/null
+++ b/fastlane/metadata/android/cs-CZ/changelogs/40103140.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: Změna na úvodních obrazovkách, včetně přihlášení do služby Analytics. V experimentálních funkcích byla přidána podpora pro události s matematikou.
+Úplný seznam změn: https://github.com/vector-im/element-android/releases/tag/v1.3.14
diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40103150.txt b/fastlane/metadata/android/cs-CZ/changelogs/40103150.txt
new file mode 100644
index 0000000000..260011b49d
--- /dev/null
+++ b/fastlane/metadata/android/cs-CZ/changelogs/40103150.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: Změna na úvodních obrazovkách, včetně přihlášení do služby Analytics. V experimentálních funkcích byla přidána podpora pro události s matematikou.
+Úplný seznam změn: https://github.com/vector-im/element-android/releases/tag/v1.3.15
diff --git a/fastlane/metadata/android/de-DE/changelogs/40103130.txt b/fastlane/metadata/android/de-DE/changelogs/40103130.txt
new file mode 100644
index 0000000000..82aaadd5f3
--- /dev/null
+++ b/fastlane/metadata/android/de-DE/changelogs/40103130.txt
@@ -0,0 +1,2 @@
+Hauptänderungen: Neues Onboarding, Unterstützung für Mathematische Ausdrücke in Labs
+Änderungsliste: https://github.com/vector-im/element-android/releases/tag/v1.3.13
diff --git a/fastlane/metadata/android/de-DE/changelogs/40103140.txt b/fastlane/metadata/android/de-DE/changelogs/40103140.txt
new file mode 100644
index 0000000000..6032784f64
--- /dev/null
+++ b/fastlane/metadata/android/de-DE/changelogs/40103140.txt
@@ -0,0 +1,2 @@
+Hauptänderungen: Neues Onboarding, Unterstützung für Mathematische Ausdrücke in Labs
+Änderungsliste: https://github.com/vector-im/element-android/releases/tag/v1.3.14
diff --git a/fastlane/metadata/android/de-DE/changelogs/40103150.txt b/fastlane/metadata/android/de-DE/changelogs/40103150.txt
new file mode 100644
index 0000000000..6e324d4ef5
--- /dev/null
+++ b/fastlane/metadata/android/de-DE/changelogs/40103150.txt
@@ -0,0 +1,2 @@
+Hauptänderungen: Neues Onboarding, Unterstützung für Mathematische Ausdrücke in Labs
+Änderungsliste: https://github.com/vector-im/element-android/releases/tag/v1.3.15
diff --git a/fastlane/metadata/android/en-US/changelogs/40103170.txt b/fastlane/metadata/android/en-US/changelogs/40103170.txt
new file mode 100644
index 0000000000..2d0062bb23
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/40103170.txt
@@ -0,0 +1,2 @@
+Main changes in this version: send your location to any room. Edit poll.
+Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.3.17
\ No newline at end of file
diff --git a/fastlane/metadata/android/et/changelogs/40103130.txt b/fastlane/metadata/android/et/changelogs/40103130.txt
new file mode 100644
index 0000000000..b2c8054559
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40103130.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: liitumisvaate täiendused, võimalus saata meile analüütikat. Katsete alla on lisandunud üritused ning matemaatiliste valemite kirjutamise võimalus.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.3.13
diff --git a/fastlane/metadata/android/et/changelogs/40103140.txt b/fastlane/metadata/android/et/changelogs/40103140.txt
new file mode 100644
index 0000000000..14c34169d0
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40103140.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: liitumisvaate täiendused, võimalus saata meile analüütikat. Katsete alla on lisandunud üritused ning matemaatiliste valemite kirjutamise võimalus.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.3.14
diff --git a/fastlane/metadata/android/et/changelogs/40103150.txt b/fastlane/metadata/android/et/changelogs/40103150.txt
new file mode 100644
index 0000000000..ce86924106
--- /dev/null
+++ b/fastlane/metadata/android/et/changelogs/40103150.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: liitumisvaate täiendused, võimalus saata meile analüütikat. Katsete alla on lisandunud üritused ning matemaatiliste valemite kirjutamise võimalus.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.3.15
diff --git a/fastlane/metadata/android/hu-HU/changelogs/40103130.txt b/fastlane/metadata/android/hu-HU/changelogs/40103130.txt
new file mode 100644
index 0000000000..4c39f156f9
--- /dev/null
+++ b/fastlane/metadata/android/hu-HU/changelogs/40103130.txt
@@ -0,0 +1,2 @@
+Fő változás ebben a verzióban: Első változások a bemutató képernyőn, beleértve az analitikai adatküldés engedélyezésének lehetőségét. Matematikai formulák támogatása a Laborok között.
+Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.3.13
diff --git a/fastlane/metadata/android/hu-HU/changelogs/40103140.txt b/fastlane/metadata/android/hu-HU/changelogs/40103140.txt
new file mode 100644
index 0000000000..b53f857896
--- /dev/null
+++ b/fastlane/metadata/android/hu-HU/changelogs/40103140.txt
@@ -0,0 +1,2 @@
+Fő változás ebben a verzióban: Első változások a bemutató képernyőn, beleértve az analitikai adatküldés engedélyezésének lehetőségét. Matematikai formulák támogatása a Laborok között.
+Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.3.14
diff --git a/fastlane/metadata/android/hu-HU/changelogs/40103150.txt b/fastlane/metadata/android/hu-HU/changelogs/40103150.txt
new file mode 100644
index 0000000000..abb4bf336a
--- /dev/null
+++ b/fastlane/metadata/android/hu-HU/changelogs/40103150.txt
@@ -0,0 +1,2 @@
+Fő változás ebben a verzióban: Első változások a bemutató képernyőn, beleértve az analitikai adatküldés engedélyezésének lehetőségét. Matematikai formulák támogatása a Laborok között.
+Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.3.15
diff --git a/fastlane/metadata/android/id/changelogs/40103130.txt b/fastlane/metadata/android/id/changelogs/40103130.txt
new file mode 100644
index 0000000000..26a784d62a
--- /dev/null
+++ b/fastlane/metadata/android/id/changelogs/40103130.txt
@@ -0,0 +1,2 @@
+Perubahan utama dalam versi ini: Perubahan pertama di layar permulaan, termasuk analitik opt-in. Dukungan untuk Peristiwa dengan Matematika ditambahkan di Uji Coba.
+Changelog lanjutan:
diff --git a/fastlane/metadata/android/id/changelogs/40103140.txt b/fastlane/metadata/android/id/changelogs/40103140.txt
new file mode 100644
index 0000000000..dfefff307f
--- /dev/null
+++ b/fastlane/metadata/android/id/changelogs/40103140.txt
@@ -0,0 +1,2 @@
+Perubahan utama dalam versi ini: Perubahan pertama di layar permulaan, termasuk analitik opt-in. Dukungan untuk Peristiwa dengan Matematika ditambahkan di Uji Coba.
+Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.3.14
diff --git a/fastlane/metadata/android/id/changelogs/40103150.txt b/fastlane/metadata/android/id/changelogs/40103150.txt
new file mode 100644
index 0000000000..c46e661d47
--- /dev/null
+++ b/fastlane/metadata/android/id/changelogs/40103150.txt
@@ -0,0 +1,2 @@
+Perubahan utama dalam versi ini: Perubahan pertama di layar permulaan, termasuk analitik opt-in. Dukungan untuk Peristiwa dengan Matematika ditambahkan di Uji Coba.
+Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.3.15
diff --git a/fastlane/metadata/android/it-IT/changelogs/40103130.txt b/fastlane/metadata/android/it-IT/changelogs/40103130.txt
new file mode 100644
index 0000000000..d113b7ac66
--- /dev/null
+++ b/fastlane/metadata/android/it-IT/changelogs/40103130.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: prima modifica nelle schermate onboarding, incluso l'opt-in di Analytics. Supporto agli eventi con Math aggiunto nei laboratori.
+Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.3.13
diff --git a/fastlane/metadata/android/it-IT/changelogs/40103140.txt b/fastlane/metadata/android/it-IT/changelogs/40103140.txt
new file mode 100644
index 0000000000..b875832368
--- /dev/null
+++ b/fastlane/metadata/android/it-IT/changelogs/40103140.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: prima modifica nelle schermate onboarding, incluso l'opt-in di Analytics. Supporto agli eventi con Math aggiunto nei laboratori.
+Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.3.14
diff --git a/fastlane/metadata/android/it-IT/changelogs/40103150.txt b/fastlane/metadata/android/it-IT/changelogs/40103150.txt
new file mode 100644
index 0000000000..0e7586be19
--- /dev/null
+++ b/fastlane/metadata/android/it-IT/changelogs/40103150.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: prima modifica nelle schermate onboarding, incluso l'opt-in di Analytics. Supporto agli eventi con Math aggiunto nei laboratori.
+Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.3.15
diff --git a/fastlane/metadata/android/pt-BR/changelogs/40103130.txt b/fastlane/metadata/android/pt-BR/changelogs/40103130.txt
new file mode 100644
index 0000000000..6f4975d01c
--- /dev/null
+++ b/fastlane/metadata/android/pt-BR/changelogs/40103130.txt
@@ -0,0 +1,2 @@
+Principais mudanças nesta versão: Primeira mudança em telas de onboarding, incluindo opt-in de Analítica. Suporte para Eventos com Matemática adicionado nos labs.
+Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.3.13
diff --git a/fastlane/metadata/android/pt-BR/changelogs/40103140.txt b/fastlane/metadata/android/pt-BR/changelogs/40103140.txt
new file mode 100644
index 0000000000..ab7470b96b
--- /dev/null
+++ b/fastlane/metadata/android/pt-BR/changelogs/40103140.txt
@@ -0,0 +1,2 @@
+Principais mudanças nesta versão: Primeira mudança em telas de onboarding, incluindo opt-in de Analítica. Suporte para Eventos com Matemática adicionado nos labs.
+Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.3.14
diff --git a/fastlane/metadata/android/pt-BR/changelogs/40103150.txt b/fastlane/metadata/android/pt-BR/changelogs/40103150.txt
new file mode 100644
index 0000000000..40439e3f94
--- /dev/null
+++ b/fastlane/metadata/android/pt-BR/changelogs/40103150.txt
@@ -0,0 +1,2 @@
+Principais mudanças nesta versão: Primeira mudança em telas de onboarding, incluindo opt-in de Analítica. Suporte para Eventos com Matemática adicionado nos labs.
+Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.3.15
diff --git a/fastlane/metadata/android/sk/changelogs/40103130.txt b/fastlane/metadata/android/sk/changelogs/40103130.txt
new file mode 100644
index 0000000000..31f6cf31db
--- /dev/null
+++ b/fastlane/metadata/android/sk/changelogs/40103130.txt
@@ -0,0 +1,2 @@
+Hlavné zmeny v tejto verzii: Prvá zmena v obrazovkách pri vstupe do systému vrátane prihlásenia do služby Analytics. Pridanie podpory pre udalosti s matematikou v laboratóriách.
+Úplný zoznam zmien: https://github.com/vector-im/element-android/releases/tag/v1.3.13
diff --git a/fastlane/metadata/android/sk/changelogs/40103140.txt b/fastlane/metadata/android/sk/changelogs/40103140.txt
new file mode 100644
index 0000000000..8e21829163
--- /dev/null
+++ b/fastlane/metadata/android/sk/changelogs/40103140.txt
@@ -0,0 +1,2 @@
+Hlavné zmeny v tejto verzii: Prvá zmena v obrazovkách pri vstupe do systému vrátane prihlásenia do služby Analytics. Pridanie podpory pre udalosti s matematikou v laboratóriách.
+Úplný zoznam zmien: https://github.com/vector-im/element-android/releases/tag/v1.3.14
diff --git a/fastlane/metadata/android/sk/changelogs/40103150.txt b/fastlane/metadata/android/sk/changelogs/40103150.txt
new file mode 100644
index 0000000000..7016270d76
--- /dev/null
+++ b/fastlane/metadata/android/sk/changelogs/40103150.txt
@@ -0,0 +1,2 @@
+Hlavné zmeny v tejto verzii: Prvá zmena v obrazovkách pri vstupe do systému vrátane prihlásenia do služby Analytics. Pridanie podpory pre udalosti s matematikou v laboratóriách.
+Úplný zoznam zmien: https://github.com/vector-im/element-android/releases/tag/v1.3.15
diff --git a/fastlane/metadata/android/uk/changelogs/40103130.txt b/fastlane/metadata/android/uk/changelogs/40103130.txt
new file mode 100644
index 0000000000..ad0bcda6e6
--- /dev/null
+++ b/fastlane/metadata/android/uk/changelogs/40103130.txt
@@ -0,0 +1,2 @@
+Основні зміни у цій версії: перша зміна на екрані привітання, включно з увімкненням аналітики. У лабораторії додано підтримку подій з математичними формулами.
+Вичерпний перелік змін: https://github.com/vector-im/element-android/releases/tag/v1.3.13
diff --git a/fastlane/metadata/android/uk/changelogs/40103140.txt b/fastlane/metadata/android/uk/changelogs/40103140.txt
new file mode 100644
index 0000000000..355f8add3e
--- /dev/null
+++ b/fastlane/metadata/android/uk/changelogs/40103140.txt
@@ -0,0 +1,2 @@
+Основні зміни у цій версії: перша зміна на екрані привітання, включно з увімкненням аналітики. У лабораторії додано підтримку подій з математичними формулами.
+Вичерпний перелік змін: https://github.com/vector-im/element-android/releases/tag/v1.3.14
diff --git a/fastlane/metadata/android/uk/changelogs/40103150.txt b/fastlane/metadata/android/uk/changelogs/40103150.txt
new file mode 100644
index 0000000000..0d9d702f02
--- /dev/null
+++ b/fastlane/metadata/android/uk/changelogs/40103150.txt
@@ -0,0 +1,2 @@
+Основні зміни у цій версії: перша зміна на екрані привітання, включно з увімкненням аналітики. У лабораторії додано підтримку подій з математичними формулами.
+Вичерпний перелік змін: https://github.com/vector-im/element-android/releases/tag/v1.3.15
diff --git a/fastlane/metadata/android/zh-TW/changelogs/40103130.txt b/fastlane/metadata/android/zh-TW/changelogs/40103130.txt
new file mode 100644
index 0000000000..e0f9b47e16
--- /dev/null
+++ b/fastlane/metadata/android/zh-TW/changelogs/40103130.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:首次使用畫面的第一個變化,包含了選擇加入的分析功能。新增對數學活動的支援至實驗室中。
+完整的變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.3.13
diff --git a/fastlane/metadata/android/zh-TW/changelogs/40103140.txt b/fastlane/metadata/android/zh-TW/changelogs/40103140.txt
new file mode 100644
index 0000000000..8366a01265
--- /dev/null
+++ b/fastlane/metadata/android/zh-TW/changelogs/40103140.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:首次使用畫面的第一個變化,包含了選擇加入的分析功能。新增對數學活動的支援至實驗室中。
+完整的變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.3.14
diff --git a/fastlane/metadata/android/zh-TW/changelogs/40103150.txt b/fastlane/metadata/android/zh-TW/changelogs/40103150.txt
new file mode 100644
index 0000000000..a6ddd5aa8c
--- /dev/null
+++ b/fastlane/metadata/android/zh-TW/changelogs/40103150.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:首次使用畫面的第一個變化,包含了選擇加入的分析功能。新增對數學活動的支援至實驗室中。
+完整的變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.3.15
diff --git a/library/ui-styles/src/main/res/values-ldrtl/bools.xml b/library/ui-styles/src/main/res/values-ldrtl/bools.xml
new file mode 100644
index 0000000000..27b280985f
--- /dev/null
+++ b/library/ui-styles/src/main/res/values-ldrtl/bools.xml
@@ -0,0 +1,6 @@
+
+
+
+ true
+
+
\ No newline at end of file
diff --git a/library/ui-styles/src/main/res/values/bools.xml b/library/ui-styles/src/main/res/values/bools.xml
index 93d5f925af..9966999f28 100644
--- a/library/ui-styles/src/main/res/values/bools.xml
+++ b/library/ui-styles/src/main/res/values/bools.xml
@@ -4,4 +4,6 @@
false
+ false
+
\ No newline at end of file
diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle
index 7b9a611c72..7b33bdd9d6 100644
--- a/matrix-sdk-android/build.gradle
+++ b/matrix-sdk-android/build.gradle
@@ -31,7 +31,7 @@ android {
// that the app's state is completely cleared between tests.
testInstrumentationRunnerArguments clearPackageData: 'true'
- buildConfigField "String", "SDK_VERSION", "\"1.3.16\""
+ buildConfigField "String", "SDK_VERSION", "\"1.3.17\""
buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\""
resValue "string", "git_sdk_revision", "\"${gitRevision()}\""
@@ -164,7 +164,7 @@ dependencies {
implementation libs.apache.commonsImaging
// Phone number https://github.com/google/libphonenumber
- implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.41'
+ implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.42'
testImplementation libs.tests.junit
testImplementation 'org.robolectric:robolectric:4.7.3'
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageLocationContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageLocationContent.kt
index 2f3db8ff51..c090487c58 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageLocationContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageLocationContent.kt
@@ -48,7 +48,8 @@ data class MessageLocationContent(
@Json(name = "m.new_content") override val newContent: Content? = null,
/**
- * m.asset defines a generic asset that can be used for location tracking but also in other places like inventories, geofencing, checkins/checkouts etc.
+ * m.asset defines a generic asset that can be used for location tracking but also in other places like
+ * inventories, geofencing, checkins/checkouts etc.
* It should contain a mandatory namespaced type key defining what particular asset is being referred to.
* For the purposes of user location tracking m.self should be used in order to avoid duplicating the mxid.
*/
@@ -62,5 +63,5 @@ data class MessageLocationContent(
@Json(name = "org.matrix.msc1767.text") val text: String? = null
) : MessageContent {
- fun getUri() = locationInfo?.geoUri ?: geoUri
+ fun getBestGeoUri() = locationInfo?.geoUri ?: geoUri
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/ProcessEventForPushTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/ProcessEventForPushTask.kt
index da15e158e5..8b05d2ea62 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/ProcessEventForPushTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/ProcessEventForPushTask.kt
@@ -74,6 +74,7 @@ internal class DefaultProcessEventForPushTask @Inject constructor(
event to it
}
}
+ Timber.d("[PushRules] matched ${matchedEvents.size} out of ${allEvents.size}")
val allRedactedEvents = params.syncResponse.join
.asSequence()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt
index 1577f3057f..3cc08df0e8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt
@@ -39,6 +39,7 @@ import org.matrix.android.sdk.api.session.room.model.message.MessagePollResponse
import org.matrix.android.sdk.api.session.room.model.message.MessageRelationContent
import org.matrix.android.sdk.api.session.room.model.relation.ReactionContent
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
+import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
import org.matrix.android.sdk.internal.SessionManager
import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent
@@ -344,15 +345,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
val targetEventId = relatedEventId ?: content.relatesTo?.eventId ?: return
val eventTimestamp = event.originServerTs ?: return
- val session = sessionManager.getSessionComponent(sessionId)?.session()
-
- val targetPollEvent = session?.getRoom(roomId)?.getTimeLineEvent(targetEventId) ?: return Unit.also {
- Timber.v("## POLL target poll event $targetEventId not found in room $roomId")
- }
-
- val targetPollContent = targetPollEvent.getLastMessageContent() as? MessagePollContent ?: return Unit.also {
- Timber.v("## POLL target poll event $targetEventId content is malformed")
- }
+ val targetPollContent = getPollContent(roomId, targetEventId) ?: return
// ok, this is a poll response
var existing = EventAnnotationsSummaryEntity.where(realm, roomId, targetEventId).findFirst()
@@ -453,6 +446,17 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
isLocalEcho: Boolean) {
val pollEventId = content.relatesTo?.eventId ?: return
+ val pollOwnerId = getPollEvent(roomId, pollEventId)?.root?.senderId
+ val isPollOwner = pollOwnerId == event.senderId
+
+ val powerLevelsHelper = stateEventDataSource.getStateEvent(roomId, EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition)
+ ?.content?.toModel()
+ ?.let { PowerLevelsHelper(it) }
+ if (!isPollOwner && !powerLevelsHelper?.isUserAbleToRedact(event.senderId ?: "").orFalse()) {
+ Timber.v("## Received poll.end event $pollEventId but user ${event.senderId} doesn't have enough power level in room $roomId")
+ return
+ }
+
var existing = EventAnnotationsSummaryEntity.where(realm, roomId, pollEventId).findFirst()
if (existing == null) {
Timber.v("## POLL creating new relation summary for $pollEventId")
@@ -470,14 +474,6 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
return
}
- val powerLevelsHelper = stateEventDataSource.getStateEvent(roomId, EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition)
- ?.content?.toModel()
- ?.let { PowerLevelsHelper(it) }
- if (!powerLevelsHelper?.isUserAbleToRedact(event.senderId ?: "").orFalse()) {
- Timber.v("## Received poll.end event $pollEventId but user ${event.senderId} doesn't have enough power level in room $roomId")
- return
- }
-
val txId = event.unsignedData?.transactionId
// is it a remote echo?
if (!isLocalEcho && existingPollSummary.sourceLocalEchoEvents.contains(txId)) {
@@ -491,6 +487,21 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
existingPollSummary.closedTime = event.originServerTs
}
+ private fun getPollEvent(roomId: String, eventId: String): TimelineEvent? {
+ val session = sessionManager.getSessionComponent(sessionId)?.session()
+ return session?.getRoom(roomId)?.getTimeLineEvent(eventId) ?: return null.also {
+ Timber.v("## POLL target poll event $eventId not found in room $roomId")
+ }
+ }
+
+ private fun getPollContent(roomId: String, eventId: String): MessagePollContent? {
+ val pollEvent = getPollEvent(roomId, eventId) ?: return null
+
+ return pollEvent.getLastMessageContent() as? MessagePollContent ?: return null.also {
+ Timber.v("## POLL target poll event $eventId content is malformed")
+ }
+ }
+
private fun handleInitialAggregatedRelations(realm: Realm,
event: Event,
roomId: String,
diff --git a/vector/build.gradle b/vector/build.gradle
index 04fb24510e..1d880736f8 100644
--- a/vector/build.gradle
+++ b/vector/build.gradle
@@ -18,7 +18,7 @@ ext.versionMinor = 3
// Note: even values are reserved for regular release, odd values for hotfix release.
// When creating a hotfix, you should decrease the value, since the current value
// is the value for the next regular release.
-ext.versionPatch = 16
+ext.versionPatch = 17
static def getGitTimestamp() {
def cmd = 'git show -s --format=%ct'
@@ -373,7 +373,7 @@ dependencies {
implementation 'com.facebook.stetho:stetho:1.6.0'
// Phone number https://github.com/google/libphonenumber
- implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.41'
+ implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.42'
// FlowBinding
implementation libs.github.flowBinding
diff --git a/vector/src/androidTest/java/im/vector/app/EspressoExt.kt b/vector/src/androidTest/java/im/vector/app/EspressoExt.kt
index 59982c72aa..ef76a9d1f3 100644
--- a/vector/src/androidTest/java/im/vector/app/EspressoExt.kt
+++ b/vector/src/androidTest/java/im/vector/app/EspressoExt.kt
@@ -160,43 +160,53 @@ fun initialSyncIdlingResource(session: Session): IdlingResource {
}
fun activityIdlingResource(activityClass: Class<*>): IdlingResource {
+ val lifecycleMonitor = ActivityLifecycleMonitorRegistry.getInstance()
+
val res = object : IdlingResource, ActivityLifecycleCallback {
private var callback: IdlingResource.ResourceCallback? = null
+ private var resumedActivity: Activity? = null
+ private val uniqTS = System.currentTimeMillis()
- var hasResumed = false
- private var currentActivity: Activity? = null
-
- val uniqTS = System.currentTimeMillis()
override fun getName() = "activityIdlingResource_${activityClass.name}_$uniqTS"
override fun isIdleNow(): Boolean {
- val currentActivity = currentActivity ?: ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(Stage.RESUMED).elementAtOrNull(0)
+ val activity = resumedActivity ?: ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(Stage.RESUMED).firstOrNull {
+ activityClass == it.javaClass
+ }
- val isIdle = hasResumed || currentActivity?.javaClass?.let { activityClass.isAssignableFrom(it) } ?: false
- println("*** [$name] isIdleNow activityIdlingResource $currentActivity isIdle:$isIdle")
+ val isIdle = activity != null
+ if (isIdle) {
+ unregister()
+ }
return isIdle
}
override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback?) {
println("*** [$name] registerIdleTransitionCallback $callback")
this.callback = callback
- // if (hasResumed) callback?.onTransitionToIdle()
}
override fun onActivityLifecycleChanged(activity: Activity?, stage: Stage?) {
- println("*** [$name] onActivityLifecycleChanged $activity $stage")
- currentActivity = ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(Stage.RESUMED).elementAtOrNull(0)
- val isIdle = currentActivity?.javaClass?.let { activityClass.isAssignableFrom(it) } ?: false
- println("*** [$name] onActivityLifecycleChanged $currentActivity isIdle:$isIdle")
- if (isIdle) {
- hasResumed = true
- println("*** [$name] onActivityLifecycleChanged callback: $callback")
- callback?.onTransitionToIdle()
- ActivityLifecycleMonitorRegistry.getInstance().removeLifecycleCallback(this)
+ if (activityClass == activity?.javaClass) {
+ when (stage) {
+ Stage.RESUMED -> {
+ unregister()
+ resumedActivity = activity
+ println("*** [$name] onActivityLifecycleChanged callback: $callback")
+ callback?.onTransitionToIdle()
+ }
+ else -> {
+ // do nothing, we're blocking until the activity resumes
+ }
+ }
}
}
+
+ private fun unregister() {
+ lifecycleMonitor.removeLifecycleCallback(this)
+ }
}
- ActivityLifecycleMonitorRegistry.getInstance().addLifecycleCallback(res)
+ lifecycleMonitor.addLifecycleCallback(res)
return res
}
diff --git a/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt b/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt
index 042e9ef3ee..d625cf0390 100644
--- a/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt
+++ b/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt
@@ -69,12 +69,11 @@ class UiAllScreensSanityTest {
preferences { crawl() }
voiceAndVideo()
ignoredUsers()
- // TODO Test analytics
securityAndPrivacy { crawl() }
labs()
advancedSettings { crawl() }
- // TODO Rework this part (Legals, etc.)
- // helpAndAbout { crawl() }
+ helpAndAbout { crawl() }
+ legals { crawl() }
}
elementRobot.newDirectMessage {
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/MessageMenuRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/MessageMenuRobot.kt
index 934c6c76a1..5973dc3473 100644
--- a/vector/src/androidTest/java/im/vector/app/ui/robot/MessageMenuRobot.kt
+++ b/vector/src/androidTest/java/im/vector/app/ui/robot/MessageMenuRobot.kt
@@ -17,12 +17,16 @@
package im.vector.app.ui.robot
import androidx.test.espresso.Espresso.pressBack
+import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
import com.adevinta.android.barista.interaction.BaristaListInteractions.clickListItem
import com.google.android.material.bottomsheet.BottomSheetBehavior
import im.vector.app.R
+import im.vector.app.espresso.tools.waitUntilActivityVisible
+import im.vector.app.espresso.tools.waitUntilViewVisible
import im.vector.app.features.home.room.detail.timeline.edithistory.ViewEditHistoryBottomSheet
+import im.vector.app.features.reactions.EmojiReactionPickerActivity
import im.vector.app.interactWithSheet
import java.lang.Thread.sleep
@@ -54,7 +58,10 @@ class MessageMenuRobot(
fun addReactionFromEmojiPicker() {
clickOn(R.string.message_add_reaction)
// Wait for emoji to load, it's async now
- sleep(2000)
+ waitUntilActivityVisible {
+ waitUntilViewVisible(withId(R.id.emojiRecyclerView))
+ waitUntilViewVisible(withText("😀"))
+ }
clickListItem(R.id.emojiRecyclerView, 4)
autoClosed = true
}
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/RoomDetailRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/RoomDetailRobot.kt
index ebf5fdf23d..da57b105d7 100644
--- a/vector/src/androidTest/java/im/vector/app/ui/robot/RoomDetailRobot.kt
+++ b/vector/src/androidTest/java/im/vector/app/ui/robot/RoomDetailRobot.kt
@@ -20,13 +20,13 @@ import androidx.recyclerview.widget.RecyclerView
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.Espresso.pressBack
import androidx.test.espresso.action.ViewActions
+import androidx.test.espresso.action.ViewActions.longClick
import androidx.test.espresso.contrib.RecyclerViewActions
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import com.adevinta.android.barista.interaction.BaristaClickInteractions
import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
-import com.adevinta.android.barista.interaction.BaristaClickInteractions.longClickOn
import com.adevinta.android.barista.interaction.BaristaEditTextInteractions.writeTo
import com.adevinta.android.barista.interaction.BaristaMenuClickInteractions.clickMenu
import com.adevinta.android.barista.interaction.BaristaMenuClickInteractions.openMenu
@@ -70,6 +70,7 @@ class RoomDetailRobot {
openMessageMenu(message) {
addQuickReaction(quickReaction)
}
+ waitUntilViewVisible(withText(quickReaction))
println("Open reactions bottom sheet")
// Open reactions
longClickReaction(quickReaction)
@@ -103,7 +104,7 @@ class RoomDetailRobot {
private fun longClickReaction(quickReaction: String) {
withRetry {
- longClickOn(quickReaction)
+ onView(withText(quickReaction)).perform(longClick())
}
}
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsHelpRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsHelpRobot.kt
index 75f610d016..cf0c997d80 100644
--- a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsHelpRobot.kt
+++ b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsHelpRobot.kt
@@ -16,10 +16,6 @@
package im.vector.app.ui.robot.settings
-import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
-import com.adevinta.android.barista.interaction.BaristaDialogInteractions.clickDialogPositiveButton
-import im.vector.app.R
-
class SettingsHelpRobot {
fun crawl() {
@@ -34,7 +30,5 @@ class SettingsHelpRobot {
clickOn(R.string.settings_privacy_policy)
pressBack()
*/
- clickOn(R.string.settings_third_party_notices)
- clickDialogPositiveButton()
}
}
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsLegalsRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsLegalsRobot.kt
new file mode 100644
index 0000000000..842471752a
--- /dev/null
+++ b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsLegalsRobot.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.ui.robot.settings
+
+import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
+import com.adevinta.android.barista.interaction.BaristaDialogInteractions.clickDialogPositiveButton
+import im.vector.app.R
+
+class SettingsLegalsRobot {
+
+ fun crawl() {
+ clickOn(R.string.settings_third_party_notices)
+ clickDialogPositiveButton()
+ }
+}
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsRobot.kt
index a9c053f6c3..561f14c6f2 100644
--- a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsRobot.kt
+++ b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsRobot.kt
@@ -64,4 +64,8 @@ class SettingsRobot {
fun helpAndAbout(block: SettingsHelpRobot.() -> Unit) {
clickOnAndGoBack(R.string.preference_root_help_about) { block(SettingsHelpRobot()) }
}
+
+ fun legals(block: SettingsLegalsRobot.() -> Unit) {
+ clickOnAndGoBack(R.string.preference_root_legals) { block(SettingsLegalsRobot()) }
+ }
}
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsSecurityRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsSecurityRobot.kt
index f2607bbc1c..168db3e0e9 100644
--- a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsSecurityRobot.kt
+++ b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsSecurityRobot.kt
@@ -33,5 +33,8 @@ class SettingsSecurityRobot {
clickOnPreference(R.string.encryption_export_e2e_room_keys)
pressBack()
*/
+
+ clickOnPreference(R.string.settings_opt_in_of_analytics)
+ Espresso.pressBack()
}
}
diff --git a/vector/src/main/java/im/vector/app/core/epoxy/bottomsheet/BottomSheetMessagePreviewItem.kt b/vector/src/main/java/im/vector/app/core/epoxy/bottomsheet/BottomSheetMessagePreviewItem.kt
index cdecd2d6c6..5295cbaec3 100644
--- a/vector/src/main/java/im/vector/app/core/epoxy/bottomsheet/BottomSheetMessagePreviewItem.kt
+++ b/vector/src/main/java/im/vector/app/core/epoxy/bottomsheet/BottomSheetMessagePreviewItem.kt
@@ -17,24 +17,25 @@
package im.vector.app.core.epoxy.bottomsheet
import android.text.method.MovementMethod
+import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.core.view.isVisible
import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass
+import com.bumptech.glide.request.RequestOptions
import im.vector.app.R
import im.vector.app.core.epoxy.ClickListener
import im.vector.app.core.epoxy.VectorEpoxyHolder
import im.vector.app.core.epoxy.VectorEpoxyModel
import im.vector.app.core.epoxy.onClick
import im.vector.app.core.extensions.setTextOrHide
+import im.vector.app.core.glide.GlideApp
import im.vector.app.features.displayname.getBestName
import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.detail.timeline.helper.LocationPinProvider
import im.vector.app.features.home.room.detail.timeline.item.BindingOptions
import im.vector.app.features.home.room.detail.timeline.tools.findPillsAndProcess
-import im.vector.app.features.location.LocationData
-import im.vector.app.features.location.MapTilerMapView
import im.vector.app.features.media.ImageContentRenderer
import im.vector.lib.core.utils.epoxy.charsequence.EpoxyCharSequence
import org.matrix.android.sdk.api.util.MatrixItem
@@ -70,7 +71,7 @@ abstract class BottomSheetMessagePreviewItem : VectorEpoxyModel
- holder.mapView.initialize {
- if (holder.view.isAttachedToWindow) {
- holder.mapView.zoomToLocation(location.latitude, location.longitude, 15.0)
- locationPinProvider?.create(matrixItem.id) { pinDrawable ->
- holder.mapView.addPinToMap(matrixItem.id, pinDrawable)
- holder.mapView.updatePinLocation(matrixItem.id, location.latitude, location.longitude)
- }
- }
+ if (locationUrl == null) {
+ holder.body.isVisible = true
+ holder.mapViewContainer.isVisible = false
+ } else {
+ holder.body.isVisible = false
+ holder.mapViewContainer.isVisible = true
+ GlideApp.with(holder.staticMapImageView)
+ .load(locationUrl)
+ .apply(RequestOptions.centerCropTransform())
+ .into(holder.staticMapImageView)
+
+ locationPinProvider?.create(matrixItem.id) { pinDrawable ->
+ GlideApp.with(holder.staticMapPinImageView)
+ .load(pinDrawable)
+ .into(holder.staticMapPinImageView)
}
}
}
@@ -124,6 +129,8 @@ abstract class BottomSheetMessagePreviewItem : VectorEpoxyModel(R.id.bottom_sheet_message_preview_body_details)
val timestamp by bind(R.id.bottom_sheet_message_preview_timestamp)
val imagePreview by bind(R.id.bottom_sheet_message_preview_image)
- val mapView by bind(R.id.bottom_sheet_message_preview_location)
+ val mapViewContainer by bind(R.id.mapViewContainer)
+ val staticMapImageView by bind(R.id.staticMapImageView)
+ val staticMapPinImageView by bind(R.id.staticMapPinImageView)
}
}
diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/PerformanceTimer.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/PerformanceTimer.kt
index 2cfc366cd3..59dd997f92 100644
--- a/vector/src/main/java/im/vector/app/features/analytics/plan/PerformanceTimer.kt
+++ b/vector/src/main/java/im/vector/app/features/analytics/plan/PerformanceTimer.kt
@@ -46,12 +46,14 @@ data class PerformanceTimer(
enum class Name {
/**
- * The time spent parsing the response from an initial /sync request.
+ * The time spent parsing the response from an initial /sync request. In
+ * this case, `itemCount` should contain the number of joined rooms.
*/
InitialSyncParsing,
/**
- * The time spent waiting for a response to an initial /sync request.
+ * The time spent waiting for a response to an initial /sync request. In
+ * this case, `itemCount` should contain the number of joined rooms.
*/
InitialSyncRequest,
@@ -62,13 +64,16 @@ data class PerformanceTimer(
NotificationsOpenEvent,
/**
- * The duration of a regular /sync request when resuming the app.
+ * The duration of a regular /sync request when resuming the app. In
+ * this case, `itemCount` should contain the number of joined rooms in
+ * the response.
*/
StartupIncrementalSync,
/**
* The duration of an initial /sync request during startup (if the store
- * has been wiped).
+ * has been wiped). In this case, `itemCount` should contain the number
+ * of joined rooms.
*/
StartupInitialSync,
diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt
index 22f1fc40a2..642d259723 100644
--- a/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt
@@ -16,6 +16,7 @@
package im.vector.app.features.call
+import android.app.Activity
import android.app.KeyguardManager
import android.app.PictureInPictureParams
import android.content.Context
@@ -43,6 +44,7 @@ import com.google.android.material.card.MaterialCardView
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
+import im.vector.app.core.extensions.registerStartForActivityResult
import im.vector.app.core.extensions.setTextOrHide
import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.core.utils.PERMISSIONS_FOR_AUDIO_IP_CALL
@@ -518,13 +520,19 @@ class VectorCallActivity : VectorBaseActivity(), CallContro
}
is VectorCallViewEvents.ShowCallTransferScreen -> {
val callId = withState(callViewModel) { it.callId }
- navigator.openCallTransfer(this, callId)
+ navigator.openCallTransfer(this, callTransferActivityResultLauncher, callId)
}
null -> {
}
}
}
+ private val callTransferActivityResultLauncher = registerStartForActivityResult { activityResult ->
+ if (activityResult.resultCode == Activity.RESULT_CANCELED) {
+ callViewModel.handle(VectorCallViewActions.CallTransferSelectionCancelled)
+ }
+ }
+
private fun onErrorTimoutConnect(turn: TurnServerResponse?) {
Timber.tag(loggerTag.value).d("onErrorTimoutConnect $turn")
// TODO ask to use default stun, etc...
diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallViewActions.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallViewActions.kt
index 67aa7bede2..fb39660282 100644
--- a/vector/src/main/java/im/vector/app/features/call/VectorCallViewActions.kt
+++ b/vector/src/main/java/im/vector/app/features/call/VectorCallViewActions.kt
@@ -36,5 +36,6 @@ sealed class VectorCallViewActions : VectorViewModelAction {
object ToggleCamera : VectorCallViewActions()
object ToggleHDSD : VectorCallViewActions()
object InitiateCallTransfer : VectorCallViewActions()
+ object CallTransferSelectionCancelled : VectorCallViewActions()
object TransferCall : VectorCallViewActions()
}
diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt
index 5af2b826af..4aca0ea499 100644
--- a/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt
@@ -319,10 +319,14 @@ class VectorCallViewModel @AssistedInject constructor(
call?.sendDtmfDigit(action.digit)
}
VectorCallViewActions.InitiateCallTransfer -> {
+ call?.updateRemoteOnHold(true)
_viewEvents.post(
VectorCallViewEvents.ShowCallTransferScreen
)
}
+ VectorCallViewActions.CallTransferSelectionCancelled -> {
+ call?.updateRemoteOnHold(false)
+ }
VectorCallViewActions.TransferCall -> {
handleCallTransfer()
}
diff --git a/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferActivity.kt b/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferActivity.kt
index 959e96cc4c..0e63316bbe 100644
--- a/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferActivity.kt
@@ -16,6 +16,7 @@
package im.vector.app.features.call.transfer
+import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
@@ -55,7 +56,7 @@ class CallTransferActivity : VectorBaseActivity() {
callTransferViewModel.observeViewEvents {
when (it) {
- is CallTransferViewEvents.Dismiss -> finish()
+ is CallTransferViewEvents.Complete -> handleComplete()
CallTransferViewEvents.Loading -> showWaitingView()
is CallTransferViewEvents.FailToTransfer -> showSnackbar(getString(R.string.call_transfer_failure))
}
@@ -93,6 +94,11 @@ class CallTransferActivity : VectorBaseActivity() {
}
}
+ private fun handleComplete() {
+ setResult(Activity.RESULT_OK)
+ finish()
+ }
+
companion object {
fun newIntent(context: Context, callId: String): Intent {
diff --git a/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewEvents.kt b/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewEvents.kt
index fd4c9d672d..a8451e4fb5 100644
--- a/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewEvents.kt
+++ b/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewEvents.kt
@@ -19,7 +19,7 @@ package im.vector.app.features.call.transfer
import im.vector.app.core.platform.VectorViewEvents
sealed class CallTransferViewEvents : VectorViewEvents {
- object Dismiss : CallTransferViewEvents()
+ object Complete : CallTransferViewEvents()
object Loading : CallTransferViewEvents()
object FailToTransfer : CallTransferViewEvents()
}
diff --git a/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewModel.kt b/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewModel.kt
index ffc6ff9bc3..de6a5de539 100644
--- a/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewModel.kt
@@ -50,14 +50,14 @@ class CallTransferViewModel @AssistedInject constructor(@Assisted initialState:
private val callListener = object : WebRtcCall.Listener {
override fun onStateUpdate(call: MxCall) {
if (call.state is CallState.Ended) {
- _viewEvents.post(CallTransferViewEvents.Dismiss)
+ _viewEvents.post(CallTransferViewEvents.Complete)
}
}
}
init {
if (call == null) {
- _viewEvents.post(CallTransferViewEvents.Dismiss)
+ _viewEvents.post(CallTransferViewEvents.Complete)
} else {
call.addListener(callListener)
}
@@ -89,7 +89,7 @@ class CallTransferViewModel @AssistedInject constructor(@Assisted initialState:
} else {
call?.transferToUser(action.selectedUserId, null)
}
- _viewEvents.post(CallTransferViewEvents.Dismiss)
+ _viewEvents.post(CallTransferViewEvents.Complete)
} catch (failure: Throwable) {
_viewEvents.post(CallTransferViewEvents.FailToTransfer)
}
@@ -111,7 +111,7 @@ class CallTransferViewModel @AssistedInject constructor(@Assisted initialState:
} else {
call?.transferToUser(result.userId, result.roomId)
}
- _viewEvents.post(CallTransferViewEvents.Dismiss)
+ _viewEvents.post(CallTransferViewEvents.Complete)
} catch (failure: Throwable) {
_viewEvents.post(CallTransferViewEvents.FailToTransfer)
}
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 58e36d2303..14c8e598f8 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
@@ -20,7 +20,6 @@ import android.net.Uri
import android.view.View
import im.vector.app.core.platform.VectorViewModelAction
import im.vector.app.features.call.conference.ConferenceEvent
-import im.vector.app.features.location.LocationData
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
import org.matrix.android.sdk.api.session.room.model.message.MessageStickerContent
import org.matrix.android.sdk.api.session.room.model.message.MessageWithAttachmentContent
@@ -90,6 +89,7 @@ sealed class RoomDetailAction : VectorViewModelAction {
data class EnsureNativeWidgetAllowed(val widget: Widget,
val userJustAccepted: Boolean,
val grantedEvents: RoomDetailViewEvents) : RoomDetailAction()
+
data class UpdateJoinJitsiCallStatus(val conferenceEvent: ConferenceEvent) : RoomDetailAction()
data class OpenOrCreateDm(val userId: String) : RoomDetailAction()
@@ -112,7 +112,4 @@ sealed class RoomDetailAction : VectorViewModelAction {
// Poll
data class EndPoll(val eventId: String) : RoomDetailAction()
-
- // Location
- data class ShowLocation(val locationData: LocationData, val userId: 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 9926ecad24..b58a1d627e 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
@@ -171,8 +171,8 @@ import im.vector.app.features.html.EventHtmlRenderer
import im.vector.app.features.html.PillImageSpan
import im.vector.app.features.html.PillsPostProcessor
import im.vector.app.features.invite.VectorInviteView
-import im.vector.app.features.location.LocationData
import im.vector.app.features.location.LocationSharingMode
+import im.vector.app.features.location.toLocationData
import im.vector.app.features.media.ImageContentRenderer
import im.vector.app.features.media.VideoContentRenderer
import im.vector.app.features.notifications.NotificationDrawerManager
@@ -481,7 +481,6 @@ class RoomDetailFragment @Inject constructor(
RoomDetailViewEvents.StopChatEffects -> handleStopChatEffects()
is RoomDetailViewEvents.DisplayAndAcceptCall -> acceptIncomingCall(it)
RoomDetailViewEvents.RoomReplacementStarted -> handleRoomReplacement()
- is RoomDetailViewEvents.ShowLocation -> handleShowLocationPreview(it)
}.exhaustive
}
@@ -613,14 +612,14 @@ class RoomDetailFragment @Inject constructor(
}
}
- private fun handleShowLocationPreview(viewEvent: RoomDetailViewEvents.ShowLocation) {
+ private fun handleShowLocationPreview(locationContent: MessageLocationContent, senderId: String) {
navigator
.openLocationSharing(
context = requireContext(),
roomId = roomDetailArgs.roomId,
mode = LocationSharingMode.PREVIEW,
- initialLocationData = viewEvent.locationData,
- locationOwnerId = viewEvent.userId
+ initialLocationData = locationContent.toLocationData(),
+ locationOwnerId = senderId
)
}
@@ -1828,6 +1827,12 @@ class RoomDetailFragment @Inject constructor(
is EncryptedEventContent -> {
roomDetailViewModel.handle(RoomDetailAction.TapOnFailedToDecrypt(informationData.eventId))
}
+ is MessageLocationContent -> {
+ handleShowLocationPreview(messageContent, informationData.senderId)
+ }
+ else -> {
+ Timber.d("No click action defined for this message content")
+ }
}
}
@@ -1940,7 +1945,7 @@ class RoomDetailFragment @Inject constructor(
when (action.messageContent) {
is MessageTextContent -> shareText(requireContext(), action.messageContent.body)
is MessageLocationContent -> {
- LocationData.create(action.messageContent.getUri())?.let {
+ action.messageContent.toLocationData()?.let {
openLocation(requireActivity(), it.latitude, it.longitude)
}
}
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 b0921e01f9..86240a5ffe 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
@@ -20,7 +20,6 @@ import android.net.Uri
import android.view.View
import im.vector.app.core.platform.VectorViewEvents
import im.vector.app.features.call.webrtc.WebRtcCall
-import im.vector.app.features.location.LocationData
import org.matrix.android.sdk.api.session.widgets.model.Widget
import org.matrix.android.sdk.api.util.MatrixItem
import org.matrix.android.sdk.internal.crypto.model.event.WithHeldCode
@@ -83,6 +82,4 @@ sealed class RoomDetailViewEvents : VectorViewEvents {
data class StartChatEffect(val type: ChatEffect) : RoomDetailViewEvents()
object StopChatEffects : RoomDetailViewEvents()
object RoomReplacementStarted : RoomDetailViewEvents()
-
- data class ShowLocation(val locationData: LocationData, val userId: String) : 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 6e14b0fc76..9149ae1dca 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
@@ -53,7 +53,6 @@ import im.vector.app.features.home.room.detail.sticker.StickerPickerActionHandle
import im.vector.app.features.home.room.detail.timeline.factory.TimelineFactory
import im.vector.app.features.home.room.detail.timeline.url.PreviewUrlRetriever
import im.vector.app.features.home.room.typing.TypingHelper
-import im.vector.app.features.location.LocationData
import im.vector.app.features.powerlevel.PowerLevelsFlowFactory
import im.vector.app.features.session.coroutineScope
import im.vector.app.features.settings.VectorDataStore
@@ -385,14 +384,9 @@ class RoomDetailViewModel @AssistedInject constructor(
_viewEvents.post(RoomDetailViewEvents.OpenRoom(action.replacementRoomId, closeCurrentRoom = true))
}
is RoomDetailAction.EndPoll -> handleEndPoll(action.eventId)
- is RoomDetailAction.ShowLocation -> handleShowLocation(action.locationData, action.userId)
}.exhaustive
}
- private fun handleShowLocation(locationData: LocationData, userId: String) {
- _viewEvents.post(RoomDetailViewEvents.ShowLocation(locationData, userId))
- }
-
private fun handleJitsiCallJoinStatus(action: RoomDetailAction.UpdateJoinJitsiCallStatus) = withState { state ->
if (state.jitsiState.confId == null) {
// If jitsi widget is removed while on the call
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt
index 1ff9679479..086a093068 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt
@@ -39,7 +39,9 @@ import im.vector.app.features.home.room.detail.timeline.item.E2EDecoration
import im.vector.app.features.home.room.detail.timeline.tools.createLinkMovementMethod
import im.vector.app.features.home.room.detail.timeline.tools.linkify
import im.vector.app.features.html.SpanUtils
-import im.vector.app.features.location.LocationData
+import im.vector.app.features.location.INITIAL_MAP_ZOOM_IN_TIMELINE
+import im.vector.app.features.location.UrlMapProvider
+import im.vector.app.features.location.toLocationData
import im.vector.app.features.media.ImageContentRenderer
import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
import org.matrix.android.sdk.api.extensions.orFalse
@@ -62,6 +64,7 @@ class MessageActionsEpoxyController @Inject constructor(
private val spanUtils: SpanUtils,
private val eventDetailsFormatter: EventDetailsFormatter,
private val dateFormatter: VectorDateFormatter,
+ private val urlMapProvider: UrlMapProvider,
private val locationPinProvider: LocationPinProvider
) : TypedEpoxyController() {
@@ -74,9 +77,11 @@ class MessageActionsEpoxyController @Inject constructor(
val formattedDate = dateFormatter.format(date, DateFormatKind.MESSAGE_DETAIL)
val body = state.messageBody.linkify(host.listener)
val bindingOptions = spanUtils.getBindingOptions(body)
- val locationData = state.timelineEvent()?.root?.getClearContent()?.toModel(catchError = true)?.let {
- LocationData.create(it.getUri())
- }
+ val locationUrl = state.timelineEvent()?.root?.getClearContent()
+ ?.toModel(catchError = true)
+ ?.toLocationData()
+ ?.let { urlMapProvider.buildStaticMapUrl(it, INITIAL_MAP_ZOOM_IN_TIMELINE, 1200, 800) }
+
bottomSheetMessagePreviewItem {
id("preview")
avatarRenderer(host.avatarRenderer)
@@ -89,7 +94,7 @@ class MessageActionsEpoxyController @Inject constructor(
body(body.toEpoxyCharSequence())
bodyDetails(host.eventDetailsFormatter.format(state.timelineEvent()?.root)?.toEpoxyCharSequence())
time(formattedDate)
- locationData(locationData)
+ locationUrl(locationUrl)
locationPinProvider(host.locationPinProvider)
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt
index eab7621d14..352b87a4d8 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt
@@ -16,6 +16,7 @@
package im.vector.app.features.home.room.detail.timeline.factory
+import android.content.res.Resources
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.Spanned
@@ -33,7 +34,6 @@ import im.vector.app.core.resources.ColorProvider
import im.vector.app.core.resources.StringProvider
import im.vector.app.core.utils.DimensionConverter
import im.vector.app.core.utils.containsOnlyEmojis
-import im.vector.app.features.home.room.detail.RoomDetailAction
import im.vector.app.features.home.room.detail.timeline.TimelineEventController
import im.vector.app.features.home.room.detail.timeline.helper.AvatarSizeProvider
import im.vector.app.features.home.room.detail.timeline.helper.ContentDownloadStateTrackerBinder
@@ -71,7 +71,9 @@ import im.vector.app.features.html.EventHtmlRenderer
import im.vector.app.features.html.PillsPostProcessor
import im.vector.app.features.html.SpanUtils
import im.vector.app.features.html.VectorHtmlCompressor
-import im.vector.app.features.location.LocationData
+import im.vector.app.features.location.INITIAL_MAP_ZOOM_IN_TIMELINE
+import im.vector.app.features.location.UrlMapProvider
+import im.vector.app.features.location.toLocationData
import im.vector.app.features.media.ImageContentRenderer
import im.vector.app.features.media.VideoContentRenderer
import im.vector.app.features.settings.VectorPreferences
@@ -127,7 +129,10 @@ class MessageItemFactory @Inject constructor(
private val session: Session,
private val voiceMessagePlaybackTracker: VoiceMessagePlaybackTracker,
private val locationPinProvider: LocationPinProvider,
- private val vectorPreferences: VectorPreferences) {
+ private val vectorPreferences: VectorPreferences,
+ private val urlMapProvider: UrlMapProvider,
+ private val resources: Resources
+) {
// TODO inject this properly?
private var roomId: String = ""
@@ -182,7 +187,7 @@ class MessageItemFactory @Inject constructor(
is MessagePollContent -> buildPollItem(messageContent, informationData, highlight, callback, attributes)
is MessageLocationContent -> {
if (vectorPreferences.labsRenderLocationsInTimeline()) {
- buildLocationItem(messageContent, informationData, highlight, callback, attributes)
+ buildLocationItem(messageContent, informationData, highlight, attributes)
} else {
buildMessageTextItem(messageContent.body, false, informationData, highlight, callback, attributes)
}
@@ -194,27 +199,21 @@ class MessageItemFactory @Inject constructor(
private fun buildLocationItem(locationContent: MessageLocationContent,
informationData: MessageInformationData,
highlight: Boolean,
- callback: TimelineEventController.Callback?,
attributes: AbsMessageItem.Attributes): MessageLocationItem? {
- val geoUri = locationContent.getUri()
- val locationData = LocationData.create(geoUri)
+ val width = resources.displayMetrics.widthPixels - dimensionConverter.dpToPx(60)
+ val height = dimensionConverter.dpToPx(200)
- val mapCallback: MessageLocationItem.Callback = object : MessageLocationItem.Callback {
- override fun onMapClicked() {
- locationData?.let {
- callback?.onTimelineItemAction(RoomDetailAction.ShowLocation(it, informationData.senderId))
- }
- }
+ val locationUrl = locationContent.toLocationData()?.let {
+ urlMapProvider.buildStaticMapUrl(it, INITIAL_MAP_ZOOM_IN_TIMELINE, width, height)
}
return MessageLocationItem_()
.attributes(attributes)
- .locationData(locationData)
+ .locationUrl(locationUrl)
.userId(informationData.senderId)
.locationPinProvider(locationPinProvider)
.highlighted(highlight)
.leftGuideline(avatarSizeProvider.leftGuideline)
- .callback(mapCallback)
}
private fun buildPollItem(pollContent: MessagePollContent,
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/LocationPinProvider.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/LocationPinProvider.kt
index fe3a7d9007..e92376c44d 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/LocationPinProvider.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/LocationPinProvider.kt
@@ -28,6 +28,7 @@ import im.vector.app.core.glide.GlideApp
import im.vector.app.core.utils.DimensionConverter
import im.vector.app.features.home.AvatarRenderer
import org.matrix.android.sdk.api.util.toMatrixItem
+import timber.log.Timber
import javax.inject.Inject
import javax.inject.Singleton
@@ -54,22 +55,36 @@ class LocationPinProvider @Inject constructor(
val size = dimensionConverter.dpToPx(44)
avatarRenderer.render(glideRequests, it, object : CustomTarget(size, size) {
override fun onResourceReady(resource: Drawable, transition: Transition?) {
- val bgUserPin = ContextCompat.getDrawable(context, R.drawable.bg_map_user_pin)!!
- val layerDrawable = LayerDrawable(arrayOf(bgUserPin, resource))
- val horizontalInset = dimensionConverter.dpToPx(4)
- val topInset = dimensionConverter.dpToPx(4)
- val bottomInset = dimensionConverter.dpToPx(8)
- layerDrawable.setLayerInset(1, horizontalInset, topInset, horizontalInset, bottomInset)
-
- cache[userId] = layerDrawable
-
- callback(layerDrawable)
+ Timber.d("## Location: onResourceReady")
+ val pinDrawable = createPinDrawable(resource)
+ cache[userId] = pinDrawable
+ callback(pinDrawable)
}
override fun onLoadCleared(placeholder: Drawable?) {
// Is it possible? Put placeholder instead?
+ // FIXME The doc says it has to be implemented and should free resources
+ Timber.d("## Location: onLoadCleared")
+ }
+
+ override fun onLoadFailed(errorDrawable: Drawable?) {
+ Timber.w("## Location: onLoadFailed")
+ errorDrawable ?: return
+ val pinDrawable = createPinDrawable(errorDrawable)
+ cache[userId] = pinDrawable
+ callback(pinDrawable)
}
})
}
}
+
+ private fun createPinDrawable(drawable: Drawable): Drawable {
+ val bgUserPin = ContextCompat.getDrawable(context, R.drawable.bg_map_user_pin)!!
+ val layerDrawable = LayerDrawable(arrayOf(bgUserPin, drawable))
+ val horizontalInset = dimensionConverter.dpToPx(4)
+ val topInset = dimensionConverter.dpToPx(4)
+ val bottomInset = dimensionConverter.dpToPx(8)
+ layerDrawable.setLayerInset(1, horizontalInset, topInset, horizontalInset, bottomInset)
+ return layerDrawable
+ }
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageLocationItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageLocationItem.kt
index 3f030866a5..6f0b6abb72 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageLocationItem.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageLocationItem.kt
@@ -16,28 +16,19 @@
package im.vector.app.features.home.room.detail.timeline.item
-import android.widget.FrameLayout
-import androidx.constraintlayout.widget.ConstraintLayout
+import android.widget.ImageView
import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass
+import com.bumptech.glide.request.RequestOptions
import im.vector.app.R
-import im.vector.app.core.epoxy.onClick
+import im.vector.app.core.glide.GlideApp
import im.vector.app.features.home.room.detail.timeline.helper.LocationPinProvider
-import im.vector.app.features.location.LocationData
-import im.vector.app.features.location.MapTilerMapView
@EpoxyModelClass(layout = R.layout.item_timeline_event_base)
abstract class MessageLocationItem : AbsMessageItem() {
- interface Callback {
- fun onMapClicked()
- }
-
@EpoxyAttribute
- var callback: Callback? = null
-
- @EpoxyAttribute
- var locationData: LocationData? = null
+ var locationUrl: String? = null
@EpoxyAttribute
var userId: String? = null
@@ -47,37 +38,31 @@ abstract class MessageLocationItem : AbsMessageItem(
override fun bind(holder: Holder) {
super.bind(holder)
- renderSendState(holder.mapViewContainer, null)
+ renderSendState(holder.view, null)
- val location = locationData ?: return
+ val location = locationUrl ?: return
val locationOwnerId = userId ?: return
- holder.clickableMapArea.onClick {
- callback?.onMapClicked()
- }
+ GlideApp.with(holder.staticMapImageView)
+ .load(location)
+ .apply(RequestOptions.centerCropTransform())
+ .into(holder.staticMapImageView)
- holder.mapView.apply {
- initialize {
- zoomToLocation(location.latitude, location.longitude, INITIAL_ZOOM)
-
- locationPinProvider?.create(locationOwnerId) { pinDrawable ->
- addPinToMap(locationOwnerId, pinDrawable)
- updatePinLocation(locationOwnerId, location.latitude, location.longitude)
- }
- }
+ locationPinProvider?.create(locationOwnerId) { pinDrawable ->
+ GlideApp.with(holder.staticMapPinImageView)
+ .load(pinDrawable)
+ .into(holder.staticMapPinImageView)
}
}
override fun getViewType() = STUB_ID
class Holder : AbsMessageItem.Holder(STUB_ID) {
- val mapViewContainer by bind(R.id.mapViewContainer)
- val mapView by bind(R.id.mapView)
- val clickableMapArea by bind(R.id.clickableMapArea)
+ val staticMapImageView by bind(R.id.staticMapImageView)
+ val staticMapPinImageView by bind(R.id.staticMapPinImageView)
}
companion object {
private const val STUB_ID = R.id.messageContentLocationStub
- private const val INITIAL_ZOOM = 15.0
}
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageTextItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageTextItem.kt
index 1794f04c2a..e5ac321d90 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageTextItem.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageTextItem.kt
@@ -109,6 +109,7 @@ abstract class MessageTextItem : AbsMessageItem() {
val textFuture = PrecomputedTextCompat.getTextFuture(message, TextViewCompat.getTextMetricsParams(this), null)
setTextFuture(textFuture)
} else {
+ setTextFuture(null)
text = message
}
}
diff --git a/vector/src/main/java/im/vector/app/features/location/Config.kt b/vector/src/main/java/im/vector/app/features/location/Config.kt
index 630df16a37..29ca6b81a9 100644
--- a/vector/src/main/java/im/vector/app/features/location/Config.kt
+++ b/vector/src/main/java/im/vector/app/features/location/Config.kt
@@ -16,6 +16,10 @@
package im.vector.app.features.location
-const val INITIAL_MAP_ZOOM = 15.0
-const val MIN_TIME_MILLIS_TO_UPDATE_LOCATION = 1 * 60 * 1000L // every 1 minute
-const val MIN_DISTANCE_METERS_TO_UPDATE_LOCATION = 10f
+const val MAP_BASE_URL = "https://api.maptiler.com/maps/streets/style.json"
+const val STATIC_MAP_BASE_URL = "https://api.maptiler.com/maps/basic/static/"
+
+const val INITIAL_MAP_ZOOM_IN_PREVIEW = 15.0
+const val INITIAL_MAP_ZOOM_IN_TIMELINE = 17.0
+const val MIN_TIME_TO_UPDATE_LOCATION_MILLIS = 5 * 1_000L // every 5 seconds
+const val MIN_DISTANCE_TO_UPDATE_LOCATION_METERS = 10f
diff --git a/vector/src/main/java/im/vector/app/features/location/LocationData.kt b/vector/src/main/java/im/vector/app/features/location/LocationData.kt
index c3ff09ebcd..a69d8d20e3 100644
--- a/vector/src/main/java/im/vector/app/features/location/LocationData.kt
+++ b/vector/src/main/java/im/vector/app/features/location/LocationData.kt
@@ -17,41 +17,43 @@
package im.vector.app.features.location
import android.os.Parcelable
+import androidx.annotation.VisibleForTesting
import kotlinx.parcelize.Parcelize
+import org.matrix.android.sdk.api.session.room.model.message.MessageLocationContent
@Parcelize
data class LocationData(
val latitude: Double,
val longitude: Double,
val uncertainty: Double?
-) : Parcelable {
+) : Parcelable
- companion object {
-
- /**
- * Creates location data from geo uri
- * @param geoUri geo:latitude,longitude;uncertainty
- * @return location data or null if geo uri is not valid
- */
- fun create(geoUri: String): LocationData? {
- val geoParts = geoUri
- .split(":")
- .takeIf { it.firstOrNull() == "geo" }
- ?.getOrNull(1)
- ?.split(",")
-
- val latitude = geoParts?.firstOrNull()
- val geoTailParts = geoParts?.getOrNull(1)?.split(";")
- val longitude = geoTailParts?.firstOrNull()
- val uncertainty = geoTailParts?.getOrNull(1)?.replace("u=", "")
-
- return if (latitude != null && longitude != null) {
- LocationData(
- latitude = latitude.toDouble(),
- longitude = longitude.toDouble(),
- uncertainty = uncertainty?.toDouble()
- )
- } else null
- }
- }
+/**
+ * Creates location data from a LocationContent
+ * "geo:40.05,29.24;30" -> LocationData(40.05, 29.24, 30)
+ * @return location data or null if geo uri is not valid
+ */
+fun MessageLocationContent.toLocationData(): LocationData? {
+ return parseGeo(getBestGeoUri())
+}
+
+@VisibleForTesting
+fun parseGeo(geo: String): LocationData? {
+ val geoParts = geo
+ .split(":")
+ .takeIf { it.firstOrNull() == "geo" }
+ ?.getOrNull(1)
+ ?.split(";") ?: return null
+
+ val gpsParts = geoParts.getOrNull(0)?.split(",") ?: return null
+ val lat = gpsParts.getOrNull(0)?.toDoubleOrNull() ?: return null
+ val lng = gpsParts.getOrNull(1)?.toDoubleOrNull() ?: return null
+
+ val uncertainty = geoParts.getOrNull(1)?.replace("u=", "")?.toDoubleOrNull()
+
+ return LocationData(
+ latitude = lat,
+ longitude = lng,
+ uncertainty = uncertainty
+ )
}
diff --git a/vector/src/main/java/im/vector/app/features/location/LocationPreviewFragment.kt b/vector/src/main/java/im/vector/app/features/location/LocationPreviewFragment.kt
index 6209bf5a4f..c4f2f148bf 100644
--- a/vector/src/main/java/im/vector/app/features/location/LocationPreviewFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/location/LocationPreviewFragment.kt
@@ -21,20 +21,30 @@ import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
+import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.args
+import com.mapbox.mapboxsdk.maps.MapView
import im.vector.app.R
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.utils.openLocation
import im.vector.app.databinding.FragmentLocationPreviewBinding
import im.vector.app.features.home.room.detail.timeline.helper.LocationPinProvider
+import java.lang.ref.WeakReference
import javax.inject.Inject
+/**
+ * TODO Move locationPinProvider to a ViewModel
+ */
class LocationPreviewFragment @Inject constructor(
+ private val urlMapProvider: UrlMapProvider,
private val locationPinProvider: LocationPinProvider
) : VectorBaseFragment() {
private val args: LocationSharingArgs by args()
+ // Keep a ref to handle properly the onDestroy callback
+ private var mapView: WeakReference? = null
+
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLocationPreviewBinding {
return FragmentLocationPreviewBinding.inflate(layoutInflater, container, false)
}
@@ -42,11 +52,15 @@ class LocationPreviewFragment @Inject constructor(
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
- views.mapView.initialize {
- if (isAdded) {
- onMapReady()
- }
- }
+ mapView = WeakReference(views.mapView)
+ views.mapView.onCreate(savedInstanceState)
+ views.mapView.initialize(urlMapProvider.mapUrl)
+ loadPinDrawable()
+ }
+
+ override fun onResume() {
+ super.onResume()
+ views.mapView.onResume()
}
override fun onPause() {
@@ -54,11 +68,32 @@ class LocationPreviewFragment @Inject constructor(
super.onPause()
}
+ override fun onLowMemory() {
+ views.mapView.onLowMemory()
+ super.onLowMemory()
+ }
+
+ override fun onStart() {
+ super.onStart()
+ views.mapView.onStart()
+ }
+
override fun onStop() {
views.mapView.onStop()
super.onStop()
}
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ views.mapView.onSaveInstanceState(outState)
+ }
+
+ override fun onDestroy() {
+ mapView?.get()?.onDestroy()
+ mapView?.clear()
+ super.onDestroy()
+ }
+
override fun getMenuRes() = R.menu.menu_location_preview
override fun onOptionsItemSelected(item: MenuItem): Boolean {
@@ -76,18 +111,20 @@ class LocationPreviewFragment @Inject constructor(
openLocation(requireActivity(), location.latitude, location.longitude)
}
- private fun onMapReady() {
- if (!isAdded) return
-
+ private fun loadPinDrawable() {
val location = args.initialLocationData ?: return
val userId = args.locationOwnerId
locationPinProvider.create(userId) { pinDrawable ->
- views.mapView.apply {
- zoomToLocation(location.latitude, location.longitude, INITIAL_MAP_ZOOM)
- deleteAllPins()
- addPinToMap(userId, pinDrawable)
- updatePinLocation(userId, location.latitude, location.longitude)
+ lifecycleScope.launchWhenResumed {
+ views.mapView.render(
+ MapState(
+ zoomOnlyOnce = true,
+ pinLocationData = location,
+ pinId = args.locationOwnerId,
+ pinDrawable = pinDrawable
+ )
+ )
}
}
}
diff --git a/vector/src/main/java/im/vector/app/features/location/LocationSharingAction.kt b/vector/src/main/java/im/vector/app/features/location/LocationSharingAction.kt
index 71101d0612..01319ef6c7 100644
--- a/vector/src/main/java/im/vector/app/features/location/LocationSharingAction.kt
+++ b/vector/src/main/java/im/vector/app/features/location/LocationSharingAction.kt
@@ -19,7 +19,5 @@ package im.vector.app.features.location
import im.vector.app.core.platform.VectorViewModelAction
sealed class LocationSharingAction : VectorViewModelAction {
- data class OnLocationUpdate(val locationData: LocationData) : LocationSharingAction()
object OnShareLocation : LocationSharingAction()
- object OnLocationProviderIsNotAvailable : LocationSharingAction()
}
diff --git a/vector/src/main/java/im/vector/app/features/location/LocationSharingFragment.kt b/vector/src/main/java/im/vector/app/features/location/LocationSharingFragment.kt
index 900f465f04..f6bad2826b 100644
--- a/vector/src/main/java/im/vector/app/features/location/LocationSharingFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/location/LocationSharingFragment.kt
@@ -20,29 +20,29 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import androidx.core.view.isGone
import com.airbnb.mvrx.fragmentViewModel
+import com.airbnb.mvrx.withState
import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.mapbox.mapboxsdk.maps.MapView
import im.vector.app.R
import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentLocationSharingBinding
-import im.vector.app.features.home.room.detail.timeline.helper.LocationPinProvider
-import org.matrix.android.sdk.api.session.Session
+import java.lang.ref.WeakReference
import javax.inject.Inject
+/**
+ * We should consider using SupportMapFragment for a out of the box lifecycle handling
+ */
class LocationSharingFragment @Inject constructor(
- private val locationTracker: LocationTracker,
- private val session: Session,
- private val locationPinProvider: LocationPinProvider
-) : VectorBaseFragment(), LocationTracker.Callback {
-
- init {
- locationTracker.callback = this
- }
+ private val urlMapProvider: UrlMapProvider
+) : VectorBaseFragment() {
private val viewModel: LocationSharingViewModel by fragmentViewModel()
- private var lastZoomValue: Double = -1.0
+ // Keep a ref to handle properly the onDestroy callback
+ private var mapView: WeakReference? = null
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLocationSharingBinding {
return FragmentLocationSharingBinding.inflate(inflater, container, false)
@@ -51,11 +51,9 @@ class LocationSharingFragment @Inject constructor(
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
- views.mapView.initialize {
- if (isAdded) {
- onMapReady()
- }
- }
+ mapView = WeakReference(views.mapView)
+ views.mapView.onCreate(savedInstanceState)
+ views.mapView.initialize(urlMapProvider.mapUrl)
views.shareLocationContainer.debouncedClicks {
viewModel.handle(LocationSharingAction.OnShareLocation)
@@ -63,54 +61,48 @@ class LocationSharingFragment @Inject constructor(
viewModel.observeViewEvents {
when (it) {
- LocationSharingViewEvents.LocationNotAvailableError -> handleLocationNotAvailableError()
- LocationSharingViewEvents.Close -> activity?.finish()
+ LocationSharingViewEvents.LocationNotAvailableError -> handleLocationNotAvailableError()
+ LocationSharingViewEvents.Close -> activity?.finish()
}.exhaustive
}
}
+ override fun onResume() {
+ super.onResume()
+ views.mapView.onResume()
+ }
+
override fun onPause() {
views.mapView.onPause()
super.onPause()
}
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ views.mapView.onSaveInstanceState(outState)
+ }
+
+ override fun onStart() {
+ super.onStart()
+ views.mapView.onStart()
+ }
+
override fun onStop() {
views.mapView.onStop()
super.onStop()
}
+ override fun onLowMemory() {
+ super.onLowMemory()
+ views.mapView.onLowMemory()
+ }
+
override fun onDestroy() {
- locationTracker.stop()
+ mapView?.get()?.onDestroy()
+ mapView?.clear()
super.onDestroy()
}
- private fun onMapReady() {
- if (!isAdded) return
-
- locationPinProvider.create(session.myUserId) {
- views.mapView.addPinToMap(
- pinId = USER_PIN_NAME,
- image = it,
- )
- // All set, start location tracker
- locationTracker.start()
- }
- }
-
- override fun onLocationUpdate(locationData: LocationData) {
- lastZoomValue = if (lastZoomValue == -1.0) INITIAL_MAP_ZOOM else views.mapView.getCurrentZoom() ?: INITIAL_MAP_ZOOM
-
- views.mapView.zoomToLocation(locationData.latitude, locationData.longitude, lastZoomValue)
- views.mapView.deleteAllPins()
- views.mapView.updatePinLocation(USER_PIN_NAME, locationData.latitude, locationData.longitude)
-
- viewModel.handle(LocationSharingAction.OnLocationUpdate(locationData))
- }
-
- override fun onLocationProviderIsNotAvailable() {
- viewModel.handle(LocationSharingAction.OnLocationProviderIsNotAvailable)
- }
-
private fun handleLocationNotAvailableError() {
MaterialAlertDialogBuilder(requireActivity())
.setTitle(R.string.location_not_available_dialog_title)
@@ -118,9 +110,15 @@ class LocationSharingFragment @Inject constructor(
.setPositiveButton(R.string.ok) { _, _ ->
activity?.finish()
}
+ .setCancelable(false)
.show()
}
+ override fun invalidate() = withState(viewModel) { state ->
+ views.mapView.render(state.toMapState())
+ views.shareLocationGpsLoading.isGone = state.lastKnownLocation != null
+ }
+
companion object {
const val USER_PIN_NAME = "USER_PIN_NAME"
}
diff --git a/vector/src/main/java/im/vector/app/features/location/LocationSharingViewModel.kt b/vector/src/main/java/im/vector/app/features/location/LocationSharingViewModel.kt
index b3c97310e1..f4e1fd0281 100644
--- a/vector/src/main/java/im/vector/app/features/location/LocationSharingViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/location/LocationSharingViewModel.kt
@@ -24,12 +24,15 @@ import im.vector.app.core.di.MavericksAssistedViewModelFactory
import im.vector.app.core.di.hiltMavericksViewModelFactory
import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.platform.VectorViewModel
+import im.vector.app.features.home.room.detail.timeline.helper.LocationPinProvider
import org.matrix.android.sdk.api.session.Session
class LocationSharingViewModel @AssistedInject constructor(
@Assisted private val initialState: LocationSharingViewState,
- session: Session
-) : VectorViewModel(initialState) {
+ private val locationTracker: LocationTracker,
+ private val locationPinProvider: LocationPinProvider,
+ private val session: Session
+) : VectorViewModel(initialState), LocationTracker.Callback {
private val room = session.getRoom(initialState.roomId)!!
@@ -38,14 +41,31 @@ class LocationSharingViewModel @AssistedInject constructor(
override fun create(initialState: LocationSharingViewState): LocationSharingViewModel
}
- companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() {
+ companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory()
+
+ init {
+ locationTracker.start(this)
+ createPin()
+ }
+
+ private fun createPin() {
+ locationPinProvider.create(session.myUserId) {
+ setState {
+ copy(
+ pinDrawable = it
+ )
+ }
+ }
+ }
+
+ override fun onCleared() {
+ super.onCleared()
+ locationTracker.stop()
}
override fun handle(action: LocationSharingAction) {
when (action) {
- is LocationSharingAction.OnLocationUpdate -> handleLocationUpdate(action.locationData)
- LocationSharingAction.OnShareLocation -> handleShareLocation()
- LocationSharingAction.OnLocationProviderIsNotAvailable -> handleLocationProviderIsNotAvailable()
+ LocationSharingAction.OnShareLocation -> handleShareLocation()
}.exhaustive
}
@@ -62,13 +82,13 @@ class LocationSharingViewModel @AssistedInject constructor(
}
}
- private fun handleLocationUpdate(locationData: LocationData) {
+ override fun onLocationUpdate(locationData: LocationData) {
setState {
copy(lastKnownLocation = locationData)
}
}
- private fun handleLocationProviderIsNotAvailable() {
+ override fun onLocationProviderIsNotAvailable() {
_viewEvents.post(LocationSharingViewEvents.LocationNotAvailableError)
}
}
diff --git a/vector/src/main/java/im/vector/app/features/location/LocationSharingViewState.kt b/vector/src/main/java/im/vector/app/features/location/LocationSharingViewState.kt
index 2869929b12..f3b937855a 100644
--- a/vector/src/main/java/im/vector/app/features/location/LocationSharingViewState.kt
+++ b/vector/src/main/java/im/vector/app/features/location/LocationSharingViewState.kt
@@ -16,6 +16,7 @@
package im.vector.app.features.location
+import android.graphics.drawable.Drawable
import androidx.annotation.StringRes
import com.airbnb.mvrx.MavericksState
import im.vector.app.R
@@ -28,7 +29,8 @@ enum class LocationSharingMode(@StringRes val titleRes: Int) {
data class LocationSharingViewState(
val roomId: String,
val mode: LocationSharingMode,
- val lastKnownLocation: LocationData? = null
+ val lastKnownLocation: LocationData? = null,
+ val pinDrawable: Drawable? = null
) : MavericksState {
constructor(locationSharingArgs: LocationSharingArgs) : this(
@@ -36,3 +38,10 @@ data class LocationSharingViewState(
mode = locationSharingArgs.mode
)
}
+
+fun LocationSharingViewState.toMapState() = MapState(
+ zoomOnlyOnce = true,
+ pinLocationData = lastKnownLocation,
+ pinId = LocationSharingFragment.USER_PIN_NAME,
+ pinDrawable = pinDrawable
+)
diff --git a/vector/src/main/java/im/vector/app/features/location/LocationTracker.kt b/vector/src/main/java/im/vector/app/features/location/LocationTracker.kt
index 0c0315cf34..162fbc5959 100644
--- a/vector/src/main/java/im/vector/app/features/location/LocationTracker.kt
+++ b/vector/src/main/java/im/vector/app/features/location/LocationTracker.kt
@@ -19,70 +19,108 @@ package im.vector.app.features.location
import android.Manifest
import android.content.Context
import android.location.Location
-import android.location.LocationListener
import android.location.LocationManager
import androidx.annotation.RequiresPermission
import androidx.core.content.getSystemService
+import androidx.core.location.LocationListenerCompat
+import im.vector.app.BuildConfig
import timber.log.Timber
import javax.inject.Inject
class LocationTracker @Inject constructor(
- private val context: Context
-) : LocationListener {
+ context: Context
+) : LocationListenerCompat {
+
+ private val locationManager = context.getSystemService()
interface Callback {
fun onLocationUpdate(locationData: LocationData)
fun onLocationProviderIsNotAvailable()
}
- private var locationManager: LocationManager? = null
- var callback: Callback? = null
+ private var callback: Callback? = null
+
+ private var hasGpsProviderLiveLocation = false
@RequiresPermission(anyOf = [Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION])
- fun start() {
- val locationManager = context.getSystemService()
+ fun start(callback: Callback?) {
+ Timber.d("## LocationTracker. start()")
+ hasGpsProviderLiveLocation = false
+ this.callback = callback
- locationManager?.let {
- val isGpsEnabled = it.isProviderEnabled(LocationManager.GPS_PROVIDER)
- val isNetworkEnabled = it.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
-
- val provider = when {
- isGpsEnabled -> LocationManager.GPS_PROVIDER
- isNetworkEnabled -> LocationManager.NETWORK_PROVIDER
- else -> {
- callback?.onLocationProviderIsNotAvailable()
- Timber.v("## LocationTracker. There is no location provider available")
- return
- }
- }
-
- // Send last known location without waiting location updates
- it.getLastKnownLocation(provider)?.let { lastKnownLocation ->
- callback?.onLocationUpdate(lastKnownLocation.toLocationData())
- }
-
- it.requestLocationUpdates(
- provider,
- MIN_TIME_MILLIS_TO_UPDATE_LOCATION,
- MIN_DISTANCE_METERS_TO_UPDATE_LOCATION,
- this
- )
- } ?: run {
+ if (locationManager == null) {
callback?.onLocationProviderIsNotAvailable()
Timber.v("## LocationTracker. LocationManager is not available")
+ return
}
+
+ locationManager.allProviders
+ .takeIf { it.isNotEmpty() }
+ // Take GPS first
+ ?.sortedByDescending { if (it == LocationManager.GPS_PROVIDER) 1 else 0 }
+ ?.forEach { provider ->
+ Timber.d("## LocationTracker. track location using $provider")
+
+ // Send last known location without waiting location updates
+ locationManager.getLastKnownLocation(provider)?.let { lastKnownLocation ->
+ if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) {
+ Timber.d("## LocationTracker. lastKnownLocation: $lastKnownLocation")
+ } else {
+ Timber.d("## LocationTracker. lastKnownLocation: ${lastKnownLocation.provider}")
+ }
+ notifyLocation(lastKnownLocation, isLive = false)
+ }
+
+ locationManager.requestLocationUpdates(
+ provider,
+ MIN_TIME_TO_UPDATE_LOCATION_MILLIS,
+ MIN_DISTANCE_TO_UPDATE_LOCATION_METERS,
+ this
+ )
+ }
+ ?: run {
+ callback?.onLocationProviderIsNotAvailable()
+ Timber.v("## LocationTracker. There is no location provider available")
+ }
}
@RequiresPermission(anyOf = [Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION])
fun stop() {
+ Timber.d("## LocationTracker. stop()")
locationManager?.removeUpdates(this)
callback = null
}
override fun onLocationChanged(location: Location) {
+ if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) {
+ Timber.d("## LocationTracker. onLocationChanged: $location")
+ } else {
+ Timber.d("## LocationTracker. onLocationChanged: ${location.provider}")
+ }
+ notifyLocation(location, isLive = true)
+ }
+
+ private fun notifyLocation(location: Location, isLive: Boolean) {
+ when (location.provider) {
+ LocationManager.GPS_PROVIDER -> {
+ hasGpsProviderLiveLocation = isLive
+ }
+ else -> {
+ if (hasGpsProviderLiveLocation) {
+ // Ignore this update
+ Timber.d("## LocationTracker. ignoring location from ${location.provider}, we have gps live location")
+ return
+ }
+ }
+ }
callback?.onLocationUpdate(location.toLocationData())
}
+ override fun onProviderDisabled(provider: String) {
+ Timber.d("## LocationTracker. onProviderDisabled: $provider")
+ callback?.onLocationProviderIsNotAvailable()
+ }
+
private fun Location.toLocationData(): LocationData {
return LocationData(latitude, longitude, accuracy.toDouble())
}
diff --git a/vector/src/main/java/im/vector/app/features/location/VectorMapView.kt b/vector/src/main/java/im/vector/app/features/location/MapState.kt
similarity index 61%
rename from vector/src/main/java/im/vector/app/features/location/VectorMapView.kt
rename to vector/src/main/java/im/vector/app/features/location/MapState.kt
index 23b59bf99a..d001457e4f 100644
--- a/vector/src/main/java/im/vector/app/features/location/VectorMapView.kt
+++ b/vector/src/main/java/im/vector/app/features/location/MapState.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 New Vector Ltd
+ * Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,15 +18,9 @@ package im.vector.app.features.location
import android.graphics.drawable.Drawable
-interface VectorMapView {
- fun initialize(onMapReady: () -> Unit)
-
- fun addPinToMap(pinId: String, image: Drawable)
- fun updatePinLocation(pinId: String, latitude: Double, longitude: Double)
- fun deleteAllPins()
-
- fun zoomToLocation(latitude: Double, longitude: Double, zoom: Double)
- fun getCurrentZoom(): Double?
-
- fun onClick(callback: () -> Unit)
-}
+data class MapState(
+ val zoomOnlyOnce: Boolean,
+ val pinLocationData: LocationData? = null,
+ val pinId: String,
+ val pinDrawable: Drawable? = null
+)
diff --git a/vector/src/main/java/im/vector/app/features/location/MapTilerMapView.kt b/vector/src/main/java/im/vector/app/features/location/MapTilerMapView.kt
index c64af1ebaa..dd80f701f6 100644
--- a/vector/src/main/java/im/vector/app/features/location/MapTilerMapView.kt
+++ b/vector/src/main/java/im/vector/app/features/location/MapTilerMapView.kt
@@ -17,7 +17,6 @@
package im.vector.app.features.location
import android.content.Context
-import android.graphics.drawable.Drawable
import android.util.AttributeSet
import com.mapbox.mapboxsdk.camera.CameraPosition
import com.mapbox.mapboxsdk.geometry.LatLng
@@ -27,65 +26,76 @@ import com.mapbox.mapboxsdk.maps.Style
import com.mapbox.mapboxsdk.plugins.annotation.SymbolManager
import com.mapbox.mapboxsdk.plugins.annotation.SymbolOptions
import com.mapbox.mapboxsdk.style.layers.Property
-import im.vector.app.BuildConfig
+import timber.log.Timber
class MapTilerMapView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
-) : MapView(context, attrs, defStyleAttr), VectorMapView {
+) : MapView(context, attrs, defStyleAttr) {
- private var map: MapboxMap? = null
- private var symbolManager: SymbolManager? = null
- private var style: Style? = null
+ private var pendingState: MapState? = null
- override fun initialize(onMapReady: () -> Unit) {
+ data class MapRefs(
+ val map: MapboxMap,
+ val symbolManager: SymbolManager,
+ val style: Style
+ )
+
+ private var mapRefs: MapRefs? = null
+ private var initZoomDone = false
+
+ /**
+ * For location fragments
+ */
+ fun initialize(url: String) {
+ Timber.d("## Location: initialize")
getMapAsync { map ->
- map.setStyle(styleUrl) { style ->
- this.symbolManager = SymbolManager(this, map, style)
- this.map = map
- this.style = style
- onMapReady()
+ map.setStyle(url) { style ->
+ mapRefs = MapRefs(
+ map,
+ SymbolManager(this, map, style),
+ style
+ )
+ pendingState?.let { render(it) }
+ pendingState = null
}
}
}
- override fun addPinToMap(pinId: String, image: Drawable) {
- style?.addImage(pinId, image)
- }
+ fun render(state: MapState) {
+ val safeMapRefs = mapRefs ?: return Unit.also {
+ pendingState = state
+ }
- override fun updatePinLocation(pinId: String, latitude: Double, longitude: Double) {
- symbolManager?.create(
- SymbolOptions()
- .withLatLng(LatLng(latitude, longitude))
- .withIconImage(pinId)
- .withIconAnchor(Property.ICON_ANCHOR_BOTTOM)
- )
- }
+ state.pinDrawable?.let { pinDrawable ->
+ if (!safeMapRefs.style.isFullyLoaded ||
+ safeMapRefs.style.getImage(state.pinId) == null) {
+ safeMapRefs.style.addImage(state.pinId, pinDrawable)
+ }
+ }
- override fun deleteAllPins() {
- symbolManager?.deleteAll()
- }
+ state.pinLocationData?.let { locationData ->
+ if (!initZoomDone || !state.zoomOnlyOnce) {
+ zoomToLocation(locationData.latitude, locationData.longitude)
+ initZoomDone = true
+ }
- override fun zoomToLocation(latitude: Double, longitude: Double, zoom: Double) {
- map?.cameraPosition = CameraPosition.Builder()
- .target(LatLng(latitude, longitude))
- .zoom(zoom)
- .build()
- }
-
- override fun getCurrentZoom(): Double? {
- return map?.cameraPosition?.zoom
- }
-
- override fun onClick(callback: () -> Unit) {
- map?.addOnMapClickListener {
- callback()
- true
+ safeMapRefs.symbolManager.deleteAll()
+ safeMapRefs.symbolManager.create(
+ SymbolOptions()
+ .withLatLng(LatLng(locationData.latitude, locationData.longitude))
+ .withIconImage(state.pinId)
+ .withIconAnchor(Property.ICON_ANCHOR_BOTTOM)
+ )
}
}
- companion object {
- private const val styleUrl = "https://api.maptiler.com/maps/streets/style.json?key=${BuildConfig.mapTilerKey}"
+ private fun zoomToLocation(latitude: Double, longitude: Double) {
+ Timber.d("## Location: zoomToLocation")
+ mapRefs?.map?.cameraPosition = CameraPosition.Builder()
+ .target(LatLng(latitude, longitude))
+ .zoom(INITIAL_MAP_ZOOM_IN_PREVIEW)
+ .build()
}
}
diff --git a/vector/src/main/java/im/vector/app/features/location/UrlMapProvider.kt b/vector/src/main/java/im/vector/app/features/location/UrlMapProvider.kt
new file mode 100644
index 0000000000..76d44f5ece
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/location/UrlMapProvider.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2022 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.location
+
+import android.content.res.Resources
+import im.vector.app.BuildConfig
+import im.vector.app.R
+import javax.inject.Inject
+
+class UrlMapProvider @Inject constructor(
+ private val resources: Resources
+) {
+ private val keyParam = "?key=${BuildConfig.mapTilerKey}"
+
+ // This is static so no need for a fun
+ val mapUrl = buildString {
+ append(MAP_BASE_URL)
+ append(keyParam)
+ }
+
+ fun buildStaticMapUrl(locationData: LocationData,
+ zoom: Double,
+ width: Int,
+ height: Int): String {
+ return buildString {
+ append(STATIC_MAP_BASE_URL)
+ append(locationData.longitude)
+ append(",")
+ append(locationData.latitude)
+ append(",")
+ append(zoom)
+ append("/")
+ append(width)
+ append("x")
+ append(height)
+ append(".png")
+ append(keyParam)
+ if (!resources.getBoolean(R.bool.is_rtl)) {
+ // On LTR languages we want the legal mentions to be displayed on the bottom left of the image
+ append("&attribution=bottomleft")
+ }
+ }
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt
index f66ced3299..8f0b1723a0 100644
--- a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt
+++ b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt
@@ -524,9 +524,13 @@ class DefaultNavigator @Inject constructor(
context.startActivity(RoomDevToolActivity.intent(context, roomId))
}
- override fun openCallTransfer(context: Context, callId: String) {
+ override fun openCallTransfer(
+ context: Context,
+ activityResultLauncher: ActivityResultLauncher,
+ callId: String
+ ) {
val intent = CallTransferActivity.newIntent(context, callId)
- context.startActivity(intent)
+ activityResultLauncher.launch(intent)
}
override fun openCreatePoll(context: Context, roomId: String, editedEventId: String?, mode: PollMode) {
diff --git a/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt b/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt
index 775272bd33..d6ca83a8a3 100644
--- a/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt
+++ b/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt
@@ -149,7 +149,11 @@ interface Navigator {
fun openDevTools(context: Context, roomId: String)
- fun openCallTransfer(context: Context, callId: String)
+ fun openCallTransfer(
+ context: Context,
+ activityResultLauncher: ActivityResultLauncher,
+ callId: String
+ )
fun openCreatePoll(context: Context, roomId: String, editedEventId: String?, mode: PollMode)
diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventProcessor.kt b/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventProcessor.kt
index 3d10d74fe3..351f085b7e 100644
--- a/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventProcessor.kt
+++ b/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventProcessor.kt
@@ -20,6 +20,7 @@ import im.vector.app.features.invite.AutoAcceptInvites
import im.vector.app.features.notifications.ProcessedEvent.Type.KEEP
import im.vector.app.features.notifications.ProcessedEvent.Type.REMOVE
import org.matrix.android.sdk.api.session.events.model.EventType
+import timber.log.Timber
import javax.inject.Inject
private typealias ProcessedEvents = List>
@@ -33,9 +34,13 @@ class NotifiableEventProcessor @Inject constructor(
val processedEvents = queuedEvents.map {
val type = when (it) {
is InviteNotifiableEvent -> if (autoAcceptInvites.hideInvites) REMOVE else KEEP
- is NotifiableMessageEvent -> if (shouldIgnoreMessageEventInRoom(currentRoomId, it.roomId) || outdatedDetector.isMessageOutdated(it)) {
- REMOVE
- } else KEEP
+ is NotifiableMessageEvent -> when {
+ shouldIgnoreMessageEventInRoom(currentRoomId, it.roomId) -> REMOVE
+ .also { Timber.d("notification message removed due to currently viewing the same room") }
+ outdatedDetector.isMessageOutdated(it) -> REMOVE
+ .also { Timber.d("notification message removed due to being read") }
+ else -> KEEP
+ }
is SimpleNotifiableEvent -> when (it.type) {
EventType.REDACTION -> REMOVE
else -> KEEP
diff --git a/vector/src/main/java/im/vector/app/features/notifications/PushRuleTriggerListener.kt b/vector/src/main/java/im/vector/app/features/notifications/PushRuleTriggerListener.kt
index ff817520db..cd08820fc1 100644
--- a/vector/src/main/java/im/vector/app/features/notifications/PushRuleTriggerListener.kt
+++ b/vector/src/main/java/im/vector/app/features/notifications/PushRuleTriggerListener.kt
@@ -55,12 +55,12 @@ class PushRuleTriggerListener @Inject constructor(
private suspend fun createNotifiableEvents(pushEvents: PushEvents, session: Session): List {
return pushEvents.matchedEvents.mapNotNull { (event, pushRule) ->
- Timber.v("Push rule match for event ${event.eventId}")
+ Timber.d("Push rule match for event ${event.eventId}")
val action = pushRule.getActions().toNotificationAction()
if (action.shouldNotify) {
resolver.resolveEvent(event, session, isNoisy = !action.soundName.isNullOrBlank())
} else {
- Timber.v("Matched push rule is set to not notify")
+ Timber.d("Matched push rule is set to not notify")
null
}
}
diff --git a/vector/src/main/res/layout/fragment_location_sharing.xml b/vector/src/main/res/layout/fragment_location_sharing.xml
index b9f00786de..ad418f3e1c 100644
--- a/vector/src/main/res/layout/fragment_location_sharing.xml
+++ b/vector/src/main/res/layout/fragment_location_sharing.xml
@@ -1,50 +1,60 @@
+ android:layout_height="0dp"
+ app:layout_constraintBottom_toTopOf="@id/shareLocationContainer"
+ app:layout_constraintTop_toTopOf="parent"
+ app:mapbox_renderTextureMode="true"
+ tools:background="#4F00" />
-
+ app:layout_constraintStart_toStartOf="parent" />
-
+
-
+
-
+
\ No newline at end of file
diff --git a/vector/src/main/res/layout/item_bottom_sheet_message_preview.xml b/vector/src/main/res/layout/item_bottom_sheet_message_preview.xml
index 95e6975803..e40760e046 100644
--- a/vector/src/main/res/layout/item_bottom_sheet_message_preview.xml
+++ b/vector/src/main/res/layout/item_bottom_sheet_message_preview.xml
@@ -103,18 +103,34 @@
tools:text="1080 x 1024 - 43s - 12kB"
tools:visibility="visible" />
-
+ tools:alpha="0.3"
+ tools:visibility="visible">
+
+
+
+
+
diff --git a/vector/src/main/res/layout/item_timeline_event_location_stub.xml b/vector/src/main/res/layout/item_timeline_event_location_stub.xml
index ea49930763..316470b5f1 100644
--- a/vector/src/main/res/layout/item_timeline_event_location_stub.xml
+++ b/vector/src/main/res/layout/item_timeline_event_location_stub.xml
@@ -1,35 +1,24 @@
-
-
+ android:layout_height="200dp"
+ android:contentDescription="@string/a11y_static_map_image" />
-
+
-
-
-
-
-
+
diff --git a/vector/src/main/res/values-cs/strings.xml b/vector/src/main/res/values-cs/strings.xml
index c54fb52153..dbbb6d5238 100644
--- a/vector/src/main/res/values-cs/strings.xml
+++ b/vector/src/main/res/values-cs/strings.xml
@@ -611,7 +611,7 @@
Zmínit
Zobrazit seznam relací
Toto je náhled místnosti. Interakce s místností byla vypnuta.
- Vykázání uživatele jej vykopne z této místnosti a zamezí, aby opět vstoupili.
+ Vykázání uživatele jej odebere z této místnosti a zamezí, aby opět vstoupil.
Důvod
Opravdu chcete pozvat uživatele %s do této konverzace\?
"%1$s, "
@@ -930,7 +930,7 @@
Ukázat potvrzení o přečtení
Klepněte na potvrzení o přečtení pro podrobnosti.
Ukázat události příchodů a odchodů
- Nemá vliv na pozvánky, nakopnutí a zákazy.
+ Pozvánky, odebrání a vykázání nejsou dotčeny.
Ukázat události účtu
Zahrnout avatar a změny veřejného jména.
Vibrovat při zmínce uživatele
@@ -2386,7 +2386,7 @@
- %d vteřin
Zobrazit stavové události účastníků v místnosti
- Zahrnuje události pozvat/vstoupit/opustit/vykopnout/vykázat a změny avatara/veřejného jména.
+ Zahrnuje události pozvat/vstoupit/opustit/odebrat/vykázat a změny avatara/veřejného jména.
Hlasování
Reagoval(a): %s
Výsledek ověření
@@ -3010,7 +3010,7 @@
Zobrazit a aktualizovat role potřebné ke změně různých částí prostoru.
Oprávnění prostoru
Zrušením vykázání uživateli umožní znovu se připojit do prostoru.
- Vykázáním uživatele z tohoto prostoru vykopnete a zabráníte mu v dalším připojení.
+ Vykázání uživatele z tohoto prostoru ho odebere a zamezí, aby opět vstoupil.
vykopnutí uživatele je z tohoto prostoru odstraní.
\n
\nAbyste jim zabránili v dalším vstupu, měli byste je raději vykázat.
@@ -3072,8 +3072,8 @@
- Konečný výsledek na základě %1$d hlasů
- - Nikdo nehlasoval
- - %1$d hlasů. Hlasujte pro zobrazení výsledků
+ - %1$d hlas. Hlasujte pro zobrazení výsledků
+ - %1$d hlasy. Hlasujte pro zobrazení výsledků
- %1$d hlasů. Hlasujte pro zobrazení výsledků
@@ -3120,7 +3120,40 @@
Přepsat barvu přezdívky
Již mám účet
Zlepšete týmovou komunikaci.
- Spojte se s kýmkoli.
+ Bezpečené zasílání zpráv.
Máte vše pod kontrolou.
Vlastněte své konverzace.
+ Sdílet polohu
+ Zobrazit polohy uživatele na časové ose
+ Po zapnutí budete moci odeslat svou polohu do libovolné místnosti
+ Povolit sdílení polohy
+ Otevřít v
+ ${app_name} nemohl získat přístup k vaší poloze. Zkuste to prosím později.
+ ${app_name} nemohl získat přístup k vaší poloze
+ Sdílet polohu
+ Sdílet polohu
+ Poloha
+ Sdílet polohu
+ Výsledky se zobrazí až po ukončení hlasování
+ Uzavřené hlasování
+ Hlasující vidí výsledky ihned po hlasování
+ Otevřené hlasování
+ Typ hlasování
+ UPRAVIT HLASOVÁNÍ
+ Upravit hlasování
+ Nikdo nehlasoval
+ Chybně nakonfigurovaná úroveň důvěryhodnosti
+ Šifrování je špatně nakonfigurováno
+ Obnovit šifrování
+ Šifrování bylo špatně nakonfigurováno, takže nelze odesílat zprávy. Kontaktujte správce, aby obnovil šifrování do funkčního stavu.
+ Kontaktujte správce, aby obnovil šifrování do funkčního stavu.
+ Šifrování bylo špatně nakonfigurováno.
+ Sdíleli svou polohu
+ Vytvořit účet
+ Zasílání zpráv pro váš tým.
+ Koncové šifrování bez potřeby telefonního čísla. Žádné reklamy ani vytěžování dat.
+ Můžete si vybrat, kde budou vaše konverzace uloženy, a získat tak kontrolu a nezávislost. Připojeno přes Matrix.
+ Bezpečná a nezávislá komunikace, která vám poskytne stejnou úroveň soukromí jako osobní rozhovor u vás doma.
+ Poloha
+ Šifrování bylo špatně nakonfigurováno, takže nelze odesílat zprávy. Kliknutím otevřete nastavení.
\ No newline at end of file
diff --git a/vector/src/main/res/values-de/strings.xml b/vector/src/main/res/values-de/strings.xml
index b4616a338c..e8a961dba5 100644
--- a/vector/src/main/res/values-de/strings.xml
+++ b/vector/src/main/res/values-de/strings.xml
@@ -3058,4 +3058,37 @@
- Endgültiges Ergebnis basiert auf %1$d Stimmen
Element verbindet Datenschutz mit tollen Features.
+ Verschlüsselung wiederherstellen
+ Standort freigeben
+ Standort freigeben
+ Standort freigeben
+ Standort freigeben
+ Standortfreigabe aktivieren
+ Öffnen mit
+ ${app_name} konnte nicht auf deinen Standort zugreifen. Bitte versuche es später noch einmal.
+ ${app_name} konnte nicht auf deinen Standort zugreifen
+ Standort
+ Ergebnisse werden erst angezeigt, wenn du die Umfrage beendest
+ Geschlossene Umfrage
+ Ergebnisse werden direkt nach Stimmabgabe angezeigt
+ Offene Umfrage
+ Umfragetyp
+ UMFRAGE BEARBEITEN
+ Umfrage bearbeiten
+ Keine Stimmen abgegeben
+ Konto erstellen
+ Nachrichtenaustausch für dein Team.
+ Ende-zu-Ende-verschlüsselt und ohne Telefonnummer nutzbar. Keine Werbung oder Datenerfassung.
+ Wähle wo deine Gespräche liegen, für Kontrolle und Unabhängigkeit. Verbunden mit Matrix.
+ Sichere und unabhängige Kommunikation, die für die gleiche Vertraulichkeit sorgt, wie ein Gespräch von Angesicht zu Angesicht in deinem eigenen Zuhause.
+ Standort
+ Fehlerhaft konfiguriertes Vertrauenslevel
+ Die Verschlüsselung ist fehlerhaft konfiguriert
+ Bitte kontaktiere einen Admin, um die Verschlüsselung zurückzusetzen.
+ Die Verschlüsselung wurde fehlerhaft konfiguriert.
+ Die Verschlüsselung wurde fehlerhaft konfiguriert und du kannst keine Nachrichten senden. Klicke, um die Einstellungen zu öffnen.
+ Die Verschlüsselung wurde fehlerhaft konfiguriert und du kannst keine Nachrichten senden. Bitte kontaktiere einen Admin, um die Verschlüsselung wiederherzustellen.
+ Geteilte Standorte anzeigen
+ Sobald aktiviert, kannst du deinen Standort in jeden Raum senden
+ Hat den Standort geteilt
\ No newline at end of file
diff --git a/vector/src/main/res/values-et/strings.xml b/vector/src/main/res/values-et/strings.xml
index 2799218362..77f854f73b 100644
--- a/vector/src/main/res/values-et/strings.xml
+++ b/vector/src/main/res/values-et/strings.xml
@@ -1381,7 +1381,7 @@
Näita kõikide sõnumite ajatempleid
Lugemisteatisele klõpsimine kuvab detailsema loendi.
Näita jututubadega liitumised ja neist lahkumised
- Siia alla ei kuulu kutsed, müksamised ja suhtluskeelud.
+ Siia alla ei kuulu kutsed, eemaldamised ja suhtluskeelud.
Näita kontoga seotud sündmusi
Sealhulgas tunnuspildi ja kuvatava nime muutusi.
Kasutaja mainimisel anna väringa märku
@@ -2342,7 +2342,7 @@
- %d sekundit
Näita jututoa liikmete olekusündmusi
- Sealhulgas kutsumisi, liitumisi, lahkumisi, müksamisi, keelamisi ning tunnuspildi ja kuvatava nime muutusi.
+ Sealhulgas kutsumisi, liitumisi, lahkumisi, eemaldamisi, keelamisi ning tunnuspildi ja kuvatava nime muutusi.
Küsitlus
Reageeris: %s
Verifitseerimise tulemus
@@ -3061,7 +3061,40 @@
Asenda hüüdnime värvid
Mul on kasutajakonto juba olemas
Lase tiimidel vabalt tegutseda.
- Suhtle kellega soovid.
+ Turvaline sõnumivahetus.
Sul on kontroll oma andmete üle.
Vestlused, mida sa tegelikult ka omad.
+ Jaga asukohta
+ Kuva ajajoonel kasutaja asukohti
+ Kui see seadistus on kasutusel, siis sa saad oma asukohta jagada igas jututoas
+ Luba asukohta jagada
+ Ava muu rakendusega
+ ${app_name} ei saanud asukohta tuvastada. Palun proovi hiljem uuesti.
+ ${app_name} ei saanud asukohta tuvastada
+ Jaga asukohta
+ Jaga asukohta
+ Asukoht
+ Jaga asukohta
+ Tulemusi kuvame vaid siis, kui küsitlus on lõppenud
+ Küsitlus on lõppenud
+ Osalejad näevad tulemusi peale oma valiku salvestamist
+ Ava küsitlus
+ Küsitluse tüüp
+ MUUDA KÜSITLUST
+ Muuda küsitlust
+ Hääletanuid ei ole
+ Seadmete usaldusseosed on valesti seadistatud
+ Krüptimise seadistustes on viga
+ Taasta krüptimine
+ Kui soovid krüptimist töökorda saada, siis võta ühendust serveri haldajaga.
+ Krüptimise seadistustes on viga.
+ Jagas oma asukohta
+ Loo kasutajakonto
+ Sõnumisuhtlus sinu tiimi või kogukonna jaoks.
+ Tagatud on andmete läbiv krüptimine ning oma telefoninumbrit ei pea sa jagama. Pole reklaame ega sinu andmete kogumist.
+ Sa ise valid serveri, kus sinu vestlusi hoitakse ning sellega tagadki kontrolli oma andmete üle. Lahendus põhineb Matrix\'i võrgul.
+ Turvaline ja sõltumatu suhtluslahendus, mis tagab sama privaatsuse, kui omavaheline vestlus sinu kodus.
+ Asukoht
+ Krüptimise seadistustes on viga ja sa ei saa sõnumeid saata. Seadistuste avamiseks klõpsi siin.
+ Krüptimise seadistustes on viga ja sa ei saa sõnumeid saata. Kui soovid krüptimist töökorda saada, siis võta ühendust serveri haldajaga.
\ No newline at end of file
diff --git a/vector/src/main/res/values-fa/strings.xml b/vector/src/main/res/values-fa/strings.xml
index 84a6a6d5ca..a3782df603 100644
--- a/vector/src/main/res/values-fa/strings.xml
+++ b/vector/src/main/res/values-fa/strings.xml
@@ -815,7 +815,7 @@
لغو نادیدهگیری
اشاره
نمایش فهرست نشست
- انسداد کاربر، او را از این اتاق اخراج کرده و از پیوستن دوبارهاش جلوگیری میکند.
+ انسداد کاربر، او را از این اتاق برداشته و از پیوستن دوبارهاش جلوگیری میکند.
دلیل
تنظیمات
پیامها
@@ -1002,7 +1002,7 @@
\nمدیرهای یکپارچگی، دادههای پیکربندی را دریافت کرده و میتوانند از طرف شما ابزارکها را تغییر داده، دعوتهای اتاق فرستاده و سطوح قدرت را تنظیم کنند.
نمایش برچسب زمانی برای تمامی پیامها
نمایش برچسبهای زمانی در قالب ۱۲ساعته
- شامل رویدادهای دعوت/پیوستن/ترک/اخراج/تحریم و تغییرهای چهرک/نام نمایشی.
+ شامل رویدادهای دعوت/پیوستن/ترک/برداشتن/تحریم و تغییرهای چهرک/نام نمایشی.
پشتیبان امن
مدیریت
برپایی پشتیبان امن
@@ -2956,7 +2956,7 @@
دیدن و بهروز رسانی نقشهای لازم برای تغییر بخشهای مختلف فضا.
اجازههای فضا
لغو تحریم کاربر، اجازهٔ پیوستن دوبارهاش به فضا را میدهد.
- تحریم کاربر، او را از این فضا اخراج کرده و از پیوستن دوبارهاش جلوگیری میکند.
+ تحریم کاربر، او را از این فضا برداشته و از پیوستن دوبارهاش جلوگیری میکند.
اخراج کاربر، از این فضا برش میدارد.
\n
\nبرای پیشگیری از پیوستن دوباره، باید تحریمش کنید.
@@ -3059,7 +3059,25 @@
سامانهتان هنگام مواجهه با خطای ناتوانی در رمزگشایی، گزارشها را به صورت خودکار خواهد فرستاد
گزارش خودکار خطاهای رمزگشایی.
از پیش حساب دارم
- ارتباط با هرکسی.
+ پیامرسانی امن.
شما کنترل میکنید.
صاحب گفتوگوهایتان باشید.
+ همرسانی مکان
+ به کار انداختن همرسانی مکان
+ گشودن با
+ همرسانی مکان
+ همرسانی مکان
+ مکان
+ همرسانی مکان
+ نظرسنجی بسته
+ گشودن نظرسنجی
+ گونهٔ نظرسنجی
+ ویرایش نظرسنجی
+ ویرایش نظرسنجی
+ رأیی داده نشده
+ بازیابی رمزنگاری
+ مکانش را همرسانی کرد
+ ایجاد حساب
+ پیامرسانی برای گروهتان.
+ مکان
\ No newline at end of file
diff --git a/vector/src/main/res/values-fr/strings.xml b/vector/src/main/res/values-fr/strings.xml
index 5a7b47622f..08dcb09190 100644
--- a/vector/src/main/res/values-fr/strings.xml
+++ b/vector/src/main/res/values-fr/strings.xml
@@ -3017,7 +3017,7 @@
- Résultat final sur la base de %1$d votes
- - Aucun vote exprimé
+ - %1$d vote exprimé. Votez pour voir les résultats
- %1$d votes exprimés. Votez pour voir les résultats
@@ -3040,8 +3040,8 @@
La politique de votre serveur d’accueil
Politique de ${app_name}
Vous pouvez désactiver ceci à tout moment dans les paramètres
- Nous ne partageons pas d’information avec des tierces parties
- Nous n’enregistrons ou ne profilons aucune donnée du compte
+ Nous ne partageons aucune information avec des tiers
+ Nous n’enregistrons ou ne profilons aucune donnée du compte
ici
Aidez nous à identifier les problèmes et améliorer Element en envoyant des rapports d’usage anonymes. Pour comprendre de quelle manière les gens utilisent Element sur plusieurs appareils, nous créeront un identifiant aléatoire commun à tous vos appareils.
\n
@@ -3061,8 +3061,41 @@
Outrepasser la couleur du pseudo
J’ai déjà un compte
Être vicTeams, ce n’est pas Slack vous voulez.
- Se connecter avec qui vous voulez.
+ Messagerie sécurisée.
Vous êtes aux commandes.
Contrôlez vos conversations.
Vous n’êtes pas autorisé à rejoindre ce salon
+ Choisissez où vos conversations sont stockées, vous avez le contrôle et êtes indépendant. Connecté via Matrix.
+ Le chiffrement a été mal configuré ce qui vous empêche d’envoyer des messages. Veuillez contacter un administrateur pour remettre le chiffrement en état de marche.
+ Partager la localisation
+ Afficher les localisations de l\'utilisateur dans le temps
+ Une fois activé il vous sera possible d\'envoyer votre localisation dans n\'importe quel salon
+ Activer le partage de localisation
+ Ouvrir avec
+ ${app_name} n\'a pas pu accéder à votre localisation. Veuillez réessayer plus tard.
+ ${app_name} n\'a pas pu accéder à votre localisation
+ Partager la localisation
+ Partager la localisation
+ Localisation
+ Partager la localisation
+ Les résultats ne sont dévoilés que lorsque vous terminez le sondage
+ Sondage fermé
+ Les votants voient les résultats dès qu\'ils ont votés
+ Ouvrir le sondage
+ Type de sondage
+ ÉDITER LE SONDAGE
+ Éditer le sondage
+ Aucun vote exprimé
+ Niveau de confiance mal configuré
+ Le chiffrement est mal configuré
+ Restaurer le Chiffrement
+ Veuillez contacter un administrateur pour reconfigurer le chiffrement.
+ Le chiffrement a été mal configuré.
+ On partagé leur localisation
+ Créer un compte
+ Messagerie pour votre équipe.
+ Chiffré de bout en bout et aucun numéro de téléphone n\'est nécessaire. Pas de pubs ni de collecte de données.
+ Communication indépendante et sécurisée qui vous donne le même niveau d\'intimité qu\'une discussion face-à-face dans votre maison.
+ Localisation
+ Le chiffrement a été mal configuré ce qui vous empêche d\'envoyer des messages. Cliquez pour ouvrir les paramètres.
\ No newline at end of file
diff --git a/vector/src/main/res/values-hu/strings.xml b/vector/src/main/res/values-hu/strings.xml
index ccdbb41c35..0a6b6d9a97 100644
--- a/vector/src/main/res/values-hu/strings.xml
+++ b/vector/src/main/res/values-hu/strings.xml
@@ -777,7 +777,7 @@ Figyelmeztetés: ez a fájl törlésre kerülhet, ha az alkalmazást törli.Biztos, hogy hanghívást akarsz indítani\?
Biztos, hogy videóhívást akarsz indítani\?
Csoportok listája
- A felhasználó kitiltása kirúgja őt a szobából, és megakadályozza, hogy újra csatlakozhasson.
+ A felhasználó kitiltása eltávolítja őt a szobából, és megakadályozza, hogy újra csatlakozhasson.
Összes üzenet (hangos)
Összes üzenet
Csak megemlítések
@@ -1009,7 +1009,7 @@ Matrixban az üzenetek láthatósága hasonlít az e-mailre. Az üzenet törlés
Olvasás visszajelzés megjelenítése
További információér kattints az olvasás visszaigazolásokra.
Be-, és kilépési események megjelenítése
- Meghívások, kirúgások és kitiltások nem változtak.
+ Meghívások, eltávolítások és kitiltások nem változtak.
Fiók események megjelenítése
Avatar és név változásokat tartalmaz.
Jelszó
@@ -2751,7 +2751,7 @@ Ha nem te állítottad be a visszaállítási metódust, akkor egy támadó pró
A üzenetek olvashatóságának változtatása csak az új üzenetekre lesz érvényes. A régi üzenetek láthatósága nem fog változni.
Az üzenet szerkesztőhöz emodzsi billentyűzet gomb hozzáadása
Emodzsi billentyűzet megjelenítése
- Magába foglalja a meghívás/belépés/kilépés/kirúgás/kitiltás eseményt és profilkép/megjelenítési név változtatást.
+ Magába foglalja a meghívás/belépés/kilépés/eltávolítás/kitiltás eseményt és profilkép/megjelenítési név változtatást.
Használd a /confetti parancsot vagy küldj üzenetet ami ❄️-t vagy 🎉-t tartalmaz
Beszélgetés effektek megjelenítése
Szoba tagok státusz eseményeinek megjelenítése
@@ -3015,7 +3015,7 @@ Ha nem te állítottad be a visszaállítási metódust, akkor egy támadó pró
- Eredmény %1$d szavazat alapján
- - Nem szavazott senki
+ - %1$d leadott szavazat. Szavazz az eredmények megtekintéséhez
- %1$d leadott szavazat. Szavazz az eredmények megtekintéséhez
@@ -3061,6 +3061,39 @@ Ha nem te állítottad be a visszaállítási metódust, akkor egy támadó pró
Becenév színének megváltoztatása
Már van fiókom
Rázd fel a csoportjaidat.
- Lépj kapcsolatba bárkivel.
+ Biztonságos üzenetküldés.
Te irányítasz.
+ Tartózkodási hely megosztása
+ A felhasználó földrajzi helyzetének megjelenítése az idővonalon
+ A beállítás után bármelyik szobában megoszthatod a földrajzi helyzetedet
+ Földrajzi hely megosztás engedélyezése
+ Megnyitás ezzel
+ ${app_name} nem fér hozzá a helyadatodhoz. Próbáld újra később.
+ ${app_name} nem fér hozzá a földrajzi helyzetedhez
+ Tartózkodási hely megosztása
+ Tartózkodási hely megosztása
+ Földrajzi helyzet
+ Tartózkodási hely megosztása
+ Az eredmény csak a szavazás végeztével válik láthatóvá
+ Lezárt szavazás
+ A szavazók a szavazásuk után látják a szavazatokat
+ Szavazás megnyitása
+ Szavazás típusa
+ SZAVAZÁS SZERKESZTÉSE
+ Szavazás szerkesztése
+ Nem adtak le szavazatot
+ Megbízhatósági szint beállítási hiba
+ A titkosítási beállítás hibás
+ Titkosítás helyreállítása
+ Kérjük vedd fel a kapcsolatot az adminisztrátorral a titkosítás helyreállítása érdekében.
+ A titkosítás beállítása hibás.
+ A földrajzi helyzetüket megosztották
+ Fiók létrehozása
+ Üzenetküldés a csoportodnak.
+ Telefonszám nélkül végpontok között titkosított. Reklámok és adatbányászat nélkül.
+ Válaszd meg hol legyenek a beszélgetéseid tárolva, visszaadja az irányítást és függetlenné tesz. Csatlakozva a Matrixhoz.
+ Biztonságos és független kommunikáció ami olyan biztonságos mintha valakivel négyszemközt beszélgetnél a házadban.
+ Földrajzi helyzet
+ A titkosítás beállítása hibás így nem lehet üzenetet küldeni. Kattints a beállításokért.
+ A titkosítás beállítása hibás így nem lehet üzenetet küldeni. Kérjük vedd fel a kapcsolatot az adminisztrátorral a titkosítás helyreállításához.
\ No newline at end of file
diff --git a/vector/src/main/res/values-in/strings.xml b/vector/src/main/res/values-in/strings.xml
index 21dfefa374..62145bf64e 100644
--- a/vector/src/main/res/values-in/strings.xml
+++ b/vector/src/main/res/values-in/strings.xml
@@ -3006,7 +3006,40 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.
Ubah warna nama tampilan
Saya sudah punya akun
Bebaskan.
- Hubung dengan siapa pun.
+ Perpesanan yang aman.
Anda dalam kendali.
Miliki percakapan Anda.
+ Bagikan lokasi
+ Tampilkan lokasi pengguna di linimasa
+ Setelah diaktifkan Anda akan dapat mengirim lokasi Anda ke ruangan apa saja
+ Aktifkan pembagian lokasi
+ Buka dengan
+ ${app_name} tidak dapat mengakses lokasi Anda. Silakan coba lagi nanti.
+ ${app_name} tidak dapat mengakses lokasi Anda
+ Bagikan lokasi
+ Bagikan lokasi
+ Lokasi
+ Bagikan lokasi
+ Hasil akan ditampilkan ketika Anda mengakhiri poll-nya
+ Poll tertutup
+ Pemberi suara akan melihat hasilnya ketika telah memberikan suara
+ Buka poll
+ Tipe poll
+ EDIT POLL
+ Edit poll
+ Tidak ada suara
+ Tingkat kepercayaan dikonfigurasi dengan salah
+ Enkripsi dikonfigurasi dengan salah
+ Pulihkan Enkripsi
+ Mohon hubungi sebuah admin untuk memulihkan enkripsi ke status yang valid.
+ Enkripsi telah dikonfigurasi dengan salah.
+ Membagikan lokasinya
+ Buat akun
+ Perpesanan untuk tim Anda.
+ Terenkripsi secara ujung-ke-ujung dan tidak memerlukan nomor telepon. Tidak ada iklan atau penambangan data.
+ Anda pilih di mana percakapan Anda disimpan, memberikan Anda kendali dan kebebasan. Terhubung via Matrix.
+ Komunikasi aman dan independen yang memberikan tingkat privasi yang sama seperti percakapan wajah-ke-wajah di dalam rumah Anda sendiri.
+ Lokasi
+ Enkripsi telah dikonfigurasi dengan salah sehingga Anda tidak dapat mengirim pesan. Klik untuk membuka pengaturan.
+ Enkripsi telah dikonfigurasi dengan salah sehingga Anda tidak dapat mengirim pesan. Mohon hubungi sebuah admin untuk memulihkan enkripsi ke status yang valid.
\ No newline at end of file
diff --git a/vector/src/main/res/values-it/strings.xml b/vector/src/main/res/values-it/strings.xml
index d581a97f0b..221a996e0c 100644
--- a/vector/src/main/res/values-it/strings.xml
+++ b/vector/src/main/res/values-it/strings.xml
@@ -846,7 +846,7 @@
- %d utente
- %d utenti
- Bandire l\'utente lo espellerà dalla stanza e gli impedirà di rientrare.
+ Bandire l\'utente lo rimuoverà da questa stanza e gli impedirà di rientrare.
- %d nuovo messaggio
- %d nuovi messaggi
@@ -1081,7 +1081,7 @@
Mostra le conferme di lettura
Clicca sulle conferme di lettura per vederne l\'elenco dettagliato.
Mostra entrata ed uscita degli utenti
- Inviti, butta fuori e ban non vengono considerati.
+ Inviti, rimozioni e ban non vengono considerati.
Mostra i cambiamenti degli account
Includi cambiamenti dell\'avatar e del nome visualizzato.
Password
@@ -2333,7 +2333,7 @@
- %d secondi
Mostra eventi di stato dei membri della stanza
- Includi eventi di invito/entrata/uscita/kick/ban e modifiche di avatar/nome.
+ Includi eventi di invito/entrata/uscita/rimozione/ban e modifiche di avatar/nome.
Sondaggio
Reagito con: %s
Verifica conclusa
@@ -2946,7 +2946,7 @@
Seleziona i ruoli necessari per cambiare varie parti dello spazio
Vedi e aggiorna i ruoli necessari per cambiare varie parti dello spazio.
Riammettere l\'utente gli permetterà di rientrare nello spazio.
- Bandire l\'utente lo espellerà da questo spazio e gli impedirà di rientrare.
+ Bandire l\'utente lo rimuoverà da questo spazio e gli impedirà di rientrare.
buttando fuori l\'utente verrà rimosso da questo spazio.
\n
\nPer impedire che possa rientrare, dovresti invece bandirlo.
@@ -3006,7 +3006,7 @@
- Risultato finale basato su %1$d voti
- - Nessun voto
+ - %1$d voto. Vota per vedere i risultati
- %1$d voti. Vota per vedere i risultati
@@ -3051,7 +3051,40 @@
Sovrascrivi colore nick
Ho già un account
Riduci il carico ai team.
- Connettiti con chiunque.
+ Messaggistica sicura.
Tu hai il controllo.
Prendi il controllo delle tue conversazioni.
+ Condividi posizione
+ Mostra le posizioni dell\'utente nella linea temporale
+ Una volta attivata, potrai inviare la tua posizione in qualsiasi stanza
+ Attiva condivisione posizione
+ Apri con
+ ${app_name} non ha potuto rilevare la tua posizione. Riprova più tardi.
+ ${app_name} non ha potuto rilevare la tua posizione
+ Condividi posizione
+ Condividi posizione
+ Posizione
+ Condividi posizione
+ I risultati verranno rivelati solo quando termini il sondaggio
+ Sondaggio chiuso
+ I votanti vedono i risultati appena avranno votato
+ Apri sondaggio
+ Tipo sondaggio
+ MODIFICA SONDAGGIO
+ Modifica sondaggio
+ Nessun voto
+ Livello di fiducia configurato male
+ La crittografia è configurata male
+ Reimposta crittografia
+ Contatta un amministratore per reimpostare la crittografia ad uno stato valido.
+ La crittografia è stata configurata male.
+ Ha condiviso la sua posizione
+ Crea account
+ Messaggistica per la tua squadra.
+ Crittografia end-to-end e nessun numero di telefono richiesto. Niente pubblicità o raccolta di dati.
+ Scegli dove vengono tenute le tue conversazioni, dandoti controllo e indipendenza. Connesso via Matrix.
+ Comunicazioni sicure e indipendenti che ti danno lo stesso livello di riservatezza di una conversazione faccia a faccia in casa tua.
+ Posizione
+ La crittografia è stata configurata male, perciò non puoi inviare messaggi. Clicca per aprire le impostazioni.
+ La crittografia è stata configurata male, perciò non puoi inviare messaggi. Contatta l\'amministratore per reimpostare la crittografia ad uno stato valido.
\ No newline at end of file
diff --git a/vector/src/main/res/values-pt-rBR/strings.xml b/vector/src/main/res/values-pt-rBR/strings.xml
index 513709c0fd..228b61cb6f 100644
--- a/vector/src/main/res/values-pt-rBR/strings.xml
+++ b/vector/src/main/res/values-pt-rBR/strings.xml
@@ -819,7 +819,7 @@
Tirar vídeo
Lista de Grupos
Chamar
- Banir usuária(o) vai expulsá-la(o) desta sala e preveni-la(o) de se juntar de novo.
+ Banir usuária(o) vai removê-la(o) desta sala e preveni-la(o) de se juntar de novo.
Todas as mensagens (barulhento)
Todas as mensagens
Menções somente
@@ -1118,7 +1118,7 @@
Mostrar recibos de leitura
Clique nos recibos de leitura para uma lista detalhada.
Mostrar eventos de juntar-se e sair
- Convites, expulsões e bans são desafetados.
+ Convites, remoções e bans são desafetados.
Mostrar eventos de conta
Inclui mudanças de avatar e nome de exibição.
Conexão no Background
@@ -2334,7 +2334,7 @@
- %d segundo
- %d segundos
- Inclui eventos de convite/juntar-se/saiu/expulsão/ban e mudanças de avatar/nome de exibição.
+ Inclui eventos de convidar/juntar-se/saiu/remover/ban e mudanças de avatar/nome de exibição.
Emails e números de telefone
Gerenciar emails e números de telefone linkados a sua conta Matrix
Código
@@ -2956,7 +2956,7 @@
Veja e atualize os papéis requeridos para mudar várias partes do espaço.
Permissões de espaço
Desbanir usuária(o) vai permiti-la(o) se juntar ao espaço de novo.
- Banir usuária(o) vai expulsá-la(o) deste espaço e preveni-la de se juntar de novo.
+ Banir usuária(o) vai removê-la(o) deste espaço e preveni-la de se juntar de novo.
expulsar usuária(o) vai removê-la(o) deste espaço.
\n
\nPara preveni-la(o) de se juntar de novo, você devia bani-la(o) em vez disso.
@@ -3061,7 +3061,40 @@
Sobrepor cor de nick
Eu já tenho uma conta
Dê liberdade a times.
- Conecte-se com qualquer pessoa.
+ Mensageria segura.
Você está em controle.
Tenha posse de suas conversas.
+ Compartilhar localização
+ Render localizações de usuária(o) na timeline
+ Uma vez habilitada você vai ser capaz de enviar sua localização a qualquer sala
+ Habilitar compartilhamento de localização
+ Abrir com
+ ${app_name} não pôde acessar sua localização. Por favor tente de novo mais tarde.
+ ${app_name} não pôde acessar sua localização
+ Compartilhar localização
+ Compartilhar localização
+ Localização
+ Compartilhar localização
+ Resultados são somente revelados quando você termina a sondagem
+ Sondagem fechada
+ Votantes veem resultados assim que elas(es) têm votado
+ Sondagem aberta
+ Tipo de sondagem
+ EDITAR SONDAGEM
+ Editar sondagem
+ Nenhum voto lançado
+ Nível de confiança malconfigurado
+ Encriptação está malconfigurada
+ Restaurar Encriptação
+ Por favor contacte um(a) admin para restaurar encriptação a um estado válido.
+ Compartilhou a localização dela(e)
+ Localização
+ Encriptação tem sido malconfigurada.
+ Criar conta
+ Mensageria para seu time.
+ Encriptado ponta-a-ponta e nenhum número de telefone requerido. Sem publicidade ou datamining.
+ Escolha onde suas conversas são mantidas, dando-lhe controle e independência. Conectado via Matrix.
+ Comunicação segura e independente que lhe dá o mesmo nível de privacidade que conversa face-a-face em sua própria casa.
+ Encriptação tem sido malconfigurada então você não pode enviar mensagens. Clique para abrir configurações.
+ Encriptação tem sido malconfigurada então você não pode enviar mensagens. Por favor contacte um(a) admin para restaurar encriptação a um estado válido.
\ No newline at end of file
diff --git a/vector/src/main/res/values-sk/strings.xml b/vector/src/main/res/values-sk/strings.xml
index e4557d5f22..5377dfe99f 100644
--- a/vector/src/main/res/values-sk/strings.xml
+++ b/vector/src/main/res/values-sk/strings.xml
@@ -795,7 +795,7 @@
Ste si istý, že chcete začať hlasový hovor?
Ste si istí, že chcete začať video hovor?
Zoznam komunít
- Zakázanie používateľa ho vylúči z tejto miestnosti a zabráni mu v ďalšom vstupe.
+ Zakázanie používateľa ho odstráni z tejto miestnosti a zabráni mu v ďalšom vstupe.
Všetky správy (hlasné)
Všetky správy
Len zmienky
@@ -2176,4 +2176,106 @@
• Servery s číslicami ako IP adresy sú povolené.
• Servery, ktorých názov sa zhoduje s %s sú povolené.
• Servery, ktorých názov sa zhoduje s %s sú zakázané.
+ Nastaviť rolu
+ Fráza pre obnovenie
+ Editor správ
+ Nedá sa skenovať
+ Iné relácie
+ Aktuálna relácia
+ Vyčistiť údaje
+ Vyčistiť údaje
+ Knižnice tretích strán
+ Pomoc a podpora
+ Pozvať pomocou používateľského mena alebo e-mailu
+ Povoliť matematiku LaTeX
+ Reštartujte aplikáciu, aby sa zmena prejavila.
+ Vy máte všetko pod kontrolou.
+ Bezpečné zasielanie správ.
+ Automatické hlásenie chýb dešifrovania.
+ Váš systém bude automaticky odosielať záznamy, keď sa vyskytne chyba dešifrovania
+ Otvoriť kameru
+ Posielajte obrázky a videá
+ Odoslať nálepku
+ Otvoriť kontakty
+ Vytvoriť anketu
+ Bezpečná a nezávislá komunikácia, ktorá vám poskytuje rovnakú úroveň súkromia ako rozhovor zoči-voči vo vašom vlastnom dome.
+ Vyberte si, kde budú vaše rozhovory uložené, a získajte tak kontrolu a nezávislosť. Pripojené cez Matrix.
+ End-to-end šifrovanie a bez potreby telefónneho čísla. Žiadne reklamy ani zneužívanie údajov.
+ Zasielanie správ pre váš tím.
+ Vytvoriť účet
+ Šifrovanie je nesprávne nastavené.
+ Obráťte sa na správcu, aby obnovil platný stav šifrovania.
+ Obnoviť šifrovanie
+ Šifrovanie je nesprávne nastavené
+ Žiadne odovzdané hlasy
+ Upraviť anketu
+ Výsledky sa zobrazia až po ukončení ankety
+ Poloha
+ Zdieľali svoju polohu
+ Zdieľať polohu
+ Poloha
+ Zdieľať polohu
+ Zdieľať polohu
+ ${app_name} nemohol získať prístup k vašej polohe
+ ${app_name} nemohol získať prístup k vašej polohe. Skúste to prosím neskôr.
+ Otvoriť s
+ Povoliť zdieľanie polohy
+ Po zapnutí tejto funkcie budete môcť odoslať svoju polohu do ľubovoľnej miestnosti
+ Vykresliť umiestnenie používateľa na časovej osi
+ Zdieľať polohu
+ Prémiový hosting pre organizácie
+ Prihlásiť sa do %1$s
+ Pripojiť sa k vlastnému serveru
+ Pripojiť sa k službám Element Matrix
+ Pripojiť sa k %1$s
+ Prémiový hosting pre organizácie
+ Pripojte sa k miliónom ľudí zadarmo na najväčšom verejnom serveri
+ Rovnako ako e-mail, aj účty majú jeden domov, hoci môžete hovoriť s kýmkoľvek
+ Začnite
+ Rozšírte a prispôsobte si možnosti
+ Udržujte konverzácie súkromné pomocou šifrovania
+ Komunikujte s ľuďmi priamo alebo v skupinách
+ Je to vaša konverzácia. Vlastnite ju.
+ Vytvorili ste miestnosť len pre pozvaných.
+ %1$s vytvoril miestnosť len na pozvanie.
+ Miestnosť ste zverejnili pre každého, kto pozná odkaz.
+ %1$s zverejnil miestnosť pre každého, kto pozná odkaz.
+ Dlhým kliknutím na miestnosť zobrazíte ďalšie možnosti
+ Nevykonali ste žiadne zmeny
+ %1$s nevykonal žiadne zmeny
+ Tento obsah bol nahlásený ako spam.
+\n
+\nAk nechcete vidieť ďalší obsah od tohto používateľa, môžete ho ignorovať a skryť jeho správy.
+ Nahlásené ako spam
+ Tento obsah bol nahlásený.
+\n
+\nAk nechcete vidieť ďalší obsah od tohto používateľa, môžete ho ignorovať a skryť jeho správy.
+ NAHLÁSIŤ
+ Dôvod nahlásenia tohto obsahu
+ V tejto miestnosti nie sú žiadne súbory
+ MÉDIÁ
+ V tejto miestnosti nie sú žiadne médiá
+ Pri načítavaní prílohy došlo k chybe.
+ Súbor \'%1$s\' (%2$s) je príliš veľký na odoslanie. Limit je %3$s.
+ Prejsť na spodok
+ Vytvoriť novú miestnosť
+ Vytvoriť novú priamu konverzáciu
+ Po prijatí podmienok domovského servera to skúste znova.
+ Zobraziť a aktualizovať role potrebné na zmenu rôznych častí priestoru.
+ Zobraziť a aktualizovať role potrebné na zmenu rôznych častí miestnosti.
+ Šifrovanie bolo nesprávne nastavené, takže nemôžete odosielať správy. Kliknutím otvorte nastavenia.
+ Šifrovanie bolo nesprávne nastavené, takže nemôžete odosielať správy. Obráťte sa na správcu, aby obnovil platný stav šifrovania.
+ Zrušenie zákazu používateľovi mu umožní znovu sa pripojiť do priestoru.
+ Zakázanie používateľa ho odstráni z tohto priestoru a zabráni mu v ďalšom vstupe.
+ Používateľ bude z tohto priestoru odstránený.
+\n
+\nAby ste mu zabránili v opätovnom pripojení, mali by ste ho zakázať.
+ Táto miestnosť nie je verejná. Bez pozvánky sa do nej nebudete môcť opätovne pripojiť.
+ Pokračovať aj tak
+ Povoľte prístup ku kontaktom.
+ Ak chcete skenovať QR kód, musíte povoliť prístup k fotoaparátu.
+ Volaný používateľ je obsadený.
+ Používateľ je obsadený
+ %s podržal hovor
+ Hlasový hovor s %s
\ No newline at end of file
diff --git a/vector/src/main/res/values-sq/strings.xml b/vector/src/main/res/values-sq/strings.xml
index a31673925d..d93331777f 100644
--- a/vector/src/main/res/values-sq/strings.xml
+++ b/vector/src/main/res/values-sq/strings.xml
@@ -500,7 +500,7 @@
ID Përdoruesi, Emër ose email-i
Përmendje
Shfaq Listë Sesionesh
- Dëbimi i përdoruesit do ta përzërë atë nga kjo dhomë dhe do t’i pengojë atij rihyrjen.
+ Dëbimi i përdoruesit do ta heqë atë nga kjo dhomë dhe do t’i pengojë atij rihyrjen.
Arsye
Jeni i sigurt se doni të ftohet %s te kjo fjalosje?
"%1$s, "
@@ -1048,7 +1048,7 @@
Parashihini lidhjet brenda fjalosjes, kur shërbyesi juaj home e mbulon këtë veçori.
Lejojuni përdoruesve të tjerë të dinë se po shtypni.
Formatojini mesazhet duke përdorur sintaksën Markdown përpara se të dërgohen. Kjo lejon formatim të thelluar, f.v., përdorimi i yllthit për ta shfaqur tekstin me të pjerrëta.
- Nuk prek ftesat, përzëniet dhe dëbimet.
+ Nuk prek ftesat, heqjet dhe dëbimet.
${app_name}-i mund të xhirojë në prapaskenë që të administrojë njoftimet tuaja në rrugë të sigurt dhe privatisht. Kjo mund të ndikojë në harxhimin e baterisë.
${app_name}-i grumbullon të dhëna analitike anonime që të na lejojë ta përmirësojmë aplikacionin.
Ju lutemi, aktivizoni analizat që të na ndihmoni të përmirësojmë ${app_name}-in.
@@ -2201,7 +2201,7 @@
- %d sekonda
Shfaq akte gjendjeje përdoruesish të dhomës
- Përfshin akte ftimi/pjesëmarrjeje/ikjeje/përzënieje/dëbimi dhe ndryshime emri avatari/shfaqjeje.
+ Përfshin akte ftimi/pjesëmarrjeje/ikjeje/heqjeje/dëbimi dhe ndryshime emri avatari/shfaqjeje.
Kopjeruajtje e Sigurt
Administroni
Ujdisni Kopjeruajtje të Sigurt
@@ -2867,8 +2867,8 @@
%1$s Prekeni që të kthehet
Thirrje aktive (%1$s) ·
- - Thirrje aktive
- - %1$d thirrje aktive
+ - Thirrje aktive ·
+ - %1$d thirrje aktive ·
Lidhja dështoi
S’ka përgjigje
@@ -2913,7 +2913,7 @@
Do të braktisni krejt dhomat dhe hapësirat te %s.
Braktis krejt dhomat dhe hapësirat
Jeni i sigurt se doni të dilni nga \'%s\?
- Zbulim (%S)
+ Zbulim (%s)
Përfundoje ujdisjen
Ftoni me email, gjeni kontakte, etj…
Përfundo ujdisjen e zbulimit.
@@ -2945,7 +2945,7 @@
Të shohë dhe përditësojë role të domosdoshëm për të ndryshuar anë të ndryshme të hapësirës.
Leje hapësire
Heqja e dëbimit përdoruesit do t’i lejojë të marrë pjesë sërish në hapësirë.
- Dëbimi i përdoruesit do ta përzërë atë nga kjo hapësirë dhe do t’i pengojë atij rihyrjen.
+ Dëbimi i përdoruesit do ta heqë atë nga kjo hapësirë dhe do t’i pengojë atij rihyrjen.
Përzënia e përdoruesit do ta heqë prej kësaj hapësire.
\n
\nQë të pengohet pjesëmarrja sërish e tij, duhet ta dëboni.
@@ -3032,8 +3032,8 @@
Ndihmoni të përmirësohet Element-in
Aktivizoje
- - S’ka vota të hedhura
- - %1$d votë e hedhur. Votoni, që të shihni përfundimet
+ - %1$d votë e hedhur. Votoni, që të shihni përfundimet
+ - %1$d vota të hedhur. Votoni, që të shihni përfundimet
Që ndryshimi të hyjë në fuqi, rinisni aplikacionin.
Aktivizo elementë LaTeX për matematikë
@@ -3048,7 +3048,40 @@
Raporto Vetvetiu Gabime Shfshehtëzimi.
Anashkalo ngjyrë nofke
Kam tashmë një llogari
- Lidhuni me këdo.
+ Shkëmbim i siguruar mesazhesh.
Kontrollin e keni ju.
Jini zot i bisedave tuaja.
+ Jepe vendndodhjen
+ Aktivizoni dhënie vendndodhjeje
+ Jepe vendndodhjen
+ Jepe vendndodhjen
+ Vendndodhje
+ Jepe vendndodhjen
+ Përfundimet shfaqen vetëm kur përfundoni anketimin
+ Anketim i mbyllur
+ Votuesit do të shohin përfundime sapo të kenë votuar
+ Anketim i hapur
+ Lloj anketimi
+ Krijoni llogari
+ Shkëmbim mesazhesh për ekipin tuaj.
+ I fshehtëzuar skaj më skaj dhe pa u dashur numër telefoni. Pa reklama, apo shfrytëzim të dhënash.
+ Zgjidhni ku mbahen bisedat tuaja, duke ju dhënë kontroll dhe pavarësi. Të lidhur përmes Matrix-i.
+ Komunikim i sigurt dhe i pavarur, që ju jep të njëjtën shkallë privatësie si biseda kokë më kokë, në shtëpinë tuaj.
+ Trego vendndodhje përdoruesi në rrjedhën kohore
+ Pasi të aktivizohet, do të jeni në gjendje të dërgoni vendndodhjen tuaj në çfarëdo dhome
+ Hape me
+ ${app_name} s’njohu dot vendndodhjen tuaj. Ju lutemi, riprovoni më vonë.
+ ${app_name} s’mësoi dot vendndodhjen tuaj
+ PËRPUNONI ANKETIMIN
+ Përpunoni anketimin
+ S’janë hedhur vota
+ Shkallë besueshmërie e formësuar gabim
+ Fshehtëzimi është formësuar gabim
+ Riktheni Fshehtëzimin
+ Ju lutemi, lidhuni me një nga përgjegjësit, që ta ktheni fshehtëzimin në një gjendje të vlefshme.
+ Fshehtëzimi është formësuar gabim.
+ Tregoi vendndodhjen e vet
+ Vendndodhje
+ Fshehtëzimi është formësuar keq, që të mos dërgoni mesazhe. Klikoni që të hapni rregullimet.
+ Fshehtëzimi është formësuar keq, që të mos dërgoni mesazhe. Ju lutemi, lidhuni me një nga përgjegjësit që ta ktheni fshehtëzimin në një gjendje të vlefshme.
\ No newline at end of file
diff --git a/vector/src/main/res/values-tr/strings.xml b/vector/src/main/res/values-tr/strings.xml
index 50177afcc5..50af4a203c 100644
--- a/vector/src/main/res/values-tr/strings.xml
+++ b/vector/src/main/res/values-tr/strings.xml
@@ -37,7 +37,7 @@
Deşifre Edilmiş Kaynağı İncele
Sil
Yeniden Adlandır
- İçeriği bildir
+ Rapor İçeriği
Şu anki görüşme
Devam eden konferans görüşmesi.
\n%1$s veya %2$s olarak katıl
@@ -118,7 +118,7 @@
Hesap oluştur
Giriş yap
Çıkış yap
- Ev Sunucusu URL\'si
+ Ana Sunucu URL\'si
Ara
Yeni Sohbete Başla
Sesli Görüşme Başlat
@@ -188,7 +188,7 @@
Hata
Sistem Uyarıları
Gönder
- Kimlik Sunucusu URL\'si
+ Kimlik sunucusu URL\'si
E-posta adresi
E-posta adresi (isteğe bağlı)
Telefon numarası
@@ -213,10 +213,10 @@
Eposta ve telefon numarası ile aynı anda kayıt yaptırmak şimdilik API yüzüden desteklenmiyor. Sadece telefon numarası hesaba eklenecektir.
\n
\nEpostanı daha sonra profil ayarlarından ekleyebilirsin.
- Ana Makine senin robot olmadığından emin olmak istiyor
+ Bu ana sunucu bir robot olmadığından emin olmak istiyor
Kullandığın kullanıcı adı
- Ana Makine:
- Tanımlayıcı Sunucu:
+ Ana sunucu:
+ Kimlik sunucusu:
Eposta adresimi doğruladım
Şifrenizi sıfırlamak için, hesabınıza bağlı eposta adresini girin:
Hesaba bağlı eposta adresi mutlaka girilmeli.
@@ -248,8 +248,8 @@
Makbuz Listesini Oku
Grup Listesi
- - 1 üyelik değişimi
- - %d üyelik değişimi
+ - %d üyelik değişikliği
+ - %d üyelik değişiklikleri
Farklı gönder
Orijinal
@@ -325,28 +325,28 @@
Yeni Sohbet
Üye ekle
- - 1 aktif üye
- - %d aktif üye
+ - %d aktif üye
+ - %d aktif üyeler
- - 1 üye
- - %d üye
+ - %d üye
+ - %d üyeler
1 üye
- - 1sn
- - %dsn
+ - %ds 1
+ - %ds
- - 1dk
+ - %ddk
- %ddk
- - 1sa
+ - %dsa
- %dsa
- - 1g
+ - %dg
- %dg
Odadan ayrıl
@@ -376,7 +376,7 @@
Oturum Listesini Göster
Bu işlemin geri dönüşü yok kullanıcıyı sen ile aynı erişim seviyesine getiriyorsun.
\nEmin misin\?
- Kullanıcıyı bu engellersen bu odadan kovulacak ve bir daha giremeyecek.
+ Kullanıcıyı yasaklamak onları bu odadan çıkaracak ve tekrar katılmalarını engelleyecektir.
Neden
%s adlı kullanıcılar(ı) bu sohbete davet etmek istediğinden emin misin\?
"%1$s, "
@@ -405,10 +405,10 @@
Gönderilmeyen mesajları tekrar gönder
Gönderilmeyen mesajları sil
Dosya bulunamadı
- Bu odada mesajlaşmaya yetkin yok
+ Bu odaya mesaj gönderme izniniz yok.
- - 1 yeni mesaj
- - %d yeni mesaj
+ - %d yeni mesaj
+ - %d yeni mesajlar
Güven
Güvenme
@@ -426,7 +426,7 @@
Dosyalar
Ayarlar
- - 1 tane seçili
+ - %d tane seçili
- %d tane seçili
Hatalı ID. Eposta adresi ya da Matrix ID\'si olmalıdır \'@localpart:domain\'
@@ -447,8 +447,8 @@
DOSYALAR
Dizinlere gözat
- - 1 oda
- - %d oda
+ - %d oda
+ - %d odalar
- %2$s adında %1$s oda bulundu
@@ -1068,7 +1068,7 @@
Hesap kurtarma epostası kaydedin. Daha sonra isteğe bağlı eposta veya telefon nuraması kullanarak sizi tanıyan kişilerin sizi bulabilmesini sağlayın.
Cihazın saldırılara açık, eski bir TLS güvenlik protokolü kullanıyor; güvenliğin için bağlantın engellendi
İkincil çağrı yardımcı sunucusuna izin ver
- Anasunucunuz çağrı yardımcı sunucusu vermez ise %s çağrı yardımcı sunucusu olarak kullanılacaktır (Çağrıda IP adresiniz paylaşılacaktır)
+ Ana sunucunuz bir tane sunmadığında %sas assist kullanacaktır (arama sırasında IP adresiniz paylaşılacaktır)
Bu eylemi gerçekleştirebilmek için ayarlarınızdan bir kimlik sunucusu ekleyin.
Şifreni doğrula
${app_name}, cihazın sınırlı kaynaklarını (pil) koruyacak şekilde arka planda senkronize olur.
@@ -1819,4 +1819,211 @@
Burada yükselttiniz.
tüm oda üyeleri, katıldıkları andan itibaren.
tüm oda üyeleri, davet edildikleri andan itibaren.
+ Hiçbiri
+ Yalnızca Söz ve Anahtar Kelimeler
+ Alanı yükseltin
+ m.room.server_acl olaylarını gönder
+ Alan adını değiştir
+ Alan şifrelemeyi etkinleştir
+ Alanın ana adresini değiştirme
+ Alan avatarını değiştir
+ Bu alanın çeşitli bölümlerini değiştirmek için gereken rolleri güncelleme izniniz yok
+ Bu alanın çeşitli bölümlerini değiştirmek için gereken rolleri seçin
+ Alanın çeşitli bölümlerini değiştirmek için gereken rolleri görüntüleyin ve güncelleyin.
+ Alan izinleri
+ Şifreleme yanlış yapılandırıldı, böylece mesaj gönderemezsiniz. Ayarlar\'ı açmak için tıklatın.
+ Şifreleme yanlış yapılandırıldı, böylece mesaj gönderemezsiniz. Şifrelemeyi geçerli bir duruma geri yüklemek için lütfen bir yöneticiyle iletişime geçin.
+ Yasağı kaldırmak, kullanıcının alana tekrar katılmasına izin verir.
+ Kullanıcıyı yasaklamak onları bu alandan kaldıracak ve tekrar katılmalarını engelleyecektir.
+ Kullanıcı bu alandan kaldırılacaktır.
+\n
+\nTekrar katılmalarını önlemek için, onları yasaklamalısınız.
+ Yine de Devam Et
+ Arama sonlandırılıyor…
+ Cevap yok
+ Aradığınız kullanıcı meşgul.
+ Kullanıcı meşgul
+ %s ile sesli arama
+ %s ile görüntülü arama
+
+ - Cevapsız görüntülü arama
+ - %d cevapsız görüntülü aramalar
+
+
+ - Cevapsız sesli arama
+ - %d cevapsız sesli aramalar
+
+ Çağrı çalıyor…
+ Yetkisiz, eksik geçerli kimlik doğrulama kimlik bilgileri
+ Ana sunucuyu seçin
+ %s url\'sinde bir ana sunucuya ulaşılamıyor. Lütfen bağlantınızı kontrol edin veya bir ana sunucuyu manuel olarak seçin.
+ Varsayılan olarak kullan ve tekrar sorma
+ Her zaman sor
+ Ana sunucu API URL\'si
+ Alanlar
+ Davetliler
+ Açık içeriğe sahip odalar da dahil olmak üzere oda dizinindeki tüm odaları göster.
+ Açık içerikli odaları göster
+ Oda rehberi
+ Önerilen Odalar
+ Yeni değer
+ Şimdi değil
+ Etkinleştirmek
+ Geri dönüş
+ Değiştirmek
+ Eksik izinler
+ Sesli mesaj göndermek için lütfen Mikrofona izin verin.
+ Bu işlemi gerçekleştirmek için lütfen Kameraya sistem ayarlarından izin verin.
+ Bazı izinler eksik, bu eylemi gerçekleştirmek için lütfen sistem ayarlarından izinleri verin.
+ Alanlar
+ daha fazla bilgi edin
+ Bildirimleri dinleme
+ Uçtan uca şifrelemeyi etkinleştirdiniz (tanınmayan algoritma %1$s).
+ %1$s uçtan uca şifrelemeyi etkinleştirdi (tanınmayan algoritma %2$s).
+ Uçtan uca şifrelemeyi açtın.
+ %1$s uçtan uca şifrelemeyi etkinleştirdi.
+ Konukların odaya katılmasını engellediniz.
+ %1$s konukların odaya katılmasını engelledi.
+ Konukların odaya katılmasını engellediniz.
+ %1$s konukların odaya katılmasını engelledi.
+ Konukların buraya katılmasına izin verdiniz.
+ %1$s konukların buraya katılmasına izin verdi.
+ Konukların odaya katılmasına izin verdiniz.
+ %1$s konukların odaya katılmasına izin verdi.
+ Bu odanın adreslerini değiştirdin.
+ %1$s bu odanın adreslerini değiştirdi.
+ Bu odanın ana ve alternatif adreslerini değiştirdiniz.
+ %1$s bu odanın ana ve alternatif adreslerini değiştirdi.
+ Bu odanın alternatif adreslerini değiştirdiniz.
+ %1$s bu odanın alternatif adreslerini değiştirdi.
+
+ - Bu oda için %1$s alternatif adresini kaldırdınız.
+ - Bu oda için %1$s alternatif adreslerini kaldırdınız.
+
+
+ - %1$s bu oda için %2$s alternatif adresini kaldırdı.
+ - %1$s bu oda için %2$s alternatif adreslerini kaldırdı.
+
+
+ - Bu oda için %1$s alternatif adresini eklediniz.
+ - Bu oda için %1$s alternatif adreslerini eklediniz.
+
+
+ - %1$s, bu oda için %2$s alternatif adresini ekledi.
+ - %1$s, bu oda için %2$s alternatif adreslerini ekledi.
+
+ Bu odanın ana adresini kaldırdınız.
+ %1$s bu odanın ana adresini kaldırdı.
+ Bu odanın ana adresini %1$s olarak ayarladınız.
+ %1$s, bu odanın ana adresini %2$s olarak belirledi.
+ Bu oda için adres olarak %1$s eklediniz ve %2$s\'i kaldırdınız.
+ %1$s, bu oda için adres olarak %2$s ekledi ve %3$s\'i kaldırdı.
+
+ - %1$s adresini bu odanın adresi olarak kaldırdınız.
+ - %1$s adresini bu oda için adres olarak kaldırdınız.
+
+
+ - %1$s, %2$s adresini bu odanın adresi olarak kaldırdı.
+ - %1$s, %2$s adresini bu odanın adresi olarak kaldırdı.
+
+
+ - Bu oda için adres olarak %1$s eklediniz.
+ - Bu oda için adres olarak %1$s eklediniz.
+
+
+ - %1$s, bu oda için bir adres olarak %2$s ekledi.
+ - %1$s, bu oda için adres olarak %2$s ekledi.
+
+ %1$s adlı kişinin davetini geri çektiniz. Neden: %2$s
+ %1$s, %2$s adlı kişinin davetini geri çekti. Neden: %3$s
+ %1$s davetini kabul ettiniz. Neden: %2$s
+ %1$s, %2$s davetini kabul etti. Neden: %3$s
+ %1$s için odaya katılma davetini iptal ettiniz. Neden: %2$s
+ %1$s, %2$s için odaya katılma davetini iptal etti. Neden: %3$s
+ Odaya katılması için %1$s\'a bir davetiye gönderdiniz. Neden: %2$s
+ %1$s, odaya katılması için %2$s\'a bir davetiye gönderdi. Neden: %3$s
+ %1$s\'i yasakladınız. Neden: %2$s
+ %1$s, %2$s\'yi yasakladı. Neden: %3$s
+ %1$s yasağını kaldırdınız. Neden: %2$s
+ %1$s planlanmamış %2$s. Nedeni: %3$s
+ %1$s kaldırdınız. Nedeni: %2$s
+ %1$s %2$s kaldırıldı. Nedeni: %3$s
+ Daveti reddettiniz. Sebep: %1$s
+ %1$s daveti reddetti. Neden: %2$s
+ Gittin. Sebep: %1$s
+ %1$s kaldı. Neden: %2$s
+ Odadan ayrıldın. Sebep: %1$s
+ %1$s odadan ayrıldı. Neden: %2$s
+ Katıldın. Sebep: %1$s
+ %1$s katıldı. Neden: %2$s
+ Odaya katıldın. Sebep: %1$s
+ %1$s odaya katıldı. Neden: %2$s
+ %1$s sizi davet etti. Neden: %2$s
+ %1$s davet ettiniz. Neden: %2$s
+ %1$s, %2$s\'i davet etti. Neden: %3$s
+ Senin davetiyen. Sebep: %1$s
+ %1$s\'in davetiyesi. Neden: %2$s
+ Gönderme kuyruğunu temizle
+ Mesajı gönderildi
+ İlk senkronizasyon:
+\nHesap verilerini içe aktarma
+ İlk senkronizasyon:
+\nToplulukları içe aktarma
+ İlk senkronizasyon:
+\nSol odalar içe aktarılıyor
+ İlk senkronizasyon:
+\nDavetli odaları içe aktarma
+ İlk senkronizasyon:
+\nKonuşmalarınız yükleniyor
+\nÇok sayıda odaya katıldıysanız, bu biraz zaman alabilir
+ İlk senkronizasyon:
+\nOdaları içe aktarma
+ İlk senkronizasyon:
+\nKripto içe aktarma
+ İlk senkronizasyon:
+\nHesap içe aktarılıyor…
+ İlk senkronizasyon:
+\nVeriler indiriliyor…
+ İlk senkronizasyon:
+\nSunucu yanıtı bekleniyor…
+ Boş oda (%s idi)
+
+ - %1$s ve 1 kişi daha
+ - %1$s ve %2$d kişi daha
+
+
+ - %1$s, %2$s, %3$s ve %4$d diğer
+ - %1$s, %2$s, %3$s ve %4$d kişi daha
+
+ %1$s, %2$s, %3$s ve %4$s
+ %1$s ve %2$s
+ %s\'den davet
+ Bu odaya katılmanıza izin verilmiyor
+ Şu anda boş bir odaya yeniden katılmak mümkün değildir.
+ redaksiyon yapılamadı
+ Gönderenin cihazı bize bu mesajın anahtarlarını göndermedi.
+ ** Şifre çözülemiyor: %s **
+ %1$s, %2$s ile %3$s arasında
+ %1$s, %2$s\'nin güç seviyesini değiştirdi.
+ %1$s\'nin güç seviyesini değiştirdiniz.
+ Özel (%1$d)
+ Moderatör
+ Admin
+ %1$s tarafından video konferans başlatıldı
+ %1$s widget\'ını değiştirdiniz
+ %1$s, %2$s widget\'ı ekledi
+ %1$s, %2$s profilini güncelledi
+ VoIP konferansı bitti
+ VoIP konferansı başladı
+ Bir VoIP konferansı talep ettiniz
+ %1$s bir VoIP konferansı istedi
+ 🎉 Tüm sunucuların katılımı yasaklanmıştır! Bu oda artık kullanılamaz.
+ • IP değişmezleriyle eşleşen sunucular artık yasaklanmıştır.
+ • IP değişmez değerleriyle eşleşen sunuculara artık izin verilmektedir.
+ • %s ile eşleşen sunucular izin verilenler listesinden kaldırıldı.
+ • %s ile eşleşen sunuculara artık izin veriliyor.
+ • %s ile eşleşen sunucular yasak listesinden kaldırıldı.
+ • %s ile eşleşen sunucular artık yasaklandı.
+ Bu oda için sunucu ACL\'lerini değiştirdiniz.
+ %s, bu oda için sunucu ACL\'lerini değiştirdi.
\ No newline at end of file
diff --git a/vector/src/main/res/values-uk/strings.xml b/vector/src/main/res/values-uk/strings.xml
index 0a6261d2c1..c9e8372cc9 100644
--- a/vector/src/main/res/values-uk/strings.xml
+++ b/vector/src/main/res/values-uk/strings.xml
@@ -3105,7 +3105,7 @@
Точно видалити опитування\? Ви не зможете відновити опитування після видалення.
Видалити опитування
Голосування завершене
- Голос надіслано
+ Проголосовано
Завершити опитування
Люди більше не зможуть голосувати, і будуть показані остаточні результати опитування.
Завершити це опитування\?
@@ -3163,7 +3163,40 @@
Замінити колір псевдоніма
Я вже маю обліковий запис
Удоскональте спілкування в команді.
- З\'єднуйтеся з будь-ким.
+ Захищене спілкування.
Ви контролюєте все.
Володійте своїми розмовами.
+ Поділитися місцеперебуванням
+ Зображувати місцеперебування користувача у стрічці
+ Після увімкнення ви зможете надіслати своє місцеперебування до будь-якої кімнати
+ Увімкнути надсилання місцеперебування
+ Відкрити за допомогою
+ ${app_name} не може отримати доступ до вашого місцеперебування. Спробуйте пізніше.
+ ${app_name} не може отримати доступ до вашого місцеперебування
+ Поділитися місцеперебуванням
+ Поділитися місцеперебуванням
+ Місцеперебування
+ Поділитися місцеперебуванням
+ Результати можна переглянути лише після завершення опитування
+ Закрите опитування
+ Усі, хто проголосує, побачать результати одразу після голосування
+ Відкрити опитування
+ Тип опитування
+ РЕДАГУВАТИ ОПИТУВАННЯ
+ Редагувати опитування
+ Немає голосових бесід
+ Неправильне налаштування рівня довіри
+ Шифрування неправильно налаштовано
+ Відновити шифрування
+ Зв\'яжіться з адміністратором для відновлення роботи шифрування.
+ Шифрування неправильно налаштовано.
+ Поділилися своїм місцеперебуванням
+ Створити обліковий запис
+ Спілкування вашої команди.
+ З наскрізним шифруванням і без вимоги номера телефону. Без реклами чи аналізу даних.
+ Оберіть де спілкуватись, що дасть вам контроль і незалежність. Під\'єднано через Matrix.
+ Захищене та незалежне спілкування, яке дає вам такий самий рівень приватності, як розмова віч-на-віч у вашому власному домі.
+ Місцеперебування
+ Шифрування було налаштовано неправильно, тому ви не можете надсилати повідомлення. Торкніться, щоб відкрити налаштування.
+ Шифрування було налаштовано неправильно, тому ви не можете надсилати повідомлення. Зверніться до адміністратора, щоб відновити роботу шифрування.
\ No newline at end of file
diff --git a/vector/src/main/res/values-zh-rTW/strings.xml b/vector/src/main/res/values-zh-rTW/strings.xml
index 9a8e90f751..3dcf132f92 100644
--- a/vector/src/main/res/values-zh-rTW/strings.xml
+++ b/vector/src/main/res/values-zh-rTW/strings.xml
@@ -542,7 +542,7 @@
提及
顯示工作階段清單
您確定想要邀請 %s 到聊天室?
- 封鎖使用者將會把他們從此聊天室中踢除,並避免他們再次加入。
+ 封鎖使用者將會把他們從此聊天室中移除,並避免他們再次加入。
透過 ID 邀請
裝置上的聯絡人(%d)
使用者目錄 (%s)
@@ -1046,7 +1046,7 @@
顯示讀取回條
點選讀取回條以顯示詳細資料。
顯示加入與離開的活動
- 邀請、踢出與封鎖不受影響。
+ 邀請、移除與封鎖不受影響。
顯示帳號活動
包含大頭貼與顯示名稱變動。
密碼
@@ -2298,7 +2298,7 @@
- %d 秒
顯示聊天室成員狀態活動
- 包含邀請/加入/離開/踢除/封鎖事件與大頭貼/顯示名稱變更等。
+ 包含邀請/加入/離開/移除/封鎖事件與大頭貼/顯示名稱變更等。
投票
反應:%s
驗證結論
@@ -2902,7 +2902,7 @@
檢視並更新變更空間各部份所需的角色。
空間權限
取消封鎖使用者將讓他們可以再次加入空間。
- 封鎖使用者會將他們踢出此空間並防止他們再次加入。
+ 封鎖使用者會將他們自此空間移除並防止他們再次加入。
踢除使用者將會將他們從此空間中移除。
\n
\n為了防止他們再加入,您應該封鎖他們。
@@ -3002,7 +3002,40 @@
覆寫暱稱色彩
我已有一個帳號
減少團隊的懈怠。
- 與任何人聯絡。
+ 安全傳送訊息。
您已掌控了您的資料。
擁有您的對話。
+ 分享位置
+ 在時間軸中繪製使用者位置
+ 啟用後,您就能將您的位置傳送至任何聊天室
+ 啟用位置分享
+ 開啟以
+ ${app_name} 無法存取您的位置。請稍後再試。
+ ${app_name} 無法存取您的位置
+ 分享位置
+ 分享位置
+ 位置
+ 分享位置
+ 結果僅在您結束投票後顯示
+ 已關閉投票
+ 投票者在投票後可以立刻看到投票結果
+ 開啟投票
+ 投票類型
+ 編輯投票
+ 編輯投票
+ 沒有投票
+ 信任層級設定錯誤
+ 加密設定錯誤
+ 還原加密
+ 請聯絡管理員以將加密還原至有效狀態。
+ 加密設定錯誤。
+ 分享了他們的位置
+ 建立帳號
+ 為您的團隊傳送訊息。
+ 端到端加密,不需要電話號碼。沒有廣告或資料挖礦。
+ 選擇保留對話的位置,讓您擁有控制權與獨立性。透過 Matrix 連結。
+ 安全且獨立的通訊,為您提供與在家中進行面對面對話相同的隱私等級。
+ 位置
+ 加密設定錯誤,因此您無法傳送訊息。點擊以開啟設定。
+ 加密設定錯誤,因此您無法傳送訊息。請聯絡管理員將加密還原至有效的狀態。
\ 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 6dbc5ae2e4..378b8d7cbf 100644
--- a/vector/src/main/res/values/strings.xml
+++ b/vector/src/main/res/values/strings.xml
@@ -2516,11 +2516,13 @@
Own your conversations.
You\'re in control.
Secure messaging.
+
Cut the slack from teams.
Secure and independent communication that gives you the same level of privacy as a face-to-face conversation in your own home.
Choose where your conversations are kept, giving you control and independence. Connected via Matrix.
End-to-end encrypted and no phone number required. No ads or datamining.
+
Messaging for your team.
${app_name} is also great for the workplace. It’s trusted by the world’s most secure organisations.
@@ -3709,6 +3711,7 @@
Share location
Location
Share location
+ Map
Share location
${app_name} could not access your location
${app_name} could not access your location. Please try again later.
diff --git a/vector/src/test/java/im/vector/app/features/location/LocationDataTest.kt b/vector/src/test/java/im/vector/app/features/location/LocationDataTest.kt
new file mode 100644
index 0000000000..fcfff0096f
--- /dev/null
+++ b/vector/src/test/java/im/vector/app/features/location/LocationDataTest.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2022 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.location
+
+import org.amshove.kluent.shouldBeEqualTo
+import org.amshove.kluent.shouldBeNull
+import org.junit.Test
+
+class LocationDataTest {
+ @Test
+ fun validCases() {
+ parseGeo("geo:12.34,56.78;13.56") shouldBeEqualTo
+ LocationData(latitude = 12.34, longitude = 56.78, uncertainty = 13.56)
+ parseGeo("geo:12.34,56.78") shouldBeEqualTo
+ LocationData(latitude = 12.34, longitude = 56.78, uncertainty = null)
+ // Error is ignored in case of invalid uncertainty
+ parseGeo("geo:12.34,56.78;13.5z6") shouldBeEqualTo
+ LocationData(latitude = 12.34, longitude = 56.78, uncertainty = null)
+ parseGeo("geo:12.34,56.78;13. 56") shouldBeEqualTo
+ LocationData(latitude = 12.34, longitude = 56.78, uncertainty = null)
+ // Space are ignored (trim)
+ parseGeo("geo: 12.34,56.78;13.56") shouldBeEqualTo
+ LocationData(latitude = 12.34, longitude = 56.78, uncertainty = 13.56)
+ parseGeo("geo:12.34,56.78; 13.56") shouldBeEqualTo
+ LocationData(latitude = 12.34, longitude = 56.78, uncertainty = 13.56)
+ }
+
+ @Test
+ fun invalidCases() {
+ parseGeo("").shouldBeNull()
+ parseGeo("geo").shouldBeNull()
+ parseGeo("geo:").shouldBeNull()
+ parseGeo("geo:12.34").shouldBeNull()
+ parseGeo("geo:12.34;13.56").shouldBeNull()
+ parseGeo("gea:12.34,56.78;13.56").shouldBeNull()
+ parseGeo("geo:12.x34,56.78;13.56").shouldBeNull()
+ parseGeo("geo:12.34,56.7y8;13.56").shouldBeNull()
+ // Spaces are not ignored if inside the numbers
+ parseGeo("geo:12.3 4,56.78;13.56").shouldBeNull()
+ parseGeo("geo:12.34,56.7 8;13.56").shouldBeNull()
+ // Or in the protocol part
+ parseGeo(" geo:12.34,56.78;13.56").shouldBeNull()
+ parseGeo("ge o:12.34,56.78;13.56").shouldBeNull()
+ parseGeo("geo :12.34,56.78;13.56").shouldBeNull()
+ }
+}