1
0
mirror of https://github.com/oliexdev/openScale.git synced 2025-08-16 05:34:05 +02:00

Add scale and measure unit to user settings

This commit is contained in:
oliexdev
2025-08-12 08:17:59 +02:00
parent db78109132
commit b9203c8d5d
6 changed files with 117 additions and 15 deletions

View File

@@ -1,12 +1,12 @@
{
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "e9e1b3a9fbc321cf52bf869c01f5be21",
"version": 7,
"identityHash": "d539026586245a45a135ae5bf3aaf73c",
"entities": [
{
"tableName": "User",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `birthDate` INTEGER NOT NULL, `gender` TEXT NOT NULL, `heightCm` REAL, `activityLevel` TEXT NOT NULL)",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `birthDate` INTEGER NOT NULL, `gender` TEXT NOT NULL, `heightCm` REAL NOT NULL, `activityLevel` TEXT NOT NULL, `scaleUnit` TEXT NOT NULL, `measureUnit` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "id",
@@ -35,13 +35,26 @@
{
"fieldPath": "heightCm",
"columnName": "heightCm",
"affinity": "REAL"
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "activityLevel",
"columnName": "activityLevel",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "scaleUnit",
"columnName": "scaleUnit",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "measureUnit",
"columnName": "measureUnit",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
@@ -279,7 +292,7 @@
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'e9e1b3a9fbc321cf52bf869c01f5be21')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'd539026586245a45a135ae5bf3aaf73c')"
]
}
}

View File

@@ -26,6 +26,8 @@ data class User(
val name: String,
val birthDate: Long,
val gender: GenderType,
val heightCm: Float? = null,
val activityLevel: ActivityLevel
val heightCm: Float,
val activityLevel: ActivityLevel,
var scaleUnit: WeightUnit,
var measureUnit: MeasureUnit
)

View File

@@ -39,7 +39,7 @@ import com.health.openscale.core.utils.LogManager
MeasurementValue::class,
MeasurementType::class
],
version = 1,
version = 7,
exportSchema = true
)
@TypeConverters(DatabaseConverters::class)

View File

@@ -22,6 +22,7 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.add
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
@@ -59,10 +60,13 @@ import androidx.navigation.NavController
import com.health.openscale.R
import com.health.openscale.core.data.ActivityLevel
import com.health.openscale.core.data.GenderType
import com.health.openscale.core.data.MeasureUnit
import com.health.openscale.core.data.User
import com.health.openscale.core.data.WeightUnit
import com.health.openscale.ui.screen.SharedViewModel
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale
@@ -94,17 +98,29 @@ fun UserDetailScreen(
}
var name by remember { mutableStateOf(user?.name.orEmpty()) }
var birthDate by remember { mutableStateOf(user?.birthDate ?: System.currentTimeMillis()) }
var birthDate by remember {
val initialBirthDate = user?.birthDate
if (initialBirthDate != null) {
mutableStateOf(initialBirthDate)
} else {
val calendar = Calendar.getInstance()
calendar.add(Calendar.YEAR, -18)
mutableStateOf(calendar.timeInMillis)
}
}
var gender by remember { mutableStateOf(user?.gender ?: GenderType.MALE) }
var height by remember { mutableStateOf(user?.heightCm?.toString().orEmpty()) }
var activityLevel by remember { mutableStateOf(user?.activityLevel ?: ActivityLevel.SEDENTARY) }
var scaleUnit by remember { mutableStateOf(user?.scaleUnit ?: WeightUnit.KG) }
var measureUnit by remember { mutableStateOf(user?.measureUnit ?: MeasureUnit.CM) }
val context = LocalContext.current
// Date formatter for displaying the birth date. Consider device locale.
val dateFormatter = remember { SimpleDateFormat("dd.MM.yyyy", Locale.getDefault()) }
val datePickerState = rememberDatePickerState(initialSelectedDateMillis = birthDate)
var showDatePicker by remember { mutableStateOf(false) }
var activityLevelExpanded by remember { mutableStateOf(false) }
var scaleUnitExpanded by remember { mutableStateOf(false) }
var measureUnitExpanded by remember { mutableStateOf(false) }
if (showDatePicker) {
DatePickerDialog(
@@ -149,7 +165,9 @@ fun UserDetailScreen(
birthDate = birthDate,
gender = gender,
heightCm = validHeight,
activityLevel = activityLevel
activityLevel = activityLevel,
scaleUnit = scaleUnit,
measureUnit = measureUnit
)
settingsViewModel.viewModelScope.launch {
if (isEdit) {
@@ -216,7 +234,6 @@ fun UserDetailScreen(
}
}
Text(stringResource(id = R.string.user_detail_label_activity_level)) // "Activity Level"
ExposedDropdownMenuBox(
expanded = activityLevelExpanded,
onExpandedChange = { activityLevelExpanded = !activityLevelExpanded },
@@ -226,7 +243,7 @@ fun UserDetailScreen(
value = activityLevel.name.lowercase().replaceFirstChar { it.uppercaseChar().toString() },
onValueChange = {}, // Input is read-only, selection via dropdown
readOnly = true,
label = { Text(stringResource(id = R.string.user_detail_label_select_level)) }, // "Select Level"
label = { Text(stringResource(id = R.string.user_detail_label_activity_level)) },
trailingIcon = {
ExposedDropdownMenuDefaults.TrailingIcon(expanded = activityLevelExpanded)
},
@@ -252,6 +269,74 @@ fun UserDetailScreen(
}
}
ExposedDropdownMenuBox(
expanded = scaleUnitExpanded,
onExpandedChange = { scaleUnitExpanded = !scaleUnitExpanded },
modifier = Modifier.fillMaxWidth()
) {
OutlinedTextField(
value = scaleUnit.toString(),
onValueChange = {},
readOnly = true,
label = { Text(stringResource(id = R.string.user_detail_label_scale_unit)) },
trailingIcon = {
ExposedDropdownMenuDefaults.TrailingIcon(expanded = scaleUnitExpanded)
},
modifier = Modifier
.menuAnchor(type = MenuAnchorType.PrimaryNotEditable)
.fillMaxWidth()
)
ExposedDropdownMenu(
expanded = scaleUnitExpanded,
onDismissRequest = { scaleUnitExpanded = false }
) {
WeightUnit.entries.forEach { selectionOption ->
DropdownMenuItem(
text = { Text(selectionOption.toString()) },
onClick = {
scaleUnit = selectionOption
scaleUnitExpanded = false
},
contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
)
}
}
}
ExposedDropdownMenuBox(
expanded = measureUnitExpanded,
onExpandedChange = { measureUnitExpanded = !measureUnitExpanded },
modifier = Modifier.fillMaxWidth()
) {
OutlinedTextField(
value = measureUnit.toString(),
onValueChange = {},
readOnly = true,
label = { Text(stringResource(id = R.string.user_detail_label_measure_unit)) },
trailingIcon = {
ExposedDropdownMenuDefaults.TrailingIcon(expanded = measureUnitExpanded)
},
modifier = Modifier
.menuAnchor(type = MenuAnchorType.PrimaryNotEditable)
.fillMaxWidth()
)
ExposedDropdownMenu(
expanded = measureUnitExpanded,
onDismissRequest = { measureUnitExpanded = false }
) {
MeasureUnit.entries.forEach { selectionOption ->
DropdownMenuItem(
text = { Text(selectionOption.toString()) },
onClick = {
measureUnit = selectionOption
measureUnitExpanded = false
},
contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
)
}
}
}
Text(stringResource(id = R.string.user_detail_label_birth_date)) // "Birth Date"
OutlinedTextField(
value = dateFormatter.format(Date(birthDate)),

View File

@@ -51,9 +51,10 @@
<string name="user_detail_label_height_cm">Größe (cm)</string>
<string name="user_detail_label_gender">Geschlecht</string>
<string name="user_detail_label_activity_level">Aktivitätslevel</string>
<string name="user_detail_label_select_level">Level auswählen</string>
<string name="user_detail_label_birth_date">Geburtsdatum</string>
<string name="user_detail_error_invalid_data">Bitte geben Sie gültige Daten ein</string>
<string name="user_detail_label_scale_unit">Gewichtseinheit</string>
<string name="user_detail_label_measure_unit">Größeneinheit</string>
<string name="height_value_cm">%.1f cm</string>
<string name="user_settings_item_details_conditional">Alter: %1$d, Größe: %2$s</string>
<string name="user_settings_content_description_edit">Benutzer bearbeiten</string>

View File

@@ -52,9 +52,10 @@
<string name="user_detail_label_height_cm">Height (cm)</string>
<string name="user_detail_label_gender">Gender</string>
<string name="user_detail_label_activity_level">Activity Level</string>
<string name="user_detail_label_select_level">Select Level</string>
<string name="user_detail_label_birth_date">Birth Date</string>
<string name="user_detail_error_invalid_data">Please enter valid data</string>
<string name="user_detail_label_scale_unit">Scale Unit</string>
<string name="user_detail_label_measure_unit">Measure Unit</string>
<string name="height_value_cm">%.1f cm</string>
<string name="user_settings_item_details_conditional">Age: %1$d, Height: %2$s</string>
<string name="user_settings_content_description_edit">Edit user</string>