Skip to content

Commit aee7eb5

Browse files
authored
1 parent 522d77d commit aee7eb5

File tree

8 files changed

+461
-211
lines changed

8 files changed

+461
-211
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
- Migrate `OverdueScreen` patient list to Jetpack Compose
1515
- Migrate blood pressure summary view to Jetpack Compose
1616
- Migrate blood sugar summary view to Jetpack Compose
17+
- Migrate medical history summary view to Jetpack Compose
1718

1819
### Fixes
1920

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
package org.simple.clinic.medicalhistory.ui
2+
3+
import androidx.compose.animation.animateColorAsState
4+
import androidx.compose.foundation.background
5+
import androidx.compose.foundation.layout.Arrangement
6+
import androidx.compose.foundation.layout.Column
7+
import androidx.compose.foundation.layout.Row
8+
import androidx.compose.foundation.layout.padding
9+
import androidx.compose.material.ChipDefaults
10+
import androidx.compose.material.Divider
11+
import androidx.compose.material.ExperimentalMaterialApi
12+
import androidx.compose.material.FilterChip
13+
import androidx.compose.material.MaterialTheme
14+
import androidx.compose.material.Text
15+
import androidx.compose.runtime.Composable
16+
import androidx.compose.runtime.getValue
17+
import androidx.compose.ui.Alignment
18+
import androidx.compose.ui.Modifier
19+
import androidx.compose.ui.res.dimensionResource
20+
import androidx.compose.ui.res.stringResource
21+
import androidx.compose.ui.text.style.TextAlign
22+
import androidx.compose.ui.text.style.TextOverflow
23+
import androidx.compose.ui.tooling.preview.Preview
24+
import org.simple.clinic.R
25+
import org.simple.clinic.common.ui.theme.SimpleTheme
26+
import org.simple.clinic.medicalhistory.Answer
27+
import org.simple.clinic.medicalhistory.MedicalHistoryQuestion
28+
29+
@Composable
30+
fun MedicalHistoryQuestionItem(
31+
question: MedicalHistoryQuestion,
32+
selectedAnswer: Answer?,
33+
modifier: Modifier = Modifier,
34+
showDivider: Boolean = true,
35+
onSelectionChange: (Answer) -> Unit,
36+
) {
37+
Column(
38+
modifier = modifier
39+
.background(MaterialTheme.colors.surface)
40+
) {
41+
Row(
42+
modifier = Modifier,
43+
verticalAlignment = Alignment.CenterVertically,
44+
horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.spacing_16))
45+
) {
46+
Text(
47+
modifier = Modifier.weight(1f),
48+
text = stringResource(question.questionRes),
49+
style = MaterialTheme.typography.body1,
50+
color = MaterialTheme.colors.onSurface,
51+
maxLines = 1,
52+
overflow = TextOverflow.Ellipsis,
53+
)
54+
55+
AnswerChipsGroup(
56+
selectedAnswer = selectedAnswer,
57+
onSelectionChange = { newAnswer ->
58+
if (newAnswer == selectedAnswer) {
59+
onSelectionChange(Answer.Unanswered)
60+
} else {
61+
onSelectionChange(newAnswer)
62+
}
63+
}
64+
)
65+
}
66+
67+
if (showDivider) {
68+
Divider(color = SimpleTheme.colors.onSurface11)
69+
}
70+
}
71+
}
72+
73+
@Composable
74+
private fun AnswerChipsGroup(
75+
selectedAnswer: Answer?,
76+
onSelectionChange: (Answer) -> Unit
77+
) {
78+
Row(
79+
horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.spacing_8)),
80+
verticalAlignment = Alignment.CenterVertically,
81+
) {
82+
MedicalHistoryAnswerChip(
83+
label = stringResource(R.string.newmedicalhistory_yes),
84+
selected = selectedAnswer == Answer.Yes,
85+
onSelectionChange = {
86+
onSelectionChange(Answer.Yes)
87+
}
88+
)
89+
90+
MedicalHistoryAnswerChip(
91+
label = stringResource(R.string.newmedicalhistory_no),
92+
selected = selectedAnswer == Answer.No,
93+
onSelectionChange = {
94+
onSelectionChange(Answer.No)
95+
}
96+
)
97+
}
98+
}
99+
100+
@OptIn(ExperimentalMaterialApi::class)
101+
@Composable
102+
private fun MedicalHistoryAnswerChip(
103+
label: String,
104+
selected: Boolean,
105+
onSelectionChange: () -> Unit
106+
) {
107+
val backgroundColor by animateColorAsState(
108+
if (selected) MaterialTheme.colors.primary else MaterialTheme.colors.primaryVariant
109+
)
110+
val textColor by animateColorAsState(
111+
if (selected) MaterialTheme.colors.onPrimary else MaterialTheme.colors.primary
112+
)
113+
114+
FilterChip(
115+
selected = selected,
116+
colors = ChipDefaults.filterChipColors(
117+
backgroundColor = backgroundColor,
118+
),
119+
onClick = onSelectionChange,
120+
) {
121+
Text(
122+
modifier = Modifier.padding(horizontal = dimensionResource(R.dimen.spacing_12)),
123+
text = label,
124+
style = MaterialTheme.typography.body2,
125+
color = textColor,
126+
textAlign = TextAlign.Center,
127+
)
128+
}
129+
}
130+
131+
@Preview
132+
@Composable
133+
private fun MedicalHistoryQuestionItemPreview() {
134+
SimpleTheme {
135+
MedicalHistoryQuestionItem(
136+
question = MedicalHistoryQuestion.DiagnosedWithHypertension,
137+
selectedAnswer = null,
138+
showDivider = true,
139+
onSelectionChange = {
140+
// no-op
141+
}
142+
)
143+
}
144+
}
145+
146+
@Preview
147+
@Composable
148+
private fun MedicalHistoryQuestionItemYesPreview() {
149+
SimpleTheme {
150+
MedicalHistoryQuestionItem(
151+
question = MedicalHistoryQuestion.DiagnosedWithDiabetes,
152+
selectedAnswer = Answer.Yes,
153+
showDivider = true,
154+
onSelectionChange = {
155+
// no-op
156+
}
157+
)
158+
}
159+
}

app/src/main/java/org/simple/clinic/summary/medicalhistory/MedicalHistorySummaryUi.kt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@ interface MedicalHistorySummaryUi {
66
fun populateMedicalHistory(medicalHistory: MedicalHistory)
77
fun showDiagnosisView()
88
fun hideDiagnosisView()
9-
fun showDiabetesHistorySection()
10-
fun hideDiabetesHistorySection()
119
fun showCurrentSmokerQuestion()
1210
fun hideCurrentSmokerQuestion()
13-
1411
}

app/src/main/java/org/simple/clinic/summary/medicalhistory/MedicalHistorySummaryUiRenderer.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,8 @@ class MedicalHistorySummaryUiRenderer(
3535
private fun toggleDiabetesManagementUi(diabetesManagementEnabled: Boolean) {
3636
if (diabetesManagementEnabled) {
3737
ui.showDiagnosisView()
38-
ui.hideDiabetesHistorySection()
3938
} else {
4039
ui.hideDiagnosisView()
41-
ui.showDiabetesHistorySection()
4240
}
4341
}
4442
}

app/src/main/java/org/simple/clinic/summary/medicalhistory/MedicalHistorySummaryView.kt

Lines changed: 42 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,32 @@ package org.simple.clinic.summary.medicalhistory
33
import android.content.Context
44
import android.os.Parcelable
55
import android.util.AttributeSet
6-
import android.view.LayoutInflater
76
import android.widget.FrameLayout
87
import androidx.appcompat.app.AppCompatActivity
8+
import androidx.compose.animation.AnimatedVisibility
9+
import androidx.compose.runtime.getValue
10+
import androidx.compose.runtime.mutableStateOf
11+
import androidx.compose.runtime.setValue
12+
import androidx.compose.ui.platform.ComposeView
13+
import androidx.compose.ui.platform.ViewCompositionStrategy
914
import io.reactivex.Observable
1015
import io.reactivex.rxkotlin.ofType
1116
import io.reactivex.subjects.PublishSubject
1217
import org.simple.clinic.ReportAnalyticsEvents
13-
import org.simple.clinic.databinding.MedicalhistorySummaryViewBinding
18+
import org.simple.clinic.common.ui.theme.SimpleTheme
1419
import org.simple.clinic.di.injector
1520
import org.simple.clinic.feature.Feature
1621
import org.simple.clinic.feature.Features
1722
import org.simple.clinic.medicalhistory.Answer
1823
import org.simple.clinic.medicalhistory.MedicalHistory
1924
import org.simple.clinic.medicalhistory.MedicalHistoryQuestion
20-
import org.simple.clinic.medicalhistory.MedicalHistoryQuestion.DiagnosedWithDiabetes
21-
import org.simple.clinic.medicalhistory.MedicalHistoryQuestion.DiagnosedWithHypertension
22-
import org.simple.clinic.medicalhistory.MedicalHistoryQuestion.HasHadAHeartAttack
23-
import org.simple.clinic.medicalhistory.MedicalHistoryQuestion.HasHadAKidneyDisease
24-
import org.simple.clinic.medicalhistory.MedicalHistoryQuestion.HasHadAStroke
25-
import org.simple.clinic.medicalhistory.MedicalHistoryQuestion.IsSmoking
2625
import org.simple.clinic.medicalhistory.SelectDiagnosisErrorDialog
2726
import org.simple.clinic.mobius.MobiusDelegate
2827
import org.simple.clinic.navigation.v2.keyprovider.ScreenKeyProvider
2928
import org.simple.clinic.summary.PatientSummaryChildView
3029
import org.simple.clinic.summary.PatientSummaryModelUpdateCallback
3130
import org.simple.clinic.summary.PatientSummaryScreenKey
31+
import org.simple.clinic.summary.medicalhistory.ui.MedicalHistorySummary
3232
import org.simple.clinic.util.unsafeLazy
3333
import org.simple.clinic.widgets.ScreenCreated
3434
import org.simple.clinic.widgets.UiEvent
@@ -39,37 +39,12 @@ class MedicalHistorySummaryView(
3939
attributeSet: AttributeSet
4040
) : FrameLayout(context, attributeSet), MedicalHistorySummaryUi, PatientSummaryChildView {
4141

42-
private var binding: MedicalhistorySummaryViewBinding? = null
43-
44-
private val heartAttackQuestionView
45-
get() = binding!!.heartAttackQuestionView
46-
47-
private val strokeQuestionView
48-
get() = binding!!.strokeQuestionView
49-
50-
private val kidneyDiseaseQuestionView
51-
get() = binding!!.kidneyDiseaseQuestionView
52-
53-
private val diabetesQuestionView
54-
get() = binding!!.diabetesQuestionView
55-
56-
private val hypertensionDiagnosisView
57-
get() = binding!!.hypertensionDiagnosisView
58-
59-
private val diabetesDiagnosisView
60-
get() = binding!!.diabetesDiagnosisView
61-
62-
private val diagnosisViewContainer
63-
get() = binding!!.diagnosisViewContainer
64-
65-
private val currentSmokerQuestionView
66-
get() = binding!!.currentSmokerQuestionView
67-
68-
private val currentSmokerQuestionContainer
69-
get() = binding!!.currentSmokerQuestionContainer
70-
7142
private val internalEvents = PublishSubject.create<MedicalHistorySummaryEvent>()
7243

44+
private var medicalHistory by mutableStateOf<MedicalHistory?>(null)
45+
private var diabetesManagementEnabled by mutableStateOf(false)
46+
private var showSmokerQuestion by mutableStateOf(false)
47+
7348
@Inject
7449
lateinit var activity: AppCompatActivity
7550

@@ -82,11 +57,6 @@ class MedicalHistorySummaryView(
8257
@Inject
8358
lateinit var features: Features
8459

85-
init {
86-
val layoutInflater = LayoutInflater.from(context)
87-
binding = MedicalhistorySummaryViewBinding.inflate(layoutInflater, this, true)
88-
}
89-
9060
private var modelUpdateCallback: PatientSummaryModelUpdateCallback? = null
9161

9262
private val screenKey by unsafeLazy { screenKeyProvider.keyFor<PatientSummaryScreenKey>(this) }
@@ -127,6 +97,31 @@ class MedicalHistorySummaryView(
12797
}
12898

12999
context.injector<MedicalHistorySummaryViewInjector>().inject(this)
100+
101+
addView(ComposeView(context).apply {
102+
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnDetachedFromWindow)
103+
104+
setContent {
105+
SimpleTheme {
106+
AnimatedVisibility(
107+
visible = medicalHistory != null
108+
) {
109+
MedicalHistorySummary(
110+
hypertensionAnswer = medicalHistory?.diagnosedWithHypertension,
111+
diabetesAnswer = medicalHistory?.diagnosedWithDiabetes,
112+
heartAttackAnswer = medicalHistory?.hasHadHeartAttack,
113+
strokeAnswer = medicalHistory?.hasHadStroke,
114+
kidneyAnswer = medicalHistory?.hasHadKidneyDisease,
115+
smokerAnswer = medicalHistory?.isSmoking,
116+
diabetesManagementEnabled = diabetesManagementEnabled,
117+
showSmokerQuestion = showSmokerQuestion,
118+
) { question, answer ->
119+
answerToggled(question, answer)
120+
}
121+
}
122+
}
123+
}
124+
})
130125
}
131126

132127
override fun onAttachedToWindow() {
@@ -150,50 +145,23 @@ class MedicalHistorySummaryView(
150145
private fun screenCreates(): Observable<UiEvent> = Observable.just(ScreenCreated)
151146

152147
override fun populateMedicalHistory(medicalHistory: MedicalHistory) {
153-
renderMedicalHistory(medicalHistory)
154-
renderDiagnosis(medicalHistory)
155-
}
156-
157-
private fun renderMedicalHistory(medicalHistory: MedicalHistory) {
158-
heartAttackQuestionView.render(HasHadAHeartAttack, medicalHistory.hasHadHeartAttack, ::answerToggled)
159-
strokeQuestionView.render(HasHadAStroke, medicalHistory.hasHadStroke, ::answerToggled)
160-
kidneyDiseaseQuestionView.render(HasHadAKidneyDisease, medicalHistory.hasHadKidneyDisease, ::answerToggled)
161-
diabetesQuestionView.render(DiagnosedWithDiabetes, medicalHistory.diagnosedWithDiabetes, ::answerToggled)
162-
currentSmokerQuestionView.render(IsSmoking, medicalHistory.isSmoking, ::answerToggled)
163-
}
164-
165-
private fun renderDiagnosis(medicalHistory: MedicalHistory) {
166-
hypertensionDiagnosisView.render(DiagnosedWithHypertension, medicalHistory.diagnosedWithHypertension, ::answerToggled)
167-
diabetesDiagnosisView.render(DiagnosedWithDiabetes, medicalHistory.diagnosedWithDiabetes, ::answerToggled)
148+
this.medicalHistory = medicalHistory
168149
}
169150

170151
override fun showDiagnosisView() {
171-
diagnosisViewContainer.visibility = VISIBLE
172-
diabetesDiagnosisView.hideDivider()
152+
this.diabetesManagementEnabled = true
173153
}
174154

175155
override fun hideDiagnosisView() {
176-
diagnosisViewContainer.visibility = GONE
177-
}
178-
179-
override fun showDiabetesHistorySection() {
180-
diabetesQuestionView.visibility = VISIBLE
181-
kidneyDiseaseQuestionView.showDivider()
182-
diabetesQuestionView.hideDivider()
183-
}
184-
185-
override fun hideDiabetesHistorySection() {
186-
diabetesQuestionView.visibility = GONE
187-
kidneyDiseaseQuestionView.hideDivider()
156+
this.diabetesManagementEnabled = false
188157
}
189158

190159
override fun showCurrentSmokerQuestion() {
191-
currentSmokerQuestionContainer.visibility = VISIBLE
192-
currentSmokerQuestionView.hideDivider()
160+
showSmokerQuestion = true
193161
}
194162

195163
override fun hideCurrentSmokerQuestion() {
196-
currentSmokerQuestionContainer.visibility = GONE
164+
showSmokerQuestion = false
197165
}
198166

199167
override fun registerSummaryModelUpdateCallback(callback: PatientSummaryModelUpdateCallback?) {

0 commit comments

Comments
 (0)