package com.suno.android.ui.screens.splash import androidx.lifecycle.viewModelScope import com.suno.android.BuildConfig import com.suno.android.common_data.l10n.L10nManager import com.suno.android.common_mvi.MviProcessorFactory import com.suno.android.common_mvi.MviViewModel import com.suno.android.framework.release.api.AppUpdateManager import com.suno.android.framework.release.api.models.AppUpdate import com.suno.android.gating.statsig.StatsigFeatureDataSource import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import javax.inject.Inject @HiltViewModel class SplashScreenVM @Inject constructor( processorFactory: MviProcessorFactory, private val l10nManager: L10nManager, private val appUpdateManager: AppUpdateManager, private val statsigManager: StatsigFeatureDataSource, ) : MviViewModel( processorFactory = processorFactory, initialState = SplashScreenState( isFetchingConfig = true, ), ) { init { logger.d { "SplashScreenVM init()" } /** * //todo: * I dislike that I have now setup 2 sources of truth for checking login state, * and this should probably be centralized into triggering a function chain in * the RootNavGraphVM or something 🤔 */ preAuthCheckFlow().distinctUntilChanged() // hacky fix for double emission .onEach { configurationPayload: ConfigurationPayload -> logger.d { configurationPayload } updateState { it.copy( appUpdate = configurationPayload.appUpdate, ) } val appUpdateGateCheck = ( configurationPayload.appUpdate == AppUpdate.None || (state.value.appUpdate is AppUpdate.UpdateAvailable && state.value.updateDismissed) ) val statsigInitGateCheck = configurationPayload.statsigInitResult if (appUpdateGateCheck) { if (statsigInitGateCheck) { emitEffect( SplashScreenEffect.ConfigurationFetchRouteResult( configurationFetchSuccess = true, ), ) } } else { emitEffect( SplashScreenEffect.ConfigurationFetchRouteResult( configurationFetchSuccess = false, ), ) } }.catch { exception -> logger.e(exception) emitEffect( SplashScreenEffect.ConfigurationFetchException, ) }.launchIn(viewModelScope) } override suspend fun reduceEvent( currentState: SplashScreenState, event: SplashScreenEvent, emitEffect: suspend (SplashScreenEffect) -> Unit, ): SplashScreenState = when (event) { SplashScreenEvent.OnUpdateDialogDismissed -> { currentState.copy( updateDismissed = true, ) } } private fun preAuthCheckFlow(): Flow = // init statsig here in its own flow combine( l10nManager.lokalizeInitializedFlow(), appUpdateManager.checkForUpdates( applicationId = BuildConfig.APPLICATION_ID, versionCode = BuildConfig.VERSION_CODE, ), statsigManager.statsigInitStatusFlow(), state.map { it.updateDismissed }, // gross ) { lokalizeInitialized: Boolean, appUpdate: AppUpdate, statsigInitResult: Boolean, updateDismissed: Boolean, -> ConfigurationPayload( lokaliseFetched = lokalizeInitialized, appUpdate = appUpdate, statsigInitResult = statsigInitResult, updateDismissed = updateDismissed, ) } data class ConfigurationPayload( val lokaliseFetched: Boolean = false, val appUpdate: AppUpdate = AppUpdate.Unknown, val statsigInitResult: Boolean = false, val updateDismissed: Boolean = false, ) }