TP-72348 | Neil | Profile Screen OneProfile animation and drawer swipability changes (#11696)

This commit is contained in:
Neil Mehta
2024-07-04 15:22:29 +05:30
committed by GitHub
parent 8ea61ea7ab
commit 5eb0c6f894
4 changed files with 15 additions and 168 deletions

View File

@@ -8,11 +8,8 @@
package com.naviapp.home.compose.profile
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateColor
import androidx.compose.animation.core.CubicBezierEasing
import androidx.compose.animation.core.animateDp
import androidx.compose.animation.core.tween
import androidx.compose.animation.core.updateTransition
import androidx.compose.animation.expandVertically
import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.ExperimentalFoundationApi
@@ -23,7 +20,6 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.foundation.rememberScrollState
@@ -32,22 +28,13 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.State
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.navi.base.utils.orTrue
import com.navi.common.ui.compose.DrawerState
@@ -57,19 +44,11 @@ import com.navi.uitron.utils.hexToComposeColor
import com.navi.uitron.utils.orFalse
import com.naviapp.forge.model.WidgetModelDefinition
import com.naviapp.home.compose.activity.HomePageActivity
import com.naviapp.home.compose.model.ContainerProperty
import com.naviapp.home.compose.model.ProfileHeaderTransitionData
import com.naviapp.home.compose.model.ProfileHeaderWidgetData
import com.naviapp.home.ui.state.ProfileScreenState
import com.naviapp.home.viewmodel.ProfileVM
import com.naviapp.home.viewmodel.SharedVM
import com.naviapp.utils.Constants.AnimationLabels.PROFILE_ANIMATION
import com.naviapp.utils.Constants.AnimationLabels.PROFILE_BACKGROUND_COLOR_ANIMATION
import com.naviapp.utils.Constants.AnimationLabels.PROFILE_CORNER_SHAPE_ANIMATION
import com.naviapp.utils.Constants.AnimationLabels.PROFILE_PADDING_ANIMATION
import com.naviapp.utils.Constants.DEFAULT_PROFILE_BACKGROUND_COLOR
import com.naviapp.utils.Constants.PROFILE
import com.naviapp.utils.Constants.PROFILE_DEFAULT_ANIMATION_TIME
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
@Composable
@@ -129,8 +108,7 @@ fun ProfileScreen(
ProfileScreenWidgetRenderer(
widget = it,
viewModel = profileVM,
drawerState = drawerState,
scrollState = { scrollState },
drawerState = drawerState
)
}
@@ -142,8 +120,7 @@ fun ProfileScreen(
ProfileScreenWidgetRenderer(
widget = widget,
viewModel = profileVM,
drawerState = drawerState,
scrollState = { scrollState },
drawerState = drawerState
)
}
}
@@ -161,28 +138,11 @@ fun AnimatedProfileContent(
content: WidgetModelDefinition<UiTronResponse>,
viewModel: ProfileVM,
drawerState: () -> DrawerState,
scrollState: () -> ScrollState
) {
val data = content.widgetData?.data?.get(PROFILE) as? ProfileHeaderWidgetData
val toolTipVisibility by remember {
derivedStateOf {
scrollState().value <=
(data?.containerProperty?.scrollPercentage ?: 0.05f) * scrollState().maxValue
}
}
val transitionData = getTransitionState(data?.containerProperty) { toolTipVisibility }
Column(
modifier =
Modifier
// Used drawBehind to save recomposition when
// transitionData.animatedBackGroundColor.value changes
.drawBehind { drawRect(color = transitionData.animatedBackGroundColor.value) }
.statusBarsPadding()
) {
Column(modifier = Modifier.background(Color.White).statusBarsPadding()) {
UiTronRenderer(data?.profileDetailsView?.data, viewModel)
.Render(composeViews = data?.profileDetailsView?.parentComposeView.orEmpty())
if (data?.oneProfileData?.isVisible.orFalse()) {
@@ -208,135 +168,24 @@ fun AnimatedProfileContent(
),
exit = shrinkVertically(shrinkTowards = Alignment.Top, animationSpec = tween(100)),
) {
Column(
modifier =
Modifier.padding(
horizontal = transitionData.animatedPadding.value,
)
.fillMaxWidth()
) {
AnimatedVisibility(
visible = toolTipVisibility,
enter =
expandVertically(
expandFrom = Alignment.Top,
animationSpec = tween(PROFILE_DEFAULT_ANIMATION_TIME)
),
exit =
shrinkVertically(
shrinkTowards = Alignment.Top,
animationSpec = tween(PROFILE_DEFAULT_ANIMATION_TIME)
),
) {
UiTronRenderer(data?.toolTipIconView?.data, viewModel)
.Render(
composeViews = data?.toolTipIconView?.parentComposeView.orEmpty()
)
}
OneProfileItem(
data = data,
animatedCornerShape = transitionData.animatedCornerShape,
viewModel = viewModel
)
}
OneProfileItem(data = data, viewModel = viewModel)
}
}
}
}
@Composable
private fun OneProfileItem(
data: ProfileHeaderWidgetData?,
animatedCornerShape: State<Dp>,
viewModel: ProfileVM
) {
private fun OneProfileItem(data: ProfileHeaderWidgetData?, viewModel: ProfileVM) {
Column(
Modifier.fillMaxWidth()
// Used drawBehind to save recomposition when animatedCornerShape.value changes
.drawBehind {
// Draw the rounded corner shape
drawRoundRect(
color = data?.oneProfileData?.backGroundColor?.hexToComposeColor ?: Color.White,
cornerRadius = CornerRadius(animatedCornerShape.value.toPx())
)
// Draw the border stroke
data?.oneProfileData?.borderStrokeData?.let {
val borderWidth = (it.width ?: 1f).dp.toPx()
drawRoundRect(
color = it.color?.hexToComposeColor ?: Color.Black,
cornerRadius = CornerRadius(animatedCornerShape.value.toPx()),
style = Stroke(borderWidth),
// Reduced the total size to draw the border inside the view
size =
Size(
height = size.height - borderWidth,
width = size.width - borderWidth
),
// Offset the border to be drawn inside the view to avoid misalignment
topLeft = Offset(borderWidth.div(2), borderWidth.div(2)),
)
}
}
modifier =
Modifier.fillMaxWidth()
.background(data?.oneProfileData?.backGroundColor?.hexToComposeColor ?: Color.White)
) {
UiTronRenderer(data?.oneProfileView?.data, viewModel)
.Render(composeViews = data?.oneProfileView?.parentComposeView.orEmpty())
}
}
@Composable
private fun getTransitionState(
animateData: ContainerProperty?,
toolTipVisibility: () -> Boolean
): ProfileHeaderTransitionData {
val transition = updateTransition(targetState = toolTipVisibility(), label = PROFILE_ANIMATION)
val animatedPadding =
transition.animateDp(
label = PROFILE_PADDING_ANIMATION,
transitionSpec = { tween(PROFILE_DEFAULT_ANIMATION_TIME) }
) { state ->
when (state) {
true -> animateData?.horizontalPadding?.dp ?: 16.dp
false -> 0.dp
}
}
val animatedCornerShape =
transition.animateDp(
label = PROFILE_CORNER_SHAPE_ANIMATION,
transitionSpec = { tween(PROFILE_DEFAULT_ANIMATION_TIME) }
) { state ->
when (state) {
true -> animateData?.cornerSize?.dp ?: 4.dp
false -> 0.dp
}
}
val animatedBackGroundColor =
transition.animateColor(
label = PROFILE_BACKGROUND_COLOR_ANIMATION,
transitionSpec = { tween(PROFILE_DEFAULT_ANIMATION_TIME) }
) { state ->
when (state) {
true ->
(animateData?.backGroundColor ?: DEFAULT_PROFILE_BACKGROUND_COLOR)
.hexToComposeColor
false -> Color.White
}
}
return remember(transition) {
ProfileHeaderTransitionData(
animatedPadding = animatedPadding,
animatedCornerShape = animatedCornerShape,
animatedBackGroundColor = animatedBackGroundColor
)
}
}
@Composable
private fun Content(
scrollState: () -> ScrollState,

View File

@@ -7,7 +7,6 @@
package com.naviapp.home.compose.profile
import androidx.compose.foundation.ScrollState
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable
import com.navi.common.ui.compose.DrawerState
@@ -25,7 +24,6 @@ fun ProfileScreenWidgetRenderer(
widget: WidgetModelDefinition<UiTronResponse>?,
viewModel: ProfileVM,
drawerState: () -> DrawerState,
scrollState: () -> ScrollState,
) {
if (widget == null) return
return when (widget.widgetType) {
@@ -39,7 +37,7 @@ fun ProfileScreenWidgetRenderer(
WidgetTypes.NATIVE_WIDGET.name -> {
when (widget.widgetName) {
HomeScreenCustomWidgetType.PROFILE_HEADER_WIDGET.name ->
AnimatedProfileContent(widget, viewModel, drawerState, scrollState)
AnimatedProfileContent(widget, viewModel, drawerState)
HomeScreenCustomWidgetType.UPI_SETTINGS_WIDGET.name -> UPISettingSDK(drawerState)
else -> Unit
}

View File

@@ -29,10 +29,10 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.constraintlayout.compose.ConstraintLayout
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.navi.design.R as DesignR
import com.navi.design.font.FontWeightEnum
import com.navi.design.theme.getFontWeight
import com.navi.design.theme.ttComposeFontFamily
import com.navi.naviwidgets.R as NaviWidgetsR
import com.navi.pay.utils.noRippleClickable
import com.naviapp.R
import com.naviapp.analytics.utils.NaviAnalytics
@@ -95,19 +95,19 @@ fun NotificationScreenRenderer(
@Composable
fun NotificationScreenHeaderRenderer(activity: Activity) {
ConstraintLayout(modifier = Modifier.fillMaxWidth().padding(16.dp)) {
val (closeIcon, title) = createRefs()
val (backIcon, title) = createRefs()
Image(
modifier =
Modifier.width(24.dp)
.height(24.dp)
.constrainAs(closeIcon) {
.constrainAs(backIcon) {
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
start.linkTo(parent.start)
}
.noRippleClickable { activity.onBackPressed() },
painter = painterResource(id = DesignR.drawable.ic_close_purple),
contentDescription = "Close Icon"
painter = painterResource(id = NaviWidgetsR.drawable.arrow_left_purple),
contentDescription = "Back Icon"
)
Text(
modifier =

View File

@@ -206,7 +206,7 @@ fun NaviModalNavigationDrawer(
anchors = anchors,
thresholds = { _, _ -> FractionalThreshold(0.5f) },
orientation = Orientation.Horizontal,
enabled = drawerState().isOpen,
enabled = false,
reverseDirection = isRtl,
velocityThreshold = DrawerVelocityThreshold,
resistance = null