TP-44454| slide to act button with property and rederer (#217)
This commit is contained in:
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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?)
|
||||
@@ -229,6 +229,7 @@ enum class ComposeViewType {
|
||||
AutoScrollView,
|
||||
CustomTextField,
|
||||
OtpBox,
|
||||
SlideToActButton
|
||||
}
|
||||
|
||||
enum class HorizontalArrangementType {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user