This commit is contained in:
sockenklaus
2022-07-20 14:46:30 +02:00
parent 39b19530ef
commit 50d952effc
5 changed files with 135 additions and 96 deletions

View File

@@ -0,0 +1,124 @@
package com.sockenklaus.batterytracker.ui.composables
import androidx.compose.foundation.background
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.*
import androidx.compose.material.TextFieldDefaults.OutlinedTextFieldDecorationBox
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.takeOrElse
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
import com.sockenklaus.batterytracker.ui.theme.Gray500
@Composable
fun MyOutlinedTextFieldWithSuffix(
value: String,
onValueChange: (String) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
readOnly: Boolean = false,
textStyle: TextStyle = LocalTextStyle.current,
placeholder: @Composable (() -> Unit)? = null,
leadingIcon: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
isError: Boolean = false,
visualTransformation: VisualTransformation = VisualTransformation.None,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
keyboardActions: KeyboardActions = KeyboardActions.Default,
singleLine: Boolean = false,
maxLines: Int = Int.MAX_VALUE,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
shape: Shape = MaterialTheme.shapes.small,
colors: TextFieldColors = TextFieldDefaults.outlinedTextFieldColors(),
suffix: String = "",
helperTextId: Int? = null,
labelId: Int
) {
// If color is not provided via the text style, use content color as a default
val textColor = textStyle.color.takeOrElse {
colors.textColor(enabled).value
}
val mergedTextStyle = textStyle.merge(TextStyle(color = textColor))
val helperTextColor = if(isError){
MaterialTheme.colors.error
} else {
Gray500
}
@OptIn(ExperimentalMaterialApi::class)
BasicTextField(
value = value,
modifier = modifier.padding(top = 8.dp)
.background(colors.backgroundColor(enabled).value, shape)
.defaultMinSize(
minWidth = TextFieldDefaults.MinWidth,
minHeight = TextFieldDefaults.MinHeight
),
onValueChange = onValueChange,
enabled = enabled,
readOnly = readOnly,
textStyle = mergedTextStyle,
cursorBrush = SolidColor(colors.cursorColor(isError).value),
visualTransformation = visualTransformation,
keyboardOptions = keyboardOptions,
keyboardActions = keyboardActions,
interactionSource = interactionSource,
singleLine = singleLine,
maxLines = maxLines,
decorationBox = @Composable { innerTextField ->
OutlinedTextFieldDecorationBox(
value = value,
visualTransformation = visualTransformation,
innerTextField = {
Row {
val alignModifier = Modifier.alignByBaseline()
Box(alignModifier.weight(1f)){
innerTextField()
}
Text(
suffix,
alignModifier,
colors.trailingIconColor(enabled = enabled, isError = isError).value
)
}
},
placeholder = placeholder,
label = { Text(stringResource(labelId)) },
leadingIcon = leadingIcon,
trailingIcon = trailingIcon,
singleLine = singleLine,
enabled = enabled,
isError = isError,
interactionSource = interactionSource,
colors = colors,
border = {
TextFieldDefaults.BorderBox(
enabled,
isError,
interactionSource,
colors,
shape
)
}
)
}
)
Text(
text = if(helperTextId != null) stringResource(helperTextId) else "",
style = MaterialTheme.typography.caption,
color = helperTextColor,
modifier = Modifier.padding(start = 16.dp)
)
}

View File

@@ -21,7 +21,7 @@ import androidx.navigation.fragment.findNavController
import com.sockenklaus.batterytracker.R import com.sockenklaus.batterytracker.R
import com.sockenklaus.batterytracker.databinding.FragmentAddBatteryBinding import com.sockenklaus.batterytracker.databinding.FragmentAddBatteryBinding
import com.sockenklaus.batterytracker.room.entities.Battery import com.sockenklaus.batterytracker.room.entities.Battery
import com.sockenklaus.batterytracker.ui.fragments.composables.MyOutlinedTextField import com.sockenklaus.batterytracker.ui.composables.MyOutlinedTextFieldWithSuffix
import com.sockenklaus.batterytracker.ui.theme.BatteryTrackerTheme import com.sockenklaus.batterytracker.ui.theme.BatteryTrackerTheme
import com.sockenklaus.batterytracker.util.validateDecimal import com.sockenklaus.batterytracker.util.validateDecimal
@@ -58,7 +58,8 @@ class AddBatteryFragment : Fragment() {
Column( Column(
Modifier.padding(outerPadding) Modifier.padding(outerPadding)
) { ) {
MyOutlinedTextField(
MyOutlinedTextFieldWithSuffix(
value = model.batteryName, value = model.batteryName,
onValueChange = { value -> onValueChange = { value ->
model.batteryName = value model.batteryName = value
@@ -77,7 +78,7 @@ class AddBatteryFragment : Fragment() {
Spacer(Modifier.size(innerPadding)) Spacer(Modifier.size(innerPadding))
MyOutlinedTextField( MyOutlinedTextFieldWithSuffix(
value = model.declaredCapacity, value = model.declaredCapacity,
onValueChange = { onValueChange = {
model.declaredCapacity = validateDecimal(it, model.declaredCapacity) model.declaredCapacity = validateDecimal(it, model.declaredCapacity)
@@ -85,6 +86,7 @@ class AddBatteryFragment : Fragment() {
labelId = R.string.hint_enter_declared_capacity, labelId = R.string.hint_enter_declared_capacity,
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal),
leadingIcon = { Icon(Icons.Default.BatteryFull, "Icon Battery Full") }, leadingIcon = { Icon(Icons.Default.BatteryFull, "Icon Battery Full") },
suffix = "Ah"
) )
Spacer(Modifier.size(outerPadding)) Spacer(Modifier.size(outerPadding))

View File

@@ -27,7 +27,7 @@ import com.google.android.material.datepicker.MaterialDatePicker
import com.sockenklaus.batterytracker.R import com.sockenklaus.batterytracker.R
import com.sockenklaus.batterytracker.databinding.FragmentAddChargeBinding import com.sockenklaus.batterytracker.databinding.FragmentAddChargeBinding
import com.sockenklaus.batterytracker.room.entities.Battery import com.sockenklaus.batterytracker.room.entities.Battery
import com.sockenklaus.batterytracker.ui.fragments.composables.MyOutlinedTextField import com.sockenklaus.batterytracker.ui.composables.MyOutlinedTextFieldWithSuffix
import com.sockenklaus.batterytracker.ui.theme.BatteryTrackerTheme import com.sockenklaus.batterytracker.ui.theme.BatteryTrackerTheme
import com.sockenklaus.batterytracker.ui.theme.Gray500 import com.sockenklaus.batterytracker.ui.theme.Gray500
import com.sockenklaus.batterytracker.util.validateDecimal import com.sockenklaus.batterytracker.util.validateDecimal
@@ -121,7 +121,7 @@ class AddChargeFragment : Fragment() {
Spacer(Modifier.size(innerPadding)) Spacer(Modifier.size(innerPadding))
MyOutlinedTextField( MyOutlinedTextFieldWithSuffix(
value = model.charge, value = model.charge,
onValueChange = { onValueChange = {
model.charge = validateDecimal(it, model.charge) model.charge = validateDecimal(it, model.charge)
@@ -129,9 +129,10 @@ class AddChargeFragment : Fragment() {
}, },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal),
labelId = R.string.hint_charge, labelId = R.string.hint_charge,
leadingIcon = { Icon(Icons.Default.BatteryChargingFull, "Icon Battery Chargin Full") }, leadingIcon = { Icon(Icons.Default.BatteryChargingFull, "Icon Battery Charging Full") },
isError = model.chargeHasError, isError = model.chargeHasError,
helperTextId = R.string.helper_required helperTextId = R.string.helper_required,
suffix = "Ah"
) )
Spacer(Modifier.size(innerPadding)) Spacer(Modifier.size(innerPadding))

View File

@@ -1,88 +0,0 @@
package com.sockenklaus.batterytracker.ui.fragments.composables
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.dp
import com.sockenklaus.batterytracker.ui.theme.Gray500
@Composable
fun MyOutlinedTextField(
value: String,
onValueChange: (String) -> Unit,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
labelId: Int,
leadingIcon: (@Composable () -> Unit)? = null,
trailingIcon: (@Composable () -> Unit)? = null,
isError: Boolean = false,
helperTextId: Int? = null,
colors: TextFieldColors = TextFieldDefaults.outlinedTextFieldColors()
) {
val helperTextColor = if(isError){
MaterialTheme.colors.error
} else {
Gray500
}
OutlinedTextField(
value = value,
onValueChange = onValueChange,
keyboardOptions = keyboardOptions,
label = { Text(stringResource(labelId)) },
leadingIcon = leadingIcon,
trailingIcon = trailingIcon,
isError = isError,
modifier = Modifier.fillMaxWidth(),
colors = colors
)
Text(
text = if(helperTextId != null) stringResource(helperTextId) else "",
style = MaterialTheme.typography.caption,
color = helperTextColor,
modifier = Modifier.padding(start = 16.dp)
)
}
@Composable
fun MyOutlinedTextField(
value: TextFieldValue,
onValueChange: (TextFieldValue) -> Unit,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
labelId: Int,
leadingIcon: (@Composable () -> Unit)? = null,
trailingIcon: (@Composable () -> Unit)? = null,
isError: Boolean = false,
helperTextId: Int? = null,
colors: TextFieldColors = TextFieldDefaults.outlinedTextFieldColors()
) {
val helperTextColor = if(isError){
MaterialTheme.colors.error
} else {
Gray500
}
Column() {
OutlinedTextField(
value = value,
onValueChange = onValueChange,
keyboardOptions = keyboardOptions,
label = { Text(stringResource(labelId)) },
leadingIcon = leadingIcon,
trailingIcon = trailingIcon,
isError = isError,
modifier = Modifier.fillMaxWidth(),
colors = colors
)
Text(
text = if(helperTextId != null) stringResource(helperTextId) else "",
style = MaterialTheme.typography.caption,
color = helperTextColor,
modifier = Modifier.padding(start = 16.dp)
)
}
}

View File

@@ -20,7 +20,7 @@
<string name="button_save_charge">Save Charge</string> <string name="button_save_charge">Save Charge</string>
<string name="date">Date</string> <string name="date">Date</string>
<string name="charge">Charge</string> <string name="charge">Charge</string>
<string name="hint_charge">Enter Charge in Ah</string> <string name="hint_charge">Enter Charge</string>
<string name="select_battery_id">Select Battery ID</string> <string name="select_battery_id">Select Battery ID</string>
<string name="hint_enter_battery_name">Enter Battery Name</string> <string name="hint_enter_battery_name">Enter Battery Name</string>
<string name="hint_enter_declared_capacity">Enter declared capacity</string> <string name="hint_enter_declared_capacity">Enter declared capacity</string>