TP-44454| slide to act button with property and rederer (#217)

This commit is contained in:
Ayushman Sharma
2023-10-23 15:03:45 +05:30
committed by GitHub
parent 14ba0c3006
commit a5dbbe5eda
10 changed files with 650 additions and 1 deletions

View File

@@ -13468,5 +13468,131 @@
}
}
]
},
"slideToActMock": {
"parentComposeView": [
{
"property": {
"layoutId": "slideToActButton",
"viewType": "SlideToActButton",
"hint": "Here is some hint",
"height": "48",
"circleButtonSize": 40,
"margin": {
"start": 16,
"end": 16
},
"shimmerColors": [
"#F0C1FF",
"#F0C1FF",
"#FFFFFF",
"#F0C1FF",
"#F0C1FF"
],
"buttonStateIcon": {
"invalidIcon":
{
"property": {
"layoutId": "invalidStateIcon",
"viewType": "Image",
"height": "24",
"width": "24"
}
},
"validIcon":
{
"property": {
"layoutId": "validStateIcon",
"viewType": "Image",
"height": "24",
"width": "24"
}
},
"completedIcon":
{
"property": {
"layoutId": "completedStateIcon",
"viewType": "Image",
"height": "24",
"width": "24"
}
}
},
"backgroundColorWithState": {
"invalidColor": "#B5ACB9",
"validColor": "#1F002A",
"loadingColor": "#6E5876"
},
"loadingStateLottie": {
"property": {
"layoutId": "loadingLottie",
"viewType": "Lottie",
"height": "WRAP_CONTENT",
"width": "MATCH_PARENT"
}
},
"slideButtonBgColor": {
"invalidColor" : "#E9E8EA",
"validColor" : "#FFFFFF"
},
"clipData": {
"shapeType": "RoundedCornerShape",
"size": 50
},
"slideBoxProperty": {
"margin": {
"start": 4,
"end": 4
},
"clipData": {
"shapeType": "RoundedCornerShape",
"size": 50
},
"contentAlignment": "Center",
"shape": {
"shapeType": "RoundedCornerShape",
"size": 50
}
},
"textProperty": {
"layoutId": "hintText",
"height": "WRAP_CONTENT",
"width": "MATCH_PARENT",
"fontSize": 14,
"textAlign": "Center",
"fontFamily": "ttComposeFontFamily",
"fontWeight": "TT_SEMI_BOLD"
}
}
}
],
"data": {
"invalidStateIcon": {
"viewType": "Image",
"iconUrl": "https://firebasestorage.googleapis.com/v0/b/getslot-ccda7.appspot.com/o/chevron_right_white.jpg?alt=media&token=7deed556-d68b-4167-982c-29003db6c21a&_gl=1*kbkn65*_ga*NTM4NDA3Njc0LjE2OTA4Nzg5NTQ.*_ga_CW55HF8NVT*MTY5NzEwNzQwMS4xNS4xLjE2OTcxMDc0OTcuNjAuMC4w"
},
"validStateIcon": {
"viewType": "Image",
"iconUrl": "https://firebasestorage.googleapis.com/v0/b/getslot-ccda7.appspot.com/o/chevron_right.png?alt=media&token=db8918be-0434-4381-a22f-e86115d9366d&_gl=1*1tuyy3i*_ga*NTM4NDA3Njc0LjE2OTA4Nzg5NTQ.*_ga_CW55HF8NVT*MTY5NzEwNzQwMS4xNS4xLjE2OTcxMDc2MDIuMzEuMC4w"
},
"completedStateIcon": {
"viewType": "Image",
"iconUrl": "https://firebasestorage.googleapis.com/v0/b/getslot-ccda7.appspot.com/o/tickcheck.png?alt=media&token=9a48ce76-4a97-4067-9ce7-e4614736e293&_gl=1*am0qkb*_ga*NTM4NDA3Njc0LjE2OTA4Nzg5NTQ.*_ga_CW55HF8NVT*MTY5NzEwNzQwMS4xNS4xLjE2OTcxMDc1NzMuNjAuMC4w"
},
"loadingLottie": {
"viewType": "Lottie",
"lottieUrl": "https://firebasestorage.googleapis.com/v0/b/getslot-ccda7.appspot.com/o/cta_loader.json?alt=media&token=8984e674-5e9a-48bd-a58f-0ea01f2784ce&_gl=1*9jntik*_ga*NTM4NDA3Njc0LjE2OTA4Nzg5NTQ.*_ga_CW55HF8NVT*MTY5NzE3ODE2MC4xNi4xLjE2OTcxNzgxODkuMzEuMC4w",
"placeholderIcon": "test_icon"
},
"hintText": {
"viewType": "Text",
"text": "Slide to confirm purchase"
},
"slideToActButton": {
"viewType": "SlideToActButton",
"text": "UITron data is here"
}
}
}
}

View File

@@ -136,6 +136,9 @@ class ComposePropertyDeserializer : JsonDeserializer<BaseProperty> {
ComposeViewType.OtpBox.name -> {
context?.deserialize(jsonObject, OtpBoxProperty::class.java)
}
ComposeViewType.SlideToActButton.name -> {
context?.deserialize(jsonObject, SlideToActButtonProperty::class.java)
}
else -> null
}
}

View File

@@ -105,6 +105,9 @@ open class UiTronDataDeserializer : JsonDeserializer<UiTronData> {
ComposeViewType.JackpotTextV2.name -> {
context?.deserialize(jsonObject, JackpotTextData::class.java)
}
ComposeViewType.SlideToActButton.name -> {
context?.deserialize(jsonObject, SlideToActButtonData::class.java)
}
else -> null
}
}

View File

@@ -0,0 +1,19 @@
package com.navi.uitron.model.data
/**
* Copyright © 2022 by Navi Technologies Private Limited
* All rights reserved. Strictly confidential
*/
data class SlideToActButtonData(
var text: String? = null,
var onSlideComplete: UiTronActionData? = null,
var onInitiateButton: UiTronActionData? = null
) : UiTronData() {
fun copyNonNull(data: SlideToActButtonData?): SlideToActButtonData {
text = data?.text
onSlideComplete = data?.onSlideComplete
onInitiateButton = data?.onInitiateButton
return this
}
}

View File

@@ -0,0 +1,52 @@
/*
*
* * Copyright © 2023 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.uitron.model.ui
import com.navi.uitron.render.SlideToActButtonRenderer
data class SlideToActButtonProperty(
var buttonState: String? = SlideToActButtonRenderer.SlideToActState.INVALID.name,
var circleButtonSize: Int? = null,
var buttonStateIcon: SlideToActIconData? = null,
var backgroundColorWithState: SlideToActBackgroundColor? = null,
var fractionalThreshold: Float? = null,
var sliderButtonPadding: ComposePadding? = null,
var shimmerColors: List<String>? = null,
var loadingStateLottie: UiTronView? = null,
var hintContent: UiTronView? = null,
var slideButtonBgColor: SlideButtonBackgroundColor? = null,
var slideBoxProperty: BoxProperty? = null,
var textProperty: TextProperty? = null
) : BaseProperty(){
override fun copyNonNullFrom(property: BaseProperty?) {
super.copyNonNullFrom(property)
val slideToActButtonProperty = property as? SlideToActButtonProperty
slideToActButtonProperty?.buttonStateIcon?.let { buttonStateIcon = it }
slideToActButtonProperty?.backgroundColorWithState?.let { backgroundColorWithState = it }
slideToActButtonProperty?.fractionalThreshold?.let { fractionalThreshold = it }
slideToActButtonProperty?.sliderButtonPadding?.let { sliderButtonPadding = it }
slideToActButtonProperty?.shimmerColors?.let { shimmerColors = it }
slideToActButtonProperty?.loadingStateLottie?.let { loadingStateLottie = it }
slideToActButtonProperty?.hintContent?.let { hintContent = it }
slideToActButtonProperty?.slideButtonBgColor?.let { slideButtonBgColor = it }
slideToActButtonProperty?.slideBoxProperty?.let { slideBoxProperty = it }
slideToActButtonProperty?.textProperty?.let { textProperty = it }
slideToActButtonProperty?.buttonState?.let { buttonState = it }
}
companion object {
const val SLIDER_STATE_SUFFIX = "_slider_state"
}
}
data class SlideToActIconData(val invalidIcon: UiTronView, val validIcon: UiTronView, val completedIcon: UiTronView)
data class SlideToActBackgroundColor(val invalidColor: String?, val validColor: String?, val loadingColor: String?)
data class SlideButtonBackgroundColor(val invalidColor: String?, val validColor: String?)

View File

@@ -229,6 +229,7 @@ enum class ComposeViewType {
AutoScrollView,
CustomTextField,
OtpBox,
SlideToActButton
}
enum class HorizontalArrangementType {

View File

@@ -0,0 +1,420 @@
package com.navi.uitron.render
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.FractionalThreshold
import androidx.compose.material.SwipeableState
import androidx.compose.material.Text
import androidx.compose.material.rememberSwipeableState
import androidx.compose.material.swipeable
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
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.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.layoutId
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.zIndex
import clipContent
import com.navi.uitron.UiTronSdkManager
import com.navi.uitron.model.action.MvelAction
import com.navi.uitron.model.data.SlideToActButtonData
import com.navi.uitron.model.data.UiTronData
import com.navi.uitron.model.ui.SlideToActButtonProperty
import com.navi.uitron.model.ui.UiTronView
import com.navi.uitron.utils.DEFAULT_INVALID_COLOR
import com.navi.uitron.utils.DEFAULT_LOADING_COLOR
import com.navi.uitron.utils.DEFAULT_VALID_COLOR
import com.navi.uitron.utils.KEY_MVEL_ACTION
import com.navi.uitron.utils.KEY_PROPERTY
import com.navi.uitron.utils.KEY_UI_TRON_DATA
import com.navi.uitron.utils.UI_TRON_VM
import com.navi.uitron.viewmodel.UiTronViewModel
import getContentAlignment
import getSliderStateId
import getTextAlignment
import hexToComposeColor
import orFalse
import orTrue
import setBackground
import setHeight
import setPadding
import kotlin.math.roundToInt
class SlideToActButtonRenderer(
private val childrenComposeViews: List<UiTronView>,
private val uiTronData: UiTronData?,
private val uiTronRenderer: UiTronRenderer
) : Renderer<SlideToActButtonProperty> {
private val defaultFontSize = 14.sp
private val defaultButtonSize = 40.dp
private val defaultTargetValue = 2000f
private val defaultFractionalThreshold = 0.5F
private val defaultShadowElevation = 10.dp
private val defaultShimmerAnimationTime = 4000
private val defaultFullVisibility = 1f
private val defaultPartialVisibility = 0.3f
private val defaultNoVisibility = 0f
private val defaultVisibilityTimeOfText = 1000
private val defaultBackgroundColorVisibilityTimer = 500
@Composable
override fun Render(
property: SlideToActButtonProperty,
uiTronData: UiTronData?,
uiTronViewModel: UiTronViewModel,
modifier: Modifier?
){
super.Render(property, uiTronData, uiTronViewModel, modifier)
var uiTronSlideToActButtonData = uiTronData as? SlideToActButtonData
if (property.isStateFul.orFalse()) {
uiTronViewModel.addKeyToSavedStateHandle(property.layoutId.orEmpty())
val viewState = uiTronViewModel.handle.getStateFlow<String?>(
property.getPropertyId(),
null
).collectAsState()
property.copyNonNullFrom(property.statesMap?.get(viewState.value))
}
if(property.isDataMutable.orFalse()){
val dataState = uiTronViewModel.handle.getStateFlow<SlideToActButtonData?>(
property.getDataId(),
null
).collectAsState()
uiTronSlideToActButtonData = uiTronSlideToActButtonData?.copyNonNull(dataState.value) ?: dataState.value
}
val extrasState = uiTronViewModel.handle.getStateFlow<Map<String, Any?>?>(
property.getExtrasId(),
null
).collectAsState()
handleMvelExtra(property.layoutId, extrasState.value, mapOf(
Pair(KEY_PROPERTY, property),
Pair(KEY_UI_TRON_DATA, uiTronSlideToActButtonData),
Pair(KEY_MVEL_ACTION, extrasState.value?.get(MvelAction.KEY_MVEL) as? MvelAction),
Pair(UI_TRON_VM, uiTronViewModel)
))
SwipeButton(
modifier= Modifier
.fillMaxWidth()
.setHeight(property.height)
.setPadding(property.margin)
.clipContent(property.clipData)
,
onSwipe = {
uiTronViewModel.handleActions(uiTronSlideToActButtonData?.onSlideComplete)
},
property = property,
uiTronData = uiTronSlideToActButtonData,
uiTronViewModel = uiTronViewModel
)
}
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun SwipeButton(
modifier: Modifier = Modifier,
onSwipe: () -> Unit,
property: SlideToActButtonProperty,
uiTronData: SlideToActButtonData?,
uiTronViewModel: UiTronViewModel,
) {
var size by remember {
mutableStateOf(IntSize.Zero)
}
val density = LocalDensity.current.density
val widthInPx = with(LocalDensity.current) {
(
(size.width/density).dp -
(((property.circleButtonSize ?: defaultButtonSize.value.roundToInt())) +
((property.slideBoxProperty?.margin?.start?: 0)*2)).dp).toPx()
}
val anchors = mapOf(
0F to 0,
widthInPx to 1,
)
val swipeableState = rememberSwipeableState(0)
val (swipeComplete, setSwipeComplete) = remember {
mutableStateOf(false)
}
val sliderState = uiTronViewModel.handle.getStateFlow<String?>(
property.getPropertyId().getSliderStateId(),
SlideToActState.INVALID.name
).collectAsState()
var showShimmer by remember {
mutableStateOf(false)
}
when(property.buttonState){
SlideToActState.INVALID.name -> {
uiTronViewModel.handle[property.getPropertyId().getSliderStateId()] = SlideToActState.INVALID.name
showShimmer = false
}
SlideToActState.READY.name -> {
uiTronViewModel.handle[property.getPropertyId().getSliderStateId()] = SlideToActState.READY.name
showShimmer = true
}
SlideToActState.LOADING.name -> {
uiTronViewModel.handle[property.getPropertyId().getSliderStateId()] = SlideToActState.LOADING.name
}
SlideToActState.COMPLETED.name -> {
uiTronViewModel.handle[property.getPropertyId().getSliderStateId()] = SlideToActState.COMPLETED.name
}
else -> {
uiTronViewModel.handle[property.getPropertyId().getSliderStateId()] = SlideToActState.INVALID.name
showShimmer = false
}
}
val visibility by animateFloatAsState(
targetValue = if(swipeableState.offset.value.roundToInt()<(widthInPx*0.4)){
defaultFullVisibility
} else if(sliderState.value == SlideToActState.LOADING.name){
defaultNoVisibility
} else{
defaultPartialVisibility
},
label = "",
animationSpec = tween(
durationMillis = defaultVisibilityTimeOfText)
)
val backgroundColor by animateColorAsState(
targetValue = when(sliderState.value) {
SlideToActState.INVALID.name -> property.backgroundColorWithState?.invalidColor?.hexToComposeColor ?: DEFAULT_INVALID_COLOR.hexToComposeColor
SlideToActState.READY.name -> property.backgroundColorWithState?.validColor?.hexToComposeColor?: DEFAULT_VALID_COLOR.hexToComposeColor
SlideToActState.LOADING.name -> property.backgroundColorWithState?.loadingColor?.hexToComposeColor ?: DEFAULT_LOADING_COLOR.hexToComposeColor
SlideToActState.COMPLETED.name -> property.backgroundColorWithState?.validColor?.hexToComposeColor?: DEFAULT_VALID_COLOR.hexToComposeColor
else -> property.backgroundColorWithState?.invalidColor?.hexToComposeColor ?: DEFAULT_INVALID_COLOR.hexToComposeColor
},
label = "",
animationSpec = tween(
durationMillis = defaultBackgroundColorVisibilityTimer
)
)
LaunchedEffect(
key1 = swipeableState.currentValue,
) {
if (swipeableState.currentValue == 1) {
setSwipeComplete(true)
onSwipe()
}
}
Box(
contentAlignment = Alignment.Center,
modifier = modifier
.onGloballyPositioned {
size = it.size
}
.background(backgroundColor)
.setPadding(property.padding)
) {
SwipeRight(
modifier = Modifier
.align(Alignment.CenterStart)
.offset {
IntOffset(swipeableState.offset.value.roundToInt(), 0)
}
.swipeable(
state = swipeableState,
anchors = anchors,
thresholds = { _, _ ->
FractionalThreshold(property.fractionalThreshold ?: defaultFractionalThreshold)
},
orientation = Orientation.Horizontal,
enabled = (swipeableState.currentValue != 1 && sliderState.value != SlideToActState.INVALID.name)
)
.setPadding(property.slideBoxProperty?.margin)
.zIndex(2f)
,
sliderState.value ?: SlideToActState.INVALID.name,
swipeableState,
widthInPx,
property
)
Text(
text = uiTronData?.text.orEmpty(),
textAlign = getTextAlignment(property.textProperty?.textAlign),
fontFamily = UiTronSdkManager.getDependencyProvider()
.getFontFamily(property.textProperty?.fontFamily),
fontWeight = UiTronSdkManager.getDependencyProvider()
.getFontWeight(property.textProperty?.fontWeight),
fontSize = property.textProperty?.fontSize?.sp ?: defaultFontSize,
modifier = Modifier
.fillMaxWidth()
.setHeight(property.textProperty?.height)
.setPadding(property.textProperty?.margin)
.setBackground(
property.textProperty?.backgroundColor,
property.textProperty?.shape,
property.textProperty?.backGroundBrushData
)
.setPadding(property.textProperty?.padding)
.layoutId(property.layoutId.orEmpty())
.alpha(visibility),
style = TextStyle(
brush = shimmerBrush(showShimmer = showShimmer, property.shimmerColors)
)
)
AnimatedVisibility(
visible = (swipeComplete && property.buttonState?.equals(SlideToActState.COMPLETED.name).orTrue().not()),
enter = fadeIn(),
exit = fadeOut()
) {
uiTronViewModel.handle[property.getPropertyId().getSliderStateId()] = SlideToActState.LOADING.name
property.loadingStateLottie?.let {
uiTronRenderer.Render(composeViews = listOf(it))
}
}
}
}
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun SwipeRight(
modifier: Modifier = Modifier,
sliderState: String,
swipeableState: SwipeableState<Int>,
width: Float,
property: SlideToActButtonProperty,
) {
val fadeIn by animateFloatAsState(
targetValue = swipeableState.offset.value.roundToInt()/width
, label = ""
)
val fadeOut by animateFloatAsState(
targetValue = 1f - swipeableState.offset.value.roundToInt()/width
, label = ""
)
Box(
contentAlignment = getContentAlignment(contentAlignment = property.slideBoxProperty?.contentAlignment),
modifier = modifier
.size(property.circleButtonSize?.dp ?: defaultButtonSize)
.shadow(
elevation = defaultShadowElevation,
shape = CircleShape,
spotColor = Color.Black
)
.setBackground(
if (sliderState == SlideToActState.INVALID.name) {
property.slideButtonBgColor?.invalidColor
} else {
property.slideButtonBgColor?.validColor
},
property.slideBoxProperty?.shape,
property.slideBoxProperty?.backGroundBrushData
)
.clip(CircleShape)
.setPadding(property.slideBoxProperty?.padding),
) {
AnimatedVisibility(visible = sliderState == SlideToActState.INVALID.name,
enter = fadeIn(),
exit = fadeOut()
) {
property.buttonStateIcon?.invalidIcon?.let {
uiTronRenderer.Render(composeViews = listOf(it))
}
}
AnimatedVisibility(visible = sliderState == SlideToActState.READY.name,
enter = fadeIn(),
exit = fadeOut()
) {
property.buttonStateIcon?.validIcon?.let {
it.property?.alpha = fadeOut
uiTronRenderer.Render(composeViews = listOf(it))
}
}
property.buttonStateIcon?.completedIcon?.let {
it.property?.alpha = fadeIn
uiTronRenderer.Render(composeViews = listOf(it))
}
}
}
@Composable
fun shimmerBrush(showShimmer: Boolean = true, shimmerColors: List<String>?, targetValue:Float = defaultTargetValue): Brush {
return if (showShimmer && shimmerColors.isNullOrEmpty().not()) {
var shimmerColorList = listOf<Color>()
shimmerColors?.let {
shimmerColorList = shimmerColors.map {
it.hexToComposeColor
}
}
val transition = rememberInfiniteTransition(label = "")
val translateAnimation = transition.animateFloat(
initialValue = 0f,
targetValue = targetValue,
animationSpec = infiniteRepeatable(
animation = tween(defaultShimmerAnimationTime),
repeatMode = RepeatMode.Restart
),
label = ""
)
Brush.linearGradient(
colors = shimmerColorList,
start = Offset.Zero,
end = Offset(x = translateAnimation.value, y = translateAnimation.value)
)
} else {
Brush.linearGradient(
colors = listOf(Color.White, Color.White),
start = Offset.Zero,
end = Offset.Zero
)
}
}
enum class SlideToActState{
INVALID,
READY,
LOADING,
COMPLETED
}
}

View File

@@ -489,6 +489,25 @@ class UiTronRenderer(
)
}
}
ComposeViewType.SlideToActButton.name -> {
(composeView.property as? SlideToActButtonProperty)?.let {
val initialData = dataMap?.getOrElse(
it.layoutId.orEmpty()
){ null }
SlideToActButtonRenderer(
childrenComposeViews = composeView.childrenViews.orEmpty(),
uiTronData = dataMap?.getOrElse(it.layoutId.orEmpty()) {
null
},
uiTronRenderer = this
).Render(
property = it,
uiTronData = initialData,
uiTronViewModel = uiTronViewModel,
modifier = modifier
)
}
}
}
}
}

View File

@@ -23,4 +23,7 @@ const val RESULT = "result"
const val CUSTOM_TEXT_FIELD_DATA ="customTextFieldData"
const val CUSTOM_TEXT_FIELD_PROPERTY ="customTextFieldProperty"
const val UI_TRON_VM ="uiTronVM"
const val HIDE = "HIDE"
const val HIDE = "HIDE"
const val DEFAULT_INVALID_COLOR = "#B5ACB9"
const val DEFAULT_VALID_COLOR = "#1F002A"
const val DEFAULT_LOADING_COLOR = "#6E5876"

View File

@@ -54,6 +54,7 @@ import com.navi.uitron.model.ui.BaseProperty.Companion.DATA_SUFFIX
import com.navi.uitron.model.ui.BaseProperty.Companion.EXTRAS_SUFFIX
import com.navi.uitron.model.ui.BaseProperty.Companion.INPUT_SUFFIX
import com.navi.uitron.model.ui.BaseProperty.Companion.PROPERTY_SUFFIX
import com.navi.uitron.model.ui.SlideToActButtonProperty.Companion.SLIDER_STATE_SUFFIX
import com.navi.uitron.utils.*
import com.navi.uitron.utils.transformations.*
import kotlinx.coroutines.flow.MutableSharedFlow
@@ -700,6 +701,8 @@ fun String?.getInputId() = this.orEmpty() + INPUT_SUFFIX
fun String?.getExtrasId() = this.orEmpty() + EXTRAS_SUFFIX
fun String?.getSliderStateId() = this.orEmpty() + SLIDER_STATE_SUFFIX
fun Modifier.conditional(condition : Boolean, modifier : Modifier.() -> Modifier) : Modifier {
return if (condition) {