Skip to content

Commit

Permalink
Add BMI Entry Sheet
Browse files Browse the repository at this point in the history
  • Loading branch information
Siddharth Agarwal committed Dec 19, 2024
1 parent 5008054 commit be27c1f
Show file tree
Hide file tree
Showing 6 changed files with 360 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import org.simple.clinic.newentry.country.di.InputFieldsFactoryModule
import org.simple.clinic.onboarding.OnboardingScreen
import org.simple.clinic.overdue.download.formatdialog.SelectOverdueDownloadFormatDialog
import org.simple.clinic.patient.download.formatdialog.SelectLineListFormatDialog
import org.simple.clinic.patientattribute.entry.BMIEntrySheet
import org.simple.clinic.reassignpatient.ReassignPatientSheet
import org.simple.clinic.recentpatient.RecentPatientsScreen
import org.simple.clinic.recentpatientsview.RecentPatientsView
Expand Down Expand Up @@ -167,7 +168,8 @@ interface TheActivityComponent :
PatientsTabLinkView.Injector,
MonthlyReportsScreen.Injector,
MonthlyReportCompleteScreen.Injector,
ReassignPatientSheet.Injector {
ReassignPatientSheet.Injector,
BMIEntrySheet.Injector {
fun inject(target: TheActivity)

@Subcomponent.Factory
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ data class BMIEntryModel(
val height: String = "",
val weight: String = ""
) : Parcelable {
companion object {
fun default(patientUUID: UUID) = BMIEntryModel(
patientUUID = patientUUID,
)
}
companion object {
fun default(patientUUID: UUID) = BMIEntryModel(
patientUUID = patientUUID,
)
}

fun heightChanged(height: String): BMIEntryModel =
copy(height = height)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package org.simple.clinic.patientattribute.entry

import android.content.Context
import android.os.Parcelable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import com.jakewharton.rxbinding3.view.clicks
import com.jakewharton.rxbinding3.widget.editorActions
import com.jakewharton.rxbinding3.widget.textChanges
import com.spotify.mobius.functions.Consumer
import io.reactivex.Observable
import io.reactivex.rxkotlin.cast
import io.reactivex.rxkotlin.toObservable
import kotlinx.parcelize.Parcelize
import org.simple.clinic.R
import org.simple.clinic.ReportAnalyticsEvents
import org.simple.clinic.databinding.SheetBmiReadingBinding
import org.simple.clinic.di.injector
import org.simple.clinic.mobius.DeferredEventSource
import org.simple.clinic.navigation.v2.Router
import org.simple.clinic.navigation.v2.ScreenKey
import org.simple.clinic.navigation.v2.Succeeded
import org.simple.clinic.navigation.v2.fragments.BaseBottomSheet
import org.simple.clinic.widgets.UiEvent
import java.util.UUID
import javax.inject.Inject

class BMIEntrySheet : BaseBottomSheet<
BMIEntrySheet.Key,
SheetBmiReadingBinding,
BMIEntryModel,
BMIEntryEvent,
BMIEntryEffect,
BMIEntryViewEffect>(),
BMIEntryUi {

@Inject
lateinit var effectHandlerFactory: BMIEntryEffectHandler.Factory

@Inject
lateinit var router: Router

private val additionalEvents = DeferredEventSource<BMIEntryEvent>()

private val rootLayout
get() = binding.rootLayout

private val backImageButton
get() = binding.backImageButton

private val heightEditText
get() = binding.heightEditText

private val weightEditText
get() = binding.weightEditText

private val bmiTextView
get() = binding.bmiTextView

override fun defaultModel() = BMIEntryModel.default(
patientUUID = screenKey.patientId,
)

override fun uiRenderer() = BMIEntryUiRenderer(this)

override fun bindView(inflater: LayoutInflater, container: ViewGroup?) =
SheetBmiReadingBinding.inflate(layoutInflater, container, false)

override fun createUpdate() = BMIEntryUpdate()

override fun createEffectHandler(viewEffectsConsumer: Consumer<BMIEntryViewEffect>) =
effectHandlerFactory.create(this).build()

override fun additionalEventSources() = listOf(
additionalEvents
)

override fun events() = Observable
.mergeArray(
heightChanges(),
weightChanges(),
weightBackspaceClicks(),
imeDoneClicks(),
hardwareBackPresses(),
backButtonClicks(),
)
.compose(ReportAnalyticsEvents())
.cast<BMIEntryEvent>()

override fun onAttach(context: Context) {
super.onAttach(context)
context.injector<Injector>().inject(this)
}

private fun backButtonClicks(): Observable<UiEvent> {
return backImageButton
.clicks()
.map { BackPressed }
}

private fun heightChanges() = heightEditText
.textChanges()
.map(CharSequence::toString)
.map(::HeightChanged)

private fun weightChanges() = weightEditText
.textChanges()
.map(CharSequence::toString)
.map(::WeightChanged)

private fun weightBackspaceClicks(): Observable<UiEvent> {
return weightEditText
.backspaceClicks
.map { WeightBackspaceClicked }
}

private fun imeDoneClicks(): Observable<SaveClicked> {
return listOf(heightEditText, weightEditText)
.map { it.editorActions { actionId -> actionId == EditorInfo.IME_ACTION_DONE } }
.toObservable()
.flatMap { it }
.map { SaveClicked }
}

private fun hardwareBackPresses(): Observable<UiEvent> {
return Observable.create { emitter ->
val interceptor = {
emitter.onNext(BackPressed)
}
emitter.setCancellable { rootLayout.backKeyPressInterceptor = null }
rootLayout.backKeyPressInterceptor = interceptor
}
}

override fun closeSheet() {
router.popWithResult(Succeeded(BMIAdded))
}

override fun changeFocusToHeight() {
heightEditText.requestFocus()
}

override fun changeFocusToWeight() {
weightEditText.requestFocus()
}

override fun showBMI(bmi: String) {
bmiTextView.text = getString(R.string.bmi_x, bmi)
bmiTextView.visibility = View.VISIBLE
}

override fun hideBMI() {
bmiTextView.visibility = View.GONE
}

@Parcelize
data class Key(
val patientId: UUID,
) : ScreenKey() {

override val analyticsName = "BMI Entry Sheet"

override val type = ScreenType.Modal

override fun instantiateFragment() = BMIEntrySheet()
}

interface Injector {
fun inject(target: BMIEntrySheet)
}

@Parcelize
object BMIAdded : Parcelable
}

10 changes: 10 additions & 0 deletions app/src/main/res/drawable/background_bmi.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/simple_light_grey" />
<corners android:radius="24dp" />
<padding
android:bottom="4dp"
android:left="72dp"
android:right="72dp"
android:top="4dp" />
</shape>
160 changes: 160 additions & 0 deletions app/src/main/res/layout/sheet_bmi_reading.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
<?xml version="1.0" encoding="utf-8"?>
<org.simple.clinic.widgets.LinearLayoutWithPreImeKeyEventListener xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rootLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:orientation="vertical"
tools:background="?attr/colorSurface"
tools:context=".bp.entry.BloodPressureEntrySheet"
tools:layout_gravity="bottom">

<LinearLayout
android:id="@+id/bloodpressureentry_flipper_bp_entry"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="@dimen/spacing_12">

<RelativeLayout
android:layout_width="match_parent"
android:layout_marginTop="24dp"
android:layout_height="wrap_content">

<ImageButton
android:id="@+id/backImageButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_8"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:background="?selectableItemBackgroundBorderless"
android:padding="@dimen/spacing_8"
app:srcCompat="@drawable/ic_arrow_back_24dp"
app:tint="?attr/colorPrimary"
tools:ignore="ContentDescription" />

<TextView
android:id="@+id/enterBMITitleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center_horizontal"
android:lines="1"
android:text="@string/bmi_entry_sheet_title_enter_bmi"
android:textAppearance="?attr/textAppearanceHeadline6"
android:textColor="?attr/colorOnSurface"
android:visibility="gone"
tools:ignore="UnusedAttribute"
tools:visibility="visible" />
</RelativeLayout>

<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/bmiEntryLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_16"
android:layout_marginBottom="@dimen/spacing_12"
app:layout_optimizationLevel="direct|barrier">

<com.google.android.material.textfield.TextInputLayout
android:id="@+id/heightTextFieldLayout"
style="@style/Widget.Simple.TextField.Layout.Large.MeasurementInput"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toStartOf="@+id/bmi_entry_height_weight_separator"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent">

<com.google.android.material.textfield.TextInputEditText
android:id="@+id/heightEditText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:imeOptions="actionDone"
android:importantForAutofill="no"
android:inputType="number"
tools:ignore="UnusedAttribute"
tools:text="120">

<requestFocus />

</com.google.android.material.textfield.TextInputEditText>

</com.google.android.material.textfield.TextInputLayout>

<TextView
android:id="@+id/bmi_entry_height_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_4"
android:gravity="center_horizontal"
android:labelFor="@+id/systolicEditText"
android:text="@string/bmi_entry_height_in_cm"
android:textAppearance="?attr/textAppearanceBody2"
android:textColor="@color/color_on_surface_67"
app:layout_constraintEnd_toEndOf="@+id/heightTextFieldLayout"
app:layout_constraintStart_toStartOf="@+id/heightTextFieldLayout"
app:layout_constraintTop_toBottomOf="@+id/heightTextFieldLayout" />

<TextView
android:id="@+id/bmi_entry_height_weight_separator"
style="@style/Widget.Simple.MeasurementInputSeparator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="@+id/heightTextFieldLayout"
app:layout_constraintEnd_toStartOf="@+id/weightTextFieldLayout"
app:layout_constraintStart_toEndOf="@+id/heightTextFieldLayout"
app:layout_constraintTop_toTopOf="@+id/heightTextFieldLayout" />

<com.google.android.material.textfield.TextInputLayout
android:id="@+id/weightTextFieldLayout"
style="@style/Widget.Simple.TextField.Layout.Large.MeasurementInput"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toStartOf="parent"
app:layout_constraintStart_toEndOf="@+id/bmi_entry_height_weight_separator"
app:layout_constraintTop_toTopOf="parent">

<org.simple.clinic.widgets.EditTextWithBackspaceListener
android:id="@+id/weightEditText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:imeOptions="actionDone"
android:importantForAutofill="no"
android:inputType="number"
tools:ignore="UnusedAttribute"
tools:text="80" />

</com.google.android.material.textfield.TextInputLayout>

<TextView
android:id="@+id/bmi_entry_weight_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:labelFor="@id/diastolicEditText"
android:text="@string/bmi_entry_weight_in_kg"
android:textAppearance="?attr/textAppearanceBody2"
android:textColor="@color/color_on_surface_67"
app:layout_constraintEnd_toEndOf="@+id/weightTextFieldLayout"
app:layout_constraintStart_toStartOf="@+id/weightTextFieldLayout"
app:layout_constraintTop_toBottomOf="@+id/weightTextFieldLayout" />

</androidx.constraintlayout.widget.ConstraintLayout>

<com.google.android.material.textview.MaterialTextView
android:id="@+id/bmiTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textAppearance="?attr/textAppearanceBody1"
android:textColor="@color/color_on_surface_67"
android:background="@drawable/background_bmi"
tools:text="BMI:32" />

</LinearLayout>

</org.simple.clinic.widgets.LinearLayoutWithPreImeKeyEventListener>
5 changes: 5 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1092,4 +1092,9 @@ The Simple app contains private health information of patients (“Data”).\n\n
<string name="purge_notification_title">Optimising database</string>
<string name="purge_notification_desc">Database maintenance in progress. This will only take a minute.</string>

<!-- BMI entry -->
<string name="bmi_entry_sheet_title_enter_bmi">BMI</string>
<string name="bmi_entry_height_in_cm">Height (cm)</string>
<string name="bmi_entry_weight_in_kg">Weight (kg)</string>
<string name="bmi_x">BMI: %s</string>
</resources>

0 comments on commit be27c1f

Please sign in to comment.