Tp-67619 showing red dot on nav bar tabs super app (#10996)

Co-authored-by: abhinavgupta <abhinav.g@navi.com>
This commit is contained in:
Hitesh Kumar
2024-05-23 17:20:17 +05:30
committed by GitHub
parent 15f98a0cf8
commit c8ec44d61c
8 changed files with 116 additions and 15 deletions

View File

@@ -53,6 +53,7 @@ fun BottomBarWithFabButton(
val bottomStickyNudgeData by bottomNavBarVM.bottomStickyNudgeData.collectAsState()
val showBottomBar by homeVM.showBottomBar.collectAsState()
val showSnackBar by homeVM.showHomeScreenSnackBar.collectAsStateWithLifecycle()
val bottomNavBarState by sharedVM.bottomNavBarStateHolder.collectAsStateWithLifecycle()
LaunchedEffect(key1 = expanded) {
if (showBottomBar) {
@@ -106,7 +107,8 @@ fun BottomBarWithFabButton(
}
AnimatedBottomBar(
visible = expanded || selectedTabId != BottomBarTabType.HOME.name || showBottomBar,
selectedTabId = selectedTabId
selectedTabId = selectedTabId,
bottomNavBarState = bottomNavBarState
) { tabId ->
onTabClick(
selectedTabId = selectedTabId,

View File

@@ -12,12 +12,16 @@ import androidx.compose.animation.expandVertically
import androidx.compose.animation.shrinkVertically
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.BottomAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
@@ -26,6 +30,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.navi.pay.utils.noRippleClickable
import com.naviapp.home.model.BottomNavBarStateHolder
import com.naviapp.home.utils.DrawIcon
import com.naviapp.home.utils.TabText
import com.naviapp.utils.BottomBarUtils
@@ -34,19 +39,28 @@ import com.naviapp.utils.BottomBarUtils
fun AnimatedBottomBar(
visible: Boolean,
selectedTabId: String,
onTabSelected: (String) -> Unit,
bottomNavBarState: BottomNavBarStateHolder,
onTabSelected: (String) -> Unit
) {
AnimatedVisibility(
visible = visible,
enter = slideInVertically { it } + expandVertically(clip = false) { 0 },
exit = slideOutVertically { it } + shrinkVertically(clip = false) { 0 }
) {
BottomBar(selectedTabId = selectedTabId, onTabSelected = onTabSelected)
BottomBar(
selectedTabId = selectedTabId,
onTabSelected = onTabSelected,
bottomNavBarState = bottomNavBarState
)
}
}
@Composable
fun BottomBar(selectedTabId: String, onTabSelected: (String) -> Unit) {
fun BottomBar(
selectedTabId: String,
onTabSelected: (String) -> Unit,
bottomNavBarState: BottomNavBarStateHolder
) {
BottomAppBar(
modifier = Modifier.navigationBarsPadding(),
backgroundColor = Color.White,
@@ -58,33 +72,55 @@ fun BottomBar(selectedTabId: String, onTabSelected: (String) -> Unit) {
modifier = Modifier.weight(1f),
item = bottomTabItem,
selectedTabId = selectedTabId,
onTabSelected = onTabSelected
onTabSelected = onTabSelected,
showRedDotBadge = isRedDotBadgeEnabled(bottomTabItem.tabId, bottomNavBarState)
)
}
}
}
fun isRedDotBadgeEnabled(tabId: String, bottomNavRedDotState: BottomNavBarStateHolder): Boolean {
val item = bottomNavRedDotState.items[tabId] ?: return false
return if (item.isTabClicked) {
false
} else {
item.showRedDotBadge
}
}
@Composable
private fun BottomBarItem(
modifier: Modifier,
item: NavigationItem,
selectedTabId: String,
onTabSelected: (String) -> Unit,
showRedDotBadge: Boolean
) {
item.tabId.let {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier.noRippleClickable { onTabSelected(it) }
) {
DrawIcon(
drawableIconId =
BottomBarUtils.fetchDefaultTabIconResourceId(
selectedTabId = selectedTabId,
tabId = it
),
content = selectedTabId,
modifier = Modifier.size(24.dp)
)
Box {
DrawIcon(
drawableIconId =
BottomBarUtils.fetchDefaultTabIconResourceId(
selectedTabId = selectedTabId,
tabId = it
),
content = selectedTabId,
modifier = Modifier.size(24.dp)
)
if (showRedDotBadge) {
Box(
modifier =
Modifier.size(8.dp)
.align(Alignment.TopEnd)
.offset(x = 4.dp, y = (-4).dp)
.background(Color.Red, shape = CircleShape)
)
}
}
Spacer(modifier = Modifier.height(4.dp))
TabText(
selectedTabId = selectedTabId,

View File

@@ -30,3 +30,11 @@ fun getDefaultBottomTabsList() =
NavigationItem.Loan,
NavigationItem.Insurance
)
fun getNavigationItemsList(): List<String> =
listOf(
NavigationItem.Home.tabId,
NavigationItem.Investment.tabId,
NavigationItem.Loan.tabId,
NavigationItem.Insurance.tabId
)

View File

@@ -46,5 +46,6 @@ fun onTabClick(
restoreState = true
}
sharedVM.updateSelectedTabId(tabId)
sharedVM.updateBottomNavBarState(tabId = tabId, isTabClicked = true)
}
}

View File

@@ -158,6 +158,12 @@ fun InitHomeScreenComponents(
activity,
nowBottomSheetListener
)
extraData.bottomNavBarDetails?.entries?.forEach { (key, value) ->
sharedVM.updateBottomNavBarState(
tabId = key,
showRedDotBadge = value.showRedDot
)
}
}
}
}

View File

@@ -0,0 +1,15 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.naviapp.home.model
data class BottomNavBarStateHolder(val items: Map<String, BottomNavBarItemData> = mapOf())
data class BottomNavBarItemData(
val isTabClicked: Boolean = false,
val showRedDotBadge: Boolean = false,
)

View File

@@ -11,7 +11,10 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.navi.common.viewmodel.BaseVM
import com.naviapp.common.model.UiTronActionHandler
import com.naviapp.home.compose.components.getNavigationItemsList
import com.naviapp.home.model.BottomBarTabType
import com.naviapp.home.model.BottomNavBarItemData
import com.naviapp.home.model.BottomNavBarStateHolder
import com.naviapp.utils.Constants
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
@@ -37,6 +40,14 @@ class SharedVM @Inject constructor() : BaseVM() {
private val _showBottomSheet = MutableStateFlow(false)
val showBottomSheet = _showBottomSheet.asStateFlow()
private val _bottomNavBarStateHolder =
MutableStateFlow(
BottomNavBarStateHolder(
items = getNavigationItemsList().associateWith { BottomNavBarItemData() }
)
)
val bottomNavBarStateHolder = _bottomNavBarStateHolder.asStateFlow()
fun updateUiTronAction(uiTronActionHandler: UiTronActionHandler?) {
_uiTronActionHandler.update { uiTronActionHandler }
}
@@ -56,4 +67,20 @@ class SharedVM @Inject constructor() : BaseVM() {
fun setBottomSheetState(show: Boolean) {
viewModelScope.launch { _showBottomSheet.emit(show) }
}
fun updateBottomNavBarState(
tabId: String,
isTabClicked: Boolean? = null,
showRedDotBadge: Boolean? = null
) {
val currentState = _bottomNavBarStateHolder.value.items.toMutableMap()
currentState[tabId]?.let {
currentState[tabId] =
BottomNavBarItemData(
isTabClicked = isTabClicked ?: it.isTabClicked,
showRedDotBadge = showRedDotBadge ?: it.showRedDotBadge
)
}
_bottomNavBarStateHolder.update { BottomNavBarStateHolder(currentState) }
}
}

View File

@@ -1,6 +1,6 @@
/*
*
* * Copyright © 2023 by Navi Technologies Limited
* * Copyright © 2023-2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
@@ -95,8 +95,14 @@ data class ExtraDataDetails(
@SerializedName("sipInfo") val sipInfo: SipInfo? = null,
@SerializedName("loaderScreen") val loaderScreen: ActionCheckResponse? = null,
@SerializedName("isUserInvested") val isUserInvested: Boolean? = null,
@SerializedName("bottomNavBarDetails")
val bottomNavBarDetails: Map<String, BottomNavBarItemInfo>? = null,
) : Parcelable
@Parcelize
data class BottomNavBarItemInfo(@SerializedName("showRedDot") val showRedDot: Boolean? = null) :
Parcelable
@Parcelize data class CacheConfig(val ttl: Long? = 0, val maxConsumptions: Int? = 0) : Parcelable
@Parcelize