mirror of
https://github.com/element-hq/element-android
synced 2024-11-24 10:25:35 +03:00
Analytics: Opt-in screen logic + remove from SplashScreen
This commit is contained in:
parent
73f5d77b05
commit
8c794b1059
12 changed files with 158 additions and 48 deletions
|
@ -236,6 +236,7 @@ android {
|
|||
// Analytics. Set to empty strings to just disable analytics
|
||||
buildConfigField "String", "ANALYTICS_POSTHOG_HOST", "\"https://posthog-poc.lab.element.dev\""
|
||||
buildConfigField "String", "ANALYTICS_POSTHOG_API_KEY", "\"rs-pJjsYJTuAkXJfhaMmPUNBhWliDyTKLOOxike6ck8\""
|
||||
buildConfigField "String", "ANALYTICS_POLICY_URL", "\"https://element.io/cookie-policy\""
|
||||
|
||||
signingConfig signingConfigs.debug
|
||||
}
|
||||
|
@ -250,6 +251,7 @@ android {
|
|||
// Analytics. Set to empty strings to just disable analytics
|
||||
buildConfigField "String", "ANALYTICS_POSTHOG_HOST", "\"https://posthog.hss.element.io\""
|
||||
buildConfigField "String", "ANALYTICS_POSTHOG_API_KEY", "\"phc_Jzsm6DTm6V2705zeU5dcNvQDlonOR68XvX2sh1sEOHO\""
|
||||
buildConfigField "String", "ANALYTICS_POLICY_URL", "\"https://element.io/cookie-policy\""
|
||||
|
||||
postprocessing {
|
||||
removeUnusedCode true
|
||||
|
|
|
@ -310,6 +310,7 @@
|
|||
<activity android:name=".features.terms.ReviewTermsActivity" />
|
||||
<activity android:name=".features.widgets.WidgetActivity" />
|
||||
<activity android:name=".features.pin.PinActivity" />
|
||||
<activity android:name=".features.analytics.ui.consent.AnalyticsOptInActivity" />
|
||||
<activity android:name=".features.home.room.detail.search.SearchActivity" />
|
||||
<activity android:name=".features.usercode.UserCodeActivity" />
|
||||
<activity android:name=".features.call.transfer.CallTransferActivity" />
|
||||
|
|
|
@ -24,6 +24,7 @@ import dagger.Module
|
|||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.components.ActivityComponent
|
||||
import dagger.multibindings.IntoMap
|
||||
import im.vector.app.features.analytics.ui.consent.AnalyticsOptInFragment
|
||||
import im.vector.app.features.attachments.preview.AttachmentsPreviewFragment
|
||||
import im.vector.app.features.contactsbook.ContactsBookFragment
|
||||
import im.vector.app.features.crypto.keysbackup.settings.KeysBackupSettingsFragment
|
||||
|
@ -519,6 +520,11 @@ interface FragmentModule {
|
|||
@FragmentKey(BreadcrumbsFragment::class)
|
||||
fun bindBreadcrumbsFragment(fragment: BreadcrumbsFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(AnalyticsOptInFragment::class)
|
||||
fun bindAnalyticsOptInFragment(fragment: AnalyticsOptInFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(EmojiChooserFragment::class)
|
||||
|
|
|
@ -20,5 +20,4 @@ import im.vector.app.core.platform.VectorViewModelAction
|
|||
|
||||
sealed class AnalyticsConsentViewActions : VectorViewModelAction {
|
||||
data class SetUserConsent(val userConsent: Boolean) : AnalyticsConsentViewActions()
|
||||
object OnGetStarted : AnalyticsConsentViewActions()
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ import dagger.assisted.AssistedInject
|
|||
import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
||||
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.platform.EmptyViewEvents
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.features.analytics.VectorAnalytics
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -31,7 +30,7 @@ import kotlinx.coroutines.launch
|
|||
class AnalyticsConsentViewModel @AssistedInject constructor(
|
||||
@Assisted initialState: AnalyticsConsentViewState,
|
||||
private val analytics: VectorAnalytics
|
||||
) : VectorViewModel<AnalyticsConsentViewState, AnalyticsConsentViewActions, EmptyViewEvents>(initialState) {
|
||||
) : VectorViewModel<AnalyticsConsentViewState, AnalyticsConsentViewActions, AnalyticsOptInViewEvents>(initialState) {
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : MavericksAssistedViewModelFactory<AnalyticsConsentViewModel, AnalyticsConsentViewState> {
|
||||
|
@ -56,24 +55,14 @@ class AnalyticsConsentViewModel @AssistedInject constructor(
|
|||
override fun handle(action: AnalyticsConsentViewActions) {
|
||||
when (action) {
|
||||
is AnalyticsConsentViewActions.SetUserConsent -> handleSetUserConsent(action)
|
||||
AnalyticsConsentViewActions.OnGetStarted -> handleOnScreenLeft()
|
||||
}.exhaustive
|
||||
}
|
||||
|
||||
private fun handleSetUserConsent(action: AnalyticsConsentViewActions.SetUserConsent) {
|
||||
viewModelScope.launch {
|
||||
analytics.setUserConsent(action.userConsent)
|
||||
if (!action.userConsent) {
|
||||
// User explicitly changed the default value, let's avoid reverting to the default value
|
||||
analytics.setDidAskUserConsent()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleOnScreenLeft() {
|
||||
// Whatever the state of the box, consider the user acknowledge it
|
||||
viewModelScope.launch {
|
||||
analytics.setDidAskUserConsent()
|
||||
_viewEvents.post(AnalyticsOptInViewEvents.OnDataSaved)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2020 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.ui.consent
|
||||
|
||||
import com.airbnb.mvrx.viewModel
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.addFragment
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.databinding.ActivitySimpleBinding
|
||||
|
||||
/**
|
||||
* Simple container for AnalyticsOptInFragment
|
||||
*/
|
||||
@AndroidEntryPoint
|
||||
class AnalyticsOptInActivity : VectorBaseActivity<ActivitySimpleBinding>() {
|
||||
|
||||
private val viewModel: AnalyticsConsentViewModel by viewModel()
|
||||
|
||||
override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater)
|
||||
|
||||
override fun getCoordinatorLayout() = views.coordinatorLayout
|
||||
|
||||
override fun initUiAndData() {
|
||||
if (isFirstCreation()) {
|
||||
addFragment(R.id.simpleFragmentContainer, AnalyticsOptInFragment::class.java)
|
||||
}
|
||||
|
||||
viewModel.observeViewEvents {
|
||||
when (it) {
|
||||
AnalyticsOptInViewEvents.OnDataSaved -> finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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.ui.consent
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
import im.vector.app.BuildConfig
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.setTextWithColoredPart
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.utils.openUrlInChromeCustomTab
|
||||
import im.vector.app.databinding.FragmentAnalyticsOptinBinding
|
||||
import javax.inject.Inject
|
||||
|
||||
class AnalyticsOptInFragment @Inject constructor(
|
||||
) : VectorBaseFragment<FragmentAnalyticsOptinBinding>() {
|
||||
|
||||
// Share the view model with the Activity so that the Activity
|
||||
// can decide what to do when the data has been saved
|
||||
private val viewModel: AnalyticsConsentViewModel by activityViewModel()
|
||||
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentAnalyticsOptinBinding {
|
||||
return FragmentAnalyticsOptinBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setupLink()
|
||||
setupListeners()
|
||||
}
|
||||
|
||||
private fun setupListeners() {
|
||||
views.submit.debouncedClicks {
|
||||
viewModel.handle(AnalyticsConsentViewActions.SetUserConsent(userConsent = true))
|
||||
}
|
||||
views.later.debouncedClicks {
|
||||
viewModel.handle(AnalyticsConsentViewActions.SetUserConsent(userConsent = false))
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupLink() {
|
||||
views.submit.setTextWithColoredPart(
|
||||
fullTextRes = R.string.analytics_opt_in_content,
|
||||
coloredTextRes = R.string.analytics_opt_in_content_link,
|
||||
onClick = {
|
||||
openUrlInChromeCustomTab(requireContext(), null, BuildConfig.ANALYTICS_POLICY_URL)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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.ui.consent
|
||||
|
||||
import im.vector.app.core.platform.VectorViewEvents
|
||||
|
||||
sealed interface AnalyticsOptInViewEvents : VectorViewEvents {
|
||||
object OnDataSaved : AnalyticsOptInViewEvents
|
||||
}
|
|
@ -22,15 +22,10 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import im.vector.app.BuildConfig
|
||||
import im.vector.app.R
|
||||
import im.vector.app.databinding.FragmentLoginSplashBinding
|
||||
import im.vector.app.features.analytics.AnalyticsConfig
|
||||
import im.vector.app.features.analytics.ui.consent.AnalyticsConsentViewActions
|
||||
import im.vector.app.features.analytics.ui.consent.AnalyticsConsentViewModel
|
||||
import im.vector.app.features.analytics.ui.consent.AnalyticsConsentViewState
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
import org.matrix.android.sdk.api.failure.Failure
|
||||
import java.net.UnknownHostException
|
||||
|
@ -43,8 +38,6 @@ class LoginSplashFragment @Inject constructor(
|
|||
private val vectorPreferences: VectorPreferences
|
||||
) : AbstractLoginFragment<FragmentLoginSplashBinding>() {
|
||||
|
||||
private val analyticsConsentViewModel: AnalyticsConsentViewModel by fragmentViewModel()
|
||||
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginSplashBinding {
|
||||
return FragmentLoginSplashBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
@ -53,24 +46,10 @@ class LoginSplashFragment @Inject constructor(
|
|||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
setupViews()
|
||||
observeAnalyticsState()
|
||||
}
|
||||
|
||||
private fun observeAnalyticsState() {
|
||||
analyticsConsentViewModel.onEach(AnalyticsConsentViewState::shouldCheckTheBox) {
|
||||
views.loginSplashAnalyticsConsent.isChecked = it
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupViews() {
|
||||
views.loginSplashSubmit.debouncedClicks { getStarted() }
|
||||
// setOnCheckedChangeListener is to annoying since it does not distinguish user changes and code changes
|
||||
views.loginSplashAnalyticsConsent.isVisible = AnalyticsConfig.isAnalyticsEnabled()
|
||||
views.loginSplashAnalyticsConsent.setOnClickListener {
|
||||
analyticsConsentViewModel.handle(AnalyticsConsentViewActions.SetUserConsent(
|
||||
views.loginSplashAnalyticsConsent.isChecked
|
||||
))
|
||||
}
|
||||
|
||||
if (BuildConfig.DEBUG || vectorPreferences.developerMode()) {
|
||||
views.loginSplashVersion.isVisible = true
|
||||
|
@ -82,7 +61,6 @@ class LoginSplashFragment @Inject constructor(
|
|||
}
|
||||
|
||||
private fun getStarted() {
|
||||
analyticsConsentViewModel.handle(AnalyticsConsentViewActions.OnGetStarted)
|
||||
loginViewModel.handle(LoginAction.OnGetStarted(resetLoginConfig = false))
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ import im.vector.app.core.di.ActiveSessionHolder
|
|||
import im.vector.app.core.error.fatalError
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.core.utils.toast
|
||||
import im.vector.app.features.analytics.ui.consent.AnalyticsOptInActivity
|
||||
import im.vector.app.features.call.conference.JitsiCallViewModel
|
||||
import im.vector.app.features.call.conference.VectorJitsiActivity
|
||||
import im.vector.app.features.call.transfer.CallTransferActivity
|
||||
|
@ -404,6 +405,10 @@ class DefaultNavigator @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun openAnalyticsOptIn(context: Context) {
|
||||
context.startActivity(Intent(context, AnalyticsOptInActivity::class.java))
|
||||
}
|
||||
|
||||
override fun openTerms(context: Context,
|
||||
activityResultLauncher: ActivityResultLauncher<Intent>,
|
||||
serviceType: TermsService.ServiceType,
|
||||
|
|
|
@ -105,6 +105,8 @@ interface Navigator {
|
|||
|
||||
fun openBigImageViewer(activity: Activity, sharedElement: View?, mxcUrl: String?, title: String?)
|
||||
|
||||
fun openAnalyticsOptIn(context: Context)
|
||||
|
||||
fun openPinCode(context: Context,
|
||||
activityResultLauncher: ActivityResultLauncher<Intent>,
|
||||
pinMode: PinMode)
|
||||
|
|
|
@ -204,20 +204,9 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:textColor="?vctr_content_secondary"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@id/loginSplashAnalyticsConsent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
tools:text="@string/settings_version"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/loginSplashAnalyticsConsent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/analytics_consent_splash"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
Loading…
Reference in a new issue