From 73e1ece5a785b2335d0e3c96cb5628791b6f826c Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Tue, 28 Jan 2025 22:04:27 +0530 Subject: [PATCH] NTP-19767 | Masthead (#14544) Co-authored-by: Ankit --- .../home/common/handler/EffectHandler.kt | 13 ++ .../compose/extension/ComposeExtenstion.kt | 18 ++- .../navigation/NavGraphNavingationItem.kt | 8 +- .../home/ui/content/FrontLayerContent.kt | 37 ++++- .../ui/content/HomeAppUpdateNudgeWidget.kt | 4 +- .../home/ui/content/HomeNotifyMeWidget.kt | 6 +- .../home/compose/home/ui/header/HomeTopBar.kt | 138 +++++++++++++++++- .../home/compose/home/ui/screen/HomeScreen.kt | 11 ++ .../home/ui/screen/HomeScreenScaffold.kt | 91 ++++++++---- .../compose/insuranceTab/InsuranceScreen.kt | 18 ++- .../investmentTab/InvestmentsScreen.kt | 15 +- .../ui/compose/loansTab/LoansTabScreen.kt | 12 +- .../home/model/HomePrioritySectionData.kt | 17 +++ .../com/naviapp/home/reducer/HomeReducer.kt | 40 ++++- .../home/usecase/AsyncDeserialization.kt | 52 ++++++- .../com/naviapp/home/utils/HomePageUtils.kt | 3 + .../naviapp/home/viewmodel/HomeViewModel.kt | 4 +- .../main/java/com/naviapp/utils/Constants.kt | 3 + .../model/AlchemistScreenDefinition.kt | 3 + .../common/model/common/MastheadWidgetData.kt | 16 ++ .../naviwidgets/utils/NaviWidgetIconUtils.kt | 4 + .../res/drawable/ic_home_notification.xml | 25 ++++ .../main/res/drawable/ic_profile_with_upi.xml | 118 +++++++++++++++ 23 files changed, 589 insertions(+), 67 deletions(-) create mode 100644 android/app/src/main/java/com/naviapp/home/model/HomePrioritySectionData.kt create mode 100644 android/navi-common/src/main/java/com/navi/common/model/common/MastheadWidgetData.kt create mode 100644 android/navi-widgets/src/main/res/drawable/ic_home_notification.xml create mode 100644 android/navi-widgets/src/main/res/drawable/ic_profile_with_upi.xml diff --git a/android/app/src/main/java/com/naviapp/home/common/handler/EffectHandler.kt b/android/app/src/main/java/com/naviapp/home/common/handler/EffectHandler.kt index a1dd1e8ce8..46476d56af 100644 --- a/android/app/src/main/java/com/naviapp/home/common/handler/EffectHandler.kt +++ b/android/app/src/main/java/com/naviapp/home/common/handler/EffectHandler.kt @@ -13,6 +13,7 @@ import com.navi.common.model.ModuleNameV2 import com.navi.common.network.ApiConstants import com.navi.common.utils.TemporaryStorageHelper import com.navi.uitron.model.action.UpdateDataAction +import com.navi.uitron.model.action.UpdateViewStateAction import com.navi.uitron.model.data.TextData import com.naviapp.analytics.utils.NaviAnalytics import com.naviapp.common.transformer.AppLoadTimerMapper @@ -23,10 +24,12 @@ import com.naviapp.home.reducer.HpEvents import com.naviapp.home.viewmodel.HomeViewModel import com.naviapp.network.di.DataDeserializers import com.naviapp.screenOverlay.utils.PopupConstants.NOTIFICATION_ICON_ANIMATE +import com.naviapp.utils.Constants.HomePageConstants.ALPHA import com.naviapp.utils.Constants.HomePageConstants.NAVI_APP_NAV_HOME_PAGE_VIEWED import com.naviapp.utils.Constants.HomePageConstants.NAVI_APP_NAV_INSURANCE_PAGE_VIEWED import com.naviapp.utils.Constants.HomePageConstants.NAVI_APP_NAV_INVESTMENT_PAGE_VIEWED import com.naviapp.utils.Constants.HomePageConstants.NAVI_APP_NAV_LOAN_PAGE_VIEWED +import com.naviapp.utils.Constants.HomePageConstants.TOP_NAV_ARC_BACKGROUND import com.naviapp.utils.Constants.Notification.HIDE_NOTIFICATION_COUNT import com.naviapp.utils.Constants.Notification.NINE_PLUS import com.naviapp.utils.Constants.Notification.NOTIFICATION_COUNT_TEXT @@ -64,9 +67,19 @@ constructor( animateInAppNotificationIcon(effects.shouldAnimate, homeVM) is HpEffects.HomePageUiRenderedEvent -> homeVM.logOnDataDisplayedEvent() is HpEffects.TopNavRevealedAnalytics -> naviAnalyticsEventTracker.topNavRevealed() + is HpEffects.UpdateMastheadIconsState -> + updateMastheadIconsState(effects.alphaFactor, homeVM) } } + private fun updateMastheadIconsState(alphaFactor: Int, homeVM: HomeViewModel) { + homeVM.handleAction( + UpdateViewStateAction( + viewStates = mapOf(TOP_NAV_ARC_BACKGROUND to ALPHA.plus(alphaFactor)) + ) + ) + } + private fun animateInAppNotificationIcon(shouldAnimate: Boolean, homeVM: HomeViewModel) { if (shouldAnimate) { homeVM.state.value.collapsingToolbar diff --git a/android/app/src/main/java/com/naviapp/home/compose/extension/ComposeExtenstion.kt b/android/app/src/main/java/com/naviapp/home/compose/extension/ComposeExtenstion.kt index 2d8d516cb8..51cb217159 100644 --- a/android/app/src/main/java/com/naviapp/home/compose/extension/ComposeExtenstion.kt +++ b/android/app/src/main/java/com/naviapp/home/compose/extension/ComposeExtenstion.kt @@ -27,6 +27,7 @@ import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.TileMode import androidx.compose.ui.graphics.isSpecified import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalContext @@ -38,7 +39,11 @@ import com.navi.naviwidgets.R import com.navi.naviwidgets.utils.NaviWidgetIconUtils.getImageFromIconCode import com.naviapp.home.utils.shimmerEffect -fun Modifier.bottomShadow(showShadow: Boolean = true, elevation: Float = 24f): Modifier = +fun Modifier.bottomShadow( + showShadow: Boolean = true, + elevation: Float = 24f, + shadowLengthFactor: Int = 2, +): Modifier = this.then( Modifier.drawBehind { drawRect( @@ -46,9 +51,14 @@ fun Modifier.bottomShadow(showShadow: Boolean = true, elevation: Float = 24f): M when (showShadow) { true -> Brush.verticalGradient( - colors = listOf(Color.Black.copy(0.09f), Color.Transparent), + colorStops = + arrayOf( + Pair(0.22f, Color(0XFFB0C0D9).copy(alpha = 0.12f)), + Pair(1f, Color.Transparent), + ), startY = size.height, - endY = size.height + elevation.times(2), + endY = size.height + elevation.times(shadowLengthFactor), + tileMode = TileMode.Decal, ) false -> Brush.verticalGradient( @@ -56,7 +66,7 @@ fun Modifier.bottomShadow(showShadow: Boolean = true, elevation: Float = 24f): M ) }, topLeft = Offset(0f, size.height), - size = Size(size.width, elevation.times(2)), + size = Size(size.width, elevation.times(shadowLengthFactor)), ) } ) 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 074b0c8dac..fcda95a71a 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 @@ -17,6 +17,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp +import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.navi.paymentclients.viewmodel.base.PaymentManager import com.naviapp.analytics.utils.NaviAnalytics import com.naviapp.common.viewmodel.BottomNavBarVM @@ -48,6 +49,7 @@ fun NavGraphNavigationItem( nudgeState: () -> NudgeState, paymentManager: PaymentManager, ) { + val uiController = rememberSystemUiController() when (tabId) { NavigationItem.Home.tabId -> HomeScreen( @@ -60,6 +62,7 @@ fun NavGraphNavigationItem( screenOverlayVM = screenOverlayVM, homeVM = homeVM, nudgeState = nudgeState, + uiController = uiController, ) NavigationItem.Investment.tabId -> InvestmentsScreen( @@ -74,8 +77,10 @@ fun NavGraphNavigationItem( bottomNavBarVM = bottomNavBarVM, paymentManager = paymentManager, dashboardSharedVM = dashboardSharedVM, + uiController = uiController, ) - NavigationItem.Loan.tabId -> LoansTabScreen(activity = activity) + NavigationItem.Loan.tabId -> + LoansTabScreen(activity = activity, uiController = uiController) NavigationItem.Insurance.tabId -> { InsuranceTabScreen( activity = activity, @@ -84,6 +89,7 @@ fun NavGraphNavigationItem( .padding(bottom = 56.dp) .statusBarsPadding() .background(Color.White), + uiController = uiController, ) } } diff --git a/android/app/src/main/java/com/naviapp/home/compose/home/ui/content/FrontLayerContent.kt b/android/app/src/main/java/com/naviapp/home/compose/home/ui/content/FrontLayerContent.kt index 85dbb1d344..ba786cd6a7 100644 --- a/android/app/src/main/java/com/naviapp/home/compose/home/ui/content/FrontLayerContent.kt +++ b/android/app/src/main/java/com/naviapp/home/compose/home/ui/content/FrontLayerContent.kt @@ -19,6 +19,7 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height @@ -45,6 +46,7 @@ import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.testTag import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.testTagsAsResourceId +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.airbnb.lottie.compose.LottieAnimation import com.airbnb.lottie.compose.LottieCompositionSpec @@ -52,6 +54,7 @@ import com.airbnb.lottie.compose.LottieConstants import com.airbnb.lottie.compose.rememberLottieComposition import com.navi.common.alchemist.model.AlchemistWidgetModelDefinition import com.navi.common.alchemist.model.WidgetRenderState +import com.navi.common.model.common.MastheadWidgetData import com.navi.naviwidgets.R import com.navi.pay.utils.conditional import com.navi.uitron.model.UiTronResponse @@ -74,6 +77,9 @@ fun FrontLayerContent( onEvent: (event: HpEvents) -> Unit, onEffect: (effect: HpEffects) -> Unit, staticNudgeContainer: @Composable () -> Unit, + mastheadWidget: MastheadWidgetData? = null, + isMastheadEnabled: Boolean, + appBarHeight: Dp, ) { CompositionLocalProvider(LocalOverscrollConfiguration provides null) { Column( @@ -85,7 +91,11 @@ fun FrontLayerContent( ) { if (!widgets.isNullOrEmpty()) { Column { - TopNotchUI() + if (isMastheadEnabled) { + MastheadWidget(homeWidgetRenderer, mastheadWidget, appBarHeight) + } else { + TopNotchUI() + } staticNudgeContainer() RenderUiTronContent( elementList = widgets, @@ -108,6 +118,29 @@ fun FrontLayerContent( } } +@Composable +private fun MastheadWidget( + homeWidgetRenderer: @Composable (UiTronResponse?) -> Unit, + mastheadWidget: MastheadWidgetData?, + appBarHeight: Dp, +) { + mastheadWidget?.let { + Box( + modifier = + Modifier.height(IntrinsicSize.Max) + .padding(bottom = it.widgetBottomPadding.dp) + .fillMaxWidth() + ) { + Box(modifier = Modifier.matchParentSize()) { + homeWidgetRenderer(it.backgroundIllustration?.uiTronResponse) + } + Box(modifier = Modifier.padding(top = appBarHeight).fillMaxWidth()) { + homeWidgetRenderer(it.widgetData?.uiTronResponse) + } + } + } +} + @Composable fun TopNotchUI() { Column( @@ -185,7 +218,7 @@ private fun AnimatedContainerForWidgets( } @Composable -private fun RenderUiTronContent( +internal fun RenderUiTronContent( elementList: List>, homeWidgetRenderer: @Composable (UiTronResponse?) -> Unit, homeVM: () -> HomeViewModel, diff --git a/android/app/src/main/java/com/naviapp/home/compose/home/ui/content/HomeAppUpdateNudgeWidget.kt b/android/app/src/main/java/com/naviapp/home/compose/home/ui/content/HomeAppUpdateNudgeWidget.kt index ca6c05b91b..2ffcd246e7 100644 --- a/android/app/src/main/java/com/naviapp/home/compose/home/ui/content/HomeAppUpdateNudgeWidget.kt +++ b/android/app/src/main/java/com/naviapp/home/compose/home/ui/content/HomeAppUpdateNudgeWidget.kt @@ -50,6 +50,7 @@ import com.naviapp.utils.Constants.HOME_SCREEN_IN_CAPS @Composable fun HomeAppUpdateWidget( + modifier: Modifier = Modifier, content: AlchemistWidgetModelDefinition, appUpdateState: AppUpdateState, inAppUpdateBridge: InAppUpdateBridge, @@ -93,7 +94,8 @@ fun HomeAppUpdateWidget( horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, modifier = - Modifier.fillMaxWidth() + modifier + .fillMaxWidth() .padding(start = 16.dp, end = 16.dp, bottom = 12.dp) .border( width = 1.dp, diff --git a/android/app/src/main/java/com/naviapp/home/compose/home/ui/content/HomeNotifyMeWidget.kt b/android/app/src/main/java/com/naviapp/home/compose/home/ui/content/HomeNotifyMeWidget.kt index 738ee746af..b1f23c4586 100644 --- a/android/app/src/main/java/com/naviapp/home/compose/home/ui/content/HomeNotifyMeWidget.kt +++ b/android/app/src/main/java/com/naviapp/home/compose/home/ui/content/HomeNotifyMeWidget.kt @@ -52,6 +52,7 @@ import com.naviapp.utils.Constants.HOME_SCREEN_IN_CAPS @OptIn(ExperimentalPermissionsApi::class) @Composable fun HomeNotifyMeWidget( + modifier: Modifier = Modifier, widget: AlchemistWidgetModelDefinition, showBottomSheet: () -> Unit, onDismissNudge: () -> Unit, @@ -87,6 +88,7 @@ fun HomeNotifyMeWidget( if (visible) { notifyMeAnalytics.notifyMeNudgeViewEvent() NotifyMeUI( + modifier = modifier, permissionGranted = (pushNotificationPermission.allPermissionsGranted), widgetData, onDismissNudge = { @@ -107,6 +109,7 @@ fun HomeNotifyMeWidget( @Composable private fun NotifyMeUI( + modifier: Modifier, permissionGranted: Boolean, widgetData: NotifyMeWidgetData?, onDismissNudge: () -> Unit, @@ -116,7 +119,8 @@ private fun NotifyMeUI( horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, modifier = - Modifier.fillMaxWidth() + modifier + .fillMaxWidth() .padding(start = 16.dp, end = 16.dp, bottom = 12.dp) .border(width = 1.dp, color = Color(0xFFE3E5E5), shape = RoundedCornerShape(4.dp)) .padding(horizontal = 16.dp, vertical = 12.dp), diff --git a/android/app/src/main/java/com/naviapp/home/compose/home/ui/header/HomeTopBar.kt b/android/app/src/main/java/com/naviapp/home/compose/home/ui/header/HomeTopBar.kt index 3ef8173c2f..2ad2db54df 100644 --- a/android/app/src/main/java/com/naviapp/home/compose/home/ui/header/HomeTopBar.kt +++ b/android/app/src/main/java/com/naviapp/home/compose/home/ui/header/HomeTopBar.kt @@ -17,6 +17,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.requiredHeight import androidx.compose.foundation.layout.size import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.remember @@ -27,11 +28,15 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import com.google.accompanist.systemuicontroller.SystemUiController +import com.navi.common.alchemist.model.AlchemistCollapsingToolbar import com.navi.common.extensions.conditional import com.navi.naviwidgets.R as WidgetR import com.navi.uitron.model.UiTronResponse import com.naviapp.R import com.naviapp.home.compose.extension.bottomShadow +import com.naviapp.home.reducer.HpEffects +import com.naviapp.utils.Constants.HomePageConstants.SCROLL_THRESHOLD @Composable fun HomeTopBar( @@ -55,15 +60,132 @@ fun HomeTopBar( } // Render the top bar - Row(modifier = topBarModifier, verticalAlignment = Alignment.Top) { + ToolbarRender(topBarModifier, statusBarHeight, topBarContent, homeWidgetRenderer) +} + +@Composable +fun MastheadTopBar( + modifier: Modifier, + statusBarHeight: Dp, + toolbarConfig: AlchemistCollapsingToolbar?, + renderWidget: @Composable (UiTronResponse) -> Unit, + scrollStateProvider: () -> ScrollState, + onEffect: (effect: HpEffects) -> Unit, + uiController: SystemUiController, +) { + val scrollState by remember { + derivedStateOf { + val scrollOffset = scrollStateProvider().value.toFloat() + val isScrolledBeyondThreshold = scrollOffset >= SCROLL_THRESHOLD + val scrollProgress = (scrollOffset / SCROLL_THRESHOLD).coerceIn(0f, 1f) + isScrolledBeyondThreshold to scrollProgress + } + } + val (isScrolledBeyondThreshold, scrollProgress) = scrollState + + // Update status bar color based on scroll + HandleStatusBarIcons( + uiController = uiController, + isScrolledBeyondThreshold = isScrolledBeyondThreshold, + toolbarConfig = toolbarConfig, + ) + // Update icon background alpha based on scroll progress + HandleToolbarIconsBackground( + scrollProgress = scrollProgress, + toolbarConfig = toolbarConfig, + onEffect = onEffect, + ) + // Create toolbar modifier with scroll progress + val toolbarModifier = modifier.createToolbarModifier(scrollProgress = scrollProgress) + + // Render the toolbar + ToolbarRender( + modifier = toolbarModifier, + statusBarHeight = statusBarHeight, + toolbarContent = toolbarConfig?.toolBarNav?.uiTronResponse, + homeWidgetRenderer = renderWidget, + mastheadEnable = true, + ) +} + +@Composable +private fun Modifier.createToolbarModifier(scrollProgress: Float): Modifier = + remember(scrollProgress) { + bottomShadow(showShadow = scrollProgress > 0, elevation = 5f, shadowLengthFactor = 8) + .drawBehind { drawRect(color = Color.White.copy(alpha = scrollProgress)) } + } + +/** + * Changes status bar icon color based on background color and scroll state. Uses dark icons for + * light backgrounds. + */ +@Composable +private fun HandleStatusBarIcons( + uiController: SystemUiController, + isScrolledBeyondThreshold: Boolean, + toolbarConfig: AlchemistCollapsingToolbar?, +) { + LaunchedEffect( + key1 = isScrolledBeyondThreshold, + key2 = toolbarConfig?.mastheadWidget?.useLightStatusBar, + ) { + toolbarConfig?.mastheadWidget?.let { mastheadWidget -> + when { + mastheadWidget.useLightStatusBar -> { + uiController.setStatusBarColor( + color = Color.Transparent, + darkIcons = isScrolledBeyondThreshold, + ) + } + + !uiController.statusBarDarkContentEnabled -> { + uiController.setStatusBarColor(color = Color.Transparent, darkIcons = true) + } + } + } + } +} + +/** + * Updates the masthead icons' background alpha based on scroll progress. Ensures a minimum alpha of + * 0.3 (factor 3) and a maximum of 1.0 (factor 10). + */ +@Composable +private fun HandleToolbarIconsBackground( + scrollProgress: Float, + toolbarConfig: AlchemistCollapsingToolbar?, + onEffect: (HpEffects) -> Unit, +) { + val iconBackgroundAlphaFactor = remember(scrollProgress) { ((scrollProgress * 7) + 3).toInt() } + + LaunchedEffect( + key1 = iconBackgroundAlphaFactor, + key2 = toolbarConfig?.mastheadWidget?.updateIconsOnScroll, + ) { + toolbarConfig + ?.mastheadWidget + ?.takeIf { it.updateIconsOnScroll } + ?.let { onEffect(HpEffects.UpdateMastheadIconsState(iconBackgroundAlphaFactor)) } + } +} + +@Composable +private fun ToolbarRender( + modifier: Modifier, + statusBarHeight: Dp, + toolbarContent: UiTronResponse?, + homeWidgetRenderer: @Composable (UiTronResponse) -> Unit, + mastheadEnable: Boolean = false, +) { + Row(modifier = modifier, verticalAlignment = Alignment.Top) { Row(Modifier.padding(top = statusBarHeight)) { - topBarContent?.let { homeWidgetRenderer(it) } ?: DefaultTopBar() + toolbarContent?.let { homeWidgetRenderer(it) } ?: DefaultTopBar(mastheadEnable) } } } @Composable -fun DefaultTopBar() { +fun DefaultTopBar(mastheadEnable: Boolean = false) { Row( Modifier.fillMaxWidth().height(60.dp).padding(start = 16.dp, end = 16.dp), horizontalArrangement = Arrangement.SpaceBetween, @@ -71,12 +193,18 @@ fun DefaultTopBar() { ) { Image( modifier = Modifier.size(40.dp), - painter = painterResource(id = R.drawable.app_ic_profile), + painter = + if (mastheadEnable) + painterResource(id = com.navi.naviwidgets.R.drawable.ic_profile_with_upi) + else painterResource(id = R.drawable.app_ic_profile), contentDescription = "Profile Icon", ) Image( modifier = Modifier.size(40.dp), - painter = painterResource(id = WidgetR.drawable.navi_widgets_ic_notification), + painter = + if (mastheadEnable) + painterResource(id = com.navi.naviwidgets.R.drawable.ic_home_notification) + else painterResource(id = WidgetR.drawable.navi_widgets_ic_notification), contentDescription = "Notifications Icon", ) } diff --git a/android/app/src/main/java/com/naviapp/home/compose/home/ui/screen/HomeScreen.kt b/android/app/src/main/java/com/naviapp/home/compose/home/ui/screen/HomeScreen.kt index b396010c0d..9ef0cf3c18 100644 --- a/android/app/src/main/java/com/naviapp/home/compose/home/ui/screen/HomeScreen.kt +++ b/android/app/src/main/java/com/naviapp/home/compose/home/ui/screen/HomeScreen.kt @@ -7,11 +7,15 @@ package com.naviapp.home.compose.home.ui.screen +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.google.accompanist.systemuicontroller.SystemUiController import com.navi.common.checkmate.core.CheckMateManager import com.navi.common.checkmate.model.MetricInfo import com.navi.common.network.models.RepoResult @@ -46,6 +50,7 @@ fun HomeScreen( naviAnalyticsEventTracker: NaviAnalytics.Home, screenOverlayVM: ScreenOverlayVM, nudgeState: () -> NudgeState, + uiController: SystemUiController, ) { val homeScrollState = rememberScrollState() val appUpdateState by sharedVM.appUpdateState.collectAsStateWithLifecycle() @@ -119,6 +124,7 @@ fun HomeScreen( }, ) }, + uiController = uiController, ) } else { HomeScreenScaffoldRoot( @@ -138,6 +144,10 @@ fun HomeScreen( state = nudgeState().staticNudgeData, widgetRenderer = { WidgetRenderer( + modifier = + if (hpStates().collapsingToolbar?.mastheadEnable == true) + Modifier.padding(top = 8.dp) + else Modifier, staticNudgeData = nudgeState().staticNudgeData, sharedVM = sharedVM, viewModel = screenOverlayVM, @@ -154,6 +164,7 @@ fun HomeScreen( }, ) }, + uiController = uiController, ) hpStates().footer?.let { handleBottomBarData(it, sharedVM) } } diff --git a/android/app/src/main/java/com/naviapp/home/compose/home/ui/screen/HomeScreenScaffold.kt b/android/app/src/main/java/com/naviapp/home/compose/home/ui/screen/HomeScreenScaffold.kt index 437027f295..e5793b1470 100644 --- a/android/app/src/main/java/com/naviapp/home/compose/home/ui/screen/HomeScreenScaffold.kt +++ b/android/app/src/main/java/com/naviapp/home/compose/home/ui/screen/HomeScreenScaffold.kt @@ -32,11 +32,13 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.Dp +import com.google.accompanist.systemuicontroller.SystemUiController import com.navi.common.utils.getStatusBarHeight import com.navi.uitron.model.UiTronResponse import com.naviapp.home.compose.home.ui.content.BackLayerContent import com.naviapp.home.compose.home.ui.content.FrontLayerContent import com.naviapp.home.compose.home.ui.header.HomeTopBar +import com.naviapp.home.compose.home.ui.header.MastheadTopBar import com.naviapp.home.compose.home.utils.TopNaviMiddlePillAnimation import com.naviapp.home.compose.home.utils.backDropNestedScrollConnection import com.naviapp.home.compose.home.utils.getFrontLayerOffset @@ -56,6 +58,7 @@ internal fun HomeScreenScaffoldRoot( homeVM: () -> HomeViewModel, homeWidgetRenderer: @Composable (UiTronResponse?) -> Unit, staticNudgeContainer: @Composable () -> Unit, + uiController: SystemUiController, ) { val density = LocalDensity.current val statusBarHeight = remember { with(density) { getStatusBarHeight().toDp() } } @@ -64,39 +67,63 @@ internal fun HomeScreenScaffoldRoot( val frontLayerShape = remember { RoundedCornerShape(topStart = HOME_SHAPE_CURVATURE, topEnd = HOME_SHAPE_CURVATURE) } - Box(Modifier.fillMaxSize().navigationBarsPadding()) { - BackLayerContent( - backLayerHeight = backLayerHeight, - homeWidgetRenderer = homeWidgetRenderer, - backLayerData = (hpStates().collapsingToolbar?.collapsingTopNav)?.uiTronResponse, - ) - - FrontLayerRoot( - hpStates = hpStates, - homeScrollState = homeScrollState, - homeVM = homeVM, - homeWidgetRenderer = homeWidgetRenderer, - frontLayerShape = frontLayerShape, - appBarHeight = appBarHeight, - backLayerHeight = backLayerHeight, - staticNudgeContainer = staticNudgeContainer, - ) - - HomeTopBar( - modifier = Modifier.align(Alignment.TopCenter), - appBarHeight = appBarHeight, - statusBarHeight = statusBarHeight, - topBarContent = (hpStates().collapsingToolbar?.toolBarNav)?.uiTronResponse, - homeWidgetRenderer = homeWidgetRenderer, - homeScrollState = homeScrollState, - ) + if (hpStates().collapsingToolbar?.mastheadEnable == true) { + FrontLayerContent( + modifier = Modifier, + widgets = (hpStates().frontLayerContent), + frontLayerShape = frontLayerShape, + homeScrollState = homeScrollState, + homeVM = homeVM, + homeWidgetRenderer = homeWidgetRenderer, + onEffect = { homeVM().setEffect { it } }, + onEvent = { homeVM().sendEvent(it) }, + isRenderingFirstTime = hpStates().isRenderingFirstTime, + staticNudgeContainer = staticNudgeContainer, + mastheadWidget = (hpStates().collapsingToolbar?.mastheadWidget), + isMastheadEnabled = true, + appBarHeight = appBarHeight, + ) + MastheadTopBar( + modifier = Modifier, + statusBarHeight = statusBarHeight, + toolbarConfig = (hpStates().collapsingToolbar), + renderWidget = homeWidgetRenderer, + scrollStateProvider = homeScrollState, + onEffect = { homeVM().setEffect { it } }, + uiController = uiController, + ) + } else { + BackLayerContent( + backLayerHeight = backLayerHeight, + homeWidgetRenderer = homeWidgetRenderer, + backLayerData = (hpStates().collapsingToolbar?.collapsingTopNav)?.uiTronResponse, + ) + FrontLayerWithBackDropScroll( + hpStates = hpStates, + homeScrollState = homeScrollState, + homeVM = homeVM, + homeWidgetRenderer = homeWidgetRenderer, + frontLayerShape = frontLayerShape, + appBarHeight = appBarHeight, + backLayerHeight = backLayerHeight, + staticNudgeContainer = staticNudgeContainer, + ) + HomeTopBar( + modifier = Modifier.align(Alignment.TopCenter), + appBarHeight = appBarHeight, + statusBarHeight = statusBarHeight, + topBarContent = (hpStates().collapsingToolbar?.toolBarNav)?.uiTronResponse, + homeWidgetRenderer = homeWidgetRenderer, + homeScrollState = homeScrollState, + ) + } } } @OptIn(ExperimentalFoundationApi::class) @Composable -private fun FrontLayerRoot( +private fun FrontLayerWithBackDropScroll( hpStates: () -> HpStates, homeScrollState: () -> ScrollState, homeVM: () -> HomeViewModel, @@ -137,15 +164,17 @@ private fun FrontLayerRoot( .nestedScroll(backDropNestedScrollConnection(draggableState)) .anchoredDraggable(state = draggableState, orientation = Orientation.Vertical) .padding(bottom = appBarHeight), - widgets = (hpStates().frontLayerContent), frontLayerShape = frontLayerShape, + widgets = (hpStates().frontLayerContent), + homeWidgetRenderer = homeWidgetRenderer, + isRenderingFirstTime = hpStates().isRenderingFirstTime, homeScrollState = homeScrollState, homeVM = homeVM, - homeWidgetRenderer = homeWidgetRenderer, - onEffect = { homeVM().setEffect { it } }, onEvent = { homeVM().sendEvent(it) }, - isRenderingFirstTime = hpStates().isRenderingFirstTime, + onEffect = { homeVM().setEffect { it } }, staticNudgeContainer = staticNudgeContainer, + isMastheadEnabled = false, + appBarHeight = appBarHeight, ) LaunchedEffect(draggableState.settledValue) { diff --git a/android/app/src/main/java/com/naviapp/home/dashboard/ui/compose/insuranceTab/InsuranceScreen.kt b/android/app/src/main/java/com/naviapp/home/dashboard/ui/compose/insuranceTab/InsuranceScreen.kt index 2b4c513d0c..5b30046ae4 100644 --- a/android/app/src/main/java/com/naviapp/home/dashboard/ui/compose/insuranceTab/InsuranceScreen.kt +++ b/android/app/src/main/java/com/naviapp/home/dashboard/ui/compose/insuranceTab/InsuranceScreen.kt @@ -5,13 +5,13 @@ * */ -import android.app.Activity import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.hilt.navigation.compose.hiltViewModel +import com.google.accompanist.systemuicontroller.SystemUiController import com.navi.base.model.NaviClickAction -import com.navi.common.utils.setStatusBarColorInt -import com.navi.design.utils.parseColorSafe +import com.navi.common.utils.parseColor import com.navi.naviwidgets.callbacks.WidgetCallback import com.naviapp.common.tab.InsuranceTabViewModel import com.naviapp.home.compose.activity.HomePageActivity @@ -19,7 +19,11 @@ import com.naviapp.home.dashboard.ui.compose.insuranceTab.InsuranceTabInit import com.naviapp.home.dashboard.ui.compose.insuranceTab.RenderUiTronDataSecondary @Composable -fun InsuranceTabScreen(activity: HomePageActivity, modifier: Modifier = Modifier) { +fun InsuranceTabScreen( + activity: HomePageActivity, + modifier: Modifier = Modifier, + uiController: SystemUiController, +) { val viewModel: InsuranceTabViewModel = hiltViewModel() val widgetCallback = object : WidgetCallback { @@ -32,10 +36,10 @@ fun InsuranceTabScreen(activity: HomePageActivity, modifier: Modifier = Modifier modifier = modifier, viewModel = viewModel, widgetCallback = widgetCallback, - toggleStatusBarColor = { color -> toggleStatusBarColor(activity, color) }, + toggleStatusBarColor = { color -> toggleStatusBarColor(uiController, color) }, ) } -private fun toggleStatusBarColor(activity: Activity, color: String) { - activity.setStatusBarColorInt(color.parseColorSafe()) +private fun toggleStatusBarColor(uiController: SystemUiController, color: String) { + uiController.setStatusBarColor(color = Color(color.parseColor()), darkIcons = true) } diff --git a/android/app/src/main/java/com/naviapp/home/dashboard/ui/compose/investmentTab/InvestmentsScreen.kt b/android/app/src/main/java/com/naviapp/home/dashboard/ui/compose/investmentTab/InvestmentsScreen.kt index 89db618c54..fb02b6dd5b 100644 --- a/android/app/src/main/java/com/naviapp/home/dashboard/ui/compose/investmentTab/InvestmentsScreen.kt +++ b/android/app/src/main/java/com/naviapp/home/dashboard/ui/compose/investmentTab/InvestmentsScreen.kt @@ -5,17 +5,17 @@ * */ -import android.app.Activity import androidx.compose.foundation.layout.Box import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.google.accompanist.systemuicontroller.SystemUiController import com.navi.common.model.ModuleNameV2 import com.navi.common.ui.errorview.FullScreenErrorComposeView -import com.navi.common.utils.setStatusBarColorInt -import com.navi.design.utils.parseColorSafe +import com.navi.common.utils.parseColor import com.navi.paymentclients.viewmodel.base.PaymentManager import com.naviapp.common.viewmodel.BottomNavBarVM import com.naviapp.dashboard.viewmodels.DashboardSharedVM @@ -38,6 +38,7 @@ fun InvestmentsScreen( bottomNavBarVM: BottomNavBarVM, paymentManager: PaymentManager, dashboardSharedVM: DashboardSharedVM, + uiController: SystemUiController, ) { val investmentsTabVm by lazy { ViewModelProvider(activity)[InvestmentsVm::class.java] } val investmentsScreenData = @@ -61,6 +62,7 @@ fun InvestmentsScreen( ) InvestmentsTabShimmer() } + is InvestmentsVm.InvestmentsTabScreenState.Success -> { investmentsTabVm.fireEvent( eventName = InvestmentTabEvents.INVESTMENT_TAB_SUCCESS.eventName, @@ -73,7 +75,7 @@ fun InvestmentsScreen( sharedVM = sharedVM, investmentsScreenHelper = investmentsScreenHelper, hopper = hopper, - toggleStatusBarColor = { toggleStatusBarColor(activity, it) }, + toggleStatusBarColor = { toggleStatusBarColor(uiController, it) }, bottomNavBarVM = bottomNavBarVM, paymentManager = paymentManager, dashboardSharedVM = dashboardSharedVM, @@ -84,6 +86,7 @@ fun InvestmentsScreen( ) } } + is InvestmentsVm.InvestmentsTabScreenState.Error -> { FullScreenErrorComposeView( error = investmentsScreenData.error, @@ -98,6 +101,6 @@ fun InvestmentsScreen( } } -private fun toggleStatusBarColor(activity: Activity, color: String) { - activity.setStatusBarColorInt(color.parseColorSafe()) +private fun toggleStatusBarColor(uiController: SystemUiController, color: String) { + uiController.setStatusBarColor(color = Color(color.parseColor()), darkIcons = true) } 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 index 47c04a6367..9791c34a02 100644 --- 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 @@ -15,9 +15,11 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.lifecycleScope +import com.google.accompanist.systemuicontroller.SystemUiController import com.navi.analytics.utils.NaviTrackEvent import com.navi.common.ui.errorview.FullScreenErrorComposeView import com.navi.common.utils.Constants.CTAData @@ -33,7 +35,14 @@ import com.naviapp.utils.Constants.PL_WEB_URL_HOST_NAME import com.naviapp.utils.Constants.STATE @Composable -fun LoansTabScreen(activity: HomePageActivity, loansTabVm: LoanTabVm = hiltViewModel()) { +fun LoansTabScreen( + activity: HomePageActivity, + loansTabVm: LoanTabVm = hiltViewModel(), + uiController: SystemUiController, +) { + LaunchedEffect(Unit) { + uiController.setStatusBarColor(color = Color.Transparent, darkIcons = true) + } val loansTabHelper by lazy { LoansTabHelper() } LoansTabWebView(loansTabVm, activity, loansTabHelper) } @@ -57,6 +66,7 @@ private fun LoansTabWebView( }, ) } + is AuthTokenState.Success -> { Box(modifier = Modifier.fillMaxSize()) { RenderWebView( diff --git a/android/app/src/main/java/com/naviapp/home/model/HomePrioritySectionData.kt b/android/app/src/main/java/com/naviapp/home/model/HomePrioritySectionData.kt new file mode 100644 index 0000000000..3f624a6650 --- /dev/null +++ b/android/app/src/main/java/com/naviapp/home/model/HomePrioritySectionData.kt @@ -0,0 +1,17 @@ +/* + * + * * Copyright © 2023-2025 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.naviapp.home.model + +import com.navi.common.alchemist.model.AlchemistCollapsingToolbar +import com.navi.common.alchemist.model.AlchemistWidgetModelDefinition +import com.navi.uitron.model.UiTronResponse + +data class HomePrioritySectionData( + val content: List>?, + val topNav: AlchemistCollapsingToolbar? = null, +) diff --git a/android/app/src/main/java/com/naviapp/home/reducer/HomeReducer.kt b/android/app/src/main/java/com/naviapp/home/reducer/HomeReducer.kt index f1cfd1e3f5..a1c7e53523 100644 --- a/android/app/src/main/java/com/naviapp/home/reducer/HomeReducer.kt +++ b/android/app/src/main/java/com/naviapp/home/reducer/HomeReducer.kt @@ -28,6 +28,7 @@ import com.naviapp.common.model.UiTronActionHandler import com.naviapp.home.compose.home.utils.updateScreenContent import com.naviapp.home.compose.model.CtaActionEvent import com.naviapp.home.compose.model.InitiatePaymentFromComposeData +import com.naviapp.home.model.HomePrioritySectionData import com.naviapp.models.response.HomeFeatureResponse class HomeReducer : BaseReducer { @@ -51,7 +52,20 @@ class HomeReducer : BaseReducer { bottomSheets = it.bottomSheets, systemBackCta = it.systemBackCta, renderActions = it.renderActions, - collapsingToolbar = it.collapsingToolbar, + collapsingToolbar = it.collapsingToolbar ?: previousState.collapsingToolbar, + screenMetaData = event.content.screenMetaData, + ) + } ?: previousState.copy(screenMetaData = event.content.screenMetaData) + } + + is HpEvents.UpdateScreenWithoutContentAndTopNav -> { + event.content.screenStructure?.let { + previousState.copy( + header = it.header, + footer = it.footer, + bottomSheets = it.bottomSheets, + systemBackCta = it.systemBackCta, + renderActions = it.renderActions, screenMetaData = event.content.screenMetaData, ) } ?: previousState.copy(screenMetaData = event.content.screenMetaData) @@ -83,6 +97,22 @@ class HomeReducer : BaseReducer { frontLayerContent = updatedList, ) } + is HpEvents.UpdatePrioritySectionData -> { + val updatedList = + updateScreenContent( + renderingFirstTime = previousState.isRenderingFirstTime, + newWidgets = + event.prioritySectionData.content ?: previousState.frontLayerContent, + oldWidgets = previousState.frontLayerContent, + ) + previousState.copy( + isLoading = false, + isError = false, + frontLayerContent = updatedList, + collapsingToolbar = + event.prioritySectionData.topNav ?: previousState.collapsingToolbar, + ) + } is HpEvents.RenderedFirstTime -> { previousState.copy(isRenderingFirstTime = false) } @@ -116,6 +146,9 @@ sealed interface HpEvents : UiEvent { data class UpdateScreenWithoutContent(val content: AlchemistScreenDefinition) : HpEvents + data class UpdateScreenWithoutContentAndTopNav(val content: AlchemistScreenDefinition) : + HpEvents + data class UpdateShadowOnFrontLayer(val showShadowOnFrontLayer: Boolean) : HpEvents data class UpdateScreenContentWidgetRenderState(val id: String, val state: WidgetRenderState) : @@ -127,6 +160,9 @@ sealed interface HpEvents : UiEvent { val content: List> ) : HpEvents + data class UpdatePrioritySectionData(val prioritySectionData: HomePrioritySectionData) : + HpEvents + data object ShowProfile : HpEvents data class UpdateProfileDrawerState(val state: Boolean) : HpEvents @@ -190,4 +226,6 @@ sealed interface HpEffects : UiEffect { data object HomePageUiRenderedEvent : HpEffects data object TopNavRevealedAnalytics : HpEffects + + data class UpdateMastheadIconsState(val alphaFactor: Int) : HpEffects } diff --git a/android/app/src/main/java/com/naviapp/home/usecase/AsyncDeserialization.kt b/android/app/src/main/java/com/naviapp/home/usecase/AsyncDeserialization.kt index e646118c20..ba8f018601 100644 --- a/android/app/src/main/java/com/naviapp/home/usecase/AsyncDeserialization.kt +++ b/android/app/src/main/java/com/naviapp/home/usecase/AsyncDeserialization.kt @@ -9,10 +9,12 @@ package com.naviapp.home.usecase import com.google.gson.Gson import com.google.gson.reflect.TypeToken +import com.navi.common.alchemist.model.AlchemistCollapsingToolbar import com.navi.common.alchemist.model.AlchemistScreenDefinition import com.navi.common.alchemist.model.AlchemistWidgetModelDefinition import com.navi.common.utils.log import com.navi.uitron.model.UiTronResponse +import com.naviapp.home.model.HomePrioritySectionData import com.naviapp.network.di.DataDeserializers import javax.inject.Inject import kotlinx.coroutines.Dispatchers @@ -25,12 +27,18 @@ class AsyncDeserialization @Inject constructor(@DataDeserializers private val de object : TypeToken>() {}.type private var contentArray: JSONArray? = null + private var topNav: JSONObject? = null private var cacheEntity: String? = null + private var isTopNavInPrioritySection: Boolean = false fun setCacheEntity(newCacheEntity: String) { if (cacheEntity != newCacheEntity) { cacheEntity = newCacheEntity contentArray = extractFrontLayerJsonArray(cacheEntity) + extractTopNavDataAndMastheadStatus(cacheEntity).let { (nav, isMastheadEnabled) -> + topNav = nav + isTopNavInPrioritySection = isMastheadEnabled + } } } @@ -40,9 +48,14 @@ class AsyncDeserialization @Inject constructor(@DataDeserializers private val de return getContentInRange(startIndex, endIndex) } - suspend fun getPrioritySection(): List>? { - val endIndex = CHUNK_SIZE.coerceAtMost(contentArray?.length() ?: 0) - return getContentInRange(0, endIndex) + suspend fun getPrioritySection(): HomePrioritySectionData { + val contentLength = contentArray?.length() ?: 0 + val endIndex = CHUNK_SIZE.coerceAtMost(contentLength) + val topNavData = if (isTopNavInPrioritySection) getTopNav() else null + return HomePrioritySectionData( + content = getContentInRange(0, endIndex), + topNav = topNavData, + ) } suspend fun getScreen(cacheEntity: String): AlchemistScreenDefinition { @@ -51,11 +64,18 @@ class AsyncDeserialization @Inject constructor(@DataDeserializers private val de } } - // Here content refers to content in Alchemist screen definition + /** + * Here content refers to content in Alchemist screen definition. This function avoid taking the + * priority section if masthead isEnabled. * + */ suspend fun getScreenDefinitionWithoutContent(): AlchemistScreenDefinition? { return withContext(Dispatchers.Default) { val screenJson = cacheEntity?.let { JSONObject(it) } screenJson?.optJSONObject("screenStructure")?.remove("content") + screenJson + ?.optJSONObject("screenStructure") + ?.takeIf { isTopNavInPrioritySection } + ?.remove("collapsingToolbar") val strippedScreenJson = screenJson.toString() deserializer.fromJson(strippedScreenJson, AlchemistScreenDefinition::class.java) } @@ -74,6 +94,12 @@ class AsyncDeserialization @Inject constructor(@DataDeserializers private val de } } + private suspend fun getTopNav(): AlchemistCollapsingToolbar { + return withContext(Dispatchers.Default) { + deserializer.fromJson(topNav.toString(), AlchemistCollapsingToolbar::class.java) + } + } + private fun extractFrontLayerJsonArray(cacheEntity: String?): JSONArray? { return try { val screenJson = cacheEntity?.let { JSONObject(it) } ?: return null @@ -87,6 +113,24 @@ class AsyncDeserialization @Inject constructor(@DataDeserializers private val de } } + private fun extractTopNavDataAndMastheadStatus( + cacheEntity: String? + ): Pair { + return try { + val screenJson = + cacheEntity + ?.let { JSONObject(it) } + ?.optJSONObject("screenStructure") + ?.optJSONObject("collapsingToolbar") + + val isMastheadEnabled = screenJson?.optBoolean("mastheadEnable", false) ?: false + Pair(screenJson, isMastheadEnabled) + } catch (e: Exception) { + e.log() + Pair(null, false) + } + } + companion object { const val CHUNK_SIZE = 4 } diff --git a/android/app/src/main/java/com/naviapp/home/utils/HomePageUtils.kt b/android/app/src/main/java/com/naviapp/home/utils/HomePageUtils.kt index c66f313e6d..709b47efe8 100644 --- a/android/app/src/main/java/com/naviapp/home/utils/HomePageUtils.kt +++ b/android/app/src/main/java/com/naviapp/home/utils/HomePageUtils.kt @@ -134,6 +134,7 @@ fun HandleUitronRenderer(uiTronResponse: UiTronResponse?, viewModel: BaseVM) { @Composable fun WidgetRenderer( + modifier: Modifier = Modifier, staticNudgeData: StaticNudgeData?, sharedVM: SharedVM, viewModel: ScreenOverlayVM, @@ -147,6 +148,7 @@ fun WidgetRenderer( when (widget.widgetName) { HomeCustomWidgetType.AppUpdateNudge.value -> { HomeAppUpdateWidget( + modifier = modifier, content = widget, appUpdateState = appUpdateState(), inAppUpdateBridge = inAppUpdateBridge, @@ -165,6 +167,7 @@ fun WidgetRenderer( } HomeCustomWidgetType.NotifyMeWidget.value -> { HomeNotifyMeWidget( + modifier = modifier, widget = widget, showBottomSheet = { sharedVM.updateBottomSheetState( diff --git a/android/app/src/main/java/com/naviapp/home/viewmodel/HomeViewModel.kt b/android/app/src/main/java/com/naviapp/home/viewmodel/HomeViewModel.kt index a729a830fc..1f1dea5651 100644 --- a/android/app/src/main/java/com/naviapp/home/viewmodel/HomeViewModel.kt +++ b/android/app/src/main/java/com/naviapp/home/viewmodel/HomeViewModel.kt @@ -262,9 +262,7 @@ constructor( deserializer.setCacheEntity(data.value) viewModelScope .async { - deserializer.getPrioritySection()?.let { - sendEvent(HpEvents.UpdateFrontLayerContent(it)) - } + sendEvent(HpEvents.UpdatePrioritySectionData(deserializer.getPrioritySection())) } .await() viewModelScope 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 0ff56e8a84..520eb1751b 100644 --- a/android/app/src/main/java/com/naviapp/utils/Constants.kt +++ b/android/app/src/main/java/com/naviapp/utils/Constants.kt @@ -270,6 +270,9 @@ object Constants { val DRAG_POSITIONAL_THRESHOLD = 56.dp val DRAG_VELOCITY_THRESHOLD = 125.dp const val SCROLL_FADE = "scroll_fade" + const val SCROLL_THRESHOLD = 60f + const val TOP_NAV_ARC_BACKGROUND = "top_nav_arc_background" + const val ALPHA = "alpha_" } // Home Custom Widget Constants diff --git a/android/navi-common/src/main/java/com/navi/common/alchemist/model/AlchemistScreenDefinition.kt b/android/navi-common/src/main/java/com/navi/common/alchemist/model/AlchemistScreenDefinition.kt index 77d6ce1e1a..c4582dec04 100644 --- a/android/navi-common/src/main/java/com/navi/common/alchemist/model/AlchemistScreenDefinition.kt +++ b/android/navi-common/src/main/java/com/navi/common/alchemist/model/AlchemistScreenDefinition.kt @@ -9,6 +9,7 @@ package com.navi.common.alchemist.model import com.google.gson.annotations.SerializedName import com.navi.common.model.common.CollapsingTopNavConfig +import com.navi.common.model.common.MastheadWidgetData import com.navi.common.model.common.UiTronActionAndResponse import com.navi.common.utils.Constants.DEFAULT_BACKGROUND_COLOR import com.navi.uitron.model.UiTronResponse @@ -64,6 +65,8 @@ data class AlchemistFloatingActionButton( data class AlchemistCollapsingToolbar( val toolBarNav: UiTronActionAndResponse? = null, val collapsingTopNav: UiTronActionAndResponse? = null, + val mastheadWidget: MastheadWidgetData? = null, + val mastheadEnable: Boolean? = null, val collapsingTopNavConfig: CollapsingTopNavConfig? = null, ) diff --git a/android/navi-common/src/main/java/com/navi/common/model/common/MastheadWidgetData.kt b/android/navi-common/src/main/java/com/navi/common/model/common/MastheadWidgetData.kt new file mode 100644 index 0000000000..d65b6381ab --- /dev/null +++ b/android/navi-common/src/main/java/com/navi/common/model/common/MastheadWidgetData.kt @@ -0,0 +1,16 @@ +/* + * + * * Copyright © 2025 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.navi.common.model.common + +data class MastheadWidgetData( + val widgetData: UiTronActionAndResponse? = null, + val backgroundIllustration: UiTronActionAndResponse? = null, + val useLightStatusBar: Boolean = false, + val updateIconsOnScroll: Boolean = false, + val widgetBottomPadding: Int = 16, +) diff --git a/android/navi-widgets/src/main/java/com/navi/naviwidgets/utils/NaviWidgetIconUtils.kt b/android/navi-widgets/src/main/java/com/navi/naviwidgets/utils/NaviWidgetIconUtils.kt index 15551c5866..4ea969f6ef 100644 --- a/android/navi-widgets/src/main/java/com/navi/naviwidgets/utils/NaviWidgetIconUtils.kt +++ b/android/navi-widgets/src/main/java/com/navi/naviwidgets/utils/NaviWidgetIconUtils.kt @@ -235,6 +235,7 @@ object NaviWidgetIconUtils { private const val ARROW_FORWARD_FILLED_PURPLE = "ARROW_FORWARD_FILLED_PURPLE" private const val ARROW_TERTIARY_BLUE = "ARROW_TERTIARY_BLUE" private const val PROFILE_ICON = "PROFILE_ICON" + private const val PROFILE_ICON_WITH_UPI = "PROFILE_ICON_WITH_UPI" private const val YELLOW_ALERT_ICON = "YELLOW_ALERT_ICON" private const val NEW_GREEN_TICK_ICON_LARGE = "NEW_GREEN_TICK_ICON_LARGE" private const val RED_BG_CROSS_LARGE = "RED_BG_CROSS_LARGE" @@ -249,6 +250,7 @@ object NaviWidgetIconUtils { private const val EXPLORE_FUNDS_MAGNIFIER = "EXPLORE_FUNDS_MAGNIFIER" private const val LI_ARROW_RIGHT = "LI_ARROW_RIGHT" private const val IN_APP_NOTIFICATION_ICON = "IN_APP_NOTIFICATION_ICON" + private const val NOTIFICATION_ICON_WITH_BORDER = "NOTIFICATION_ICON_WITH_BORDER" const val ARROW_LEFT_PURPLE = "ARROW_LEFT_PURPLE" const val TRIANGULAR_TIP_BLUE = "TRIANGULAR_TIP_BLUE" const val BULLET_ELLIPSE_GREY = "BULLET_ELLIPSE_GREY" @@ -560,6 +562,7 @@ object NaviWidgetIconUtils { ORANGE_GRADIENT_LOADER_ICON -> R.drawable.ic_orange_gradient_loader ARROW_TERTIARY_BLUE -> R.drawable.ic_blue_chevron_right PROFILE_ICON -> R.drawable.navi_widgets_ic_profile + PROFILE_ICON_WITH_UPI -> R.drawable.ic_profile_with_upi YELLOW_ALERT_ICON -> R.drawable.navi_widgets_ic_yellow_alert WHITE_TICK_GREEN_BG_60 -> R.drawable.ic_green_tick_60 ICON_SINGLE_SELECTED_V2 -> R.drawable.ic_single_selected_v2 @@ -657,6 +660,7 @@ object NaviWidgetIconUtils { NAVI_COIN_GREY -> R.drawable.ic_navi_coin_grey HOLIDAY_SCRATCH_CARD_IMAGE -> R.drawable.ic_christmas_sc REPUBLIC_DAY_SCRATCH_CARD_IMAGE -> R.drawable.ic_republic_day_scratch_card + NOTIFICATION_ICON_WITH_BORDER -> R.drawable.ic_home_notification else -> -1 } } diff --git a/android/navi-widgets/src/main/res/drawable/ic_home_notification.xml b/android/navi-widgets/src/main/res/drawable/ic_home_notification.xml new file mode 100644 index 0000000000..3548a3e748 --- /dev/null +++ b/android/navi-widgets/src/main/res/drawable/ic_home_notification.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/android/navi-widgets/src/main/res/drawable/ic_profile_with_upi.xml b/android/navi-widgets/src/main/res/drawable/ic_profile_with_upi.xml new file mode 100644 index 0000000000..45abf4f326 --- /dev/null +++ b/android/navi-widgets/src/main/res/drawable/ic_profile_with_upi.xml @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +