mirror of
https://github.com/oliexdev/openScale.git
synced 2025-08-16 21:54:05 +02:00
Refactor measurement type to improves the logic for setting the initial and updating selectedInputType
based on allowed types.
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.health.openscale.core.data
|
package com.health.openscale.core.data
|
||||||
|
|
||||||
|
import android.text.InputType
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import com.health.openscale.R
|
import com.health.openscale.R
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
@@ -145,35 +146,36 @@ enum class MeasureUnit {
|
|||||||
enum class MeasurementTypeKey(
|
enum class MeasurementTypeKey(
|
||||||
val id: Int,
|
val id: Int,
|
||||||
@StringRes val localizedNameResId: Int,
|
@StringRes val localizedNameResId: Int,
|
||||||
val allowedUnitTypes: List<UnitType>
|
val allowedUnitTypes: List<UnitType>,
|
||||||
|
val allowedInputType: List<InputFieldType>
|
||||||
) {
|
) {
|
||||||
WEIGHT(1, R.string.measurement_type_weight, listOf(UnitType.KG, UnitType.LB, UnitType.ST)),
|
WEIGHT(1, R.string.measurement_type_weight, listOf(UnitType.KG, UnitType.LB, UnitType.ST), listOf(InputFieldType.FLOAT)),
|
||||||
BMI(2, R.string.measurement_type_bmi, listOf(UnitType.NONE)),
|
BMI(2, R.string.measurement_type_bmi, listOf(UnitType.NONE), listOf(InputFieldType.FLOAT)),
|
||||||
BODY_FAT(3, R.string.measurement_type_body_fat, listOf(UnitType.PERCENT)),
|
BODY_FAT(3, R.string.measurement_type_body_fat, listOf(UnitType.PERCENT), listOf(InputFieldType.FLOAT)),
|
||||||
WATER(4, R.string.measurement_type_water, listOf(UnitType.PERCENT)),
|
WATER(4, R.string.measurement_type_water, listOf(UnitType.PERCENT), listOf(InputFieldType.FLOAT)),
|
||||||
MUSCLE(5, R.string.measurement_type_muscle, listOf(UnitType.PERCENT, UnitType.KG, UnitType.LB)),
|
MUSCLE(5, R.string.measurement_type_muscle, listOf(UnitType.PERCENT, UnitType.KG, UnitType.LB), listOf(InputFieldType.FLOAT)),
|
||||||
LBM(6, R.string.measurement_type_lbm, listOf(UnitType.KG, UnitType.LB, UnitType.ST)),
|
LBM(6, R.string.measurement_type_lbm, listOf(UnitType.KG, UnitType.LB, UnitType.ST), listOf(InputFieldType.FLOAT)),
|
||||||
BONE(7, R.string.measurement_type_bone, listOf(UnitType.KG, UnitType.LB)),
|
BONE(7, R.string.measurement_type_bone, listOf(UnitType.KG, UnitType.LB), listOf(InputFieldType.FLOAT)),
|
||||||
WAIST(8, R.string.measurement_type_waist, listOf(UnitType.CM, UnitType.INCH)),
|
WAIST(8, R.string.measurement_type_waist, listOf(UnitType.CM, UnitType.INCH), listOf(InputFieldType.FLOAT)),
|
||||||
WHR(9, R.string.measurement_type_whr, listOf(UnitType.NONE)),
|
WHR(9, R.string.measurement_type_whr, listOf(UnitType.NONE), listOf(InputFieldType.FLOAT)),
|
||||||
WHTR(10, R.string.measurement_type_whtr, listOf(UnitType.NONE)),
|
WHTR(10, R.string.measurement_type_whtr, listOf(UnitType.NONE), listOf(InputFieldType.FLOAT)),
|
||||||
HIPS(11, R.string.measurement_type_hips, listOf(UnitType.CM, UnitType.INCH)),
|
HIPS(11, R.string.measurement_type_hips, listOf(UnitType.CM, UnitType.INCH), listOf(InputFieldType.FLOAT)),
|
||||||
VISCERAL_FAT(12, R.string.measurement_type_visceral_fat, listOf(UnitType.PERCENT, UnitType.NONE)),
|
VISCERAL_FAT(12, R.string.measurement_type_visceral_fat, listOf(UnitType.PERCENT, UnitType.NONE), listOf(InputFieldType.INT, InputFieldType.FLOAT)),
|
||||||
CHEST(13, R.string.measurement_type_chest, listOf(UnitType.CM, UnitType.INCH)),
|
CHEST(13, R.string.measurement_type_chest, listOf(UnitType.CM, UnitType.INCH), listOf(InputFieldType.FLOAT)),
|
||||||
THIGH(14, R.string.measurement_type_thigh, listOf(UnitType.CM, UnitType.INCH)),
|
THIGH(14, R.string.measurement_type_thigh, listOf(UnitType.CM, UnitType.INCH), listOf(InputFieldType.FLOAT)),
|
||||||
BICEPS(15, R.string.measurement_type_biceps, listOf(UnitType.CM, UnitType.INCH)),
|
BICEPS(15, R.string.measurement_type_biceps, listOf(UnitType.CM, UnitType.INCH), listOf(InputFieldType.FLOAT)),
|
||||||
NECK(16, R.string.measurement_type_neck, listOf(UnitType.CM, UnitType.INCH)),
|
NECK(16, R.string.measurement_type_neck, listOf(UnitType.CM, UnitType.INCH), listOf(InputFieldType.FLOAT)),
|
||||||
CALIPER_1(17, R.string.measurement_type_caliper1, listOf(UnitType.CM, UnitType.INCH)),
|
CALIPER_1(17, R.string.measurement_type_caliper1, listOf(UnitType.CM, UnitType.INCH), listOf(InputFieldType.FLOAT)),
|
||||||
CALIPER_2(18, R.string.measurement_type_caliper2, listOf(UnitType.CM, UnitType.INCH)),
|
CALIPER_2(18, R.string.measurement_type_caliper2, listOf(UnitType.CM, UnitType.INCH), listOf(InputFieldType.FLOAT)),
|
||||||
CALIPER_3(19, R.string.measurement_type_caliper3, listOf(UnitType.CM, UnitType.INCH)),
|
CALIPER_3(19, R.string.measurement_type_caliper3, listOf(UnitType.CM, UnitType.INCH), listOf(InputFieldType.FLOAT)),
|
||||||
CALIPER(20, R.string.measurement_type_fat_caliper, listOf(UnitType.PERCENT, UnitType.NONE)),
|
CALIPER(20, R.string.measurement_type_fat_caliper, listOf(UnitType.PERCENT, UnitType.NONE), listOf(InputFieldType.FLOAT)),
|
||||||
BMR(21, R.string.measurement_type_bmr, listOf(UnitType.KCAL)),
|
BMR(21, R.string.measurement_type_bmr, listOf(UnitType.KCAL), listOf(InputFieldType.INT)),
|
||||||
TDEE(22, R.string.measurement_type_tdee, listOf(UnitType.KCAL)),
|
TDEE(22, R.string.measurement_type_tdee, listOf(UnitType.KCAL), listOf(InputFieldType.INT)),
|
||||||
CALORIES(23, R.string.measurement_type_calories, listOf(UnitType.KCAL)),
|
CALORIES(23, R.string.measurement_type_calories, listOf(UnitType.KCAL), listOf(InputFieldType.INT)),
|
||||||
DATE(24, R.string.measurement_type_date, listOf(UnitType.NONE)),
|
DATE(24, R.string.measurement_type_date, listOf(UnitType.NONE), listOf(InputFieldType.DATE)),
|
||||||
TIME(25, R.string.measurement_type_time, listOf(UnitType.NONE)),
|
TIME(25, R.string.measurement_type_time, listOf(UnitType.NONE), listOf(InputFieldType.TIME)),
|
||||||
COMMENT(26, R.string.measurement_type_comment, listOf(UnitType.NONE)),
|
COMMENT(26, R.string.measurement_type_comment, listOf(UnitType.NONE), listOf(InputFieldType.TEXT)),
|
||||||
CUSTOM(99, R.string.measurement_type_custom_default_name, UnitType.entries.toList());
|
CUSTOM(99, R.string.measurement_type_custom_default_name, UnitType.entries.toList(), listOf(InputFieldType.FLOAT, InputFieldType.INT, InputFieldType.TEXT, InputFieldType.DATE, InputFieldType.TIME));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -111,6 +111,10 @@ fun MeasurementTypeDetailScreen(
|
|||||||
currentMeasurementTypeKey.allowedUnitTypes
|
currentMeasurementTypeKey.allowedUnitTypes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val allowedInputTypesForKey = remember(currentMeasurementTypeKey) {
|
||||||
|
currentMeasurementTypeKey.allowedInputType
|
||||||
|
}
|
||||||
|
|
||||||
var name by remember { mutableStateOf(originalExistingType?.getDisplayName(context).orEmpty()) }
|
var name by remember { mutableStateOf(originalExistingType?.getDisplayName(context).orEmpty()) }
|
||||||
|
|
||||||
// Safely set selectedUnit. If the existing unit isn't allowed or if no existing unit,
|
// Safely set selectedUnit. If the existing unit isn't allowed or if no existing unit,
|
||||||
@@ -124,7 +128,14 @@ fun MeasurementTypeDetailScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var selectedInputType by remember { mutableStateOf(originalExistingType?.inputType ?: InputFieldType.FLOAT) }
|
var selectedInputType by remember {
|
||||||
|
val initialInputType = originalExistingType?.inputType
|
||||||
|
if (initialInputType != null && initialInputType in allowedInputTypesForKey) {
|
||||||
|
mutableStateOf(initialInputType)
|
||||||
|
} else {
|
||||||
|
mutableStateOf(allowedInputTypesForKey.firstOrNull() ?: InputFieldType.FLOAT)
|
||||||
|
}
|
||||||
|
}
|
||||||
var selectedColor by remember { mutableStateOf(originalExistingType?.color ?: 0xFF6200EE.toInt()) }
|
var selectedColor by remember { mutableStateOf(originalExistingType?.color ?: 0xFF6200EE.toInt()) }
|
||||||
var selectedIcon by remember { mutableStateOf(originalExistingType?.icon ?: "ic_weight") }
|
var selectedIcon by remember { mutableStateOf(originalExistingType?.icon ?: "ic_weight") }
|
||||||
var isEnabled by remember { mutableStateOf(originalExistingType?.isEnabled ?: true) }
|
var isEnabled by remember { mutableStateOf(originalExistingType?.isEnabled ?: true) }
|
||||||
@@ -142,13 +153,13 @@ fun MeasurementTypeDetailScreen(
|
|||||||
val titleEdit = stringResource(R.string.measurement_type_detail_title_edit)
|
val titleEdit = stringResource(R.string.measurement_type_detail_title_edit)
|
||||||
val titleAdd = stringResource(R.string.measurement_type_detail_title_add)
|
val titleAdd = stringResource(R.string.measurement_type_detail_title_add)
|
||||||
|
|
||||||
// Determines if the unit dropdown should be enabled (i.e., if there's more than one allowed unit).
|
|
||||||
val unitDropdownEnabled by remember(allowedUnitsForKey) {
|
val unitDropdownEnabled by remember(allowedUnitsForKey) {
|
||||||
derivedStateOf { allowedUnitsForKey.size > 1 }
|
derivedStateOf { allowedUnitsForKey.size > 1 }
|
||||||
}
|
}
|
||||||
|
val inputTypeDropdownEnabled by remember(allowedInputTypesForKey) {
|
||||||
|
derivedStateOf { allowedInputTypesForKey.size > 1 }
|
||||||
|
}
|
||||||
|
|
||||||
// Effect to re-evaluate and set selectedUnit if originalExistingType or allowedUnitsForKey change.
|
|
||||||
// This ensures selectedUnit is always valid.
|
|
||||||
LaunchedEffect(originalExistingType, allowedUnitsForKey) {
|
LaunchedEffect(originalExistingType, allowedUnitsForKey) {
|
||||||
val currentUnitInExistingType = originalExistingType?.unit
|
val currentUnitInExistingType = originalExistingType?.unit
|
||||||
if (currentUnitInExistingType != null && currentUnitInExistingType in allowedUnitsForKey) {
|
if (currentUnitInExistingType != null && currentUnitInExistingType in allowedUnitsForKey) {
|
||||||
@@ -163,6 +174,19 @@ fun MeasurementTypeDetailScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(originalExistingType, allowedInputTypesForKey) {
|
||||||
|
val currentInputTypeInExistingType = originalExistingType?.inputType
|
||||||
|
if (currentInputTypeInExistingType != null && currentInputTypeInExistingType in allowedInputTypesForKey) {
|
||||||
|
if (selectedInputType != currentInputTypeInExistingType) {
|
||||||
|
selectedInputType = currentInputTypeInExistingType
|
||||||
|
}
|
||||||
|
} else if (allowedInputTypesForKey.isNotEmpty() && selectedInputType !in allowedInputTypesForKey) {
|
||||||
|
selectedInputType = allowedInputTypesForKey.first()
|
||||||
|
} else if (allowedInputTypesForKey.isEmpty()) {
|
||||||
|
selectedInputType = InputFieldType.FLOAT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
sharedViewModel.setTopBarTitle(if (isEdit) titleEdit else titleAdd)
|
sharedViewModel.setTopBarTitle(if (isEdit) titleEdit else titleAdd)
|
||||||
sharedViewModel.setTopBarAction(
|
sharedViewModel.setTopBarAction(
|
||||||
@@ -252,15 +276,14 @@ fun MeasurementTypeDetailScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isEdit || (originalExistingType?.key == MeasurementTypeKey.CUSTOM)) {
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = name,
|
value = name,
|
||||||
onValueChange = { name = it },
|
onValueChange = { name = it },
|
||||||
label = { Text(stringResource(R.string.measurement_type_label_name)) },
|
label = { Text(stringResource(R.string.measurement_type_label_name)) },
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
// Name field is editable for new types or existing CUSTOM types.
|
|
||||||
// For predefined types, the name is typically not user-editable.
|
|
||||||
enabled = !isEdit || (originalExistingType?.key == MeasurementTypeKey.CUSTOM)
|
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = String.format("#%06X", 0xFFFFFF and selectedColor),
|
value = String.format("#%06X", 0xFFFFFF and selectedColor),
|
||||||
@@ -376,6 +399,7 @@ fun MeasurementTypeDetailScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// InputFieldType Dropdown
|
// InputFieldType Dropdown
|
||||||
|
if (inputTypeDropdownEnabled) {
|
||||||
ExposedDropdownMenuBox(
|
ExposedDropdownMenuBox(
|
||||||
expanded = expandedInputType,
|
expanded = expandedInputType,
|
||||||
onExpandedChange = { expandedInputType = !expandedInputType }
|
onExpandedChange = { expandedInputType = !expandedInputType }
|
||||||
@@ -394,9 +418,12 @@ fun MeasurementTypeDetailScreen(
|
|||||||
expanded = expandedInputType,
|
expanded = expandedInputType,
|
||||||
onDismissRequest = { expandedInputType = false }
|
onDismissRequest = { expandedInputType = false }
|
||||||
) {
|
) {
|
||||||
InputFieldType.entries.forEach { type ->
|
allowedInputTypesForKey.forEach { type ->
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
text = { Text(type.name.lowercase().replaceFirstChar { it.uppercase() }) },
|
text = {
|
||||||
|
Text(
|
||||||
|
type.name.lowercase().replaceFirstChar { it.uppercase() })
|
||||||
|
},
|
||||||
onClick = {
|
onClick = {
|
||||||
selectedInputType = type
|
selectedInputType = type
|
||||||
expandedInputType = false
|
expandedInputType = false
|
||||||
@@ -405,6 +432,7 @@ fun MeasurementTypeDetailScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
OutlinedSettingRow(label = stringResource(R.string.measurement_type_label_pinned)) {
|
OutlinedSettingRow(label = stringResource(R.string.measurement_type_label_pinned)) {
|
||||||
Switch(
|
Switch(
|
||||||
|
@@ -251,7 +251,6 @@ fun UserDetailScreen(
|
|||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
)
|
)
|
||||||
|
|
||||||
Text(stringResource(id = R.string.user_detail_label_height))
|
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = heightValueString,
|
value = heightValueString,
|
||||||
onValueChange = { newValue ->
|
onValueChange = { newValue ->
|
||||||
@@ -302,9 +301,6 @@ fun UserDetailScreen(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Text(stringResource(id = R.string.user_detail_label_gender)) // "Gender"
|
|
||||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||||
GenderType.entries.forEach { option ->
|
GenderType.entries.forEach { option ->
|
||||||
Row(
|
Row(
|
||||||
@@ -358,9 +354,9 @@ fun UserDetailScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text(stringResource(id = R.string.user_detail_label_birth_date)) // "Birth Date"
|
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = dateFormatter.format(Date(birthDate)),
|
value = dateFormatter.format(Date(birthDate)),
|
||||||
|
label = { Text(stringResource(R.string.user_detail_label_birth_date)) },
|
||||||
onValueChange = {}, // Input is read-only, selection via DatePicker
|
onValueChange = {}, // Input is read-only, selection via DatePicker
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
Reference in New Issue
Block a user