From b68e9e1f7f344302cc9110916f82268d1ff380a1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 23 Nov 2021 13:42:46 +0100 Subject: [PATCH] Analytics: setup the first classes --- .../im/vector/app/core/di/SingletonModule.kt | 5 ++ .../app/features/analytics/VectorAnalytics.kt | 56 ++++++++++++++ .../analytics/impl/DefaultVectorAnalytics.kt | 55 ++++++++++++++ .../analytics/store/AnalyticsStore.kt | 75 +++++++++++++++++++ 4 files changed, 191 insertions(+) create mode 100644 vector/src/main/java/im/vector/app/features/analytics/VectorAnalytics.kt create mode 100644 vector/src/main/java/im/vector/app/features/analytics/impl/DefaultVectorAnalytics.kt create mode 100644 vector/src/main/java/im/vector/app/features/analytics/store/AnalyticsStore.kt diff --git a/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt b/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt index 350e1f6b7a..14ed17d0bb 100644 --- a/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt @@ -31,6 +31,8 @@ import im.vector.app.core.error.DefaultErrorFormatter import im.vector.app.core.error.ErrorFormatter import im.vector.app.core.time.Clock import im.vector.app.core.time.DefaultClock +import im.vector.app.features.analytics.VectorAnalytics +import im.vector.app.features.analytics.impl.DefaultVectorAnalytics import im.vector.app.features.invite.AutoAcceptInvites import im.vector.app.features.invite.CompileTimeAutoAcceptInvites import im.vector.app.features.navigation.DefaultNavigator @@ -57,6 +59,9 @@ abstract class VectorBindModule { @Binds abstract fun bindNavigator(navigator: DefaultNavigator): Navigator + @Binds + abstract fun bindVectorAnalytics(analytics: DefaultVectorAnalytics): VectorAnalytics + @Binds abstract fun bindErrorFormatter(formatter: DefaultErrorFormatter): ErrorFormatter diff --git a/vector/src/main/java/im/vector/app/features/analytics/VectorAnalytics.kt b/vector/src/main/java/im/vector/app/features/analytics/VectorAnalytics.kt new file mode 100644 index 0000000000..55e6147461 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/analytics/VectorAnalytics.kt @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.analytics + +import kotlinx.coroutines.flow.Flow + +interface VectorAnalytics { + /** + * Return a Flow of Boolean, true if the user has given their consent + */ + fun getUserConsent(): Flow + + /** + * Update the user consent value + */ + suspend fun setUserConsent(userConsent: Boolean) + + /** + * Return a Flow of Boolean, true if the user has been asked for their consent + */ + fun didAskUserConsent(): Flow + + /** + * Store the fact that the user has been asked for their consent + */ + suspend fun setDidAskUserConsent(didAskUserConsent: Boolean) + + /** + * Return a Flow of String, used for analytics Id + */ + fun getAnalyticsId(): Flow + + /** + * Update analyticsId from the AccountData + */ + suspend fun setAnalyticsId(analyticsId: String) + + /** + * To be called when a session is destroyed + */ + suspend fun onSignOut() +} diff --git a/vector/src/main/java/im/vector/app/features/analytics/impl/DefaultVectorAnalytics.kt b/vector/src/main/java/im/vector/app/features/analytics/impl/DefaultVectorAnalytics.kt new file mode 100644 index 0000000000..7eca77c74f --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/analytics/impl/DefaultVectorAnalytics.kt @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.analytics.impl + +import im.vector.app.features.analytics.VectorAnalytics +import im.vector.app.features.analytics.store.AnalyticsStore +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class DefaultVectorAnalytics @Inject constructor( + private val analyticsStore: AnalyticsStore +) : VectorAnalytics { + override fun getUserConsent(): Flow { + return analyticsStore.userConsentFlow + } + + override suspend fun setUserConsent(userConsent: Boolean) { + analyticsStore.setUserConsent(userConsent) + } + + override fun didAskUserConsent(): Flow { + return analyticsStore.didAskUserConsentFlow + } + + override suspend fun setDidAskUserConsent(didAskUserConsent: Boolean) { + analyticsStore.setDidAskUserConsent(didAskUserConsent) + } + + override fun getAnalyticsId(): Flow { + return analyticsStore.analyticsIdFlow + } + + override suspend fun setAnalyticsId(analyticsId: String) { + analyticsStore.setAnalyticsId(analyticsId) + } + + override suspend fun onSignOut() { + // reset the analyticsId + setAnalyticsId("") + } +} diff --git a/vector/src/main/java/im/vector/app/features/analytics/store/AnalyticsStore.kt b/vector/src/main/java/im/vector/app/features/analytics/store/AnalyticsStore.kt new file mode 100644 index 0000000000..b4d93e674f --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/analytics/store/AnalyticsStore.kt @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.analytics.store + +import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.booleanPreferencesKey +import androidx.datastore.preferences.core.edit +import androidx.datastore.preferences.core.stringPreferencesKey +import androidx.datastore.preferences.preferencesDataStore +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import org.matrix.android.sdk.api.extensions.orFalse +import javax.inject.Inject + +private val Context.dataStore: DataStore by preferencesDataStore(name = "vector_analytics") + +/** + * Local storage for: + * - user consent (Boolean) + * - did ask user consent (Boolean) + * - analytics Id (String) + */ +class AnalyticsStore @Inject constructor( + private val context: Context +) { + private val userConsent = booleanPreferencesKey("user_consent") + private val didAskUserConsent = booleanPreferencesKey("did_ask_user_consent") + private val analyticsId = stringPreferencesKey("analytics_id") + + val userConsentFlow: Flow = context.dataStore.data.map { preferences -> + preferences[userConsent].orFalse() + } + + val didAskUserConsentFlow: Flow = context.dataStore.data.map { preferences -> + preferences[didAskUserConsent].orFalse() + } + + val analyticsIdFlow: Flow = context.dataStore.data.map { preferences -> + preferences[analyticsId].orEmpty() + } + + suspend fun setUserConsent(newUserConsent: Boolean) { + context.dataStore.edit { settings -> + settings[userConsent] = newUserConsent + } + } + + suspend fun setDidAskUserConsent(newDidAskUserConsent: Boolean) { + context.dataStore.edit { settings -> + settings[didAskUserConsent] = newDidAskUserConsent + } + } + + suspend fun setAnalyticsId(newAnalyticsId: String) { + context.dataStore.edit { settings -> + settings[analyticsId] = newAnalyticsId + } + } +}