mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-08-03 23:02:28 +02:00
Enables new fields for vision prescriptions
This commit is contained in:
@@ -94,16 +94,31 @@ class VisionPrescription(
|
||||
var dateWritten: String? = null,
|
||||
var prescriber: Reference? = Reference(),
|
||||
var lensSpecification: List<LensSpecification> = arrayListOf(),
|
||||
) : Resource(resourceType, id)
|
||||
) : Resource(resourceType, id) {
|
||||
fun glasses() = lensSpecification.filter { it.product == "lens" }
|
||||
|
||||
fun contacts() = lensSpecification.filter { it.product == "contacts" }
|
||||
|
||||
fun glassesRightEyes() = lensSpecification.filter { it.product == "lens" && it.eye == "right" }
|
||||
|
||||
fun glassesLeftEyes() = lensSpecification.filter { it.product == "lens" && it.eye == "left" }
|
||||
|
||||
fun contactsRightEyes() = lensSpecification.filter { it.product == "contacts" && it.eye == "right" }
|
||||
|
||||
fun contactsLeftEyes() = lensSpecification.filter { it.product == "contacts" && it.eye == "left" }
|
||||
}
|
||||
|
||||
@Stable
|
||||
class LensSpecification(
|
||||
var product: String? = null,
|
||||
var eye: String? = null,
|
||||
var sphere: Double? = null,
|
||||
var cylinder: Double? = null,
|
||||
var axis: Double? = null,
|
||||
var pd: Double? = null,
|
||||
var interAdd: Double? = null,
|
||||
var add: Double? = null,
|
||||
var prism: List<Prism> = arrayListOf(),
|
||||
var prism: Prism? = null,
|
||||
// contact lenses
|
||||
var power: Double? = null,
|
||||
var backCurve: Double? = null,
|
||||
|
@@ -45,6 +45,8 @@ import com.vitorpamplona.amethyst.model.LensSpecification
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.model.Patient
|
||||
import com.vitorpamplona.amethyst.model.Practitioner
|
||||
import com.vitorpamplona.amethyst.model.Prism
|
||||
import com.vitorpamplona.amethyst.model.Reference
|
||||
import com.vitorpamplona.amethyst.model.Resource
|
||||
import com.vitorpamplona.amethyst.model.VisionPrescription
|
||||
import com.vitorpamplona.amethyst.model.findReferenceInDb
|
||||
@@ -58,10 +60,12 @@ import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.quartz.events.Event
|
||||
import com.vitorpamplona.quartz.events.FhirResourceEvent
|
||||
import kotlinx.collections.immutable.ImmutableMap
|
||||
import kotlinx.collections.immutable.toImmutableMap
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.text.DecimalFormat
|
||||
import java.text.NumberFormat
|
||||
import kotlin.math.abs
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
@@ -74,6 +78,97 @@ fun RenderEyeGlassesPrescriptionPreview() {
|
||||
RenderFhirResource(prescriptionEvent)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun RenderEyeGlassesPrescription2Preview() {
|
||||
val vision =
|
||||
VisionPrescription(
|
||||
id = "1",
|
||||
status = null,
|
||||
created = null,
|
||||
patient = Reference(),
|
||||
encounter = Reference(),
|
||||
dateWritten = null,
|
||||
prescriber = Reference(),
|
||||
lensSpecification =
|
||||
listOf(
|
||||
LensSpecification(
|
||||
product = "lens",
|
||||
eye = "right",
|
||||
sphere = -1.00,
|
||||
cylinder = -2.00,
|
||||
axis = 180.0,
|
||||
pd = 31.0,
|
||||
interAdd = 1.50,
|
||||
add = 1.75,
|
||||
prism = Prism(12.0, "down"),
|
||||
power = null,
|
||||
diameter = null,
|
||||
color = null,
|
||||
brand = null,
|
||||
note = null,
|
||||
),
|
||||
LensSpecification(
|
||||
product = "lens",
|
||||
eye = "left",
|
||||
sphere = -1.00,
|
||||
cylinder = -2.00,
|
||||
axis = 180.0,
|
||||
pd = 31.0,
|
||||
interAdd = 1.50,
|
||||
add = 1.75,
|
||||
prism = Prism(12.0, "down"),
|
||||
power = null,
|
||||
diameter = null,
|
||||
color = null,
|
||||
brand = null,
|
||||
note = null,
|
||||
),
|
||||
LensSpecification(
|
||||
product = "contacts",
|
||||
eye = "right",
|
||||
sphere = -1.00,
|
||||
cylinder = -2.00,
|
||||
axis = 180.0,
|
||||
pd = null,
|
||||
interAdd = null,
|
||||
add = null,
|
||||
prism = null,
|
||||
backCurve = 12.0,
|
||||
power = 1.2,
|
||||
diameter = 1.2,
|
||||
color = "blue",
|
||||
brand = "Blue Glasses",
|
||||
note = "note",
|
||||
),
|
||||
LensSpecification(
|
||||
product = "contacts",
|
||||
eye = "left",
|
||||
sphere = -1.00,
|
||||
cylinder = -2.00,
|
||||
axis = 180.0,
|
||||
pd = null,
|
||||
interAdd = null,
|
||||
add = null,
|
||||
prism = null,
|
||||
backCurve = 12.0,
|
||||
power = 1.2,
|
||||
diameter = 1.2,
|
||||
color = "blue",
|
||||
brand = "Blue Glasses",
|
||||
note = "note",
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
val db =
|
||||
mapOf(
|
||||
"1" to vision,
|
||||
).toImmutableMap()
|
||||
|
||||
RenderEyeGlassesPrescription(vision, db)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RenderFhirResource(
|
||||
baseNote: Note,
|
||||
@@ -99,7 +194,7 @@ fun RenderFhirResource(event: FhirResourceEvent) {
|
||||
state.baseResource?.let { resource ->
|
||||
when (resource) {
|
||||
is Bundle -> {
|
||||
val vision = resource.entry.filterIsInstance(VisionPrescription::class.java)
|
||||
val vision = resource.entry.filterIsInstance<VisionPrescription>()
|
||||
|
||||
vision.firstOrNull()?.let {
|
||||
RenderEyeGlassesPrescription(it, state.localDb)
|
||||
@@ -125,11 +220,25 @@ fun RenderEyeGlassesPrescription(
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = Size10dp),
|
||||
) {
|
||||
val rightEye = visionPrescription.lensSpecification.firstOrNull { it.eye == "right" }
|
||||
val leftEye = visionPrescription.lensSpecification.firstOrNull { it.eye == "left" }
|
||||
val glassesRightEye = visionPrescription.glassesRightEyes().firstOrNull()
|
||||
val glassesLeftEye = visionPrescription.glassesLeftEyes().firstOrNull()
|
||||
|
||||
val contactsRightEye = visionPrescription.contactsRightEyes().firstOrNull()
|
||||
val contactsLeftEye = visionPrescription.contactsLeftEyes().firstOrNull()
|
||||
|
||||
val isGlasses = glassesRightEye != null || glassesLeftEye != null
|
||||
val isContacts = contactsRightEye != null || contactsLeftEye != null
|
||||
|
||||
Text(
|
||||
"Eyeglasses Prescription",
|
||||
if (isGlasses && isContacts) {
|
||||
"Vision Prescription"
|
||||
} else if (isGlasses) {
|
||||
"Glasses Prescription"
|
||||
} else if (isContacts) {
|
||||
"Contact Lenses Prescription"
|
||||
} else {
|
||||
"Empty Prescription"
|
||||
},
|
||||
modifier = Modifier.padding(4.dp).fillMaxWidth(),
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
@@ -155,18 +264,37 @@ fun RenderEyeGlassesPrescription(
|
||||
|
||||
Spacer(DoubleVertSpacer)
|
||||
|
||||
if (isGlasses) {
|
||||
RenderEyeGlassesPrescriptionHeaderRow()
|
||||
HorizontalDivider(thickness = DividerThickness)
|
||||
|
||||
rightEye?.let {
|
||||
glassesRightEye?.let {
|
||||
RenderEyeGlassesPrescriptionRow(data = it)
|
||||
HorizontalDivider(thickness = DividerThickness)
|
||||
}
|
||||
|
||||
leftEye?.let {
|
||||
glassesLeftEye?.let {
|
||||
RenderEyeGlassesPrescriptionRow(data = it)
|
||||
HorizontalDivider(thickness = DividerThickness)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(DoubleVertSpacer)
|
||||
|
||||
if (isContacts) {
|
||||
RenderEyeContactsPrescriptionHeaderRow()
|
||||
HorizontalDivider(thickness = DividerThickness)
|
||||
|
||||
contactsRightEye?.let {
|
||||
RenderEyeContactsPrescriptionRow(data = it)
|
||||
HorizontalDivider(thickness = DividerThickness)
|
||||
}
|
||||
|
||||
contactsLeftEye?.let {
|
||||
RenderEyeContactsPrescriptionRow(data = it)
|
||||
HorizontalDivider(thickness = DividerThickness)
|
||||
}
|
||||
}
|
||||
|
||||
visionPrescription.prescriber?.reference?.let {
|
||||
val practitioner = findReferenceInDb(it, db) as? Practitioner
|
||||
@@ -211,7 +339,7 @@ fun RenderEyeGlassesPrescriptionHeaderRow() {
|
||||
)
|
||||
VerticalDivider(thickness = DividerThickness)
|
||||
Text(
|
||||
text = "Add",
|
||||
text = "PD",
|
||||
textAlign = TextAlign.Right,
|
||||
modifier = Modifier.padding(4.dp).weight(1f),
|
||||
)
|
||||
@@ -220,14 +348,15 @@ fun RenderEyeGlassesPrescriptionHeaderRow() {
|
||||
|
||||
@Composable
|
||||
fun RenderEyeGlassesPrescriptionRow(data: LensSpecification) {
|
||||
val numberFormat = DecimalFormat("##.00")
|
||||
val pdFormat = DecimalFormat("##.0")
|
||||
val integerFormat = DecimalFormat("###")
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().height(IntrinsicSize.Min),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
val numberFormat = DecimalFormat("##.00")
|
||||
val integerFormat = DecimalFormat("###")
|
||||
|
||||
Text(
|
||||
text = data.eye?.capitalize() ?: "Unknown",
|
||||
modifier = Modifier.padding(4.dp).weight(1f),
|
||||
@@ -250,11 +379,241 @@ fun RenderEyeGlassesPrescriptionRow(data: LensSpecification) {
|
||||
)
|
||||
VerticalDivider(thickness = DividerThickness)
|
||||
Text(
|
||||
text = formatOrBlank(data.add, numberFormat),
|
||||
text = formatOrBlank(data.pd, pdFormat),
|
||||
textAlign = TextAlign.Right,
|
||||
modifier = Modifier.padding(4.dp).weight(1f),
|
||||
)
|
||||
}
|
||||
|
||||
if (data.interAdd != null) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().height(IntrinsicSize.Min),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
text = "",
|
||||
modifier = Modifier.padding(4.dp).weight(1f),
|
||||
)
|
||||
VerticalDivider(thickness = DividerThickness)
|
||||
|
||||
if (data.interAdd != null) {
|
||||
Text(
|
||||
text = "Inter Add:",
|
||||
textAlign = TextAlign.Right,
|
||||
modifier = Modifier.padding(4.dp).weight(2f),
|
||||
)
|
||||
|
||||
Text(
|
||||
text = formatOrBlank(data.interAdd, numberFormat),
|
||||
textAlign = TextAlign.Right,
|
||||
modifier = Modifier.padding(4.dp).weight(2f),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data.add != null) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().height(IntrinsicSize.Min),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
text = "",
|
||||
modifier = Modifier.padding(4.dp).weight(1f),
|
||||
)
|
||||
VerticalDivider(thickness = DividerThickness)
|
||||
|
||||
if (data.add != null) {
|
||||
Text(
|
||||
text = "Add:",
|
||||
textAlign = TextAlign.Right,
|
||||
modifier = Modifier.padding(4.dp).weight(2f),
|
||||
)
|
||||
|
||||
Text(
|
||||
text = formatOrBlank(data.add, numberFormat),
|
||||
textAlign = TextAlign.Right,
|
||||
modifier = Modifier.padding(4.dp).weight(2f),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data.prism?.amount != null || data.prism?.base != null) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().height(IntrinsicSize.Min),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
text = "",
|
||||
modifier = Modifier.padding(4.dp).weight(1f),
|
||||
)
|
||||
VerticalDivider(thickness = DividerThickness)
|
||||
|
||||
Text(
|
||||
text = "Prism:",
|
||||
textAlign = TextAlign.Right,
|
||||
modifier = Modifier.padding(4.dp).weight(2f),
|
||||
)
|
||||
|
||||
Text(
|
||||
text = formatOrBlank(data.prism?.amount, numberFormat),
|
||||
textAlign = TextAlign.Right,
|
||||
modifier = Modifier.padding(4.dp).weight(1f),
|
||||
)
|
||||
|
||||
Text(
|
||||
text = data.prism?.base ?: "",
|
||||
textAlign = TextAlign.Right,
|
||||
modifier = Modifier.padding(4.dp).weight(1f),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RenderEyeContactsPrescriptionHeaderRow() {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().height(IntrinsicSize.Min),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
Text(
|
||||
text = "Eye",
|
||||
modifier = Modifier.padding(4.dp).weight(1f),
|
||||
)
|
||||
VerticalDivider(thickness = DividerThickness)
|
||||
Text(
|
||||
text = "Sph",
|
||||
textAlign = TextAlign.Right,
|
||||
modifier = Modifier.padding(4.dp).weight(1f),
|
||||
)
|
||||
Text(
|
||||
text = "Cyl",
|
||||
textAlign = TextAlign.Right,
|
||||
modifier = Modifier.padding(4.dp).weight(1f),
|
||||
)
|
||||
Text(
|
||||
text = "Axis",
|
||||
textAlign = TextAlign.Right,
|
||||
modifier = Modifier.padding(4.dp).weight(1f),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RenderEyeContactsPrescriptionRow(data: LensSpecification) {
|
||||
val numberFormat = DecimalFormat("##.00")
|
||||
val integerFormat = DecimalFormat("###")
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().height(IntrinsicSize.Min),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
text = data.eye?.capitalize() ?: "Unknown",
|
||||
modifier = Modifier.padding(4.dp).weight(1f),
|
||||
)
|
||||
VerticalDivider(thickness = DividerThickness)
|
||||
Text(
|
||||
text = formatOrBlank(data.sphere, numberFormat),
|
||||
textAlign = TextAlign.Right,
|
||||
modifier = Modifier.padding(4.dp).weight(1f),
|
||||
)
|
||||
Text(
|
||||
text = formatOrBlank(data.cylinder, numberFormat),
|
||||
textAlign = TextAlign.Right,
|
||||
modifier = Modifier.padding(4.dp).weight(1f),
|
||||
)
|
||||
Text(
|
||||
text = formatOrBlank(data.axis, integerFormat),
|
||||
textAlign = TextAlign.Right,
|
||||
modifier = Modifier.padding(4.dp).weight(1f),
|
||||
)
|
||||
}
|
||||
|
||||
if (data.backCurve != null || data.diameter != null) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().height(IntrinsicSize.Min),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
text = "",
|
||||
textAlign = TextAlign.Right,
|
||||
modifier = Modifier.padding(4.dp).weight(1f),
|
||||
)
|
||||
VerticalDivider(thickness = DividerThickness)
|
||||
Text(
|
||||
text = "",
|
||||
textAlign = TextAlign.Right,
|
||||
modifier = Modifier.padding(4.dp).weight(1f),
|
||||
)
|
||||
Text(
|
||||
text = "Curve:",
|
||||
textAlign = TextAlign.Right,
|
||||
modifier = Modifier.padding(4.dp).weight(1f),
|
||||
)
|
||||
Text(
|
||||
text = formatOrBlank(data.backCurve, numberFormat),
|
||||
textAlign = TextAlign.Right,
|
||||
modifier = Modifier.padding(4.dp).weight(1f),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (data.backCurve != null || data.diameter != null) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().height(IntrinsicSize.Min),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
text = "",
|
||||
textAlign = TextAlign.Right,
|
||||
modifier = Modifier.padding(4.dp).weight(1f),
|
||||
)
|
||||
VerticalDivider(thickness = DividerThickness)
|
||||
Text(
|
||||
text = "",
|
||||
textAlign = TextAlign.Right,
|
||||
modifier = Modifier.padding(4.dp).weight(1f),
|
||||
)
|
||||
Text(
|
||||
text = "Diameter:",
|
||||
textAlign = TextAlign.Right,
|
||||
modifier = Modifier.padding(4.dp).weight(1f),
|
||||
)
|
||||
Text(
|
||||
text = formatOrBlank(data.diameter, numberFormat),
|
||||
textAlign = TextAlign.Right,
|
||||
modifier = Modifier.padding(4.dp).weight(1f),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (data.brand != null) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().height(IntrinsicSize.Min),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
text = "",
|
||||
textAlign = TextAlign.Right,
|
||||
modifier = Modifier.padding(4.dp).weight(1f),
|
||||
)
|
||||
VerticalDivider(thickness = DividerThickness)
|
||||
Text(
|
||||
text = data.brand ?: "",
|
||||
textAlign = TextAlign.Right,
|
||||
modifier = Modifier.padding(4.dp).weight(3f),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun formatOrBlank(
|
||||
@@ -262,6 +621,6 @@ fun formatOrBlank(
|
||||
numberFormat: NumberFormat,
|
||||
): String {
|
||||
if (amount == null) return ""
|
||||
if (Math.abs(amount) < 0.01) return ""
|
||||
if (abs(amount) < 0.01) return ""
|
||||
return numberFormat.format(amount)
|
||||
}
|
||||
|
Reference in New Issue
Block a user