Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions vector/src/main/java/im/vector/app/core/extensions/Session.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import androidx.core.content.ContextCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ProcessLifecycleOwner
import im.vector.app.core.services.VectorSyncService
import im.vector.app.features.session.VectorSessionStore
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState
import org.matrix.android.sdk.api.session.sync.FilterService
Expand Down Expand Up @@ -76,3 +77,5 @@ fun Session.cannotLogoutSafely(): Boolean {
// That are not backed up
!sharedSecretStorageService.isRecoverySetup())
}

fun Session.vectorStore(context: Context) = VectorSessionStore(context, myUserId)
13 changes: 9 additions & 4 deletions vector/src/main/java/im/vector/app/features/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import im.vector.app.R
import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.error.ErrorFormatter
import im.vector.app.core.extensions.startSyncing
import im.vector.app.core.extensions.vectorStore
import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.core.utils.deleteAllFiles
import im.vector.app.databinding.ActivityMainBinding
Expand All @@ -40,6 +41,7 @@ import im.vector.app.features.pin.PinCodeStore
import im.vector.app.features.pin.PinLocker
import im.vector.app.features.pin.UnlockedActivity
import im.vector.app.features.popup.PopupAlertManager
import im.vector.app.features.session.VectorSessionStore
import im.vector.app.features.settings.VectorPreferences
import im.vector.app.features.signout.hard.SignedOutActivity
import im.vector.app.features.themes.ActivityOtherThemes
Expand Down Expand Up @@ -143,13 +145,15 @@ class MainActivity : VectorBaseActivity<ActivityMainBinding>(), UnlockedActivity
startNextActivityAndFinish()
return
}

val onboardingStore = session.vectorStore(this)
when {
args.isAccountDeactivated -> {
lifecycleScope.launch {
// Just do the local cleanup
Timber.w("Account deactivated, start app")
sessionHolder.clearActiveSession()
doLocalCleanup(clearPreferences = true)
doLocalCleanup(clearPreferences = true, onboardingStore)
startNextActivityAndFinish()
}
}
Expand All @@ -163,14 +167,14 @@ class MainActivity : VectorBaseActivity<ActivityMainBinding>(), UnlockedActivity
}
Timber.w("SIGN_OUT: success, start app")
sessionHolder.clearActiveSession()
doLocalCleanup(clearPreferences = true)
doLocalCleanup(clearPreferences = true, onboardingStore)
startNextActivityAndFinish()
}
}
args.clearCache -> {
lifecycleScope.launch {
session.clearCache()
doLocalCleanup(clearPreferences = false)
doLocalCleanup(clearPreferences = false, onboardingStore)
session.startSyncing(applicationContext)
startNextActivityAndFinish()
}
Expand All @@ -183,7 +187,7 @@ class MainActivity : VectorBaseActivity<ActivityMainBinding>(), UnlockedActivity
Timber.w("Ignoring invalid token global error")
}

private suspend fun doLocalCleanup(clearPreferences: Boolean) {
private suspend fun doLocalCleanup(clearPreferences: Boolean, vectorSessionStore: VectorSessionStore) {
// On UI Thread
Glide.get(this@MainActivity).clearMemory()

Expand All @@ -193,6 +197,7 @@ class MainActivity : VectorBaseActivity<ActivityMainBinding>(), UnlockedActivity
pinLocker.unlock()
pinCodeStore.deleteEncodedPin()
vectorAnalytics.onSignOut()
vectorSessionStore.clear()
}
withContext(Dispatchers.IO) {
// On BG thread
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package im.vector.app.features.analytics

import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
import im.vector.app.features.analytics.itf.VectorAnalyticsScreen
import im.vector.app.features.analytics.plan.Identity

interface AnalyticsTracker {
/**
Expand All @@ -29,4 +30,9 @@ interface AnalyticsTracker {
* Track a displayed screen
*/
fun screen(screen: VectorAnalyticsScreen)

/**
* Update user specific properties
*/
fun updateUserProperties(identity: Identity)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package im.vector.app.features.analytics.extensions

import im.vector.app.features.analytics.plan.Identity
import im.vector.app.features.onboarding.FtueUseCase

fun FtueUseCase.toTrackingValue(): Identity.FtueUseCaseSelection {
return when (this) {
FtueUseCase.FRIENDS_FAMILY -> Identity.FtueUseCaseSelection.PersonalMessaging
FtueUseCase.TEAMS -> Identity.FtueUseCaseSelection.WorkMessaging
FtueUseCase.COMMUNITIES -> Identity.FtueUseCaseSelection.CommunityMessaging
FtueUseCase.SKIP -> Identity.FtueUseCaseSelection.Skip
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package im.vector.app.features.analytics.impl

import android.content.Context
import com.posthog.android.Options
import com.posthog.android.PostHog
import com.posthog.android.Properties
import im.vector.app.BuildConfig
Expand All @@ -25,6 +26,7 @@ import im.vector.app.features.analytics.VectorAnalytics
import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
import im.vector.app.features.analytics.itf.VectorAnalyticsScreen
import im.vector.app.features.analytics.log.analyticsTag
import im.vector.app.features.analytics.plan.Identity
import im.vector.app.features.analytics.store.AnalyticsStore
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.Flow
Expand All @@ -34,6 +36,9 @@ import timber.log.Timber
import javax.inject.Inject
import javax.inject.Singleton

private val REUSE_EXISTING_ID: String? = null
private val IGNORED_OPTIONS: Options? = null

@Singleton
class DefaultVectorAnalytics @Inject constructor(
private val context: Context,
Expand Down Expand Up @@ -170,6 +175,10 @@ class DefaultVectorAnalytics @Inject constructor(
?.screen(screen.getName(), screen.getProperties()?.toPostHogProperties())
}

override fun updateUserProperties(identity: Identity) {
posthog?.identify(REUSE_EXISTING_ID, identity.getProperties().toPostHogProperties(), IGNORED_OPTIONS)
}

private fun Map<String, Any>?.toPostHogProperties(): Properties? {
if (this == null) return null

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@

package im.vector.app.features.onboarding

enum class FtueUseCase {
FRIENDS_FAMILY,
TEAMS,
COMMUNITIES,
SKIP
enum class FtueUseCase(val persistableValue: String) {
FRIENDS_FAMILY("friends_family"),
TEAMS("teams"),
COMMUNITIES("communities"),
SKIP("skip");

companion object {
fun from(persistedValue: String) = values().first { it.persistableValue == persistedValue }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,14 @@ import im.vector.app.core.di.MavericksAssistedViewModelFactory
import im.vector.app.core.di.hiltMavericksViewModelFactory
import im.vector.app.core.extensions.configureAndStart
import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.extensions.vectorStore
import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.resources.StringProvider
import im.vector.app.core.utils.ensureTrailingSlash
import im.vector.app.features.VectorFeatures
import im.vector.app.features.analytics.AnalyticsTracker
import im.vector.app.features.analytics.extensions.toTrackingValue
import im.vector.app.features.analytics.plan.Identity
import im.vector.app.features.login.HomeServerConnectionConfigFactory
import im.vector.app.features.login.LoginConfig
import im.vector.app.features.login.LoginMode
Expand Down Expand Up @@ -73,7 +77,8 @@ class OnboardingViewModel @AssistedInject constructor(
private val reAuthHelper: ReAuthHelper,
private val stringProvider: StringProvider,
private val homeServerHistoryService: HomeServerHistoryService,
private val vectorFeatures: VectorFeatures
private val vectorFeatures: VectorFeatures,
private val analyticsTracker: AnalyticsTracker
) : VectorViewModel<OnboardingViewState, OnboardingAction, OnboardingViewEvents>(initialState) {

@AssistedFactory
Expand Down Expand Up @@ -125,7 +130,7 @@ class OnboardingViewModel @AssistedInject constructor(
when (action) {
is OnboardingAction.OnGetStarted -> handleSplashAction(action.resetLoginConfig, action.onboardingFlow)
is OnboardingAction.OnIAlreadyHaveAnAccount -> handleSplashAction(action.resetLoginConfig, action.onboardingFlow)
is OnboardingAction.UpdateUseCase -> handleUpdateUseCase()
is OnboardingAction.UpdateUseCase -> handleUpdateUseCase(action)
OnboardingAction.ResetUseCase -> resetUseCase()
is OnboardingAction.UpdateServerType -> handleUpdateServerType(action)
is OnboardingAction.UpdateSignMode -> handleUpdateSignMode(action)
Expand Down Expand Up @@ -458,13 +463,15 @@ class OnboardingViewModel @AssistedInject constructor(
}
}

private fun handleUpdateUseCase() {
// TODO act on the use case selection
private fun handleUpdateUseCase(action: OnboardingAction.UpdateUseCase) {
setState { copy(useCase = action.useCase) }
analyticsTracker.updateUserProperties(Identity(ftueUseCaseSelection = action.useCase.toTrackingValue()))
_viewEvents.post(OnboardingViewEvents.OpenServerSelection)
}

private fun resetUseCase() {
// TODO remove stored use case
setState { copy(useCase = null) }
analyticsTracker.updateUserProperties(Identity(ftueUseCaseSelection = null))
}

private fun handleUpdateServerType(action: OnboardingAction.UpdateServerType) {
Expand Down Expand Up @@ -745,6 +752,9 @@ class OnboardingViewModel @AssistedInject constructor(
}

private suspend fun onSessionCreated(session: Session) {
awaitState().useCase?.let { useCase ->
session.vectorStore(applicationContext).setUseCase(useCase)
}
activeSessionHolder.setActiveSession(session)

authenticationService.reset()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ data class OnboardingViewState(
@PersistState
val serverType: ServerType = ServerType.Unknown,
@PersistState
val useCase: FtueUseCase? = null,
@PersistState
val signMode: SignMode = SignMode.Unknown,
@PersistState
val resetPasswordEmail: String? = null,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* 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.session

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import im.vector.app.features.onboarding.FtueUseCase
import kotlinx.coroutines.flow.first
import org.matrix.android.sdk.internal.util.md5

/**
* Local storage for:
* - messaging use case (Enum/String)
*/
class VectorSessionStore constructor(
private val context: Context,
myUserId: String
) {

private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "vector_session_store_${myUserId.md5()}")
private val useCaseKey = stringPreferencesKey("use_case")

suspend fun readUseCase() = context.dataStore.data.first().let { preferences ->
preferences[useCaseKey]?.let { FtueUseCase.from(it) }
}

suspend fun setUseCase(useCase: FtueUseCase) {
context.dataStore.edit { settings ->
settings[useCaseKey] = useCase.persistableValue
}
}

suspend fun resetUseCase() {
context.dataStore.edit { settings ->
settings.remove(useCaseKey)
}
}

suspend fun clear() {
context.dataStore.edit { settings -> settings.clear() }
}
}