Created
October 10, 2021 08:20
-
-
Save ch8n/ad2f3ff524c67bb9218efb1ce18c93bc to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.proptiger.ui.components.edittext | |
import androidx.compose.animation.ExperimentalAnimationApi | |
import androidx.compose.foundation.layout.* | |
import androidx.compose.foundation.text.BasicTextField | |
import androidx.compose.material.Divider | |
import androidx.compose.material.Icon | |
import androidx.compose.material.MaterialTheme | |
import androidx.compose.material.Text | |
import androidx.compose.material.icons.Icons | |
import androidx.compose.material.icons.filled.CheckCircle | |
import androidx.compose.material.icons.filled.Error | |
import androidx.compose.runtime.* | |
import androidx.compose.ui.Alignment | |
import androidx.compose.ui.Modifier | |
import androidx.compose.ui.focus.FocusState | |
import androidx.compose.ui.focus.onFocusEvent | |
import androidx.compose.ui.graphics.Color | |
import androidx.compose.ui.text.input.TextFieldValue | |
import androidx.compose.ui.tooling.preview.Preview | |
import androidx.compose.ui.unit.dp | |
import com.proptiger.R | |
import com.proptiger.ui.components.utils.Preview | |
import com.proptiger.ui.theme.textStyle18spSemibold | |
data class EditTextState( | |
val hint: String, | |
val isError: Boolean, | |
val maxLines: Int = 1, | |
val tailingResId: Int, | |
val errorResId: Int, | |
val errorMessage: String = "Something Went Wrong!", | |
val isValid: Boolean = false | |
) | |
@ExperimentalAnimationApi | |
@Composable | |
fun PTEditText( | |
state: State<EditTextState>, | |
onTextChanged: (String) -> Unit = {}, | |
onFocusChanged: (isFocused: Boolean) -> Unit = {}, | |
) { | |
Column( | |
modifier = Modifier | |
.fillMaxWidth() | |
.padding(start = 16.dp, end = 16.dp) | |
.height(75.dp) | |
) { | |
var editTextValue by remember { mutableStateOf(TextFieldValue("")) } | |
var isHintVisible by remember { mutableStateOf(false) } | |
var isEditTextFocused by remember { mutableStateOf(false) } | |
if (isHintVisible) { | |
Text( | |
text = state.value.hint, | |
style = MaterialTheme.typography.body2, | |
color = if (state.value.isError) { | |
Color.Red | |
} else { | |
Color.Unspecified | |
} | |
) | |
Spacer(modifier = Modifier.height(5.dp)) | |
} else { | |
Spacer( | |
modifier = Modifier | |
.width(200.dp) | |
.height(19.dp) | |
) | |
} | |
Box( | |
modifier = Modifier | |
.fillMaxWidth() | |
.wrapContentHeight(), | |
contentAlignment = Alignment.Center | |
) { | |
BasicTextField( | |
value = editTextValue, | |
onValueChange = { | |
editTextValue = it | |
onTextChanged.invoke(it.text) | |
}, | |
modifier = Modifier | |
.fillMaxWidth() | |
.wrapContentHeight() | |
.onFocusEvent { ft: FocusState -> | |
if (ft.isFocused) { | |
isHintVisible = true | |
} | |
isEditTextFocused = ft.isFocused | |
onFocusChanged.invoke(ft.isFocused) | |
}, | |
singleLine = state.value.maxLines == 1, | |
maxLines = state.value.maxLines, | |
decorationBox = { innerTextField -> | |
Row( | |
verticalAlignment = Alignment.CenterVertically | |
) { | |
if (editTextValue.text.isEmpty()) { | |
isHintVisible = false | |
if (!isEditTextFocused) { | |
Text( | |
text = state.value.hint, | |
style = MaterialTheme.typography.body2, | |
color = if (state.value.isError) { | |
Color.Red | |
} else { | |
Color.Unspecified | |
}, | |
) | |
} | |
} | |
innerTextField() //<-- Add this | |
} | |
}, | |
textStyle = textStyle18spSemibold | |
) | |
if (state.value.isValid) { | |
Box( | |
modifier = Modifier | |
.fillMaxWidth() | |
.padding(end = 8.dp) | |
.wrapContentHeight(), | |
contentAlignment = Alignment.CenterEnd | |
) { | |
Icon( | |
contentDescription = "", | |
modifier = Modifier.size(16.dp), | |
imageVector = Icons.Filled.CheckCircle, | |
tint = Color.Green | |
) | |
} | |
} | |
} | |
Spacer(modifier = Modifier.height(6.dp)) | |
Box( | |
modifier = Modifier | |
.fillMaxWidth() | |
.wrapContentHeight(), | |
contentAlignment = Alignment.Center | |
) { | |
Divider( | |
color = if (state.value.isError) { | |
Color.Red | |
} else { | |
Color.LightGray | |
}, | |
) | |
} | |
if (state.value.isError) { | |
Spacer(modifier = Modifier.height(3.dp)) | |
Column( | |
modifier = Modifier | |
.fillMaxWidth() | |
.wrapContentHeight(), | |
horizontalAlignment = Alignment.End | |
) { | |
Row { | |
Icon( | |
contentDescription = "", | |
modifier = Modifier.size(16.dp), | |
imageVector = Icons.Filled.Error, | |
tint = Color.Red | |
) | |
Spacer(modifier = Modifier.width(14.dp)) | |
Text( | |
state.value.errorMessage, | |
color = Color.Red, | |
maxLines = 1 | |
) | |
} | |
} | |
} | |
} | |
} | |
@ExperimentalAnimationApi | |
@Preview | |
@Composable | |
fun PTEditTextPreview() { | |
Preview { | |
val state = EditTextState( | |
hint = "Name", | |
isError = false, | |
errorMessage = "are you sure this is valid name?", | |
tailingResId = R.drawable.ic_launcher_foreground, | |
errorResId = R.drawable.ic_launcher_foreground, | |
isValid = true | |
) | |
Column { | |
PTEditText( | |
state = remember { mutableStateOf(state.copy(isError = true, isValid = false)) }, | |
onTextChanged = { | |
// value should be collected from here | |
}, | |
onFocusChanged = { | |
// should do validation and error state step up here | |
} | |
) | |
PTEditText( | |
state = remember { mutableStateOf(state) }, | |
onTextChanged = { | |
// value should be collected from here | |
}, | |
onFocusChanged = { | |
// should do validation and error state step up here | |
} | |
) | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment