diff --git a/app/src/main/java/com/sockenklaus/batterytracker/ui/composables/Composables.kt b/app/src/main/java/com/sockenklaus/batterytracker/ui/composables/Composables.kt new file mode 100644 index 0000000..d3b8067 --- /dev/null +++ b/app/src/main/java/com/sockenklaus/batterytracker/ui/composables/Composables.kt @@ -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) + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/add_battery/AddBatteryFragment.kt b/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/add_battery/AddBatteryFragment.kt index 720db06..988f591 100644 --- a/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/add_battery/AddBatteryFragment.kt +++ b/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/add_battery/AddBatteryFragment.kt @@ -21,7 +21,7 @@ import androidx.navigation.fragment.findNavController import com.sockenklaus.batterytracker.R import com.sockenklaus.batterytracker.databinding.FragmentAddBatteryBinding 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.util.validateDecimal @@ -58,7 +58,8 @@ class AddBatteryFragment : Fragment() { Column( Modifier.padding(outerPadding) ) { - MyOutlinedTextField( + + MyOutlinedTextFieldWithSuffix( value = model.batteryName, onValueChange = { value -> model.batteryName = value @@ -77,7 +78,7 @@ class AddBatteryFragment : Fragment() { Spacer(Modifier.size(innerPadding)) - MyOutlinedTextField( + MyOutlinedTextFieldWithSuffix( value = model.declaredCapacity, onValueChange = { model.declaredCapacity = validateDecimal(it, model.declaredCapacity) @@ -85,6 +86,7 @@ class AddBatteryFragment : Fragment() { labelId = R.string.hint_enter_declared_capacity, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal), leadingIcon = { Icon(Icons.Default.BatteryFull, "Icon Battery Full") }, + suffix = "Ah" ) Spacer(Modifier.size(outerPadding)) diff --git a/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/add_charge/AddChargeFragment.kt b/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/add_charge/AddChargeFragment.kt index d0c5e1f..94adf7b 100644 --- a/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/add_charge/AddChargeFragment.kt +++ b/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/add_charge/AddChargeFragment.kt @@ -27,7 +27,7 @@ import com.google.android.material.datepicker.MaterialDatePicker import com.sockenklaus.batterytracker.R import com.sockenklaus.batterytracker.databinding.FragmentAddChargeBinding 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.Gray500 import com.sockenklaus.batterytracker.util.validateDecimal @@ -121,7 +121,7 @@ class AddChargeFragment : Fragment() { Spacer(Modifier.size(innerPadding)) - MyOutlinedTextField( + MyOutlinedTextFieldWithSuffix( value = model.charge, onValueChange = { model.charge = validateDecimal(it, model.charge) @@ -129,9 +129,10 @@ class AddChargeFragment : Fragment() { }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal), 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, - helperTextId = R.string.helper_required + helperTextId = R.string.helper_required, + suffix = "Ah" ) Spacer(Modifier.size(innerPadding)) diff --git a/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/composables/Composables.kt b/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/composables/Composables.kt deleted file mode 100644 index 9bccad9..0000000 --- a/app/src/main/java/com/sockenklaus/batterytracker/ui/fragments/composables/Composables.kt +++ /dev/null @@ -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) - ) - } -} \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index eb2ec1d..4b95960 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -20,7 +20,7 @@ Save Charge Date Charge - Enter Charge in Ah + Enter Charge Select Battery ID Enter Battery Name Enter declared capacity