First Commit

This commit is contained in:
2025-12-18 16:28:50 +07:00
commit 8c3e4f491f
9974 changed files with 396488 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
plugins {
id("io.element.android-compose-library")
}
android {
namespace = "io.element.android.features.analytics.api"
}
dependencies {
implementation(projects.libraries.architecture)
implementation(projects.libraries.designsystem)
implementation(projects.libraries.androidutils)
implementation(projects.libraries.uiStrings)
}
@@ -0,0 +1,13 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.analytics.api
import io.element.android.libraries.architecture.SimpleFeatureEntryPoint
fun interface AnalyticsEntryPoint : SimpleFeatureEntryPoint
@@ -0,0 +1,13 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.analytics.api
sealed interface AnalyticsOptInEvents {
data class EnableAnalytics(val isEnabled: Boolean) : AnalyticsOptInEvents
}
@@ -0,0 +1,18 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.analytics.api.preferences
import io.element.android.features.analytics.api.AnalyticsOptInEvents
data class AnalyticsPreferencesState(
val applicationName: String,
val isEnabled: Boolean,
val policyUrl: String,
val eventSink: (AnalyticsOptInEvents) -> Unit,
)
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.analytics.api.preferences
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
open class AnalyticsPreferencesStateProvider : PreviewParameterProvider<AnalyticsPreferencesState> {
override val values: Sequence<AnalyticsPreferencesState>
get() = sequenceOf(
aAnalyticsPreferencesState().copy(isEnabled = true),
aAnalyticsPreferencesState().copy(isEnabled = true, policyUrl = ""),
)
}
fun aAnalyticsPreferencesState(
applicationName: String = "Element X",
isEnabled: Boolean = false,
policyUrl: String = "https://element.io",
) = AnalyticsPreferencesState(
applicationName = applicationName,
isEnabled = isEnabled,
policyUrl = policyUrl,
eventSink = {}
)
@@ -0,0 +1,74 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.analytics.api.preferences
import androidx.compose.foundation.layout.Column
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewParameter
import io.element.android.features.analytics.api.AnalyticsOptInEvents
import io.element.android.features.analytics.api.R
import io.element.android.libraries.designsystem.components.LINK_TAG
import io.element.android.libraries.designsystem.components.list.ListItemContent
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.text.buildAnnotatedStringWithStyledPart
import io.element.android.libraries.designsystem.theme.components.ListItem
import io.element.android.libraries.designsystem.theme.components.ListSupportingText
import io.element.android.libraries.designsystem.theme.components.Text
@Composable
fun AnalyticsPreferencesView(
state: AnalyticsPreferencesState,
modifier: Modifier = Modifier,
) {
fun onEnabledChanged(isEnabled: Boolean) {
state.eventSink(AnalyticsOptInEvents.EnableAnalytics(isEnabled = isEnabled))
}
val supportingText = stringResource(
id = R.string.screen_analytics_settings_help_us_improve,
state.applicationName
)
Column(modifier) {
ListItem(
headlineContent = {
Text(stringResource(id = R.string.screen_analytics_settings_share_data))
},
supportingContent = {
Text(supportingText)
},
leadingContent = null,
trailingContent = ListItemContent.Switch(
checked = state.isEnabled,
),
onClick = {
onEnabledChanged(!state.isEnabled)
}
)
if (state.policyUrl.isNotEmpty()) {
val linkText = buildAnnotatedStringWithStyledPart(
R.string.screen_analytics_settings_read_terms,
R.string.screen_analytics_settings_read_terms_content_link,
tagAndLink = LINK_TAG to state.policyUrl,
)
ListSupportingText(annotatedString = linkText)
}
}
}
@PreviewsDayNight
@Composable
internal fun AnalyticsPreferencesViewPreview(@PreviewParameter(AnalyticsPreferencesStateProvider::class) state: AnalyticsPreferencesState) =
ElementPreview {
AnalyticsPreferencesView(
state = state,
)
}
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Даваць ананімныя дадзеныя аб выкарыстанні, каб дапамагчы нам выявіць праблемы."</string>
<string name="screen_analytics_settings_read_terms">"Вы можаце азнаёміцца з усімі нашымі ўмовамі %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"тут"</string>
<string name="screen_analytics_settings_share_data">"Дзяліцеся дадзенымі аналітыкі"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Споделяне на анонимни данни за използване, за да ни помогнете да идентифицираме проблеми."</string>
<string name="screen_analytics_settings_read_terms">"Можете да прочетете всички наши условия %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"тук"</string>
<string name="screen_analytics_settings_share_data">"Споделяне на статистически данни"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Sdílejte anonymní údaje o používání, které nám pomohou identifikovat problémy."</string>
<string name="screen_analytics_settings_read_terms">"Můžete si přečíst všechny naše podmínky %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"zde"</string>
<string name="screen_analytics_settings_share_data">"Sdílet analytická data"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Rhannu data defnydd dienw i\'n helpu i nodi problemau."</string>
<string name="screen_analytics_settings_read_terms">"Gallwch ddarllen ein holl amodau %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"yma"</string>
<string name="screen_analytics_settings_share_data">"Rhannu data dadansoddeg"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Del anonyme brugsdata for at hjælpe os med at identificere problemer."</string>
<string name="screen_analytics_settings_read_terms">"Du kan læse alle vores vilkår %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"her"</string>
<string name="screen_analytics_settings_share_data">"Del analysedata"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Teile anonyme Nutzungsdaten, um uns bei der Identifizierung von Problemen zu helfen."</string>
<string name="screen_analytics_settings_read_terms">"Weitere Informationen findest du %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"hier"</string>
<string name="screen_analytics_settings_share_data">"Analysedaten teilen"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Μοιράσου ανώνυμα δεδομένα χρήσης για να μάς βοηθήσεις να εντοπίσουμε προβλήματα."</string>
<string name="screen_analytics_settings_read_terms">"Μπορείς να διαβάσεις όλους τους όρους μας %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"εδώ"</string>
<string name="screen_analytics_settings_share_data">"Κοινή χρήση δεδομένων αναλυτικών στοιχείων"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Compartir datos de uso anónimos para ayudarnos a identificar problemas."</string>
<string name="screen_analytics_settings_read_terms">"Puedes leer todos nuestros términos %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"aquí"</string>
<string name="screen_analytics_settings_share_data">"Compartir datos analíticos"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Võimalike rakenduse vigade leidmiseks palun jaga anonüümset kasutusteavet."</string>
<string name="screen_analytics_settings_read_terms">"Sa võid lugeda meie kasutustingimusi %1$s"</string>
<string name="screen_analytics_settings_read_terms_content_link">"siin"</string>
<string name="screen_analytics_settings_share_data">"Jaga andmeid rakenduse kasutuse kohta"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Partekatu erabilerari buruzko datu anonimoak arazoak identifikatzen laguntzeko."</string>
<string name="screen_analytics_settings_read_terms">"Gure baldintza guztiak irakur ditzakezu %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"hemen"</string>
<string name="screen_analytics_settings_share_data">"Partekatu analisi-datuak"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"داده های استفاده ناشناس را به اشتراک بگذارید تا به ما در شناسایی مشکلات کمک کند."</string>
<string name="screen_analytics_settings_read_terms">"شما می‌توانید تمام شرایط ما را بخوانید%1$s ."</string>
<string name="screen_analytics_settings_read_terms_content_link">"این‌جا"</string>
<string name="screen_analytics_settings_share_data">"هم رسانی داده‌های تحلیلی"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Jaa anonyymejä käyttötietoja auttaaksesi meitä tunnistamaan ongelmat."</string>
<string name="screen_analytics_settings_read_terms">"Voit lukea kaikki ehtomme %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"täällä"</string>
<string name="screen_analytics_settings_share_data">"Jaa analytiikkatietoja"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Partagez des données dutilisation anonymes pour nous aider à identifier les problèmes."</string>
<string name="screen_analytics_settings_read_terms">"Vous pouvez lire toutes nos conditions %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"ici"</string>
<string name="screen_analytics_settings_share_data">"Partagez des données de statistiques dutilisation"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Anonim használati adatok megosztása a problémák azonosítása érdekében."</string>
<string name="screen_analytics_settings_read_terms">"%1$s olvashatja el a feltételeinket."</string>
<string name="screen_analytics_settings_read_terms_content_link">"Itt"</string>
<string name="screen_analytics_settings_share_data">"Elemzési adatok megosztása"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Bagikan data penggunaan anonim untuk membantu kami mengidentifikasi masalah."</string>
<string name="screen_analytics_settings_read_terms">"Anda dapat membaca semua persyaratan kami %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"di sini"</string>
<string name="screen_analytics_settings_share_data">"Bagikan data analitik"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Condividi dati di utilizzo anonimi per aiutarci a identificare problemi."</string>
<string name="screen_analytics_settings_read_terms">"Puoi leggere tutti i nostri termini %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"qui"</string>
<string name="screen_analytics_settings_share_data">"Condividi statistiche"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"გააზიარეთ ანონიმური გამოყენების მონაცემები, რათა დაგვეხმაროთ პრობლემების იდენტიფიცირებაში."</string>
<string name="screen_analytics_settings_read_terms">"შეგიძლიათ, წაიკითხოთ ჩვენი ყველა პირობა %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"აქ"</string>
<string name="screen_analytics_settings_share_data">"გააზიარეთ ანალიტიკური მონაცემები"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"익명화된 사용 데이터를 공유하여 문제점을 파악하는 데 도움을 주십시오."</string>
<string name="screen_analytics_settings_read_terms">"모든 이용 약관은 %1$s 에서 확인하실 수 있습니다."</string>
<string name="screen_analytics_settings_read_terms_content_link">"여기"</string>
<string name="screen_analytics_settings_share_data">"분석 데이터 공유"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Dalinkitės anoniminiais naudojimo duomenimis ir padėkite mums nustatyti problemas."</string>
<string name="screen_analytics_settings_read_terms">"Galite perskaityti visas mūsų sąlygas %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"čia"</string>
<string name="screen_analytics_settings_share_data">"Dalytis analitiniais duomenimis"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Del anonyme bruksdata for å hjelpe oss med å identifisere problemer."</string>
<string name="screen_analytics_settings_read_terms">"Du kan lese alle vilkårene våre på %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"her"</string>
<string name="screen_analytics_settings_share_data">"Del analysedata"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Deel anonieme gebruiksgegevens om ons te helpen problemen te identificeren."</string>
<string name="screen_analytics_settings_read_terms">"Je kunt al onze voorwaarden %1$s lezen."</string>
<string name="screen_analytics_settings_read_terms_content_link">"hier"</string>
<string name="screen_analytics_settings_share_data">"Gebruiksgegevens delen"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Udostępniaj anonimowe dane użytkowania, aby pomóc nam identyfikować problemy."</string>
<string name="screen_analytics_settings_read_terms">"Przeczytaj nasze warunki użytkowania %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"tutaj"</string>
<string name="screen_analytics_settings_share_data">"Udostępniaj dane analityczne"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Compartilhe dados de uso anônimos para nos ajudar a identificar problemas."</string>
<string name="screen_analytics_settings_read_terms">"Você pode ler todos os nossos termos %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"aqui"</string>
<string name="screen_analytics_settings_share_data">"Compartilhar dados analíticos"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Partilhe dados de utilização anónimos para nos ajudar a identificar problemas."</string>
<string name="screen_analytics_settings_read_terms">"Podes ler todos os nossos termos %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"aqui"</string>
<string name="screen_analytics_settings_share_data">"Partilhar dados de utilização"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Distribuiți date anonime de utilizare pentru a ne ajuta să identificăm probleme."</string>
<string name="screen_analytics_settings_read_terms">"Puteți citi toate condițiile noastre %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"aici"</string>
<string name="screen_analytics_settings_share_data">"Partajați datele analitice"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Предоставьте разработчикам анонимные данные об использовании, чтобы помочь им выявлять проблемы эффективнее."</string>
<string name="screen_analytics_settings_read_terms">"Вы можете ознакомиться со всеми нашими условиями %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"здесь"</string>
<string name="screen_analytics_settings_share_data">"Отправлять аналитические данные"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Zdieľajte anonymné údaje o používaní, aby sme mohli identifikovať problémy."</string>
<string name="screen_analytics_settings_read_terms">"Môžete si prečítať všetky naše podmienky %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"tu"</string>
<string name="screen_analytics_settings_share_data">"Zdieľať analytické údaje"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Dela anonyma användningsdata för att hjälpa oss att identifiera problem."</string>
<string name="screen_analytics_settings_read_terms">"Du kan läsa alla våra villkor %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"här"</string>
<string name="screen_analytics_settings_share_data">"Dela analysdata"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Sorunları tanımlamamıza yardımcı olmak için anonim kullanım verilerini paylaşın."</string>
<string name="screen_analytics_settings_read_terms">"Tüm şartlarımızı okuyabilirsiniz %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"burada"</string>
<string name="screen_analytics_settings_share_data">"Analitik verileri paylaşın"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Ділитися анонімними даними про використання, щоб допомогати нам виявляти проблеми."</string>
<string name="screen_analytics_settings_read_terms">"Ви можете прочитати всі наші умови %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"тут"</string>
<string name="screen_analytics_settings_share_data">"Поділитися аналітичними даними"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"مسائل کی نشاندہی کرنے میں ہماری مدد کے لیے گمنام استعمال کے بیانات کا اشتراک کریں۔"</string>
<string name="screen_analytics_settings_read_terms">"آپ ہماری تمام شرائط پڑھ سکتے ہیں %1$s۔"</string>
<string name="screen_analytics_settings_read_terms_content_link">"یہاں"</string>
<string name="screen_analytics_settings_share_data">"تجزیاتی بیانات کا اشتراک کریں"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Muammolarni aniqlashda yordam berish uchun anonim foydalanish maʼlumotlarini baham koʻring."</string>
<string name="screen_analytics_settings_read_terms">"Siz bizning barcha shartlarimizni o\'qishingiz mumkin%1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"Bu yerga"</string>
<string name="screen_analytics_settings_share_data">"Analitik ma\'lumotlarni ulashish"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"提供匿名的使用數據以協助我們釐清問題。"</string>
<string name="screen_analytics_settings_read_terms">"您可以到%1$s閱讀我們的條款。"</string>
<string name="screen_analytics_settings_read_terms_content_link">"這裡"</string>
<string name="screen_analytics_settings_share_data">"提供分析數據"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"共享匿名使用数据以帮助我们排查问题。"</string>
<string name="screen_analytics_settings_read_terms">"您可以阅读我们的所有条款 %1$s。"</string>
<string name="screen_analytics_settings_read_terms_content_link">"此处"</string>
<string name="screen_analytics_settings_share_data">"共享分析数据"</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Share anonymous usage data to help us identify issues."</string>
<string name="screen_analytics_settings_read_terms">"You can read all our terms %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"here"</string>
<string name="screen_analytics_settings_share_data">"Share analytics data"</string>
</resources>
+38
View File
@@ -0,0 +1,38 @@
import extension.setupDependencyInjection
import extension.testCommonDependencies
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023, 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
plugins {
id("io.element.android-compose-library")
id("kotlin-parcelize")
}
android {
namespace = "io.element.android.features.analytics.impl"
}
setupDependencyInjection()
dependencies {
implementation(projects.libraries.androidutils)
implementation(projects.libraries.core)
implementation(projects.libraries.architecture)
implementation(projects.libraries.designsystem)
implementation(projects.libraries.uiStrings)
api(projects.features.analytics.api)
api(projects.services.analytics.api)
implementation(projects.appconfig)
implementation(libs.androidx.datastore.preferences)
implementation(libs.androidx.browser)
testCommonDependencies(libs)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.services.analytics.test)
}
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.analytics.impl
import android.app.Activity
import androidx.activity.compose.LocalActivity
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedInject
import io.element.android.annotations.ContributesNode
import io.element.android.appconfig.AnalyticsConfig
import io.element.android.compound.theme.ElementTheme
import io.element.android.libraries.androidutils.browser.openUrlInChromeCustomTab
@ContributesNode(AppScope::class)
@AssistedInject
class AnalyticsOptInNode(
@Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>,
private val presenter: AnalyticsOptInPresenter,
) : Node(buildContext, plugins = plugins) {
private fun onClickTerms(activity: Activity, darkTheme: Boolean) {
activity.openUrlInChromeCustomTab(null, darkTheme, AnalyticsConfig.POLICY_LINK)
}
@Composable
override fun View(modifier: Modifier) {
val activity = requireNotNull(LocalActivity.current)
val isDark = ElementTheme.isLightTheme.not()
val state = presenter.present()
AnalyticsOptInView(
state = state,
modifier = modifier,
onClickTerms = { onClickTerms(activity, isDark) },
)
}
}
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.analytics.impl
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import dev.zacsweers.metro.Inject
import io.element.android.appconfig.AnalyticsConfig
import io.element.android.features.analytics.api.AnalyticsOptInEvents
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.services.analytics.api.AnalyticsService
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@Inject
class AnalyticsOptInPresenter(
private val buildMeta: BuildMeta,
private val analyticsService: AnalyticsService,
) : Presenter<AnalyticsOptInState> {
@Composable
override fun present(): AnalyticsOptInState {
val localCoroutineScope = rememberCoroutineScope()
fun handleEvent(event: AnalyticsOptInEvents) {
when (event) {
is AnalyticsOptInEvents.EnableAnalytics -> localCoroutineScope.setIsEnabled(event.isEnabled)
}
localCoroutineScope.launch {
analyticsService.setDidAskUserConsent()
}
}
return AnalyticsOptInState(
applicationName = buildMeta.applicationName,
hasPolicyLink = AnalyticsConfig.POLICY_LINK.isNotEmpty(),
eventSink = ::handleEvent,
)
}
private fun CoroutineScope.setIsEnabled(enabled: Boolean) = launch {
analyticsService.setUserConsent(enabled)
}
}
@@ -0,0 +1,17 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.analytics.impl
import io.element.android.features.analytics.api.AnalyticsOptInEvents
data class AnalyticsOptInState(
val applicationName: String,
val hasPolicyLink: Boolean,
val eventSink: (AnalyticsOptInEvents) -> Unit
)
@@ -0,0 +1,27 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.analytics.impl
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
open class AnalyticsOptInStateProvider : PreviewParameterProvider<AnalyticsOptInState> {
override val values: Sequence<AnalyticsOptInState>
get() = sequenceOf(
aAnalyticsOptInState(),
aAnalyticsOptInState(hasPolicyLink = false),
)
}
fun aAnalyticsOptInState(
hasPolicyLink: Boolean = true,
) = AnalyticsOptInState(
applicationName = "Element X",
hasPolicyLink = hasPolicyLink,
eventSink = {}
)
@@ -0,0 +1,180 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.analytics.impl
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.BiasAlignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.appconfig.AnalyticsConfig
import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.analytics.api.AnalyticsOptInEvents
import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
import io.element.android.libraries.designsystem.atomic.organisms.InfoListItem
import io.element.android.libraries.designsystem.atomic.organisms.InfoListOrganism
import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage
import io.element.android.libraries.designsystem.background.OnboardingBackground
import io.element.android.libraries.designsystem.components.BigIcon
import io.element.android.libraries.designsystem.components.ClickableLinkText
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.text.buildAnnotatedStringWithStyledPart
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.ButtonSize
import io.element.android.libraries.designsystem.theme.components.TextButton
import io.element.android.libraries.ui.strings.CommonStrings
import kotlinx.collections.immutable.persistentListOf
@Composable
fun AnalyticsOptInView(
state: AnalyticsOptInState,
onClickTerms: () -> Unit,
modifier: Modifier = Modifier,
) {
val eventSink = state.eventSink
fun onAcceptTerms() {
eventSink(AnalyticsOptInEvents.EnableAnalytics(true))
}
fun onDeclineTerms() {
eventSink(AnalyticsOptInEvents.EnableAnalytics(false))
}
BackHandler(onBack = ::onDeclineTerms)
HeaderFooterPage(
modifier = modifier
.fillMaxSize()
.systemBarsPadding()
.imePadding(),
background = { OnboardingBackground() },
header = { AnalyticsOptInHeader(state, onClickTerms) },
content = { AnalyticsOptInContent() },
footer = {
AnalyticsOptInFooter(
onAcceptTerms = ::onAcceptTerms,
onDeclineTerms = ::onDeclineTerms,
)
}
)
}
private const val LINK_TAG = "link"
@Composable
private fun AnalyticsOptInHeader(
state: AnalyticsOptInState,
onClickTerms: () -> Unit,
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
) {
IconTitleSubtitleMolecule(
modifier = Modifier.padding(top = 60.dp, bottom = 28.dp),
title = stringResource(id = R.string.screen_analytics_prompt_title, state.applicationName),
subTitle = stringResource(id = R.string.screen_analytics_prompt_help_us_improve),
iconStyle = BigIcon.Style.Default(CompoundIcons.Chart())
)
if (state.hasPolicyLink) {
val text = buildAnnotatedStringWithStyledPart(
R.string.screen_analytics_prompt_read_terms,
R.string.screen_analytics_prompt_read_terms_content_link,
color = Color.Unspecified,
underline = false,
bold = true,
tagAndLink = LINK_TAG to AnalyticsConfig.POLICY_LINK,
)
ClickableLinkText(
annotatedString = text,
onClick = { onClickTerms() },
modifier = Modifier
.padding(8.dp),
style = ElementTheme.typography.fontBodyMdRegular
.copy(
color = ElementTheme.colors.textSecondary,
textAlign = TextAlign.Center,
)
)
}
}
}
@Composable
private fun AnalyticsOptInContent() {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = BiasAlignment(
horizontalBias = 0f,
verticalBias = -0.4f
)
) {
InfoListOrganism(
items = persistentListOf(
InfoListItem(
message = stringResource(id = R.string.screen_analytics_prompt_data_usage),
iconVector = CompoundIcons.CheckCircle(),
),
InfoListItem(
message = stringResource(id = R.string.screen_analytics_prompt_third_party_sharing),
iconVector = CompoundIcons.CheckCircle(),
),
InfoListItem(
message = stringResource(id = R.string.screen_analytics_prompt_settings),
iconVector = CompoundIcons.CheckCircle(),
),
),
textStyle = ElementTheme.typography.fontBodyLgMedium,
iconTint = ElementTheme.colors.iconSuccessPrimary,
)
}
}
@Composable
private fun AnalyticsOptInFooter(
onAcceptTerms: () -> Unit,
onDeclineTerms: () -> Unit,
) {
ButtonColumnMolecule {
Button(
text = stringResource(id = CommonStrings.action_ok),
onClick = onAcceptTerms,
modifier = Modifier.fillMaxWidth(),
)
TextButton(
text = stringResource(id = CommonStrings.action_not_now),
size = ButtonSize.Medium,
onClick = onDeclineTerms,
modifier = Modifier.fillMaxWidth(),
)
}
}
@PreviewsDayNight
@Composable
internal fun AnalyticsOptInViewPreview(@PreviewParameter(AnalyticsOptInStateProvider::class) state: AnalyticsOptInState) = ElementPreview {
AnalyticsOptInView(
state = state,
onClickTerms = {},
)
}
@@ -0,0 +1,23 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.analytics.impl
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesBinding
import io.element.android.features.analytics.api.AnalyticsEntryPoint
import io.element.android.libraries.architecture.createNode
@ContributesBinding(AppScope::class)
class DefaultAnalyticsEntryPoint : AnalyticsEntryPoint {
override fun createNode(parentNode: Node, buildContext: BuildContext): Node {
return parentNode.createNode<AnalyticsOptInNode>(buildContext)
}
}
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2024, 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.analytics.impl.di
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.Binds
import dev.zacsweers.metro.ContributesTo
import io.element.android.features.analytics.api.preferences.AnalyticsPreferencesState
import io.element.android.features.analytics.impl.preferences.AnalyticsPreferencesPresenter
import io.element.android.libraries.architecture.Presenter
@ContributesTo(AppScope::class)
@BindingContainer
interface AnalyticsModule {
@Binds
fun bindAnalyticsPreferencesPresenter(presenter: AnalyticsPreferencesPresenter): Presenter<AnalyticsPreferencesState>
}
@@ -0,0 +1,51 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.analytics.impl.preferences
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.rememberCoroutineScope
import dev.zacsweers.metro.Inject
import io.element.android.appconfig.AnalyticsConfig
import io.element.android.features.analytics.api.AnalyticsOptInEvents
import io.element.android.features.analytics.api.preferences.AnalyticsPreferencesState
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.services.analytics.api.AnalyticsService
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@Inject
class AnalyticsPreferencesPresenter(
private val analyticsService: AnalyticsService,
private val buildMeta: BuildMeta,
) : Presenter<AnalyticsPreferencesState> {
@Composable
override fun present(): AnalyticsPreferencesState {
val localCoroutineScope = rememberCoroutineScope()
val isEnabled = analyticsService.userConsentFlow.collectAsState(initial = false)
fun handleEvent(event: AnalyticsOptInEvents) {
when (event) {
is AnalyticsOptInEvents.EnableAnalytics -> localCoroutineScope.setIsEnabled(event.isEnabled)
}
}
return AnalyticsPreferencesState(
applicationName = buildMeta.applicationName,
isEnabled = isEnabled.value,
policyUrl = AnalyticsConfig.POLICY_LINK,
eventSink = ::handleEvent,
)
}
private fun CoroutineScope.setIsEnabled(enabled: Boolean) = launch {
analyticsService.setUserConsent(enabled)
}
}
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Мы не будзем запісваць або прафіляваць любыя асабістыя даныя"</string>
<string name="screen_analytics_prompt_help_us_improve">"Даваць ананімныя дадзеныя аб выкарыстанні, каб дапамагчы нам выявіць праблемы."</string>
<string name="screen_analytics_prompt_read_terms">"Вы можаце азнаёміцца з усімі нашымі ўмовамі %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"тут"</string>
<string name="screen_analytics_prompt_settings">"Вы можаце адключыць гэта ў любы час"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Мы не будзем перадаваць вашыя дадзеныя трэцім асобам"</string>
<string name="screen_analytics_prompt_title">"Дапамажыце палепшыць %1$s"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Няма да записваме или профилираме лични данни"</string>
<string name="screen_analytics_prompt_help_us_improve">"Споделяне на анонимни данни за използване, за да ни помогнете да идентифицираме проблеми."</string>
<string name="screen_analytics_prompt_read_terms">"Можете да прочетете всички наши условия %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"тук"</string>
<string name="screen_analytics_prompt_settings">"Можете да изключите това по всяко време"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Няма да споделяме данни ви с трети страни"</string>
<string name="screen_analytics_prompt_title">"Помогнете за подобряването на %1$s"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Nezaznamenáváme ani neprofilujeme žádné údaje o účtu"</string>
<string name="screen_analytics_prompt_help_us_improve">"Sdílejte anonymní údaje o používání, které nám pomohou identifikovat problémy."</string>
<string name="screen_analytics_prompt_read_terms">"Můžete si přečíst všechny naše podmínky %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"zde"</string>
<string name="screen_analytics_prompt_settings">"Tuto funkci můžete kdykoli vypnout"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Nesdílíme informace s třetími stranami"</string>
<string name="screen_analytics_prompt_title">"Pomozte vylepšit %1$s"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Fyddwn ni ddim yn cofnodi nac yn proffilio unrhyw ddata personol"</string>
<string name="screen_analytics_prompt_help_us_improve">"Rhannu data defnydd dienw i\'n helpu i nodi problemau."</string>
<string name="screen_analytics_prompt_read_terms">"Gallwch ddarllen ein holl amodau %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"yma"</string>
<string name="screen_analytics_prompt_settings">"Gallwch ddiffodd hwn unrhyw bryd"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Fyddwn ni ddim yn rhannu eich data gyda thrydydd parti"</string>
<string name="screen_analytics_prompt_title">"Helpwch i wella %1$s"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Vi vil ikke registrere eller profilere nogen personlige data"</string>
<string name="screen_analytics_prompt_help_us_improve">"Del anonyme brugsdata for at hjælpe os med at identificere problemer."</string>
<string name="screen_analytics_prompt_read_terms">"Du kan læse alle vores vilkår %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"her"</string>
<string name="screen_analytics_prompt_settings">"Du kan slå dette fra når som helst"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Vi deler ikke dine data med tredjeparter"</string>
<string name="screen_analytics_prompt_title">"Hjælp med at forbedre %1$s"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Wir speichern oder profilieren keine personenbezogenen Daten."</string>
<string name="screen_analytics_prompt_help_us_improve">"Teile anonyme Nutzungsdaten, um uns bei der Identifizierung von Problemen zu helfen."</string>
<string name="screen_analytics_prompt_read_terms">"Weitere Informationen findest du %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"hier"</string>
<string name="screen_analytics_prompt_settings">"Du kannst diese Funktion jederzeit deaktivieren"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Wir geben deine Daten nicht an Dritte weiter"</string>
<string name="screen_analytics_prompt_title">"Hilf uns %1$s zu verbessern"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Δεν θα καταγράψουμε ούτε θα δημιουργήσουμε προφίλ προσωπικών δεδομένων"</string>
<string name="screen_analytics_prompt_help_us_improve">"Μοιράσου ανώνυμα δεδομένα χρήσης για να μάς βοηθήσεις να εντοπίσουμε προβλήματα."</string>
<string name="screen_analytics_prompt_read_terms">"Μπορείς να διαβάσεις όλους τους όρους μας %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"εδώ"</string>
<string name="screen_analytics_prompt_settings">"Μπορείς να το απενεργοποιήσεις ανά πάσα στιγμή"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Δεν θα μοιραστούμε τα δεδομένα σου με τρίτους"</string>
<string name="screen_analytics_prompt_title">"Βοήθησε στη βελτίωση του %1$s"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"No registraremos o perfilaremos ningún dato personal"</string>
<string name="screen_analytics_prompt_help_us_improve">"Compartir datos de uso anónimos para ayudarnos a identificar problemas."</string>
<string name="screen_analytics_prompt_read_terms">"Puedes leer todos nuestros términos %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"aquí"</string>
<string name="screen_analytics_prompt_settings">"Puedes desactivarlo en cualquier momento"</string>
<string name="screen_analytics_prompt_third_party_sharing">"No compartiremos tus datos con terceros"</string>
<string name="screen_analytics_prompt_title">"Ayuda a mejorar %1$s"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Me ei salvesta ega profileeri sinu isiklikke andmeid"</string>
<string name="screen_analytics_prompt_help_us_improve">"Võimalike rakenduse vigade leidmiseks palun jaga anonüümset kasutusteavet."</string>
<string name="screen_analytics_prompt_read_terms">"Sa võid lugeda meie kasutustingimusi %1$s"</string>
<string name="screen_analytics_prompt_read_terms_content_link">"siin"</string>
<string name="screen_analytics_prompt_settings">"Selle valiku saad igal ajal välja lülitada"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Me ei jaga sinu andmeid kolmandate osapooltega"</string>
<string name="screen_analytics_prompt_title">"Aita parandada rakendust %1$s"</string>
</resources>
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_help_us_improve">"Partekatu erabilerari buruzko datu anonimoak arazoak identifikatzen laguntzeko."</string>
<string name="screen_analytics_prompt_read_terms">"Gure baldintza guztiak irakur ditzakezu %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"hemen"</string>
<string name="screen_analytics_prompt_settings">"Edozein unetan desaktibatu dezakezu"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Ez ditugu zure datuak hirugarrenekin partekatuko"</string>
<string name="screen_analytics_prompt_title">"Lagundu %1$s hobetzen"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"ما هیچ گونه اطلاعات شخصی را ضبط یا نمایه‌سازی نمی‌کنیم"</string>
<string name="screen_analytics_prompt_help_us_improve">"داده های استفاده ناشناس را به اشتراک بگذارید تا به ما در شناسایی مشکلات کمک کند."</string>
<string name="screen_analytics_prompt_read_terms">"شما می‌توانید تمام شرایط ما را بخوانید%1$s ."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"این‌جا"</string>
<string name="screen_analytics_prompt_settings">"می‌توانید در هر زمان خاموشش کنید"</string>
<string name="screen_analytics_prompt_third_party_sharing">"داده‌هایتان را با سوم‌شخص‌ها هم‌نمی‌رسانیم"</string>
<string name="screen_analytics_prompt_title">"کمک به بهبود %1$s"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Emme tallenna tai profiloi henkilötietoja"</string>
<string name="screen_analytics_prompt_help_us_improve">"Jaa anonyymejä käyttötietoja auttaaksesi meitä tunnistamaan ongelmat."</string>
<string name="screen_analytics_prompt_read_terms">"Voit lukea kaikki ehtomme %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"täällä"</string>
<string name="screen_analytics_prompt_settings">"Voit poistaa tämän käytöstä milloin tahansa"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Emme jaa tietojasi kolmansien osapuolien kanssa"</string>
<string name="screen_analytics_prompt_title">"Auta parantamaan %1$s -sovellusta"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Nous nenregistrerons ni ne profilerons aucune donnée personnelle"</string>
<string name="screen_analytics_prompt_help_us_improve">"Partagez des données dutilisation anonymes pour nous aider à identifier les problèmes."</string>
<string name="screen_analytics_prompt_read_terms">"Vous pouvez lire toutes nos conditions %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"ici"</string>
<string name="screen_analytics_prompt_settings">"Vous pouvez le désactiver à tout moment"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Nous ne partagerons pas vos données avec des tiers"</string>
<string name="screen_analytics_prompt_title">"Aidez à améliorer %1$s"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Nem rögzítünk vagy profilozunk személyes adatokat"</string>
<string name="screen_analytics_prompt_help_us_improve">"Anonim használati adatok megosztása a problémák azonosítása érdekében."</string>
<string name="screen_analytics_prompt_read_terms">"%1$s olvashatja el a feltételeinket."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"Itt"</string>
<string name="screen_analytics_prompt_settings">"Ezt bármikor kikapcsolhatja"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Adatait nem osztjuk meg harmadik felekkel"</string>
<string name="screen_analytics_prompt_title">"Segítsen az %1$s fejlesztésében"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Kami tidak akan merekam atau memprofil data pribadi apa pun"</string>
<string name="screen_analytics_prompt_help_us_improve">"Bagikan data penggunaan anonim untuk membantu kami mengidentifikasi masalah."</string>
<string name="screen_analytics_prompt_read_terms">"Anda dapat membaca semua persyaratan kami %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"di sini"</string>
<string name="screen_analytics_prompt_settings">"Anda dapat mematikan ini kapan saja"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Kami tidak akan membagikan data Anda dengan pihak ketiga"</string>
<string name="screen_analytics_prompt_title">"Bantu sempurnakan %1$s"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Non registreremo né profileremo alcun dato personale"</string>
<string name="screen_analytics_prompt_help_us_improve">"Condividi dati di utilizzo anonimi per aiutarci a identificare problemi."</string>
<string name="screen_analytics_prompt_read_terms">"Puoi leggere tutti i nostri termini %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"qui"</string>
<string name="screen_analytics_prompt_settings">"Puoi disattivarlo in qualsiasi momento"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Non condivideremo i tuoi dati con terze parti"</string>
<string name="screen_analytics_prompt_title">"Aiutaci a migliorare %1$s"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"ჩვენ არ ჩავწერთ და არ დავაფიქსირებთ პერსონალურ მონაცემებს"</string>
<string name="screen_analytics_prompt_help_us_improve">"გააზიარეთ ანონიმური გამოყენების მონაცემები, რათა დაგვეხმაროთ პრობლემების იდენტიფიცირებაში."</string>
<string name="screen_analytics_prompt_read_terms">"შეგიძლიათ, წაიკითხოთ ჩვენი ყველა პირობა %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"აქ"</string>
<string name="screen_analytics_prompt_settings">"ამის გამორთვა ნებისმიერ დროს შეგიძლიათ"</string>
<string name="screen_analytics_prompt_third_party_sharing">"თქვენს მონაცემებს მესამე პირს არ გადავცემთ"</string>
<string name="screen_analytics_prompt_title">"დაგვეხმარეთ, გავაუმჯობესოთ %1$s"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"개인 데이터는 기록하거나 프로파일링하지 않습니다."</string>
<string name="screen_analytics_prompt_help_us_improve">"익명화된 사용 데이터를 공유하여 문제점을 파악하는 데 도움을 주십시오."</string>
<string name="screen_analytics_prompt_read_terms">"모든 이용 약관은 %1$s 에서 확인하실 수 있습니다."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"여기"</string>
<string name="screen_analytics_prompt_settings">"이 기능을 언제든지 비활성화할 수 있습니다."</string>
<string name="screen_analytics_prompt_third_party_sharing">"우리는 귀하의 데이터를 제3자와 공유하지 않습니다."</string>
<string name="screen_analytics_prompt_title">"%1$s 개선하기"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Mes nekaupsime ir neprofiliuosime jokių asmens duomenų"</string>
<string name="screen_analytics_prompt_help_us_improve">"Dalinkitės anoniminiais naudojimo duomenimis ir padėkite mums nustatyti problemas."</string>
<string name="screen_analytics_prompt_read_terms">"Galite perskaityti visas mūsų sąlygas %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"čia"</string>
<string name="screen_analytics_prompt_settings">"Tai galite bet kada išjungti"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Mes nesidalinsime Jūsų duomenimis su trečiosiomis šalimis"</string>
<string name="screen_analytics_prompt_title">"Padėkite pagerinti %1$s"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Vi vil ikke registrere eller profilere noen personlige data"</string>
<string name="screen_analytics_prompt_help_us_improve">"Del anonyme bruksdata for å hjelpe oss med å identifisere problemer."</string>
<string name="screen_analytics_prompt_read_terms">"Du kan lese alle vilkårene våre på %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"her"</string>
<string name="screen_analytics_prompt_settings">"Du kan slå av dette når som helst"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Vi deler ikke dataene dine med tredjeparter"</string>
<string name="screen_analytics_prompt_title">"Hjelp til å forbedre %1$s"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"We zullen geen persoonlijke gegevens registreren of er een profiel van maken"</string>
<string name="screen_analytics_prompt_help_us_improve">"Deel anonieme gebruiksgegevens om ons te helpen problemen te identificeren."</string>
<string name="screen_analytics_prompt_read_terms">"Je kunt al onze voorwaarden %1$s lezen."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"hier"</string>
<string name="screen_analytics_prompt_settings">"Je kunt dit op elk moment uitschakelen"</string>
<string name="screen_analytics_prompt_third_party_sharing">"We delen je gegevens niet met derden"</string>
<string name="screen_analytics_prompt_title">"Help %1$s te verbeteren"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Nie będziemy rejestrować ani profilować żadnych danych osobistych"</string>
<string name="screen_analytics_prompt_help_us_improve">"Udostępniaj anonimowe dane użytkowania, aby pomóc nam identyfikować problemy."</string>
<string name="screen_analytics_prompt_read_terms">"Przeczytaj nasze warunki użytkowania %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"tutaj"</string>
<string name="screen_analytics_prompt_settings">"Możesz to wyłączyć w dowolnym momencie"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Nie będziemy udostępniać Twoich danych stronom trzecim"</string>
<string name="screen_analytics_prompt_title">"Pomóż nam ulepszyć %1$s"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Não iremos gravar ou personificar qualquer dado pessoal"</string>
<string name="screen_analytics_prompt_help_us_improve">"Compartilhe dados de uso anônimos para nos ajudar a identificar problemas."</string>
<string name="screen_analytics_prompt_read_terms">"Você pode ler todos os nossos termos %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"aqui"</string>
<string name="screen_analytics_prompt_settings">"Você pode desativar isso a qualquer momento"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Não compartilharemos seus dados com terceiros"</string>
<string name="screen_analytics_prompt_title">"Ajude a melhorar o %1$s"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Não recolheremos ou analisaremos quaisquer dados pessoais"</string>
<string name="screen_analytics_prompt_help_us_improve">"Partilhe dados de utilização anónimos para nos ajudar a identificar problemas."</string>
<string name="screen_analytics_prompt_read_terms">"Podes ler todos os nossos termos %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"aqui"</string>
<string name="screen_analytics_prompt_settings">"Pode desactivar a qualquer momento"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Não partilharemos os teus dados com terceiros"</string>
<string name="screen_analytics_prompt_title">"Ajude a melhorar a %1$s"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Nu vom înregistra și nu vom face profiluri cu privire la datele personale."</string>
<string name="screen_analytics_prompt_help_us_improve">"Distribuiți date anonime de utilizare pentru a ne ajuta să identificăm probleme."</string>
<string name="screen_analytics_prompt_read_terms">"Puteți citi toate condițiile noastre %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"aici"</string>
<string name="screen_analytics_prompt_settings">"Puteți dezactiva această opțiune oricând din setări"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Nu vom partaja datele dvs. cu terțe părți"</string>
<string name="screen_analytics_prompt_title">"Ajutați la îmbunătățirea %1$s"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Мы не будем записывать или профилировать какие-либо персональные данные"</string>
<string name="screen_analytics_prompt_help_us_improve">"Предоставьте разработчикам анонимные данные об использовании, чтобы помочь им выявлять проблемы эффективнее."</string>
<string name="screen_analytics_prompt_read_terms">"Вы можете ознакомиться со всеми нашими условиями %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"здесь"</string>
<string name="screen_analytics_prompt_settings">"Вы можете отключить эту функцию в любое время"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Мы не будем передавать ваши данные третьим лицам"</string>
<string name="screen_analytics_prompt_title">"Помогите улучшить %1$s"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Nezaznamenávame ani neprofilujeme žiadne osobné údaje"</string>
<string name="screen_analytics_prompt_help_us_improve">"Zdieľajte anonymné údaje o používaní, aby sme mohli identifikovať problémy."</string>
<string name="screen_analytics_prompt_read_terms">"Môžete si prečítať všetky naše podmienky %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"tu"</string>
<string name="screen_analytics_prompt_settings">"Môžete to kedykoľvek vypnúť"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Vaše údaje nebudeme zdieľať s tretími stranami"</string>
<string name="screen_analytics_prompt_title">"Pomôžte zlepšiť %1$s"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Vi kommer inte att registrera eller profilera några personuppgifter"</string>
<string name="screen_analytics_prompt_help_us_improve">"Dela anonyma användningsdata för att hjälpa oss att identifiera problem."</string>
<string name="screen_analytics_prompt_read_terms">"Du kan läsa alla våra villkor %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"här"</string>
<string name="screen_analytics_prompt_settings">"Du kan stänga av detta när som helst"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Vi delar inte dina uppgifter med tredje part"</string>
<string name="screen_analytics_prompt_title">"Hjälp till att förbättra %1$s"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Hiçbir kişisel veriyi kaydetmeyeceğiz veya profillemeyeceğiz"</string>
<string name="screen_analytics_prompt_help_us_improve">"Sorunları tanımlamamıza yardımcı olmak için anonim kullanım verilerini paylaşın."</string>
<string name="screen_analytics_prompt_read_terms">"Tüm şartlarımızı okuyabilirsiniz %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"burada"</string>
<string name="screen_analytics_prompt_settings">"Bu özelliği istediğiniz zaman kapatabilirsiniz"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Verilerinizi üçüncü taraflarla paylaşmayacağız"</string>
<string name="screen_analytics_prompt_title">"%1$s geliştirilmesine yardımcı olun"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Ми не записуватимемо та не профілюватимемо жодні персональні дані"</string>
<string name="screen_analytics_prompt_help_us_improve">"Ділитися анонімними даними про використання, щоб допомогати нам виявляти проблеми."</string>
<string name="screen_analytics_prompt_read_terms">"Ви можете прочитати всі наші умови %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"тут"</string>
<string name="screen_analytics_prompt_settings">"Ви можете вимкнути цю функцію в будь-який час"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Ми не передаватимемо ваші дані третім особам"</string>
<string name="screen_analytics_prompt_title">"Допоможіть вдосконалити %1$s"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"ہم کسی بھی ذاتی ڈیٹا کو ثبت یا پروفائل نہیں کریں گے"</string>
<string name="screen_analytics_prompt_help_us_improve">"مسائل کی نشاندہی کرنے میں ہماری مدد کے لیے گمنام استعمال کے بیانات کا اشتراک کریں۔"</string>
<string name="screen_analytics_prompt_read_terms">"آپ ہماری تمام شرائط پڑھ سکتے ہیں %1$s۔"</string>
<string name="screen_analytics_prompt_read_terms_content_link">"یہاں"</string>
<string name="screen_analytics_prompt_settings">"آپ اسے کسی بھی وقت بند کر سکتے ہیں"</string>
<string name="screen_analytics_prompt_third_party_sharing">"ہم آپکے بیانات کا فریق ثالث کے ساتھ اشتراک نہیں کریں گے"</string>
<string name="screen_analytics_prompt_title">"%1$s کو بہتر بنانے میں مدد کریں"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Biz hech qanday shaxsiy ma\'lumotlarni yozmaymiz yoki profilga kiritmaymiz"</string>
<string name="screen_analytics_prompt_help_us_improve">"Muammolarni aniqlashda yordam berish uchun anonim foydalanish maʼlumotlarini baham koʻring."</string>
<string name="screen_analytics_prompt_read_terms">"Siz bizning barcha shartlarimizni o\'qishingiz mumkin%1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"Bu yerga"</string>
<string name="screen_analytics_prompt_settings">"Buni istalgan vaqtda oʻchirib qoʻyishingiz mumkin"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Biz sizning ma\'lumotlaringizni uchinchi tomonlar bilan baham ko\'rmaymiz"</string>
<string name="screen_analytics_prompt_title">"Yaxshilashga yordam bering%1$s"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"我們不會紀錄或剖繪您的個人資料"</string>
<string name="screen_analytics_prompt_help_us_improve">"提供匿名的使用數據以協助我們釐清問題。"</string>
<string name="screen_analytics_prompt_read_terms">"您可以到%1$s閱讀我們的條款。"</string>
<string name="screen_analytics_prompt_read_terms_content_link">"這裡"</string>
<string name="screen_analytics_prompt_settings">"您可以在任何時候關閉它"</string>
<string name="screen_analytics_prompt_third_party_sharing">"我們不會和第三方分享您的資料"</string>
<string name="screen_analytics_prompt_title">"讓 %1$s 變得更好"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"我们不会记录或分析任何个人数据"</string>
<string name="screen_analytics_prompt_help_us_improve">"共享匿名使用数据以帮助我们排查问题。"</string>
<string name="screen_analytics_prompt_read_terms">"您可以阅读我们的所有条款 %1$s。"</string>
<string name="screen_analytics_prompt_read_terms_content_link">"此处"</string>
<string name="screen_analytics_prompt_settings">"可以随时关闭此功能"</string>
<string name="screen_analytics_prompt_third_party_sharing">"我们不会与第三方共享您的数据"</string>
<string name="screen_analytics_prompt_title">"帮助改进 %1$s"</string>
</resources>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"We won\'t record or profile any personal data"</string>
<string name="screen_analytics_prompt_help_us_improve">"Share anonymous usage data to help us identify issues."</string>
<string name="screen_analytics_prompt_read_terms">"You can read all our terms %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"here"</string>
<string name="screen_analytics_prompt_settings">"You can turn this off anytime"</string>
<string name="screen_analytics_prompt_third_party_sharing">"We won\'t share your data with third parties"</string>
<string name="screen_analytics_prompt_title">"Help improve %1$s"</string>
</resources>
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.analytics.impl
import app.cash.molecule.RecompositionMode
import app.cash.molecule.moleculeFlow
import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import io.element.android.features.analytics.api.AnalyticsOptInEvents
import io.element.android.libraries.matrix.test.core.aBuildMeta
import io.element.android.services.analytics.test.FakeAnalyticsService
import io.element.android.tests.testutils.WarmUpRule
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test
class AnalyticsOptInPresenterTest {
@get:Rule
val warmUpRule = WarmUpRule()
@Test
fun `present - enable`() = runTest {
val analyticsService = FakeAnalyticsService(isEnabled = false)
val presenter = AnalyticsOptInPresenter(
aBuildMeta(),
analyticsService
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
assertThat(analyticsService.didAskUserConsentFlow.first()).isFalse()
initialState.eventSink.invoke(AnalyticsOptInEvents.EnableAnalytics(true))
assertThat(analyticsService.didAskUserConsentFlow.first()).isTrue()
assertThat(analyticsService.userConsentFlow.first()).isTrue()
}
}
@Test
fun `present - not now`() = runTest {
val analyticsService = FakeAnalyticsService(isEnabled = false)
val presenter = AnalyticsOptInPresenter(
aBuildMeta(),
analyticsService
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
assertThat(analyticsService.didAskUserConsentFlow.first()).isFalse()
initialState.eventSink.invoke(AnalyticsOptInEvents.EnableAnalytics(false))
assertThat(analyticsService.didAskUserConsentFlow.first()).isTrue()
assertThat(analyticsService.userConsentFlow.first()).isFalse()
}
}
}
@@ -0,0 +1,40 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.analytics.impl
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.bumble.appyx.core.modality.BuildContext
import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.matrix.test.core.aBuildMeta
import io.element.android.services.analytics.test.FakeAnalyticsService
import io.element.android.tests.testutils.node.TestParentNode
import org.junit.Rule
import org.junit.Test
class DefaultAnalyticsEntryPointTest {
@get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule()
@Test
fun `test node creation`() {
val entryPoint = DefaultAnalyticsEntryPoint()
val parentNode = TestParentNode.create { buildContext, plugins ->
AnalyticsOptInNode(
buildContext = buildContext,
plugins = plugins,
AnalyticsOptInPresenter(
buildMeta = aBuildMeta(),
analyticsService = FakeAnalyticsService()
)
)
}
val result = entryPoint.createNode(parentNode, BuildContext.root(null))
assertThat(result).isInstanceOf(AnalyticsOptInNode::class.java)
}
}
@@ -0,0 +1,76 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.analytics.impl.preferences
import app.cash.molecule.RecompositionMode
import app.cash.molecule.moleculeFlow
import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import io.element.android.appconfig.AnalyticsConfig
import io.element.android.features.analytics.api.AnalyticsOptInEvents
import io.element.android.libraries.matrix.test.core.aBuildMeta
import io.element.android.services.analytics.test.FakeAnalyticsService
import io.element.android.tests.testutils.WarmUpRule
import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test
class AnalyticsPreferencesPresenterTest {
@get:Rule
val warmUpRule = WarmUpRule()
@Test
fun `present - initial state available`() = runTest {
val presenter = AnalyticsPreferencesPresenter(
FakeAnalyticsService(isEnabled = true, didAskUserConsent = true),
aBuildMeta()
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
skipItems(1)
val initialState = awaitItem()
assertThat(initialState.isEnabled).isTrue()
assertThat(initialState.policyUrl).isEqualTo(AnalyticsConfig.POLICY_LINK)
}
}
@Test
fun `present - initial state not available`() = runTest {
val presenter = AnalyticsPreferencesPresenter(
FakeAnalyticsService(isEnabled = false, didAskUserConsent = false),
aBuildMeta()
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
assertThat(initialState.isEnabled).isFalse()
}
}
@Test
fun `present - enable and disable`() = runTest {
val presenter = AnalyticsPreferencesPresenter(
FakeAnalyticsService(isEnabled = true, didAskUserConsent = true),
aBuildMeta()
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
skipItems(1)
val initialState = awaitItem()
assertThat(initialState.isEnabled).isTrue()
initialState.eventSink.invoke(AnalyticsOptInEvents.EnableAnalytics(false))
assertThat(awaitItem().isEnabled).isFalse()
initialState.eventSink.invoke(AnalyticsOptInEvents.EnableAnalytics(true))
assertThat(awaitItem().isEnabled).isTrue()
}
}
}
@@ -0,0 +1,14 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
plugins {
id("io.element.android-compose-library")
}
android {
namespace = "io.element.android.features.announcement.api"
}
@@ -0,0 +1,14 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.announcement.api
enum class Announcement {
Space,
NewNotificationSound,
}
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.announcement.api
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import kotlinx.coroutines.flow.Flow
interface AnnouncementService {
suspend fun showAnnouncement(announcement: Announcement)
suspend fun onAnnouncementDismissed(announcement: Announcement)
fun announcementsToShowFlow(): Flow<List<Announcement>>
/**
* Use this composable to render the announcement UI in Fullscreen.
*/
@Composable
fun Render(
modifier: Modifier,
)
}
@@ -0,0 +1,38 @@
import extension.setupDependencyInjection
import extension.testCommonDependencies
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
plugins {
id("io.element.android-compose-library")
}
android {
namespace = "io.element.android.features.announcement.impl"
testOptions {
unitTests {
isIncludeAndroidResources = true
}
}
}
setupDependencyInjection()
dependencies {
implementation(projects.libraries.architecture)
implementation(projects.libraries.designsystem)
implementation(projects.libraries.preferences.api)
implementation(projects.libraries.uiStrings)
api(projects.features.announcement.api)
implementation(libs.androidx.datastore.preferences)
testCommonDependencies(libs, true)
testImplementation(projects.libraries.matrix.test)
}
@@ -0,0 +1,37 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.announcement.impl
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import dev.zacsweers.metro.Inject
import io.element.android.features.announcement.api.Announcement
import io.element.android.features.announcement.impl.store.AnnouncementStatus
import io.element.android.features.announcement.impl.store.AnnouncementStore
import io.element.android.libraries.architecture.Presenter
import kotlinx.coroutines.flow.map
@Inject
class AnnouncementPresenter(
private val announcementStore: AnnouncementStore,
) : Presenter<AnnouncementState> {
@Composable
override fun present(): AnnouncementState {
val showSpaceAnnouncement by remember {
announcementStore.announcementStatusFlow(Announcement.Space).map {
it == AnnouncementStatus.Show
}
}.collectAsState(false)
return AnnouncementState(
showSpaceAnnouncement = showSpaceAnnouncement,
)
}
}
@@ -0,0 +1,19 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.announcement.impl
data class AnnouncementState(
val showSpaceAnnouncement: Boolean,
)
fun anAnnouncementState(
showSpaceAnnouncement: Boolean = false,
) = AnnouncementState(
showSpaceAnnouncement = showSpaceAnnouncement,
)
@@ -0,0 +1,89 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.announcement.impl
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesBinding
import io.element.android.features.announcement.api.Announcement
import io.element.android.features.announcement.api.AnnouncementService
import io.element.android.features.announcement.impl.spaces.SpaceAnnouncementState
import io.element.android.features.announcement.impl.spaces.SpaceAnnouncementView
import io.element.android.features.announcement.impl.store.AnnouncementStatus
import io.element.android.features.announcement.impl.store.AnnouncementStore
import io.element.android.libraries.architecture.Presenter
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.first
@ContributesBinding(AppScope::class)
class DefaultAnnouncementService(
private val announcementStore: AnnouncementStore,
private val announcementPresenter: Presenter<AnnouncementState>,
private val spaceAnnouncementPresenter: Presenter<SpaceAnnouncementState>,
) : AnnouncementService {
override suspend fun showAnnouncement(announcement: Announcement) {
when (announcement) {
Announcement.Space -> showSpaceAnnouncement()
Announcement.NewNotificationSound -> {
announcementStore.setAnnouncementStatus(Announcement.NewNotificationSound, AnnouncementStatus.Show)
}
}
}
override suspend fun onAnnouncementDismissed(announcement: Announcement) {
announcementStore.setAnnouncementStatus(announcement, AnnouncementStatus.Shown)
}
override fun announcementsToShowFlow(): Flow<List<Announcement>> {
return combine(
announcementStore.announcementStatusFlow(Announcement.Space),
announcementStore.announcementStatusFlow(Announcement.NewNotificationSound),
) { spaceAnnouncementStatus, newNotificationSoundStatus ->
buildList {
if (spaceAnnouncementStatus == AnnouncementStatus.Show) {
add(Announcement.Space)
}
if (newNotificationSoundStatus == AnnouncementStatus.Show) {
add(Announcement.NewNotificationSound)
}
}
}
}
private suspend fun showSpaceAnnouncement() {
val currentValue = announcementStore.announcementStatusFlow(Announcement.Space).first()
if (currentValue == AnnouncementStatus.NeverShown) {
announcementStore.setAnnouncementStatus(Announcement.Space, AnnouncementStatus.Show)
}
}
@Composable
override fun Render(modifier: Modifier) {
val announcementState = announcementPresenter.present()
Box(modifier = modifier.fillMaxSize()) {
AnimatedVisibility(
visible = announcementState.showSpaceAnnouncement,
enter = fadeIn(),
exit = fadeOut(),
) {
val spaceAnnouncementState = spaceAnnouncementPresenter.present()
SpaceAnnouncementView(
state = spaceAnnouncementState,
)
}
}
}
}
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.announcement.impl.di
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.Binds
import dev.zacsweers.metro.ContributesTo
import io.element.android.features.announcement.impl.AnnouncementPresenter
import io.element.android.features.announcement.impl.AnnouncementState
import io.element.android.features.announcement.impl.spaces.SpaceAnnouncementPresenter
import io.element.android.features.announcement.impl.spaces.SpaceAnnouncementState
import io.element.android.libraries.architecture.Presenter
@ContributesTo(AppScope::class)
@BindingContainer
interface AnnouncementModule {
@Binds
fun bindAnnouncementPresenter(presenter: AnnouncementPresenter): Presenter<AnnouncementState>
@Binds
fun bindSpaceAnnouncementPresenter(presenter: SpaceAnnouncementPresenter): Presenter<SpaceAnnouncementState>
}
@@ -0,0 +1,13 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.announcement.impl.spaces
sealed interface SpaceAnnouncementEvents {
data object Continue : SpaceAnnouncementEvents
}
@@ -0,0 +1,40 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.announcement.impl.spaces
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import dev.zacsweers.metro.Inject
import io.element.android.features.announcement.api.Announcement
import io.element.android.features.announcement.impl.store.AnnouncementStatus
import io.element.android.features.announcement.impl.store.AnnouncementStore
import io.element.android.libraries.architecture.Presenter
import kotlinx.coroutines.launch
@Inject
class SpaceAnnouncementPresenter(
private val announcementStore: AnnouncementStore,
) : Presenter<SpaceAnnouncementState> {
@Composable
override fun present(): SpaceAnnouncementState {
val localCoroutineScope = rememberCoroutineScope()
fun handleEvent(event: SpaceAnnouncementEvents) {
when (event) {
SpaceAnnouncementEvents.Continue -> localCoroutineScope.launch {
announcementStore.setAnnouncementStatus(Announcement.Space, AnnouncementStatus.Shown)
}
}
}
return SpaceAnnouncementState(
eventSink = ::handleEvent,
)
}
}
@@ -0,0 +1,13 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.announcement.impl.spaces
data class SpaceAnnouncementState(
val eventSink: (SpaceAnnouncementEvents) -> Unit
)
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.announcement.impl.spaces
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
open class SpaceAnnouncementStateProvider : PreviewParameterProvider<SpaceAnnouncementState> {
override val values: Sequence<SpaceAnnouncementState>
get() = sequenceOf(
aSpaceAnnouncementState(),
)
}
fun aSpaceAnnouncementState(
eventSink: (SpaceAnnouncementEvents) -> Unit = {},
) = SpaceAnnouncementState(
eventSink = eventSink,
)

Some files were not shown because too many files have changed in this diff Show More