First Commit
This commit is contained in:
@@ -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)
|
||||
}
|
||||
+13
@@ -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
|
||||
+13
@@ -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
|
||||
}
|
||||
+18
@@ -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,
|
||||
)
|
||||
+30
@@ -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 = {}
|
||||
)
|
||||
+74
@@ -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 d’utilisation 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 d’utilisation"</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>
|
||||
@@ -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)
|
||||
}
|
||||
+48
@@ -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) },
|
||||
)
|
||||
}
|
||||
}
|
||||
+50
@@ -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)
|
||||
}
|
||||
}
|
||||
+17
@@ -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
|
||||
)
|
||||
+27
@@ -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 = {}
|
||||
)
|
||||
+180
@@ -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 = {},
|
||||
)
|
||||
}
|
||||
+23
@@ -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)
|
||||
}
|
||||
}
|
||||
+24
@@ -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>
|
||||
}
|
||||
+51
@@ -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 n’enregistrerons ni ne profilerons aucune donnée personnelle"</string>
|
||||
<string name="screen_analytics_prompt_help_us_improve">"Partagez des données d’utilisation 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>
|
||||
+63
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
+40
@@ -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)
|
||||
}
|
||||
}
|
||||
+76
@@ -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"
|
||||
}
|
||||
+14
@@ -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,
|
||||
}
|
||||
+29
@@ -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)
|
||||
}
|
||||
+37
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
+19
@@ -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,
|
||||
)
|
||||
+89
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+29
@@ -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>
|
||||
}
|
||||
+13
@@ -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
|
||||
}
|
||||
+40
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
+13
@@ -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
|
||||
)
|
||||
+24
@@ -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
Reference in New Issue
Block a user