diff --git a/android/app/src/main/java/com/naviapp/home/compose/activity/HomePageActivity.kt b/android/app/src/main/java/com/naviapp/home/compose/activity/HomePageActivity.kt index 8567a56f1e..7b2809c241 100644 --- a/android/app/src/main/java/com/naviapp/home/compose/activity/HomePageActivity.kt +++ b/android/app/src/main/java/com/naviapp/home/compose/activity/HomePageActivity.kt @@ -438,6 +438,9 @@ class HomePageActivity : BottomBarTabType.INSURANCE.name -> { setStatusBarColor(R.color.white) } + BottomBarTabType.LOAN.name -> { + setStatusBarColor(R.color.white) + } } } @@ -597,6 +600,7 @@ class HomePageActivity : observeNpsRatingSubmitResponse() observeInAppUpdateData() observeNetworkConnectivity() + observeLoansTabPaymentData() } private fun observeGIPaymentFailed() { @@ -2432,4 +2436,12 @@ class HomePageActivity : } } } + + private fun observeLoansTabPaymentData() { + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + sharedVM.initiatePaymentFromLoansTabScreen.collect { initiatePaymentClick(it) } + } + } + } } diff --git a/android/app/src/main/java/com/naviapp/home/compose/home/navigation/HomePageNavHost.kt b/android/app/src/main/java/com/naviapp/home/compose/home/navigation/HomePageNavHost.kt index de3a198fca..64ac074640 100644 --- a/android/app/src/main/java/com/naviapp/home/compose/home/navigation/HomePageNavHost.kt +++ b/android/app/src/main/java/com/naviapp/home/compose/home/navigation/HomePageNavHost.kt @@ -36,7 +36,6 @@ fun HomePageNavHost( paymentVM: PaymentVM, naviHomeAnalytics: NaviAnalytics.Home, investmentListState: () -> LazyListState, - loanTabScrollState: () -> LazyListState, inAppUpdateVM: InAppUpdateVM ) { NavHost( @@ -58,7 +57,6 @@ fun HomePageNavHost( sharedVM = sharedVM, naviHomeAnalytics = naviHomeAnalytics, investmentListState = investmentListState, - loanTabScrollState = loanTabScrollState, inAppUpdateVM = inAppUpdateVM ) } diff --git a/android/app/src/main/java/com/naviapp/home/compose/home/navigation/NavGraphNavingationItem.kt b/android/app/src/main/java/com/naviapp/home/compose/home/navigation/NavGraphNavingationItem.kt index 8301d5a226..f439343459 100644 --- a/android/app/src/main/java/com/naviapp/home/compose/home/navigation/NavGraphNavingationItem.kt +++ b/android/app/src/main/java/com/naviapp/home/compose/home/navigation/NavGraphNavingationItem.kt @@ -23,11 +23,9 @@ import com.naviapp.dashboard.viewmodels.DashboardSharedVM import com.naviapp.home.compose.activity.HomePageActivity import com.naviapp.home.compose.fragment.InsuranceContainerFragment import com.naviapp.home.compose.home.ui.footer.utils.FragmentContainer -import com.naviapp.home.compose.home.ui.footer.utils.loadFragmentInContainer import com.naviapp.home.compose.home.ui.screen.HomeScreen import com.naviapp.home.compose.listener.HomeScreenCallbackListener -import com.naviapp.home.dashboard.ui.DashboardFragment -import com.naviapp.home.dashboard.ui.ProductFragment +import com.naviapp.home.dashboard.ui.compose.loansTab.LoansTabScreen import com.naviapp.home.viewmodel.HomeVM import com.naviapp.home.viewmodel.NotificationVM import com.naviapp.home.viewmodel.SharedVM @@ -44,7 +42,6 @@ fun NavGraphNavigationItem( sharedVM: SharedVM, naviHomeAnalytics: NaviAnalytics.Home, investmentListState: () -> LazyListState, - loanTabScrollState: () -> LazyListState, inAppUpdateVM: InAppUpdateVM ) { val insuranceScrollState = rememberLazyListState() @@ -82,34 +79,11 @@ fun NavGraphNavigationItem( sharedVM = sharedVM ) NavigationItem.Loan.tabId -> - FragmentContainer( - modifier = Modifier.fillMaxSize().padding(bottom = 56.dp).statusBarsPadding(), - fragmentManager = activity.supportFragmentManager - ) { containerId -> - val subType = ProductFragment.DashboardTypes.Loans.name - val currentScreenTag = DashboardFragment.TAG - val fragmentTag = currentScreenTag + subType - val fragment = - loadFragmentInContainer( - activity = activity, - currentScreenTag = currentScreenTag, - bundle = null, - subType = subType, - fragmentTag = fragmentTag - ) { - loanTabScrollState() - } - homeVM.setCurrentFragmentScreenName( - (fragment as? BaseFragment)?.screenName ?: NaviAnalytics.NEW_HOME_ACTIVITY - ) - if (!fragment.isStateSaved && !fragment.isAdded) { - if (fragment.isAdded) { - show(fragment) - } else { - add(containerId, fragment, fragmentTag) - } - } - } + LoansTabScreen( + activity = activity, + sharedVM = sharedVM, + modifier = Modifier.fillMaxSize().padding(bottom = 56.dp).statusBarsPadding() + ) NavigationItem.Insurance.tabId -> { FragmentContainer( modifier = Modifier.fillMaxSize().padding(bottom = 56.dp).statusBarsPadding(), diff --git a/android/app/src/main/java/com/naviapp/home/compose/home/ui/footer/utils/BottomBarFragmentManager.kt b/android/app/src/main/java/com/naviapp/home/compose/home/ui/footer/utils/BottomBarFragmentManager.kt index fc8eab2ea5..9a85a3bb5d 100644 --- a/android/app/src/main/java/com/naviapp/home/compose/home/ui/footer/utils/BottomBarFragmentManager.kt +++ b/android/app/src/main/java/com/naviapp/home/compose/home/ui/footer/utils/BottomBarFragmentManager.kt @@ -34,7 +34,6 @@ import com.naviapp.home.compose.activity.HomePageActivity import com.naviapp.home.dashboard.models.response.DashboardTab import com.naviapp.home.dashboard.ui.DashboardFragment import com.naviapp.home.dashboard.ui.ProductFragment -import com.naviapp.home.fragment.LoanTabFragment import com.naviapp.utils.Constants @Composable @@ -83,7 +82,6 @@ fun getDashboardFragment( listState: () -> LazyListState? = { null } ): Fragment { return when (subType) { - ProductFragment.DashboardTypes.Loans.name -> getLoansTabFragment(listState) ProductFragment.DashboardTypes.Insurance.name -> handleInsuranceDashboardTab( activity = activity, @@ -100,10 +98,6 @@ fun getDashboardFragment( } } -private fun getLoansTabFragment(listState: () -> LazyListState? = { null }): Fragment { - return LoanTabFragment.getInstance(listState) -} - @SuppressLint("CommitTransaction") private fun handleInsuranceDashboardTab( activity: HomePageActivity, diff --git a/android/app/src/main/java/com/naviapp/home/compose/home/ui/screen/HomePageActivityMainScreen.kt b/android/app/src/main/java/com/naviapp/home/compose/home/ui/screen/HomePageActivityMainScreen.kt index a86f66900c..ccbc0d5568 100644 --- a/android/app/src/main/java/com/naviapp/home/compose/home/ui/screen/HomePageActivityMainScreen.kt +++ b/android/app/src/main/java/com/naviapp/home/compose/home/ui/screen/HomePageActivityMainScreen.kt @@ -26,7 +26,9 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavHostController import androidx.navigation.compose.rememberNavController import com.navi.analytics.utils.NaviTrackEvent +import com.navi.base.deeplink.DeepLinkManager import com.navi.base.deeplink.util.DeeplinkConstants +import com.navi.base.utils.orFalse import com.navi.common.ui.compose.DrawerState import com.navi.common.ui.compose.NaviDrawerValue import com.navi.common.ui.compose.NaviModalNavigationDrawer @@ -136,7 +138,6 @@ private fun InitHomeActivityScreen( navController: NavHostController ) { val drawerState = rememberNaviDrawerState(NaviDrawerValue.Closed) - val loanTabScrollState = rememberLazyListState() val investmentListState = rememberLazyListState() val coroutineScope = rememberCoroutineScope() @@ -183,7 +184,6 @@ private fun InitHomeActivityScreen( bottomNavBarVM = bottomNavBarVM, inAppUpdateVM = inAppUpdateVM, investmentListState = { investmentListState }, - loanTabScrollState = { loanTabScrollState }, homeVM = homeVM, paymentVM = paymentVM, dashboardSharedVM = dashboardSharedVM, @@ -198,16 +198,26 @@ private fun InitHomeActivityScreen( private fun handleBottomSheetAction(action: UiTronAction?, activity: HomePageActivity) { when (action) { is CtaAction -> { - when (action.ctaData?.type) { - HomeCtaTypes.REDIRECTION_CTA.name -> { - when (action.ctaData?.url) { - DeeplinkConstants.LOGOUT -> { - activity.logout() + action.ctaData?.let { ctaData -> + when (ctaData.type) { + HomeCtaTypes.REDIRECTION_CTA.name -> { + when (ctaData.url) { + DeeplinkConstants.LOGOUT -> { + activity.logout() + } + else -> Unit } - else -> Unit + } + else -> { + DeepLinkManager.getDeepLinkListener() + ?.navigateTo( + activity = activity, + ctaData, + finish = ctaData.finish.orFalse(), + clearTask = ctaData.clearTask.orFalse() + ) } } - else -> Unit } } is AnalyticsAction -> { @@ -240,7 +250,6 @@ private fun ScreenContent( bottomNavBarVM: BottomNavBarVM, inAppUpdateVM: InAppUpdateVM, investmentListState: () -> LazyListState, - loanTabScrollState: () -> LazyListState, homeVM: HomeVM, dashboardSharedVM: DashboardSharedVM, paymentVM: PaymentVM, @@ -260,7 +269,6 @@ private fun ScreenContent( sharedVM = sharedVM, paymentVM = paymentVM, naviHomeAnalytics = naviHomeAnalytics, - loanTabScrollState = loanTabScrollState, investmentListState = investmentListState, inAppUpdateVM = inAppUpdateVM ) diff --git a/android/app/src/main/java/com/naviapp/home/dashboard/ui/compose/LoanTab.kt b/android/app/src/main/java/com/naviapp/home/dashboard/ui/compose/loansTab/LoanTab.kt similarity index 81% rename from android/app/src/main/java/com/naviapp/home/dashboard/ui/compose/LoanTab.kt rename to android/app/src/main/java/com/naviapp/home/dashboard/ui/compose/loansTab/LoanTab.kt index 8dfcf05116..6c37d67b28 100644 --- a/android/app/src/main/java/com/naviapp/home/dashboard/ui/compose/LoanTab.kt +++ b/android/app/src/main/java/com/naviapp/home/dashboard/ui/compose/loansTab/LoanTab.kt @@ -5,7 +5,7 @@ * */ -package com.naviapp.home.dashboard.ui.compose +package com.naviapp.home.dashboard.ui.compose.loansTab import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.LocalOverscrollConfiguration @@ -14,13 +14,11 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.Modifier -import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.navi.base.utils.orZero import com.navi.uitron.model.UiTronResponse @@ -31,15 +29,15 @@ import com.naviapp.home.dashboard.viewmodels.LoanTabVm @Composable fun LoansTab( - loansTabVm: LoanTabVm = hiltViewModel(), - toggleStatusBarColor: (String, String, String) -> Unit, - lazyListState: () -> LazyListState? + loansTabVm: LoanTabVm, + toggleStatusBarColor: (String) -> Unit, + modifier: Modifier = Modifier ) { val loansTabUiTronConfig = loansTabVm.loansTabUiTronData.collectAsStateWithLifecycle() loansTabUiTronConfig.value.let { state -> if (state is LoanTabVm.LoansTabUiTronScreenState.Success) { - RenderWidgets(loansTabVm, state.data, toggleStatusBarColor, lazyListState) + RenderWidgets(loansTabVm, state.data, toggleStatusBarColor, modifier) } } } @@ -47,10 +45,10 @@ fun LoansTab( @OptIn(ExperimentalFoundationApi::class) @Composable fun RenderWidgets( - loansTabVm: LoanTabVm = hiltViewModel(), + loansTabVm: LoanTabVm, data: ScreenDefinition, - toggleStatusBarColor: (String, String, String) -> Unit, - lazyListState: () -> LazyListState? = { null } + toggleStatusBarColor: (String) -> Unit, + modifier: Modifier = Modifier ) { data.screenStructure ?.header @@ -61,15 +59,13 @@ fun RenderWidgets( ?.backGroundBrushData ?.let { toggleStatusBarColor( - it.brushType.orEmpty(), it.colorStops?.get(0)?.second.toString(), - it.colorStops?.get(1)?.second.toString() ) } loansTabVm.handleActions(actionData = data.screenStructure?.renderActions?.postRenderAction) - val scrollState = lazyListState() ?: rememberLazyListState() + val scrollState = rememberLazyListState() Scaffold( - modifier = Modifier.fillMaxSize(), + modifier = modifier.fillMaxSize(), content = { CompositionLocalProvider(LocalOverscrollConfiguration provides null) { LazyColumn( @@ -107,14 +103,14 @@ fun LoansTabWidgetRenderer(widget: WidgetModelDefinition?, viewM if (widget == null) return return when (widget.widgetType) { LoanTabVm.WidgetTypes.UI_TRON_WIDGET.name -> { - renderUitronWidgets(widget, viewModel) + RenderUitronWidgets(widget, viewModel) } else -> Unit } } @Composable -fun renderUitronWidgets(widget: WidgetModelDefinition?, viewModel: LoanTabVm) { +fun RenderUitronWidgets(widget: WidgetModelDefinition?, viewModel: LoanTabVm) { UiTronRenderer( dataMap = widget?.widgetData?.data, uiTronViewModel = viewModel, diff --git a/android/app/src/main/java/com/naviapp/home/dashboard/ui/compose/loansTab/LoansTabHelper.kt b/android/app/src/main/java/com/naviapp/home/dashboard/ui/compose/loansTab/LoansTabHelper.kt new file mode 100644 index 0000000000..e6ad6f949f --- /dev/null +++ b/android/app/src/main/java/com/naviapp/home/dashboard/ui/compose/loansTab/LoansTabHelper.kt @@ -0,0 +1,106 @@ +/* + * + * * Copyright © 2024 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.naviapp.home.dashboard.ui.compose.loansTab + +import android.app.Activity +import com.navi.base.deeplink.DeepLinkManager +import com.navi.base.model.CtaData +import com.navi.base.model.CtaType +import com.navi.base.utils.orFalse +import com.navi.common.utils.Constants.HL_DYNAMIC_MODULE_NAME +import com.navi.common.utils.Constants.PL_DYNAMIC_MODULE_NAME +import com.navi.common.utils.isDynamicModuleInstalled +import com.navi.common.utils.setStatusBarColorInt +import com.navi.design.utils.parseColorSafe +import com.navi.rr.utils.NaviRRAnalytics.Companion.currency +import com.naviapp.home.compose.model.InitiatePaymentFromComposeData +import com.naviapp.home.dashboard.viewmodels.LoanTabVm +import com.naviapp.home.model.HpBottomSheetContent +import com.naviapp.home.model.HpBottomSheetRenderType +import com.naviapp.home.model.HpBottomSheetState +import com.naviapp.home.viewmodel.SharedVM +import com.naviapp.part_prepayment.PartPrePaymentActivity +import com.naviapp.payment.activities.NaviPaymentActivity +import com.naviapp.payment.fragments.PaymentType +import com.naviapp.payment.models.Amount +import com.naviapp.utils.Constants +import com.naviapp.utils.Constants.SEE_MORE_BOTTOMSHEET +import com.naviapp.utils.LOAN_ACCOUNT_NUMBER + +class LoansTabHelper { + fun navigateTo(ctaData: CtaData, activity: Activity, sharedVM: SharedVM, viewModel: LoanTabVm) { + viewModel.setLoansTabInitStatus(false) + when (ctaData.url) { + SEE_MORE_BOTTOMSHEET -> { + viewModel.screenDefinition?.let { data -> + sharedVM.updateBottomSheetState( + state = HpBottomSheetState.Visible, + content = + HpBottomSheetContent( + renderType = HpBottomSheetRenderType.UI_TRON, + uiTronContent = listOf(data) + ) + ) + } + } + CtaType.PAYMENT_PL.name -> { + handlePaymentActionData(ctaData, sharedVM) + } + else -> { + DeepLinkManager.getDeepLinkListener() + ?.navigateTo( + activity = activity, + ctaData, + finish = ctaData.finish.orFalse(), + clearTask = ctaData.clearTask.orFalse() + ) + } + } + } + + fun toggleStatusBarColor(startColor: String, activity: Activity) { + activity.setStatusBarColorInt(startColor.parseColorSafe()) + } + + private fun handlePaymentActionData(actionData: CtaData, sharedVM: SharedVM) { + sharedVM.updatePaymentDataFromLoansTabScreen( + data = + InitiatePaymentFromComposeData( + amount = + Amount( + value = + actionData.parameters + ?.firstOrNull { it.key == NaviPaymentActivity.AMOUNT_DATA } + ?.value + ?.toDouble(), + currency = currency + ), + isPreClosure = false, + paymentType = + PaymentType.get( + actionData.parameters + ?.firstOrNull { it.key == PartPrePaymentActivity.PAYMENT_TYPE } + ?.value + ) + .toString(), + repaymentType = null, + loanType = + actionData.parameters?.firstOrNull { it.key == Constants.LOAN_TYPE }?.value, + loanAccountNumber = + actionData.parameters?.firstOrNull { it.key == LOAN_ACCOUNT_NUMBER }?.value + ) + ) + } + + fun fetchLoansTab(viewModel: LoanTabVm) { + viewModel.refreshLoansTabUiTronConfigs( + cashLoanAppInstalled = isDynamicModuleInstalled(PL_DYNAMIC_MODULE_NAME), + homeLoanAppInstalled = isDynamicModuleInstalled(HL_DYNAMIC_MODULE_NAME) + ) + } +} diff --git a/android/app/src/main/java/com/naviapp/home/dashboard/ui/compose/loansTab/LoansTabLifeCycleListener.kt b/android/app/src/main/java/com/naviapp/home/dashboard/ui/compose/loansTab/LoansTabLifeCycleListener.kt new file mode 100644 index 0000000000..13299353b5 --- /dev/null +++ b/android/app/src/main/java/com/naviapp/home/dashboard/ui/compose/loansTab/LoansTabLifeCycleListener.kt @@ -0,0 +1,39 @@ +/* + * + * * Copyright © 2024 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.naviapp.home.dashboard.ui.compose.loansTab + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver +import com.naviapp.home.dashboard.viewmodels.LoanTabVm +import com.naviapp.utils.Constants.LOANS_TAB_SCREEN + +@Composable +fun LoansTabLifeCycleListener(loansTabVm: LoanTabVm, loansTabHelper: LoansTabHelper) { + val lifecycleOwner = LocalLifecycleOwner.current + val lifecycle = lifecycleOwner.lifecycle + + DisposableEffect(lifecycle) { + val observer = LifecycleEventObserver { _, event -> + when (event) { + Lifecycle.Event.ON_RESUME -> { + if (loansTabVm.getLoansTabInitStatus().not()) { + sendInitEvent(LOANS_TAB_SCREEN) + loansTabVm.setLoansTabInitStatus(true) + loansTabHelper.fetchLoansTab(loansTabVm) + } + } + else -> {} + } + } + lifecycle.addObserver(observer) + onDispose { lifecycle.removeObserver(observer) } + } +} diff --git a/android/app/src/main/java/com/naviapp/home/dashboard/ui/compose/loansTab/LoansTabScreen.kt b/android/app/src/main/java/com/naviapp/home/dashboard/ui/compose/loansTab/LoansTabScreen.kt new file mode 100644 index 0000000000..ac39616d7e --- /dev/null +++ b/android/app/src/main/java/com/naviapp/home/dashboard/ui/compose/loansTab/LoansTabScreen.kt @@ -0,0 +1,84 @@ +/* + * + * * Copyright © 2024 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.naviapp.home.dashboard.ui.compose.loansTab + +import android.app.Activity +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.navi.analytics.utils.NaviTrackEvent +import com.navi.common.ui.errorview.FullScreenErrorComposeView +import com.navi.common.utils.Constants.HL_DYNAMIC_MODULE_NAME +import com.navi.common.utils.Constants.PL_DYNAMIC_MODULE_NAME +import com.navi.common.utils.isDynamicModuleInstalled +import com.naviapp.home.compose.activity.HomePageActivity +import com.naviapp.home.compose.home.ui.content.HomePageContentShimmer +import com.naviapp.home.dashboard.viewmodels.LoanTabVm +import com.naviapp.home.viewmodel.SharedVM + +@Composable +fun LoansTabScreen(activity: HomePageActivity, sharedVM: SharedVM, modifier: Modifier = Modifier) { + val loansTabVm by lazy { ViewModelProvider(activity)[LoanTabVm::class.java] } + val loansTabHelper by lazy { LoansTabHelper() } + LoansTabLifeCycleListener(loansTabVm, loansTabHelper) + InitObserver( + viewModel = loansTabVm, + activity = activity, + sharedVM = sharedVM, + modifier = modifier, + loansTabHelper = loansTabHelper + ) +} + +@Composable +private fun InitObserver( + viewModel: LoanTabVm, + activity: Activity, + sharedVM: SharedVM, + modifier: Modifier = Modifier, + loansTabHelper: LoansTabHelper +) { + val lifecycleOwner = LocalLifecycleOwner.current + when (val shimmerState = viewModel.loansTabUiTronData.collectAsStateWithLifecycle().value) { + is LoanTabVm.LoansTabUiTronScreenState.Loading -> { + HomePageContentShimmer() + } + is LoanTabVm.LoansTabUiTronScreenState.Success -> { + LoansTab( + loansTabVm = viewModel, + toggleStatusBarColor = { loansTabHelper.toggleStatusBarColor(it, activity) }, + modifier = modifier + ) + } + is LoanTabVm.LoansTabUiTronScreenState.Error -> { + FullScreenErrorComposeView( + error = shimmerState.error, + onRetryClick = { + viewModel.fetchLoansTabUiTronConfigs( + cashLoanAppInstalled = isDynamicModuleInstalled(PL_DYNAMIC_MODULE_NAME), + homeLoanAppInstalled = isDynamicModuleInstalled(HL_DYNAMIC_MODULE_NAME) + ) + } + ) + } + } + viewModel.redirectionCta.observe(lifecycleOwner) { ctaData -> + loansTabHelper.navigateTo( + ctaData, + activity = activity, + viewModel = viewModel, + sharedVM = sharedVM + ) + } +} + +fun sendInitEvent(screenName: String) { + NaviTrackEvent.trackEvent(screenName) +} diff --git a/android/app/src/main/java/com/naviapp/home/dashboard/viewmodels/LoanTabVm.kt b/android/app/src/main/java/com/naviapp/home/dashboard/viewmodels/LoanTabVm.kt index b017be1ba9..108b8fac8d 100644 --- a/android/app/src/main/java/com/naviapp/home/dashboard/viewmodels/LoanTabVm.kt +++ b/android/app/src/main/java/com/naviapp/home/dashboard/viewmodels/LoanTabVm.kt @@ -21,12 +21,13 @@ import com.navi.uitron.model.data.UiTronAction import com.naviapp.forge.model.ScreenDefinition import com.naviapp.forge.model.WidgetModelDefinition import com.naviapp.home.dashboard.repo.LoanTabRepository -import com.naviapp.home.fragment.LoanTabFragment.Companion.LOAN_TAB_FRAGMENT +import com.naviapp.utils.Constants.LOANS_TAB_SCREEN import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update @HiltViewModel class LoanTabVm @Inject constructor(private val repository: LoanTabRepository) : BaseVM() { @@ -37,6 +38,7 @@ class LoanTabVm @Inject constructor(private val repository: LoanTabRepository) : val redirectionCta = SingleLiveEvent() var screenDefinition: WidgetModelDefinition? = null + private var isLoansTabInitCalled: Boolean = false init { handleCallbacks() @@ -68,7 +70,7 @@ class LoanTabVm @Inject constructor(private val repository: LoanTabRepository) : fun fetchLoansTabUiTronConfigs(cashLoanAppInstalled: Boolean, homeLoanAppInstalled: Boolean) { viewModelScope.safeLaunch(Dispatchers.IO) { - _loansTabUiTronData.emit(LoansTabUiTronScreenState.Loading) + _loansTabUiTronData.update { LoansTabUiTronScreenState.Loading } fetchData(cashLoanAppInstalled, homeLoanAppInstalled) } } @@ -80,6 +82,7 @@ class LoanTabVm @Inject constructor(private val repository: LoanTabRepository) : } private suspend fun fetchData(cashLoanAppInstalled: Boolean, homeLoanAppInstalled: Boolean) { + _loansTabUiTronData.emit(LoansTabUiTronScreenState.Loading) val response = repository.fetchLoansTabUiTronConfig(cashLoanAppInstalled, homeLoanAppInstalled) _loansTabUiTronData.emit( @@ -94,12 +97,20 @@ class LoanTabVm @Inject constructor(private val repository: LoanTabRepository) : ?: run { val errorUnifiedResponse = getErrorUnifiedResponse(errors = response.errors, error = response.error) - sendFailureEvent(LOAN_TAB_FRAGMENT, errorUnifiedResponse) + sendFailureEvent(LOANS_TAB_SCREEN, errorUnifiedResponse) LoansTabUiTronScreenState.Error(errorUnifiedResponse.errorResponse) } ) } + fun getLoansTabInitStatus(): Boolean { + return isLoansTabInitCalled + } + + fun setLoansTabInitStatus(status: Boolean) { + isLoansTabInitCalled = status + } + sealed interface LoansTabUiTronScreenState { data object Loading : LoansTabUiTronScreenState diff --git a/android/app/src/main/java/com/naviapp/home/fragment/LoanTabFragment.kt b/android/app/src/main/java/com/naviapp/home/fragment/LoanTabFragment.kt deleted file mode 100644 index 791904081d..0000000000 --- a/android/app/src/main/java/com/naviapp/home/fragment/LoanTabFragment.kt +++ /dev/null @@ -1,354 +0,0 @@ -/* - * - * * Copyright © 2024 by Navi Technologies Limited - * * All rights reserved. Strictly confidential - * - */ - -package com.naviapp.home.fragment - -import android.app.Activity -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.lazy.LazyListState -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.ExperimentalMaterialApi -import androidx.compose.material.ModalBottomSheetLayout -import androidx.compose.material.ModalBottomSheetState -import androidx.compose.material.ModalBottomSheetValue -import androidx.compose.material.rememberModalBottomSheetState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.ComposeView -import androidx.compose.ui.viewinterop.AndroidView -import androidx.core.content.ContextCompat -import androidx.fragment.app.viewModels -import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.facebook.shimmer.ShimmerFrameLayout -import com.navi.analytics.utils.NaviTrackEvent -import com.navi.ap.utils.constants.BOTTOMSHEET -import com.navi.ap.utils.constants.BOTTOM_SHEET_TOP_CORNER_RADIUS -import com.navi.base.deeplink.DeepLinkManager -import com.navi.base.model.CtaData -import com.navi.base.model.CtaType -import com.navi.base.utils.orFalse -import com.navi.common.ui.errorview.FullScreenErrorComposeView -import com.navi.common.utils.Constants.HL_DYNAMIC_MODULE_NAME -import com.navi.common.utils.Constants.PL_DYNAMIC_MODULE_NAME -import com.navi.common.utils.isDynamicModuleInstalled -import com.navi.common.utils.setStatusBarColorInt -import com.navi.design.utils.parseColorSafe -import com.navi.uitron.model.UiTronResponse -import com.naviapp.R -import com.naviapp.analytics.utils.NaviAnalytics -import com.naviapp.common.fragment.InfoBottomSheetListener -import com.naviapp.forge.model.WidgetModelDefinition -import com.naviapp.home.dashboard.ui.compose.LoansTab -import com.naviapp.home.dashboard.ui.compose.renderUitronWidgets -import com.naviapp.home.dashboard.viewmodels.LoanTabVm -import com.naviapp.home.model.BottomBarTabType -import com.naviapp.home.viewmodel.SharedVM -import com.naviapp.part_prepayment.PartPrePaymentActivity -import com.naviapp.payment.activities.NaviPaymentActivity -import com.naviapp.payment.fragments.PaymentBaseFragment -import com.naviapp.payment.fragments.PaymentType -import com.naviapp.payment.models.Amount -import com.naviapp.utils.Constants -import com.naviapp.utils.LOAN_ACCOUNT_NUMBER -import dagger.hilt.android.AndroidEntryPoint - -@AndroidEntryPoint -class LoanTabFragment(private val listState: () -> LazyListState? = { null }) : - PaymentBaseFragment(), InfoBottomSheetListener { - - private val viewModel by viewModels() - private val sharedVM by lazy { ViewModelProvider(requireActivity())[SharedVM::class.java] } - private var isFirstHiddenCallDone = false - - override val screenName: String - get() = LOAN_TAB_FRAGMENT - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - - val layout = - ComposeView(requireContext()).apply { - setContent { - InitTabChangeObserver() - ScreenComposable(listState) - showBottomSheet() - } - } - sendInitEvent() - initObserver() - initializationPaymentDetail() - return layout - } - - private fun sendInitEvent() { - NaviTrackEvent.trackEvent(screenName) - } - - @Composable - fun ScreenComposable(listState: () -> LazyListState? = { null }) { - when (val shimmerState = viewModel.loansTabUiTronData.collectAsStateWithLifecycle().value) { - is LoanTabVm.LoansTabUiTronScreenState.Loading -> { - shimmerView() - } - is LoanTabVm.LoansTabUiTronScreenState.Success -> { - LoansTab( - loansTabVm = viewModel, - toggleStatusBarColor = ::toggleStatusBarColor, - lazyListState = listState - ) - } - is LoanTabVm.LoansTabUiTronScreenState.Error -> { - FullScreenErrorComposeView( - error = shimmerState.error, - onRetryClick = { - viewModel.fetchLoansTabUiTronConfigs( - cashLoanAppInstalled = isDynamicModuleInstalled(PL_DYNAMIC_MODULE_NAME), - homeLoanAppInstalled = isDynamicModuleInstalled(HL_DYNAMIC_MODULE_NAME) - ) - } - ) - } - } - } - - private fun toggleStatusBarColor(orientation: String, startColor: String, endColor: String) { - if (this@LoanTabFragment.isVisible) { - activity?.setStatusBarColorInt(startColor.parseColorSafe()) - } - } - - @Composable - fun shimmerView() { - val layout = ShimmerFrameLayout(requireContext()) - layout.addView( - LayoutInflater.from(requireContext()) - .inflate(R.layout.shimmer_tab_layout, layout, false) - ) - AndroidView(modifier = Modifier.fillMaxSize().background(Color.White), factory = { layout }) - } - - override fun onResume() { - super.onResume() - refreshLoansTabUiTronConfigs() - } - - private fun refreshLoansTabUiTronConfigs() { - viewModel.refreshLoansTabUiTronConfigs( - cashLoanAppInstalled = isDynamicModuleInstalled(PL_DYNAMIC_MODULE_NAME), - homeLoanAppInstalled = isDynamicModuleInstalled(HL_DYNAMIC_MODULE_NAME) - ) - } - - private fun initObserver() { - viewModel.redirectionCta.observe(viewLifecycleOwner) { ctaData -> - sharedVM.setBottomSheetState(false) - navigateTo(ctaData) - } - } - - private fun navigateTo(ctaData: CtaData) { - when (ctaData.url) { - SEE_MORE_BOTTOMSHEET -> { - when (ctaData.type) { - BOTTOMSHEET -> { - sharedVM.setBottomSheetState(true) - } - } - } - CtaType.PAYMENT_PL.name -> { - handlePaymentActionData(ctaData) - } - else -> { - DeepLinkManager.getDeepLinkListener() - ?.navigateTo( - activity = activity, - ctaData, - finish = ctaData.finish.orFalse(), - clearTask = ctaData.clearTask.orFalse() - ) - } - } - } - - private fun handlePaymentActionData(actionData: CtaData) { - actionData.parameters?.apply { - loanAccountNumber = firstOrNull { it.key == LOAN_ACCOUNT_NUMBER }?.value - val amountData = firstOrNull { it.key == NaviPaymentActivity.AMOUNT_DATA }?.value - val currency = firstOrNull { it.key == PartPrePaymentActivity.CURRENCY }?.value - val symbol = firstOrNull { it.key == PartPrePaymentActivity.SYMBOL }?.value - val paymentType: PaymentType = - PaymentType.get( - firstOrNull { it.key == PartPrePaymentActivity.PAYMENT_TYPE }?.value - ) - loanType = firstOrNull { it.key == Constants.LOAN_TYPE }?.value - val isPreClosure = false - updatePaymentType(paymentType) - onPaymentClick( - Amount(amountData?.toDoubleOrNull(), currency = currency, symbol = symbol), - isPreClosure, - loanType = loanType - ) - } - } - - override fun onHiddenChanged(hidden: Boolean) { - super.onHiddenChanged(hidden) - handleHiddenChange(hidden) - } - - private fun handleHiddenChange(hidden: Boolean) { - if (hidden.not()) { - if (viewModel.loansTabUiTronData.value is LoanTabVm.LoansTabUiTronScreenState.Success) { - activity?.setStatusBarColorInt( - (viewModel.loansTabUiTronData.value - as LoanTabVm.LoansTabUiTronScreenState.Success) - .data - .screenStructure - ?.header - ?.widgetData - ?.parentComposeView - ?.get(0) - ?.property - ?.backGroundBrushData - ?.colorStops - ?.get(0) - ?.second - .toString() - .parseColorSafe(Constants.WHITE_COLOR) - ) - } else { - activity?.setStatusBarColorInt( - ContextCompat.getColor(requireContext(), R.color.white) - ) - } - } - } - - @Composable - private fun InitTabChangeObserver() { - val selectedTabId by sharedVM.selectedTabId.collectAsStateWithLifecycle() - when (selectedTabId) { - BottomBarTabType.LOAN.name -> - if (isFirstHiddenCallDone) handleHiddenChange(hidden = false) - else isFirstHiddenCallDone = true - else -> handleHiddenChange(hidden = true) - } - } - - @OptIn(ExperimentalMaterialApi::class) - @Composable - fun showBottomSheet() { - val showBottomSheet = sharedVM.showBottomSheet.collectAsState().value - val modalBottomSheetState = - rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden) - LaunchedEffect(showBottomSheet) { - when (showBottomSheet) { - true -> { - modalBottomSheetState.show() - activity?.showAsBottomSheet( - content = { content -> - RenderBottomSheetContent(viewModel.screenDefinition, viewModel) - }, - modalBottomSheetState = modalBottomSheetState - ) - } - else -> { - modalBottomSheetState.hide() - NaviTrackEvent.trackEvent(NaviAnalytics.PL_POST_MANAGE_LOAN_BOTTOMSHEET_DISMISS) - } - } - } - } - - @OptIn(ExperimentalMaterialApi::class) - fun Activity.showAsBottomSheet( - content: @Composable (() -> Unit) -> Unit, - modalBottomSheetState: ModalBottomSheetState - ) { - val viewGroup: ViewGroup = this.findViewById(android.R.id.content) - addContentToView(viewGroup, content, modalBottomSheetState) - } - - @OptIn(ExperimentalMaterialApi::class) - private fun addContentToView( - viewGroup: ViewGroup, - content: @Composable (() -> Unit) -> Unit, - modalBottomSheetState: ModalBottomSheetState - ) { - viewGroup.addView( - ComposeView(viewGroup.context).apply { - setContent { BottomSheetWrapper(viewGroup, this, content, modalBottomSheetState) } - } - ) - } - - @OptIn(ExperimentalMaterialApi::class) - @Composable - private fun BottomSheetWrapper( - parent: ViewGroup, - composeView: ComposeView, - content: @Composable (() -> Unit) -> Unit, - modalBottomSheetState: ModalBottomSheetState - ) { - ModalBottomSheetLayout( - sheetShape = - RoundedCornerShape( - topStart = BOTTOM_SHEET_TOP_CORNER_RADIUS, - topEnd = BOTTOM_SHEET_TOP_CORNER_RADIUS - ), - sheetState = modalBottomSheetState, - sheetContent = { content {} } - ) {} - - LaunchedEffect(modalBottomSheetState.isVisible) { - when (modalBottomSheetState.isVisible) { - false -> { - sharedVM.setBottomSheetState(false) - parent.removeView(composeView) - } - else -> {} - } - } - } - - @Composable - fun RenderBottomSheetContent( - data: WidgetModelDefinition?, - viewModel: LoanTabVm - ) { - renderUitronWidgets(widget = data, viewModel = viewModel) - } - - companion object { - - const val SEE_MORE_BOTTOMSHEET = "SEE_MORE_BOTTOMSHEET" - const val LOAN_TAB_FRAGMENT = "LoanTabFragment" - - fun getInstance(listState: () -> LazyListState? = { null }): LoanTabFragment { - return LoanTabFragment(listState) - } - } - - override fun onPrimaryActionClick(ctaData: CtaData) {} - - override fun onSecondaryActionClick(ctaData: CtaData) { - handlePaymentActionData(ctaData) - } -} diff --git a/android/app/src/main/java/com/naviapp/home/viewmodel/SharedVM.kt b/android/app/src/main/java/com/naviapp/home/viewmodel/SharedVM.kt index 0fe2ced7bc..1ddf8d907e 100644 --- a/android/app/src/main/java/com/naviapp/home/viewmodel/SharedVM.kt +++ b/android/app/src/main/java/com/naviapp/home/viewmodel/SharedVM.kt @@ -11,6 +11,7 @@ import androidx.lifecycle.viewModelScope import com.navi.common.viewmodel.BaseVM import com.naviapp.common.model.UiTronActionHandler import com.naviapp.home.compose.home.navigation.getNavigationItemsList +import com.naviapp.home.compose.model.InitiatePaymentFromComposeData import com.naviapp.home.model.BottomBarTabType import com.naviapp.home.model.BottomNavBarItemData import com.naviapp.home.model.BottomNavBarStateHolder @@ -20,7 +21,9 @@ import com.naviapp.home.model.HpBottomSheetState import com.naviapp.home.model.HpBottomSheetStateHolder import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch @@ -40,6 +43,10 @@ class SharedVM @Inject constructor() : BaseVM() { private val _showBottomSheet = MutableStateFlow(false) val showBottomSheet = _showBottomSheet.asStateFlow() + private val _initiatePaymentFromLoansTabScreen = + MutableSharedFlow() + val initiatePaymentFromLoansTabScreen = _initiatePaymentFromLoansTabScreen.asSharedFlow() + private val _bottomNavBarStateHolder = MutableStateFlow( BottomNavBarStateHolder( @@ -100,4 +107,8 @@ class SharedVM @Inject constructor() : BaseVM() { ) { _bottomSheetStateHolder.update { HpBottomSheetStateHolder(state, config, content) } } + + fun updatePaymentDataFromLoansTabScreen(data: InitiatePaymentFromComposeData) { + viewModelScope.launch { _initiatePaymentFromLoansTabScreen.emit(data) } + } } diff --git a/android/app/src/main/java/com/naviapp/utils/Constants.kt b/android/app/src/main/java/com/naviapp/utils/Constants.kt index da9e0bbbd7..de7c6a853f 100644 --- a/android/app/src/main/java/com/naviapp/utils/Constants.kt +++ b/android/app/src/main/java/com/naviapp/utils/Constants.kt @@ -456,6 +456,7 @@ object Constants { const val PL_LOAN_DOCUMENT_SCREEN = "PL_LOAN_DOCUMENT_SCREEN" const val DOCUMENTS = "DOCUMENTS" const val DOCUMENT_NAME = "documentName" + const val SEE_MORE_BOTTOMSHEET = "SEE_MORE_BOTTOMSHEET" const val LENDING_PERMISSION_SCREEN = "LENDING_PERMISSION_SCREEN" const val ON_SYSTEM_BACK_PRESSED = "on_system_back_pressed" const val LENDING_PERMISSION_PAGE_LANDS = "lending_permission_page_lands"