TP-84905 | Naman Khurmi | Fixing MVI set effect and scoping for the relevant functions (#12662)

Signed-off-by: namankhurmi <naman.khurmi@navi.com>
This commit is contained in:
Naman Khurmi
2024-09-20 17:48:49 +05:30
committed by GitHub
parent d8d9acbbc6
commit f98ffa3a30
15 changed files with 39 additions and 94 deletions

View File

@@ -456,9 +456,7 @@ class HomePageActivity :
}
}
if (redirectionUseCase.isUpiNuxRedirection(intent.extras).not()) {
homeVM.sendEffect(homeVM.coroutineScope) {
HpEffects.ShowNotificationPermissions(permissionsManager)
}
homeVM.sendEffect { HpEffects.ShowNotificationPermissions(permissionsManager) }
}
}
@@ -913,7 +911,7 @@ class HomePageActivity :
}
private fun trackLaunchEvents() {
homeVM.sendEffect(homeVM.coroutineScope) { HpEffects.TrackBottomBarEvents }
homeVM.sendEffect { HpEffects.TrackBottomBarEvents }
}
private fun initHomeScreenActions() {

View File

@@ -80,9 +80,7 @@ fun NavGraphNavigationItem(
)
}
is HomeScreenCallbackListener.InitiatePaymentOnHomePage -> {
homeVM().sendEffect(homeVM().coroutineScope) {
HpEffects.InitiatePayment(it.paymentData)
}
homeVM().sendEffect { HpEffects.InitiatePayment(it.paymentData) }
}
}
}

View File

@@ -54,8 +54,6 @@ import com.naviapp.home.reducer.HpEvents
import com.naviapp.home.reducer.HpStates
import com.naviapp.home.utils.getHomeWidgetAnimationSpec
import com.naviapp.home.viewmodel.HomeViewModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@Composable
@OptIn(ExperimentalFoundationApi::class, ExperimentalComposeUiApi::class)
@@ -176,9 +174,7 @@ private fun RenderUiTronContent(
}
LaunchedEffect(hpStates().renderingFirstTime) {
if (hpStates().renderingFirstTime) {
homeVM.sendEffect(CoroutineScope(Dispatchers.Main)) {
HpEffects.OnPrioritySectionRendered
}
homeVM.sendEffect { HpEffects.OnPrioritySectionRendered }
}
}
}

View File

@@ -31,8 +31,6 @@ import com.naviapp.home.reducer.HpEffects
import com.naviapp.home.reducer.HpEvents
import com.naviapp.home.reducer.HpStates
import com.naviapp.home.viewmodel.HomeViewModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@Composable
fun HomeScreenDialog(homeVM: () -> HomeViewModel, hpStates: () -> HpStates) {
@@ -42,9 +40,7 @@ fun HomeScreenDialog(homeVM: () -> HomeViewModel, hpStates: () -> HpStates) {
LaunchedEffect(dialogStateHolder.state) {
if (dialogStateHolder.state == HpDialogStateHolder.HpDialogState.Hidden) {
dialogStateHolder.dialogUIContent?.onDismissAction?.let {
homeVM().sendEffect(CoroutineScope(Dispatchers.Default)) {
HpEffects.OnActionData(it)
}
homeVM().sendEffect { HpEffects.OnActionData(it) }
}
}
}

View File

@@ -47,9 +47,7 @@ fun handleCtaActionEvents(
)
}
is HomeScreenCallbackListener.InitiatePaymentOnHomePage -> {
homeVM.sendEffect(homeVM.coroutineScope) {
HpEffects.InitiatePayment(callback.paymentData)
}
homeVM.sendEffect { HpEffects.InitiatePayment(callback.paymentData) }
}
}
}

View File

@@ -32,8 +32,6 @@ import com.naviapp.home.reducer.HpStates
import com.naviapp.home.viewmodel.HomeViewModel
import com.naviapp.home.viewmodel.SharedVM
import com.naviapp.payment.viewmodel.PaymentVM
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@Composable
fun InitLifecycleListener(
@@ -49,21 +47,13 @@ fun InitLifecycleListener(
AlfredManager.setCurrentScreenName(screenName = activity.screenName)
homeVM()
.observeUPIVpa(
onAction = {
homeVM().sendEffect(CoroutineScope(Dispatchers.Default)) {
HpEffects.OnUitronAction(it)
}
},
onActionData = {
homeVM().sendEffect(CoroutineScope(Dispatchers.Default)) {
HpEffects.OnActionData(it)
}
}
onAction = { homeVM().sendEffect { HpEffects.OnUitronAction(it) } },
onActionData = { homeVM().sendEffect { HpEffects.OnActionData(it) } }
)
}
Lifecycle.Event.ON_RESUME -> {
if (homeVM().shouldRefreshHomeApi) {
homeVM().sendEffect(homeVM().coroutineScope) { HpEffects.OnRenderActions }
homeVM().sendEffect { HpEffects.OnRenderActions }
callBackToActivityScreen.invoke(
HomeScreenCallbackListener.ApiCallingWithCondition
)

View File

@@ -28,8 +28,6 @@ import com.naviapp.home.viewmodel.HomeViewModel
import com.naviapp.home.viewmodel.NotificationVM
import com.naviapp.home.viewmodel.SharedVM
import com.naviapp.utils.toast
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@Composable
fun InitHomeScreenComponents(
@@ -68,9 +66,7 @@ fun InitHomeScreenComponents(
LaunchedEffect(key1 = Unit) {
sharedVM.uiTronActionHandler.collect { uiTronActionHandler ->
uiTronActionHandler?.let {
homeVM().sendEffect(CoroutineScope(Dispatchers.Default)) {
HpEffects.OnActionsFromJson(it)
}
homeVM().sendEffect { HpEffects.OnActionsFromJson(it) }
sharedVM.updateUiTronAction(uiTronActionHandler = null)
}
}
@@ -85,9 +81,7 @@ fun InitHomeScreenComponents(
LaunchedEffect(key1 = Unit) {
notificationVM.unReadNotificationCount.collect { count ->
if (count > 0) naviAnalyticsEventTracker.onInAppNotificationsCountUpdate(count)
homeVM().sendEffect(CoroutineScope(Dispatchers.Default)) {
HpEffects.OnNotificationUpdatedCount(count)
}
homeVM().sendEffect { HpEffects.OnNotificationUpdatedCount(count) }
}
}

View File

@@ -39,7 +39,7 @@ import com.naviapp.home.model.HpDialogStateHolder
import com.naviapp.home.model.HpDialogStateHolder.HpDialogState
import com.naviapp.models.response.HomeFeatureResponse
class HomeReducer : BaseReducer<HpStates, HpEvents, HpEffects> {
class HomeReducer : BaseReducer<HpStates, HpEvents> {
override fun reduce(previousState: HpStates, event: HpEvents): HpStates {
return when (event) {

View File

@@ -51,11 +51,8 @@ import com.naviapp.utils.Constants.HomePageConstants.FETCH_HOME_ITEMS_TIMEOUT
import dagger.Lazy
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -63,7 +60,6 @@ import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.withTimeout
@HiltViewModel
@@ -101,20 +97,17 @@ constructor(
private val _internetConnectivity = MutableSharedFlow<ConnectivityObserver.Status>()
val internetConnectivity: SharedFlow<ConnectivityObserver.Status> = _internetConnectivity
private fun vmScope(context: CoroutineContext = Dispatchers.IO) =
CoroutineScope(context + SupervisorJob())
init {
vmScope().safeLaunch { observeActionCallback() }
vmScope().safeLaunch { observeInternetConnectivity() }
viewModelScope.safeLaunch((Dispatchers.IO)) { observeActionCallback() }
viewModelScope.safeLaunch((Dispatchers.IO)) { observeInternetConnectivity() }
}
private suspend fun observeActionCallback() {
getActionCallback().collect { action ->
ctaHandler.onActionTriggered(
uiTronAction = action,
shouldFetchHomeApi = { sendEffect(vmScope()) { HpEffects.FetchHomeApi } },
onCtaActionEvent = { sendEffect(vmScope()) { HpEffects.HandleCtaActionEvents(it) } }
shouldFetchHomeApi = { sendEffect { HpEffects.FetchHomeApi } },
onCtaActionEvent = { sendEffect { HpEffects.HandleCtaActionEvents(it) } }
)
}
}
@@ -124,7 +117,7 @@ constructor(
}
fun updateBackdropScaffoldProgress(offset: Float) {
viewModelScope.launch { _backdropScaffoldProgress.update { offset } }
viewModelScope.safeLaunch { _backdropScaffoldProgress.update { offset } }
}
fun setHomeApiRefreshFlag(shouldRefresh: Boolean) {
@@ -162,10 +155,10 @@ constructor(
installedModules = getInstalledDynamicModulesCommaSeparated(),
screenHash = null,
onFailure = { errorMessage, errors ->
sendEffect(vmScope()) { HpEffects.OnApiFailure(errorMessage, errors) }
sendEffect { HpEffects.OnApiFailure(errorMessage, errors) }
},
noInternetCallback = {
viewModelScope.launch {
viewModelScope.safeLaunch(Dispatchers.IO) {
_internetConnectivity.emit(ConnectivityObserver.Status.Unavailable)
}
}
@@ -225,7 +218,7 @@ constructor(
) {
if (homePageRefreshJob?.isActive == true) return
homePageRefreshJob =
viewModelScope.launch(Dispatchers.IO) {
viewModelScope.safeLaunch(Dispatchers.IO) {
handleDataModification()
val screenHash = state.value.screenDefinition?.screenMetaData?.get(SCREEN_HASH)
fetchAndHandleCacheData(
@@ -264,10 +257,10 @@ constructor(
installedModules = installedModules,
screenHash = screenHash,
onFailure = { errorMessage, errors ->
sendEffect(vmScope()) { HpEffects.OnApiFailure(errorMessage, errors) }
sendEffect { HpEffects.OnApiFailure(errorMessage, errors) }
},
noInternetCallback = {
viewModelScope.launch {
viewModelScope.safeLaunch(Dispatchers.IO) {
_internetConnectivity.emit(ConnectivityObserver.Status.Unavailable)
}
}
@@ -307,7 +300,7 @@ constructor(
}
private fun finishProcessing(data: NaviCacheEntity) {
sendEffect(vmScope(Dispatchers.Default)) { HpEffects.OnRenderActions }
sendEffect { HpEffects.OnRenderActions }
updateHomeApiTimestamp()
data.updatedAt.let { homeTabLastUpdateTimestamp = it }
selectiveRefreshHandler.handleSuccessState(this@HomeViewModel)
@@ -331,13 +324,13 @@ constructor(
}
fun fetchNuxScreenDataForEligibleUsers(navigateToNuxScreen: () -> Unit) {
vmScope().launch {
viewModelScope.safeLaunch((Dispatchers.IO)) {
nuxHandler.fetchNuxScreenDataForEligibleUsers(UPI_NUX_SCREEN, navigateToNuxScreen)
}
}
fun fetchHomeFeature(type: String) {
viewModelScope.launch {
viewModelScope.safeLaunch((Dispatchers.IO)) {
val response = homeRepository.fetchHomeFeature(type)
if (response.error == null && response.errors.isNullOrEmpty()) {
sendEvent(HpEvents.UpdateHpFeatures(response.data))
@@ -347,17 +340,13 @@ constructor(
fun handleUpiAdaptations() {
upiUseCase.updateUPI(
onAction = {
sendEffect(vmScope(Dispatchers.Default)) { HpEffects.OnUitronAction(it) }
},
onActionData = {
sendEffect(vmScope(Dispatchers.Default)) { HpEffects.OnActionData(it) }
}
onAction = { sendEffect { HpEffects.OnUitronAction(it) } },
onActionData = { sendEffect { HpEffects.OnActionData(it) } }
)
}
fun observeUPIVpa(onAction: (UiTronAction) -> Unit, onActionData: (UiTronActionData) -> Unit) {
vmScope().launch {
viewModelScope.safeLaunch((Dispatchers.IO)) {
upiUseCase.naviPayManager.getVpaOfPrimaryAccount().collect { upiId ->
upiUseCase.handleVpa(upiId, onAction, onActionData)
}

View File

@@ -8,12 +8,10 @@
package com.naviapp.nux.reducer
import com.navi.common.basemvi.BaseReducer
import com.naviapp.nux.model.MainScreenUiEffect
import com.naviapp.nux.model.MainScreenUiState
import com.naviapp.nux.model.NuxGenericScreenUiEvent
class NuxGenericScreenReducer :
BaseReducer<MainScreenUiState, NuxGenericScreenUiEvent, MainScreenUiEffect> {
class NuxGenericScreenReducer : BaseReducer<MainScreenUiState, NuxGenericScreenUiEvent> {
override fun reduce(
previousState: MainScreenUiState,

View File

@@ -42,11 +42,7 @@ fun NuxGenericScreen(
}
LaunchedEffect(Unit) { getViewModel.invoke().getScreenDefinition() }
BackHandler {
getViewModel().sendEffect(getViewModel().coroutineScope) {
MainScreenUiEffect.Navigation.Back
}
}
BackHandler { getViewModel().sendEffect { MainScreenUiEffect.Navigation.Back } }
Box(modifier = Modifier.navigationBarsPadding()) {
if (state.isLoading) {

View File

@@ -34,7 +34,7 @@ class NuxViewModel @Inject constructor(val nuxHandler: NewUserExperienceHandler)
nuxHandler.getNuxScreenDefinition(
queryMap = queryMap,
onSuccess = { sendEvent(NuxGenericScreenUiEvent.RenderUI(it)) },
onFailure = { sendEffect(coroutineScope) { MainScreenUiEffect.Navigation.Back } }
onFailure = { sendEffect { MainScreenUiEffect.Navigation.Back } }
)
}
}

View File

@@ -196,9 +196,7 @@ class RegistrationActivity :
content.viewTreeObserver.addOnPreDrawListener(
object : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean {
homeVM.sendEffect(homeVM.coroutineScope) {
HpEffects.LogAppLaunchTime(LOGIN_SCREEN)
}
homeVM.sendEffect { HpEffects.LogAppLaunchTime(LOGIN_SCREEN) }
content.viewTreeObserver.removeOnPreDrawListener(this)
return true
}

View File

@@ -7,37 +7,31 @@
package com.navi.common.basemvi
import androidx.lifecycle.viewModelScope
import com.navi.common.viewmodel.BaseVM
import kotlinx.coroutines.CoroutineScope
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
abstract class BaseMviViewModel<State : UiState, Event : UiEvent, Effect : UiEffect>(
initialState: State,
private val reducer: BaseReducer<State, Event, Effect>
private val reducer: BaseReducer<State, Event>
) : BaseVM() {
private val _state: MutableStateFlow<State> = MutableStateFlow(initialState)
val state: StateFlow<State>
get() = _state.asStateFlow()
private val _event: MutableSharedFlow<Event> = MutableSharedFlow()
val event: SharedFlow<Event>
get() = _event.asSharedFlow()
private val _effects = Channel<Effect>(capacity = Channel.CONFLATED)
val effect = _effects.receiveAsFlow()
fun sendEffect(scope: CoroutineScope, effect: () -> Effect) {
scope.launch { _effects.send(effect()) }
fun sendEffect(dispatcher: CoroutineContext? = null, effect: () -> Effect) {
viewModelScope.safeLaunch(dispatcher ?: Dispatchers.IO) { _effects.send(effect()) }
}
fun sendEvent(event: Event) {

View File

@@ -7,7 +7,7 @@
package com.navi.common.basemvi
interface BaseReducer<State : UiState, Event : UiEvent, Effect : UiEffect> {
interface BaseReducer<State : UiState, Event : UiEvent> {
fun reduce(previousState: State, event: Event): State
}