Fix glucose details screen

This commit is contained in:
Sylwester Zieliński
2022-01-31 14:54:57 +01:00
parent 9cdd253efc
commit 80fb980c38
7 changed files with 251 additions and 132 deletions

View File

@@ -7,6 +7,10 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import no.nordicsemi.android.gls.R
@Composable
internal fun Field(title: String, value: String) {
@@ -16,11 +20,41 @@ internal fun Field(title: String, value: String) {
) {
Text(
text = title,
style = MaterialTheme.typography.titleMedium
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.outline
)
Text(
text = value,
style = MaterialTheme.typography.bodyMedium
style = MaterialTheme.typography.bodyMedium,
textAlign = TextAlign.End
)
}
}
@Composable
internal fun BooleanField(title: String, value: Boolean) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = title,
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.outline
)
if (value) {
Text(
text = stringResource(id = R.string.gls_yes),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.error
)
} else {
Text(
text = stringResource(id = R.string.gls_no),
style = MaterialTheme.typography.bodyMedium,
color = colorResource(id = no.nordicsemi.android.material.you.R.color.nordicGrass)
)
}
}
}

View File

@@ -1,119 +1,197 @@
package no.nordicsemi.android.gls.details.view
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Divider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import no.nordicsemi.android.ble.common.profile.glucose.GlucoseMeasurementCallback
import no.nordicsemi.android.ble.common.profile.glucose.GlucoseMeasurementContextCallback
import no.nordicsemi.android.gls.R
import no.nordicsemi.android.gls.data.*
import no.nordicsemi.android.gls.data.GLSRecord
import no.nordicsemi.android.gls.main.view.toDisplayString
import java.util.*
@Composable
internal fun GLSDetailsContentView(record: GLSRecord) {
Field(stringResource(id = R.string.gls_details_sequence_number), record.sequenceNumber.toString())
Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
Column(modifier = Modifier.padding(16.dp)) {
Field(
stringResource(id = R.string.gls_details_sequence_number),
record.sequenceNumber.toString()
)
record.time?.let {
Field(stringResource(id = R.string.gls_details_date_and_time), stringResource(R.string.gls_timestamp, it))
Spacer(modifier = Modifier.size(4.dp))
}
record.type?.let {
Field(stringResource(id = R.string.gls_details_type), it.toDisplayString())
Spacer(modifier = Modifier.size(4.dp))
}
record.sampleLocation?.let {
Field(stringResource(id = R.string.gls_details_location), it.toDisplayString())
Spacer(modifier = Modifier.size(4.dp))
}
record.time?.let {
Field(
stringResource(id = R.string.gls_details_date_and_time),
stringResource(R.string.gls_timestamp, it)
)
}
Field(stringResource(id = R.string.gls_details_glucose_condensation_title), stringResource(id = R.string.gls_details_glucose_condensation_field, record.glucoseConcentration, record.unit.toDisplayString()))
Divider(
color = MaterialTheme.colorScheme.secondary,
thickness = 1.dp,
modifier = Modifier.padding(vertical = 16.dp)
)
record.status?.let {
Field(stringResource(id = R.string.gls_details_battery_low), it.deviceBatteryLow.toGLSStatus())
Spacer(modifier = Modifier.size(4.dp))
Field(stringResource(id = R.string.gls_details_sensor_malfunction), it.sensorMalfunction.toGLSStatus())
Spacer(modifier = Modifier.size(4.dp))
Field(stringResource(id = R.string.gls_details_insufficient_sample), it.sampleSizeInsufficient.toGLSStatus())
Spacer(modifier = Modifier.size(4.dp))
Field(stringResource(id = R.string.gls_details_strip_insertion_error), it.stripInsertionError.toGLSStatus())
Spacer(modifier = Modifier.size(4.dp))
Field(stringResource(id = R.string.gls_details_strip_type_incorrect), it.stripTypeIncorrect.toGLSStatus())
Spacer(modifier = Modifier.size(4.dp))
Field(stringResource(id = R.string.gls_details_sensor_result_too_high), it.sensorResultHigherThenDeviceCanProcess.toGLSStatus())
Spacer(modifier = Modifier.size(4.dp))
Field(stringResource(id = R.string.gls_details_sensor_result_too_low), it.sensorResultLowerThenDeviceCanProcess.toGLSStatus())
Spacer(modifier = Modifier.size(4.dp))
Field(stringResource(id = R.string.gls_details_temperature_too_high), it.sensorTemperatureTooHigh.toGLSStatus())
Spacer(modifier = Modifier.size(4.dp))
Field(stringResource(id = R.string.gls_details_temperature_too_low), it.sensorTemperatureTooLow.toGLSStatus())
Spacer(modifier = Modifier.size(4.dp))
Field(stringResource(id = R.string.gls_details_strip_pulled_too_soon), it.sensorReadInterrupted.toGLSStatus())
Spacer(modifier = Modifier.size(4.dp))
Field(stringResource(id = R.string.gls_details_general_device_fault), it.generalDeviceFault.toGLSStatus())
Spacer(modifier = Modifier.size(4.dp))
Field(stringResource(id = R.string.gls_details_time_fault), it.timeFault.toGLSStatus())
Spacer(modifier = Modifier.size(4.dp))
}
record.type?.let {
Field(stringResource(id = R.string.gls_details_type), it.toDisplayString())
Spacer(modifier = Modifier.size(4.dp))
}
record.context?.let {
Field(stringResource(id = R.string.gls_context_title), stringResource(id = R.string.gls_available))
Spacer(modifier = Modifier.size(4.dp))
it.carbohydrate?.let {
Field(stringResource(id = R.string.gls_context_carbohydrate), it.toDisplayString())
Spacer(modifier = Modifier.size(4.dp))
record.sampleLocation?.let {
Field(stringResource(id = R.string.gls_details_location), it.toDisplayString())
Spacer(modifier = Modifier.size(4.dp))
}
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.Bottom
) {
Text(
text = stringResource(id = R.string.gls_details_glucose_condensation_title),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.outline
)
Text(
text = stringResource(
id = R.string.gls_details_glucose_condensation_field,
record.glucoseConcentration,
record.unit.toDisplayString()
),
style = MaterialTheme.typography.titleLarge
)
}
Divider(
color = MaterialTheme.colorScheme.secondary,
thickness = 1.dp,
modifier = Modifier.padding(vertical = 16.dp)
)
record.status?.let {
BooleanField(
stringResource(id = R.string.gls_details_battery_low),
it.deviceBatteryLow
)
Spacer(modifier = Modifier.size(4.dp))
BooleanField(
stringResource(id = R.string.gls_details_sensor_malfunction),
it.sensorMalfunction
)
Spacer(modifier = Modifier.size(4.dp))
BooleanField(
stringResource(id = R.string.gls_details_insufficient_sample),
it.sampleSizeInsufficient
)
Spacer(modifier = Modifier.size(4.dp))
BooleanField(
stringResource(id = R.string.gls_details_strip_insertion_error),
it.stripInsertionError
)
Spacer(modifier = Modifier.size(4.dp))
BooleanField(
stringResource(id = R.string.gls_details_strip_type_incorrect),
it.stripTypeIncorrect
)
Spacer(modifier = Modifier.size(4.dp))
BooleanField(
stringResource(id = R.string.gls_details_sensor_result_too_high),
it.sensorResultHigherThenDeviceCanProcess
)
Spacer(modifier = Modifier.size(4.dp))
BooleanField(
stringResource(id = R.string.gls_details_sensor_result_too_low),
it.sensorResultLowerThenDeviceCanProcess
)
Spacer(modifier = Modifier.size(4.dp))
BooleanField(
stringResource(id = R.string.gls_details_temperature_too_high),
it.sensorTemperatureTooHigh
)
Spacer(modifier = Modifier.size(4.dp))
BooleanField(
stringResource(id = R.string.gls_details_temperature_too_low),
it.sensorTemperatureTooLow
)
Spacer(modifier = Modifier.size(4.dp))
BooleanField(
stringResource(id = R.string.gls_details_strip_pulled_too_soon),
it.sensorReadInterrupted
)
Spacer(modifier = Modifier.size(4.dp))
BooleanField(
stringResource(id = R.string.gls_details_general_device_fault),
it.generalDeviceFault
)
Spacer(modifier = Modifier.size(4.dp))
BooleanField(stringResource(id = R.string.gls_details_time_fault), it.timeFault)
Spacer(modifier = Modifier.size(4.dp))
}
Divider(
color = MaterialTheme.colorScheme.secondary,
thickness = 1.dp,
modifier = Modifier.padding(vertical = 16.dp)
)
record.context?.let {
Field(
stringResource(id = R.string.gls_context_title),
stringResource(id = R.string.gls_available)
)
Spacer(modifier = Modifier.size(4.dp))
it.carbohydrate?.let {
Field(
stringResource(id = R.string.gls_context_carbohydrate),
it.toDisplayString()
)
Spacer(modifier = Modifier.size(4.dp))
}
it.meal?.let {
Field(stringResource(id = R.string.gls_context_meal), it.toDisplayString())
Spacer(modifier = Modifier.size(4.dp))
}
it.tester?.let {
Field(stringResource(id = R.string.gls_context_tester), it.toDisplayString())
Spacer(modifier = Modifier.size(4.dp))
}
it.health?.let {
Field(stringResource(id = R.string.gls_context_health), it.toDisplayString())
Spacer(modifier = Modifier.size(4.dp))
}
Field(
stringResource(id = R.string.gls_context_exercise_title),
stringResource(
id = R.string.gls_context_exercise_field,
it.exerciseDuration,
it.exerciseIntensity
)
)
Spacer(modifier = Modifier.size(4.dp))
val medicationField = String.format(
stringResource(id = R.string.gls_context_medication_field),
it.medicationQuantity,
it.medicationUnit.toDisplayString(),
it.medication?.toDisplayString()
)
Field(stringResource(id = R.string.gls_context_medication_title), medicationField)
Spacer(modifier = Modifier.size(4.dp))
Field(
stringResource(id = R.string.gls_context_hba1c_title),
stringResource(id = R.string.gls_context_hba1c_field, it.HbA1c)
)
Spacer(modifier = Modifier.size(4.dp))
} ?: Field(
stringResource(id = R.string.gls_context_title),
stringResource(id = R.string.gls_unavailable)
)
}
it.meal?.let {
Field(stringResource(id = R.string.gls_context_meal), it.toDisplayString())
Spacer(modifier = Modifier.size(4.dp))
}
it.tester?.let {
Field(stringResource(id = R.string.gls_context_tester), it.toDisplayString())
Spacer(modifier = Modifier.size(4.dp))
}
it.health?.let {
Field(stringResource(id = R.string.gls_context_health), it.toDisplayString())
Spacer(modifier = Modifier.size(4.dp))
}
Field(stringResource(id = R.string.gls_context_exercise_title), stringResource(id = R.string.gls_context_exercise_field, it.exerciseDuration, it.exerciseIntensity))
Spacer(modifier = Modifier.size(4.dp))
val medicationField = String.format(stringResource(id = R.string.gls_context_medication_field), it.medicationQuantity, it.medicationUnit.toDisplayString(), it.medication?.toDisplayString())
Field(stringResource(id = R.string.gls_context_medication_title), medicationField)
Spacer(modifier = Modifier.size(4.dp))
Field(stringResource(id = R.string.gls_context_hba1c_title), stringResource(id = R.string.gls_context_hba1c_field, it.HbA1c))
Spacer(modifier = Modifier.size(4.dp))
} ?: Field(stringResource(id = R.string.gls_context_title), stringResource(id = R.string.gls_unavailable))
}
@Composable
private fun GLSDetailsContentView() {
val record = GLSRecord(
sequenceNumber = 1,
time = Calendar.getInstance(),
glucoseConcentration = 12f,
type = RecordType.ARTERIAL_PLASMA,
status = GlucoseMeasurementCallback.GlucoseStatus(0x0004),
unit = ConcentrationUnit.UNIT_KGPL,
sampleLocation = SampleLocation.FINGER,
context = MeasurementContext(
sequenceNumber = 3,
carbohydrate = GlucoseMeasurementContextCallback.Carbohydrate.BREAKFAST,
carbohydrateAmount = 23f,
meal = GlucoseMeasurementContextCallback.Meal.BEDTIME,
tester = GlucoseMeasurementContextCallback.Tester.HEALTH_CARE_PROFESSIONAL,
health = GlucoseMeasurementContextCallback.Health.MAJOR_HEALTH_ISSUES,
exerciseDuration = 3,
exerciseIntensity = 3,
medication = GlucoseMeasurementContextCallback.Medication.INTERMEDIATE_ACTING_INSULIN,
medicationQuantity = 4f,
medicationUnit = MedicationUnit.UNIT_KG,
HbA1c = 21f
)
)
GLSDetailsContentView(record)
}
}

View File

@@ -100,12 +100,3 @@ internal fun Meal.toDisplayString(): String {
Meal.BEDTIME -> stringResource(id = R.string.gls_meal_bedtime)
}
}
@Composable
internal fun Boolean.toGLSStatus(): String {
return if (this) {
stringResource(id = R.string.gls_yes)
} else {
stringResource(id = R.string.gls_no)
}
}

View File

@@ -2,10 +2,10 @@ package no.nordicsemi.android.gls.details.viewmodel
import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import no.nordicsemi.android.gls.GlsDetailsDestinationId
import no.nordicsemi.android.gls.data.GLSRecord
import no.nordicsemi.android.navigation.AnyArgument
import no.nordicsemi.android.navigation.NavigationManager
import no.nordicsemi.ui.scanner.ScannerDestinationId
import javax.inject.Inject
@HiltViewModel
@@ -14,7 +14,7 @@ internal class GLSDetailsViewModel @Inject constructor(
) : ViewModel() {
val record =
(navigationManager.getImmediateArgument(ScannerDestinationId) as AnyArgument).value as GLSRecord
(navigationManager.getImmediateArgument(GlsDetailsDestinationId) as AnyArgument).value as GLSRecord
fun navigateBack() {
navigationManager.navigateUp()

View File

@@ -2,6 +2,7 @@ package no.nordicsemi.android.gls.main.view
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Search
import androidx.compose.material.icons.filled.Settings
@@ -11,6 +12,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
@@ -103,7 +105,7 @@ private fun RecordsViewWithData(state: GLSData) {
state.records.forEachIndexed { i, it ->
RecordItem(it)
if (i < state.records.size-1) {
if (i < state.records.size - 1) {
Spacer(modifier = Modifier.size(8.dp))
}
}
@@ -114,32 +116,46 @@ private fun RecordsViewWithData(state: GLSData) {
private fun RecordItem(record: GLSRecord) {
val viewModel: GLSViewModel = hiltViewModel()
Row(verticalAlignment = Alignment.CenterVertically) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.clip(RoundedCornerShape(10.dp))
.clickable { viewModel.onEvent(OnGLSRecordClick(record)) }
.padding(8.dp)
) {
Column(
modifier = Modifier
.fillMaxWidth()
.weight(1f)
.clickable { viewModel.onEvent(OnGLSRecordClick(record)) }
) {
record.time?.let {
Text(
text = stringResource(R.string.gls_timestamp, it),
style = MaterialTheme.typography.labelLarge
style = MaterialTheme.typography.titleMedium
)
}
Text(
text = record.type.toDisplayString(),
style = MaterialTheme.typography.bodyMedium
)
Spacer(modifier = Modifier.size(4.dp))
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.Bottom,
modifier = Modifier.fillMaxWidth()
) {
Text(
text = record.type.toDisplayString(),
style = MaterialTheme.typography.bodySmall
)
Text(
text = glucoseConcentrationDisplayValue(
record.glucoseConcentration,
record.unit
),
style = MaterialTheme.typography.labelLarge,
)
}
}
Spacer(modifier = Modifier.size(16.dp))
Text(
text = glucoseConcentrationDisplayValue(record.glucoseConcentration, record.unit),
style = MaterialTheme.typography.titleMedium,
)
}
}

View File

@@ -103,7 +103,7 @@
<string name="gls_context_exercise_title">Exercise:</string>
<string name="gls_context_exercise_field">%d min %d%%</string>
<string name="gls_context_medication_title">Medication:</string>
<string name="gls_context_medication_field">%d %s \n %s</string>
<string name="gls_context_medication_field">%.2f%s\n%s</string>
<string name="gls_context_hba1c_title">HbA1c:</string>
<string name="gls_context_hba1c_field">%.2f%%</string>
</resources>

View File

@@ -33,7 +33,7 @@ dependencyResolutionManagement {
version('compose', '1.0.5')
alias('compose-livedata').to('androidx.compose.runtime', 'runtime-livedata').versionRef('compose')
alias('compose-ui').to('androidx.compose.ui', 'ui').versionRef('compose')
alias('compose-material').to('androidx.compose.material3:material3:1.0.0-alpha01')
alias('compose-material').to('androidx.compose.material3:material3:1.0.0-alpha04')
alias('compose-tooling-preview').to('androidx.compose.ui', 'ui-tooling-preview').versionRef('compose')
alias('compose-navigation').to('androidx.navigation:navigation-compose:2.4.0-alpha09')
bundle('compose', ['compose-livedata', 'compose-ui', 'compose-material', 'compose-tooling-preview', 'compose-navigation'])