Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Review screen ux changes like font style, error icon, not answered text color etc. #1737

Merged
merged 31 commits into from
Mar 10, 2023
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
20d8aed
Reduce question text font size in review mode.
Nov 29, 2022
8de6331
Do not show help button in review mode.
Nov 30, 2022
61ec125
Add error icon if text is not answered and set error color to text if…
Nov 30, 2022
a7d83a5
spotless apply
Nov 30, 2022
92f2d7f
Merge branch 'master' into sp/issue-1716
santosh-pingle Nov 30, 2022
e9d9ce6
update not answered text color.
Dec 2, 2022
0440bd4
Merge branch 'master' into sp/issue-1716
santosh-pingle Dec 2, 2022
b762bfa
Merge branch 'master' into sp/issue-1716
Dec 5, 2022
0dca5af
Address review comment.
Dec 5, 2022
b161676
Remove test which is not required.
Dec 5, 2022
05b8c7a
Address review comments.
Jan 4, 2023
74c9075
Merge branch 'master' into sp/issue-1716
Jan 4, 2023
a7cb781
Merge branch 'master' into sp/issue-1716
santosh-pingle Jan 5, 2023
757e3cb
Merge branch 'master' into sp/issue-1716
santosh-pingle Jan 5, 2023
9bdb777
Merge branch 'master' into sp/issue-1716
santosh-pingle Jan 6, 2023
fa92580
Address review comments.
Jan 10, 2023
8772162
Address review comment.
Jan 10, 2023
81ac57e
Fix failed test.
Jan 10, 2023
56c84a0
Merge branch 'master' into sp/issue-1716
Feb 20, 2023
2269700
Address review comments.
Mar 1, 2023
04be654
Refactored the code
Mar 1, 2023
5071f31
Merge branch 'master' into sp/issue-1716
Mar 1, 2023
5797150
Refactore the file name.
Mar 1, 2023
6cf983e
Fix local unit tests.
Mar 2, 2023
6f625d2
Merge branch 'master' into sp/issue-1716
santosh-pingle Mar 2, 2023
5c87587
Address review comment.
Mar 2, 2023
3c9f7ca
Add more unit tests.
Mar 2, 2023
13dc266
Merge branch 'master' into sp/issue-1716
Mar 6, 2023
9dde44f
Remove updateUI call from on review button click.
Mar 9, 2023
6ab7c3b
Merge branch 'master' into sp/issue-1716
santosh-pingle Mar 9, 2023
c0f26a9
Merge branch 'master' into sp/issue-1716
santosh-pingle Mar 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,10 @@ class QuestionnaireFragment : Fragment() {
reviewModeEditButton.setOnClickListener { viewModel.setReviewMode(false) }

val reviewModeButton = view.findViewById<View>(R.id.review_mode_button)
reviewModeButton.setOnClickListener { viewModel.setReviewMode(true) }
reviewModeButton.setOnClickListener {
viewModel.setReviewMode(true)
viewModel.validateQuestionnaireAndUpdateUI()
}

questionnaireEditRecyclerView.adapter = questionnaireEditAdapter
val linearLayoutManager = LinearLayoutManager(view.context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ internal class QuestionnaireViewModel(application: Application, state: SavedStat
/** Forces response validation each time [getQuestionnaireAdapterItems] is called. */
private var hasPressedSubmitButton = false

private var hasPressedReviewButton = false

/**
* Map of [QuestionnaireResponseItemAnswerComponent] for
* [Questionnaire.QuestionnaireItemComponent]s that are disabled now. The answers will be used to
Expand Down Expand Up @@ -312,6 +314,7 @@ internal class QuestionnaireViewModel(application: Application, state: SavedStat
.also { result ->
if (result.values.flatten().filterIsInstance<Invalid>().isNotEmpty()) {
hasPressedSubmitButton = true
hasPressedReviewButton = true
santosh-pingle marked this conversation as resolved.
Show resolved Hide resolved
modificationCount.update { it + 1 }
}
}
Expand Down Expand Up @@ -612,7 +615,8 @@ internal class QuestionnaireViewModel(application: Application, state: SavedStat
val validationResult =
if (modifiedQuestionnaireResponseItemSet.contains(questionnaireResponseItem) ||
isPaginationButtonPressed ||
hasPressedSubmitButton
hasPressedSubmitButton ||
hasPressedReviewButton
) {
QuestionnaireResponseItemValidator.validate(
questionnaireItem,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.android.fhir.datacapture.extensions

import android.text.Spanned
import android.view.View.GONE
import android.view.View.VISIBLE
import android.widget.Button
import android.widget.TextView
import com.google.android.fhir.datacapture.hasHelpButton
import com.google.android.fhir.datacapture.localizedHelpSpanned
import com.google.android.material.card.MaterialCardView
import org.hl7.fhir.r4.model.Questionnaire

internal fun TextView.updateTextAndVisibility(localizedText: Spanned? = null) {
text = localizedText
visibility =
if (localizedText.isNullOrEmpty()) {
GONE
} else {
VISIBLE
}
}

/** Returns [VISIBLE] if any of the [view] is visible, else returns [GONE]. */
santosh-pingle marked this conversation as resolved.
Show resolved Hide resolved
internal fun headerViewVisibility(vararg view: TextView): Int {
santosh-pingle marked this conversation as resolved.
Show resolved Hide resolved
if (view.any { it.visibility == VISIBLE }) {
return VISIBLE
}
return GONE
}

internal fun initHelpViews(
santosh-pingle marked this conversation as resolved.
Show resolved Hide resolved
helpButton: Button,
helpCardView: MaterialCardView,
helpTextView: TextView,
questionnaireItem: Questionnaire.QuestionnaireItemComponent
) {
helpButton.visibility =
if (questionnaireItem.hasHelpButton) {
VISIBLE
} else {
GONE
}
helpButton.setOnClickListener {
helpCardView.visibility =
when (helpCardView.visibility) {
VISIBLE -> GONE
else -> VISIBLE
}
}
helpTextView.updateTextAndVisibility(questionnaireItem.localizedHelpSpanned)
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ import android.view.LayoutInflater
import android.widget.LinearLayout
import android.widget.TextView
import com.google.android.fhir.datacapture.R
import com.google.android.fhir.datacapture.extensions.headerViewVisibility
import com.google.android.fhir.datacapture.extensions.initHelpViews
import com.google.android.fhir.datacapture.extensions.updateTextAndVisibility
import com.google.android.fhir.datacapture.localizedInstructionsSpanned
import com.google.android.fhir.datacapture.localizedPrefixSpanned
import com.google.android.fhir.datacapture.localizedTextSpanned
Expand All @@ -38,10 +41,15 @@ internal class GroupHeaderView(context: Context, attrs: AttributeSet?) :
val prefix = findViewById<TextView>(R.id.prefix)
val question = findViewById<TextView>(R.id.question)
val hint = findViewById<TextView>(R.id.hint)
initHelpButton(this, questionnaireItem)
initHelpViews(
helpButton = findViewById(R.id.helpButton),
helpCardView = findViewById(R.id.helpCardView),
helpTextView = findViewById(R.id.helpText),
questionnaireItem
)
prefix.updateTextAndVisibility(questionnaireItem.localizedPrefixSpanned)
question.updateTextAndVisibility(questionnaireItem.localizedTextSpanned)
hint.updateTextAndVisibility(questionnaireItem.localizedInstructionsSpanned)
visibility = getViewGroupVisibility(prefix, question, hint)
visibility = headerViewVisibility(prefix, question, hint)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,17 @@
package com.google.android.fhir.datacapture.views

import android.content.Context
import android.text.Spanned
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
import android.widget.Button
import android.widget.LinearLayout
import android.widget.TextView
import com.google.android.fhir.datacapture.R
import com.google.android.fhir.datacapture.hasHelpButton
import com.google.android.fhir.datacapture.localizedHelpSpanned
import com.google.android.fhir.datacapture.extensions.headerViewVisibility
import com.google.android.fhir.datacapture.extensions.initHelpViews
import com.google.android.fhir.datacapture.extensions.updateTextAndVisibility
import com.google.android.fhir.datacapture.localizedInstructionsSpanned
import com.google.android.fhir.datacapture.localizedPrefixSpanned
import com.google.android.fhir.datacapture.localizedTextSpanned
import com.google.android.material.card.MaterialCardView
import org.hl7.fhir.r4.model.Questionnaire

/** View for the prefix, question, and hint of a questionnaire item. */
Expand All @@ -51,10 +46,15 @@ internal class HeaderView(context: Context, attrs: AttributeSet?) : LinearLayout
prefix.updateTextAndVisibility(questionnaireItem.localizedPrefixSpanned)
question.updateTextAndVisibility(questionnaireItem.localizedTextSpanned)
hint.updateTextAndVisibility(questionnaireItem.localizedInstructionsSpanned)
initHelpButton(this, questionnaireItem)
initHelpViews(
helpButton = findViewById(R.id.helpButton),
helpCardView = findViewById(R.id.helpCardView),
helpTextView = findViewById(R.id.helpText),
questionnaireItem
)
// Make the entire view GONE if there is nothing to show. This is to avoid an empty row in the
// questionnaire.
visibility = getViewGroupVisibility(prefix, question, hint)
visibility = headerViewVisibility(prefix, question, hint)
}

/**
Expand All @@ -74,49 +74,3 @@ internal class HeaderView(context: Context, attrs: AttributeSet?) : LinearLayout
errorTextView.text = errorText
}
}

internal fun TextView.updateTextAndVisibility(localizedText: Spanned? = null) {
text = localizedText
visibility =
if (localizedText.isNullOrEmpty()) {
GONE
} else {
VISIBLE
}
}

/** Returns [VISIBLE] if any of the [view] is visible, else returns [GONE]. */
internal fun getViewGroupVisibility(vararg view: TextView): Int {
if (view.any { it.visibility == VISIBLE }) {
return VISIBLE
}
return GONE
}

internal fun initHelpButton(
view: View,
questionnaireItem: Questionnaire.QuestionnaireItemComponent
) {
val helpButton = view.findViewById<Button>(R.id.helpButton)
helpButton.visibility =
if (questionnaireItem.hasHelpButton) {
VISIBLE
} else {
GONE
}
val helpCardView = view.findViewById<MaterialCardView>(R.id.helpCardView)
var isHelpCardViewVisible = false
helpButton.setOnClickListener {
if (isHelpCardViewVisible) {
isHelpCardViewVisible = false
helpCardView.visibility = GONE
} else {
isHelpCardViewVisible = true
helpCardView.visibility = VISIBLE
}
}

view
.findViewById<TextView>(R.id.helpText)
.updateTextAndVisibility(questionnaireItem.localizedHelpSpanned)
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,15 @@ import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import com.google.android.fhir.datacapture.R
import com.google.android.fhir.datacapture.extensions.headerViewVisibility
import com.google.android.fhir.datacapture.extensions.updateTextAndVisibility
import com.google.android.fhir.datacapture.localizedFlyoverSpanned
import com.google.android.fhir.datacapture.views.HeaderView
import com.google.android.fhir.datacapture.localizedInstructionsSpanned
import com.google.android.fhir.datacapture.localizedPrefixSpanned
import com.google.android.fhir.datacapture.localizedTextSpanned
import com.google.android.fhir.datacapture.validation.Invalid
import com.google.android.fhir.datacapture.views.QuestionnaireViewItem
import com.google.android.material.divider.MaterialDivider
import org.hl7.fhir.r4.model.Questionnaire
Expand All @@ -34,21 +40,39 @@ import org.hl7.fhir.r4.model.Questionnaire
internal object ReviewViewHolderFactory : QuestionnaireItemViewHolderFactory(R.layout.review_view) {
override fun getQuestionnaireItemViewHolderDelegate() =
object : QuestionnaireItemViewHolderDelegate {
private lateinit var header: HeaderView
private lateinit var header: ConstraintLayout
private lateinit var flyOverTextView: TextView
private lateinit var answerTextView: TextView
private lateinit var errorView: View
private lateinit var answerView: TextView
private lateinit var divider: MaterialDivider
private lateinit var prefix: TextView
private lateinit var question: TextView
private lateinit var hint: TextView
override lateinit var questionnaireViewItem: QuestionnaireViewItem

override fun init(itemView: View) {
header = itemView.findViewById(R.id.header)
flyOverTextView = itemView.findViewById(R.id.flyover_text_view)
answerTextView = itemView.findViewById(R.id.answer_text_view)
divider = itemView.findViewById(R.id.text_divider)
prefix = itemView.findViewById(R.id.prefix)
question = itemView.findViewById(R.id.question)
hint = itemView.findViewById(R.id.hint)
errorView = itemView.findViewById(R.id.error_view)
answerView = itemView.findViewById(R.id.answer_text_view)
}

override fun bind(questionnaireViewItem: QuestionnaireViewItem) {
header.bind(questionnaireViewItem.questionnaireItem)
prefix.updateTextAndVisibility(
questionnaireViewItem.questionnaireItem.localizedPrefixSpanned
)
question.updateTextAndVisibility(
questionnaireViewItem.questionnaireItem.localizedTextSpanned
)
hint.updateTextAndVisibility(
questionnaireViewItem.questionnaireItem.localizedInstructionsSpanned
)
header.visibility = headerViewVisibility(prefix, question, hint)

val localizedFlyoverSpanned =
questionnaireViewItem.questionnaireItem.localizedFlyoverSpanned
flyOverTextView.apply {
Expand All @@ -60,21 +84,30 @@ internal object ReviewViewHolderFactory : QuestionnaireItemViewHolderFactory(R.l
}
text = localizedFlyoverSpanned
}

answerTextView.apply {
visibility =
when (questionnaireViewItem.questionnaireItem.type) {
Questionnaire.QuestionnaireItemType.GROUP,
Questionnaire.QuestionnaireItemType.DISPLAY -> GONE
else -> VISIBLE
when (questionnaireViewItem.questionnaireItem.type) {
Questionnaire.QuestionnaireItemType.GROUP,
Questionnaire.QuestionnaireItemType.DISPLAY -> {
errorView.visibility = GONE
answerView.visibility = GONE
}
else -> {
answerView.text = questionnaireViewItem.answerString(answerView.context)
answerView.visibility = VISIBLE
if (questionnaireViewItem.validationResult is Invalid) {
errorView.findViewById<TextView>(R.id.error_text_view).text =
questionnaireViewItem.validationResult.getSingleStringValidationMessage()
errorView.visibility = VISIBLE
} else {
errorView.visibility = GONE
}
text = questionnaireViewItem.answerString(context)
}
}

divider.visibility =
if (header.visibility == VISIBLE ||
flyOverTextView.visibility == VISIBLE ||
answerTextView.visibility == VISIBLE
answerView.visibility == VISIBLE ||
errorView.visibility == VISIBLE
) {
VISIBLE
} else {
Expand Down
14 changes: 14 additions & 0 deletions datacapture/src/main/res/drawable/ic_error_48px.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<vector
android:autoMirrored="true"
android:height="48dp"
android:tint="?attr/colorControlNormal"
android:viewportHeight="48"
android:viewportWidth="48"
android:width="48dp"
xmlns:android="http://schemas.android.com/apk/res/android"
>
<path
android:fillColor="@android:color/white"
android:pathData="M24,34Q24.7,34 25.175,33.525Q25.65,33.05 25.65,32.35Q25.65,31.65 25.175,31.175Q24.7,30.7 24,30.7Q23.3,30.7 22.825,31.175Q22.35,31.65 22.35,32.35Q22.35,33.05 22.825,33.525Q23.3,34 24,34ZM22.65,26.35H25.65V13.7H22.65ZM24,44Q19.9,44 16.25,42.425Q12.6,40.85 9.875,38.125Q7.15,35.4 5.575,31.75Q4,28.1 4,23.95Q4,19.85 5.575,16.2Q7.15,12.55 9.875,9.85Q12.6,7.15 16.25,5.575Q19.9,4 24.05,4Q28.15,4 31.8,5.575Q35.45,7.15 38.15,9.85Q40.85,12.55 42.425,16.2Q44,19.85 44,24Q44,28.1 42.425,31.75Q40.85,35.4 38.15,38.125Q35.45,40.85 31.8,42.425Q28.15,44 24,44Z"
/>
</vector>
Loading