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 b2ae281f3a..0b330733b0 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 @@ -559,6 +559,8 @@ class HomePageActivity : homeVM.updateProfileDrawerState(false) } else if (selectedTabId == BottomBarTabType.HOME.name) { super.onBackPressed() + } else if (selectedTabId == BottomBarTabType.LOAN.name && sharedVM.showBottomSheet.value) { + sharedVM.setBottomSheetState(false) } else { navigateToHomeTab() } diff --git a/android/app/src/main/java/com/naviapp/home/compose/components/BottomBarWithFabButton.kt b/android/app/src/main/java/com/naviapp/home/compose/components/BottomBarWithFabButton.kt index 83f22ac77f..98ec1a5036 100644 --- a/android/app/src/main/java/com/naviapp/home/compose/components/BottomBarWithFabButton.kt +++ b/android/app/src/main/java/com/naviapp/home/compose/components/BottomBarWithFabButton.kt @@ -47,7 +47,6 @@ fun BottomBarWithFabButton( ) { val expanded = listState().isScrollingUp() val isInvestmentTabScrollingDown = investmentListState.isScrollingDown() - val isLoanTabScrollingDown = loanTabScrollState.isScrollingDown() val bottomStickyNudgeData by bottomNavBarVM.bottomStickyNudgeData.collectAsState() val showBottomBar by homeVM.showBottomBar.collectAsState() val selectedTabId by sharedVM.selectedTabId.collectAsStateWithLifecycle() @@ -64,12 +63,11 @@ fun BottomBarWithFabButton( AppInstallSnackBar(inAppUpdateVM = inAppUpdateVM, homeVM = homeVM) } if ( - selectedTabId != BottomBarTabType.INSURANCE.name && homeVM.isScanPayFabButtonEnabled() + selectedTabId != BottomBarTabType.INSURANCE.name && selectedTabId != BottomBarTabType.LOAN.name && homeVM.isScanPayFabButtonEnabled() ) { AnimatedFloatingActionButton( shouldExpandFabButton = when (selectedTabId) { BottomBarTabType.HOME.name -> expanded - BottomBarTabType.LOAN.name -> isLoanTabScrollingDown.not() BottomBarTabType.INVESTMENT.name -> isInvestmentTabScrollingDown.not() else -> false }, 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/LoanTab.kt index b85753f4e6..ec8aa17d93 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/LoanTab.kt @@ -1,7 +1,5 @@ package com.naviapp.home.dashboard.ui.compose -import android.app.Activity -import android.view.ViewGroup import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.LocalOverscrollConfiguration import androidx.compose.foundation.layout.PaddingValues @@ -11,164 +9,38 @@ 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.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.Scaffold -import androidx.compose.material.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableIntStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.ComposeView import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.navi.analytics.utils.NaviTrackEvent -import com.navi.ap.utils.constants.BOTTOM_SHEET_TOP_CORNER_RADIUS import com.navi.base.utils.orZero -import com.navi.common.listeners.DashboardFragmentListener import com.navi.uitron.model.UiTronResponse import com.navi.uitron.render.UiTronRenderer -import com.naviapp.analytics.utils.NaviAnalytics.Companion.PL_POST_MANAGE_LOAN_BOTTOMSHEET_DISMISS import com.naviapp.forge.model.ScreenDefinition import com.naviapp.forge.model.WidgetModelDefinition import com.naviapp.home.dashboard.viewmodels.LoanTabVm -@OptIn(ExperimentalMaterialApi::class) @Composable fun LoansTab( loansTabVm: LoanTabVm = hiltViewModel(), toggleStatusBarColor: (String, String, String) -> Unit, - dashboardFragmentListener: DashboardFragmentListener? = null, - activity: Activity, lazyListState: () -> LazyListState? ) { val loansTabUiTronConfig = loansTabVm.loansTabUiTronData.collectAsStateWithLifecycle() - val showBottomSheet = loansTabVm.showBottomSheet.collectAsStateWithLifecycle().value - val modalBottomSheetState = - rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden) - loansTabUiTronConfig.value.let { state -> if (state is LoanTabVm.LoansTabUiTronScreenState.Success) { RenderWidgets( loansTabVm, state.data, toggleStatusBarColor, - dashboardFragmentListener, lazyListState ) } } - - LaunchedEffect(showBottomSheet) { - when (showBottomSheet) { - true -> { - modalBottomSheetState.show() - activity.showAsBottomSheet( - content = { content -> - RenderBottomSheetContent( - loansTabVm.screenDefinition, - loansTabVm - ) - }, - modalBottomSheetState = modalBottomSheetState, - viewModel = loansTabVm, - activity = activity - ) - } - - else -> { - modalBottomSheetState.hide() - NaviTrackEvent.trackEvent(PL_POST_MANAGE_LOAN_BOTTOMSHEET_DISMISS) - } - } - } -} - -@OptIn(ExperimentalMaterialApi::class) -fun Activity.showAsBottomSheet( - content: @Composable (() -> Unit) -> Unit, - modalBottomSheetState: ModalBottomSheetState, - viewModel: LoanTabVm, - activity: Activity -) { - val viewGroup = this.findViewById(android.R.id.content) as ViewGroup - addContentToView(viewGroup, content, modalBottomSheetState, viewModel, activity) -} - -@OptIn(ExperimentalMaterialApi::class) -private fun addContentToView( - viewGroup: ViewGroup, - content: @Composable (() -> Unit) -> Unit, - modalBottomSheetState: ModalBottomSheetState, - viewModel: LoanTabVm, - activity: Activity -) { - viewGroup.addView( - ComposeView(viewGroup.context).apply { - setContent { - BottomSheetWrapper( - viewGroup, - this, - content, - modalBottomSheetState, - viewModel, - activity - ) - } - } - ) -} - -@OptIn(ExperimentalMaterialApi::class) -@Composable -private fun BottomSheetWrapper( - parent: ViewGroup, - composeView: ComposeView, - content: @Composable (() -> Unit) -> Unit, - modalBottomSheetState: ModalBottomSheetState, - viewModel: LoanTabVm, - activity: Activity -) { - 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 -> { - viewModel.setBottomSheetState(false) - parent.removeView(composeView) - } - - else -> {} - } - } -} - - -@Composable -fun RenderBottomSheetContent( - data: WidgetModelDefinition?, - viewModel: LoanTabVm -) { - renderUitronWidgets(widget = data, viewModel = viewModel) } @OptIn(ExperimentalFoundationApi::class) @@ -177,7 +49,6 @@ fun RenderWidgets( loansTabVm: LoanTabVm = hiltViewModel(), data: ScreenDefinition, toggleStatusBarColor: (String, String, String) -> Unit, - dashboardFragmentListener: DashboardFragmentListener? = null, lazyListState: () -> LazyListState? = { null } ) { data.screenStructure?.header?.widgetData?.parentComposeView?.get(0)?.property?.backGroundBrushData?.let { @@ -187,12 +58,8 @@ fun RenderWidgets( it.colorStops?.get(1)?.second.toString() ) } + loansTabVm.handleActions(actionData = data.screenStructure?.renderActions?.postRenderAction) val scrollState = lazyListState() ?: rememberLazyListState() - val isScrollingDown = scrollState.isScrollingDown() - - LaunchedEffect(isScrollingDown) { - dashboardFragmentListener?.toggleFabButton(isScrollingDown.not()) - } Scaffold( modifier = Modifier .fillMaxSize(), @@ -245,26 +112,6 @@ fun LoansTabWidgetRenderer( } } -@Composable -private fun LazyListState.isScrollingDown(): Boolean { - var previousIndex by remember(this) { mutableIntStateOf(firstVisibleItemIndex) } - var previousScrollOffset by remember(this) { mutableIntStateOf(firstVisibleItemScrollOffset) } - return remember(this) { - derivedStateOf { - if (previousIndex != firstVisibleItemIndex) { - previousIndex < firstVisibleItemIndex - } else { - previousScrollOffset <= firstVisibleItemScrollOffset - } - .also { - previousIndex = firstVisibleItemIndex - previousScrollOffset = firstVisibleItemScrollOffset - } - } - } - .value -} - @Composable fun renderUitronWidgets( widget: WidgetModelDefinition?, 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 2e03a81614..498f2b07dc 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 @@ -19,7 +19,6 @@ import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel @@ -33,8 +32,6 @@ class LoanTabVm @Inject constructor(private val repository: LoanTabRepository) : val redirectionCta = SingleLiveEvent() var screenDefinition: WidgetModelDefinition? = null - private val _showBottomSheet = MutableStateFlow(false) - val showBottomSheet = _showBottomSheet.asStateFlow() init { @@ -110,11 +107,6 @@ class LoanTabVm @Inject constructor(private val repository: LoanTabRepository) : ) : LoansTabUiTronScreenState } - fun setBottomSheetState(show: Boolean) { - viewModelScope.launch { - _showBottomSheet.emit(show) - } - } enum class WidgetTypes { UI_TRON_WIDGET, 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 index 3a935e0d5b..16476e278a 100644 --- a/android/app/src/main/java/com/naviapp/home/fragment/LoanTabFragment.kt +++ b/android/app/src/main/java/com/naviapp/home/fragment/LoanTabFragment.kt @@ -1,6 +1,6 @@ package com.naviapp.home.fragment -import android.content.Context +import android.app.Activity import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -8,7 +8,15 @@ 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 @@ -21,21 +29,24 @@ 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.listeners.DashboardFragmentListener 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.setStatusBarColor 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 @@ -51,13 +62,12 @@ import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint class LoanTabFragment( private val listState: () -> LazyListState? = { null } -) : PaymentBaseFragment(),InfoBottomSheetListener { +) : PaymentBaseFragment(), InfoBottomSheetListener { private val viewModel by viewModels() private val sharedVM by lazy { ViewModelProvider(requireActivity())[SharedVM::class.java] } - private var dashboardFragmentListener: DashboardFragmentListener? = null private var isFirstHiddenCallDone = false override val screenName: String @@ -72,6 +82,7 @@ class LoanTabFragment( setContent { InitTabChangeObserver() ScreenComposable(listState) + showBottomSheet() } } sendInitEvent() @@ -95,8 +106,6 @@ class LoanTabFragment( LoansTab( loansTabVm = viewModel, toggleStatusBarColor = ::toggleStatusBarColor, - dashboardFragmentListener = dashboardFragmentListener, - activity = this.requireActivity(), lazyListState = listState ) } @@ -155,15 +164,9 @@ class LoanTabFragment( ) } - override fun onAttach(context: Context) { - super.onAttach(context) - dashboardFragmentListener = context as? DashboardFragmentListener - } - - private fun initObserver() { viewModel.redirectionCta.observe(viewLifecycleOwner) { ctaData -> - viewModel.setBottomSheetState(false) + sharedVM.setBottomSheetState(false) navigateTo(ctaData) } } @@ -173,7 +176,7 @@ class LoanTabFragment( SEE_MORE_BOTTOMSHEET -> { when (ctaData.type) { BOTTOMSHEET -> { - viewModel.setBottomSheetState(true) + sharedVM.setBottomSheetState(true) } } } @@ -201,7 +204,7 @@ class LoanTabFragment( val symbol = firstOrNull { it.key == PartPrePaymentActivity.SYMBOL }?.value val paymentType: PaymentType = PaymentType.get(firstOrNull { it.key == PartPrePaymentActivity.PAYMENT_TYPE }?.value) - loanType = firstOrNull { it.key == com.naviapp.utils.Constants.LOAN_TYPE }?.value + loanType = firstOrNull { it.key == Constants.LOAN_TYPE }?.value val isPreClosure = false updatePaymentType(paymentType) onPaymentClick( @@ -218,9 +221,7 @@ class LoanTabFragment( } private fun handleHiddenChange(hidden: Boolean) { - if (hidden) { - viewModel.setBottomSheetState(false) - } else { + 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( @@ -247,6 +248,105 @@ class LoanTabFragment( } } + @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 { 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 c9fbfea287..9bd07dca88 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 @@ -34,6 +34,9 @@ class SharedVM @Inject constructor() : BaseVM() { private val _selectedTabId = MutableStateFlow(BottomBarTabType.HOME.name) val selectedTabId = _selectedTabId.asStateFlow() + private val _showBottomSheet = MutableStateFlow(false) + val showBottomSheet = _showBottomSheet.asStateFlow() + fun updateUiTronAction(uiTronActionHandler: UiTronActionHandler?) { _uiTronActionHandler.update { uiTronActionHandler } } @@ -45,4 +48,10 @@ class SharedVM @Inject constructor() : BaseVM() { fun updateSelectedTabId(tabId: String) { _selectedTabId.update { tabId } } + + fun setBottomSheetState(show: Boolean) { + viewModelScope.launch { + _showBottomSheet.emit(show) + } + } }