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

Per question custom style #2636

Merged
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
2fc5790
per question custom style
Jul 24, 2024
5cacca5
adding missing file.
Jul 25, 2024
26215c9
update default style.
Aug 1, 2024
e55fa8a
textAppearance support
Aug 2, 2024
4e05007
rename custom attributes.
Aug 2, 2024
4094268
github documentation for custom style example.
Aug 6, 2024
d746d06
Address review comments.
Aug 6, 2024
d532701
address review comment.
Aug 6, 2024
ad00fff
update text format icon as component icon.
Aug 7, 2024
60accde
code cleanup.
Aug 7, 2024
83c4e2a
Code refactoring and cleanup.
Aug 7, 2024
89f468c
custom style example with multiple question items.
Aug 13, 2024
7dbb60a
Address review comments.
Aug 14, 2024
e1cd2aa
support prefix per question item custom style
Aug 14, 2024
26863e7
Revert dataconfig changes for custom style mapping.
Aug 14, 2024
8c41bd3
Merge branch 'master' into sp/per-question-custom-style
santosh-pingle Aug 14, 2024
f414f68
Address review comments.
Aug 20, 2024
7fc7ecb
Address review comments.
Aug 20, 2024
5e21f7b
Merge branch 'master' into sp/per-question-custom-style
santosh-pingle Aug 21, 2024
7c4e9b1
Address review comments.
Sep 2, 2024
c82bbe1
Merge branch 'master' into sp/per-question-custom-style
santosh-pingle Sep 2, 2024
6088d27
Address review comments.
Sep 3, 2024
e64ed22
Merge branch 'master' into sp/per-question-custom-style
santosh-pingle Sep 3, 2024
bd6f0b7
Address review comment.
Sep 4, 2024
63caac8
Merge branch 'master' into sp/per-question-custom-style
santosh-pingle Sep 4, 2024
9d5cdee
Merge branch 'master' into sp/per-question-custom-style
santosh-pingle Sep 4, 2024
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
santosh-pingle marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
{
"resourceType": "Questionnaire",
"item": [
{
"linkId": "1",
"text": "Question text custom style",
"type": "display",
"extension": [
{
"url": "https://github.com/google/android-fhir/tree/master/datacapture/android-style",
"extension": [
{
"url": "question_text_view",
"valueString": "CustomStyle_1"
},
{
"url": "subtitle_text_view",
"valueString": "CustomStyle_2"
}
]
}
],
"item": [
{
"extension": [
{
"url": "http://hl7.org/fhir/StructureDefinition/questionnaire-displayCategory",
"valueCodeableConcept": {
"coding": [
{
"system": "http://hl7.org/fhir/questionnaire-display-category",
"code": "instructions"
}
]
}
}
],
"linkId": "1.3",
"text": "Instructions custom style.",
"type": "display"
}
]
},
{
"linkId": "2",
"text": "Question text default style",
"type": "display",
"item": [
{
"extension": [
{
"url": "http://hl7.org/fhir/StructureDefinition/questionnaire-displayCategory",
"valueCodeableConcept": {
"coding": [
{
"system": "http://hl7.org/fhir/questionnaire-display-category",
"code": "instructions"
}
]
}
}
],
"linkId": "1.3",
"text": "Instructions default style.",
"type": "display"
}
]
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,17 @@ class CatalogApplication : Application(), DataCaptureConfig.Provider {

FhirEngineProvider.init(FhirEngineConfiguration())

val styleMap =
mapOf(
"CustomStyle_1" to R.style.CustomStyle_1,
"CustomStyle_2" to R.style.CustomStyle_2,
)
dataCaptureConfig =
DataCaptureConfig(
xFhirQueryResolver = { fhirEngine.search(it).map { it.resource } },
questionnaireItemViewHolderFactoryMatchersProviderFactory =
ContribQuestionnaireItemViewHolderFactoryMatchersProviderFactory,
questionnaireItemViewStyleResolver = { styleMap[it]!! },
)

CoroutineScope(Dispatchers.IO).launch {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@ class ComponentListViewModel(application: Application, private val state: SavedS
R.string.component_name_location_widget,
"component_location_widget.json",
),
QUESTION_ITEM_CUSTOM_STYLE(
R.drawable.text_format_48dp,
R.string.component_name_per_question_custom_style,
"component_per_question_custom_style.json",
),
}

val viewItemList =
Expand All @@ -177,6 +182,7 @@ class ComponentListViewModel(application: Application, private val state: SavedS
ViewItem.ComponentItem(Component.ITEM_ANSWER_MEDIA),
ViewItem.ComponentItem(Component.INITIAL_VALUE),
ViewItem.ComponentItem(Component.LOCATION_WIDGET),
ViewItem.ComponentItem(Component.QUESTION_ITEM_CUSTOM_STYLE),
)

fun isComponent(context: Context, title: String) =
Expand Down
4 changes: 2 additions & 2 deletions catalog/src/main/res/drawable/ic_location_on.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="128dp"
android:height="128dp"
android:width="64dp"
android:height="64dp"
android:tint="#1A73E8"
android:viewportWidth="24"
android:viewportHeight="24"
Expand Down
15 changes: 15 additions & 0 deletions catalog/src/main/res/drawable/text_format_48dp.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:autoMirrored="true"
android:height="64dp"
android:viewportHeight="960"
android:viewportWidth="960"
android:width="64dp"
>

<path
android:fillColor="#1A73E8"
android:pathData="M200,760v-60h560v60L200,760ZM276,600 L451,160h58l175,440h-55l-45,-119L376,481l-45,119h-55ZM393,436h174l-85,-222h-4l-85,222Z"
/>

</vector>
3 changes: 3 additions & 0 deletions catalog/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
<string name="component_name_repeated_group">Repeated Group</string>
<string name="component_name_attachment">Attachment</string>
<string name="component_name_location_widget">Location Widget</string>
<string
name="component_name_per_question_custom_style"
>Per question custom style</string>
<string name="layout_name_default_text">Default</string>
<string name="layout_name_paginated">Paginated</string>
<string name="layout_name_review">Review</string>
Expand Down
48 changes: 47 additions & 1 deletion catalog/src/main/res/values/styles.xml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,10 @@

<style name="Theme.MyQuestionnaire.PaginatedLayout">
<item name="questionnaireQuestionTextStyle">
@style/TextAppearance.Material3.HeadlineMedium
@style/QuestionTextStyle
</item>
<item name="questionnaireSubtitleTextStyle">
@style/SubtitleTextStyle
</item>
</style>

Expand All @@ -98,4 +101,47 @@
<item name="android:minLines">2</item>
</style>

<style name="QuestionTextStyle">
<item
name="android:textAppearance"
>@style/TextAppearance.Material3.HeadlineMedium</item>
<item name="android:background">?attr/colorSurface</item>
</style>

<style name="SubtitleTextStyle">
<item
name="android:textAppearance"
>@style/TextAppearance.Material3.BodyMedium</item>
<item name="android:background">?attr/colorSurface</item>
</style>

<style name="CustomStyle_1">
<item
name="questionnaire_textAppearance"
>@style/CustomTextAppearance_1</item>
<item
name="questionnaire_background"
>?attr/colorTertiaryContainer</item>
</style>

<style
name="CustomTextAppearance_1"
parent="TextAppearance.Material3.HeadlineLarge"
>
<item name="android:textColor">?attr/colorOnTertiaryContainer</item>
</style>

<style name="CustomStyle_2">
<item
name="questionnaire_textAppearance"
>@style/CustomTextAppearance_2</item>
<item name="questionnaire_background">?attr/colorSurfaceVariant</item>
</style>

<style
name="CustomTextAppearance_2"
parent="TextAppearance.Material3.BodyLarge"
>
<item name="android:textColor">?attr/colorOnSurfaceVariant</item>
</style>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ data class DataCaptureConfig(
var questionnaireItemViewHolderFactoryMatchersProviderFactory:
QuestionnaireItemViewHolderFactoryMatchersProviderFactory? =
null,
val questionnaireItemViewStyleResolver: QuestionnaireItemViewStyleResolver? = null,
) {

/**
Expand Down Expand Up @@ -114,3 +115,15 @@ interface UrlResolver {
fun interface QuestionnaireItemViewHolderFactoryMatchersProviderFactory {
fun get(provider: String): QuestionnaireItemViewHolderFactoryMatchersProvider
}

/** Functional interface for resolving the style resource associated with a given style name. */
fun interface QuestionnaireItemViewStyleResolver {

/**
* Returns the style resource ID for the given style name.
*
* @param style The name of the style to resolve.
* @return The resource ID of the style.
*/
fun getStyleResource(style: String): Int
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* Copyright 2024 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.content.Context
import android.content.res.TypedArray
import android.view.View
import android.widget.TextView
import androidx.core.content.ContextCompat
import applyDefaultStyle
import com.google.android.fhir.datacapture.R

private enum class CustomStyleViewAttributes(val attrId: Int) {
TEXT_APPEARANCE(R.styleable.QuestionnaireCustomStyle_questionnaire_textAppearance),
BACKGROUND(R.styleable.QuestionnaireCustomStyle_questionnaire_background),
}

/**
* Applies either a custom style or a default style to the given view based on the provided custom
* style name and default style resource ID.
*
* If the custom style resource name is valid, it applies the custom style to the view. If the
* custom style resource name is not valid or not found, it falls back to applying the default style
* defined by the given style resource ID.
*
* @param context the context used to access resources.
* @param view the view to which the style should be applied.
* @param customStyleName the name of the custom style to apply.
* @param defaultStyleResId the default style resource ID to use if no custom style is found.
*/
internal fun applyCustomOrDefaultStyle(
context: Context,
view: View,
customStyleName: String?,
defaultStyleResId: Int,
) {
if (customStyleName != null) {
val customStyleResId = getStyleResIdByName(context, customStyleName)
when {
customStyleResId != 0 -> {
view.tag = customStyleResId
applyCustomStyle(context, view, customStyleResId)
}
defaultStyleResId != 0 -> {
(view.tag as? Int)?.let {
santosh-pingle marked this conversation as resolved.
Show resolved Hide resolved
applyDefaultStyle(context, view, defaultStyleResId)
view.tag = null
}
}
}
} else if (defaultStyleResId != 0) {
santosh-pingle marked this conversation as resolved.
Show resolved Hide resolved
(view.tag as? Int)?.let {
applyDefaultStyle(context, view, defaultStyleResId)
view.tag = null
}
}
}

/**
* Retrieves the resource ID of a style given its name.
*
* This function uses the `getIdentifier` method to look up the style resource ID based on the style
* name provided. If the style name is not found, it returns 0.
*
* @param context The context used to access resources.
* @param styleName The name of the style whose resource ID is to be retrieved.
* @return The resource ID of the style, or 0 if the style name is not found.
*/
private fun getStyleResIdByName(context: Context, styleName: String): Int {
return context.resources.getIdentifier(styleName, "style", context.packageName)
}

private fun getTypedArrayForQuestionnaireCustomStyle(
context: Context,
styleResId: Int,
): TypedArray {
return context.obtainStyledAttributes(styleResId, R.styleable.QuestionnaireCustomStyle)
}

/**
* Applies custom styles to a view based on its type.
*
* This function first applies common style attributes that can be applied to any view, and then
* applies attributes specific to `TextView` if the view is an instance of `TextView`.
*
* @param context The context to access resources and theme.
* @param view The view to which the style should be applied.
* @param styleResId The resource ID of the style to be applied.
*/
private fun applyCustomStyle(context: Context, view: View, styleResId: Int) {
val typedArray = getTypedArrayForQuestionnaireCustomStyle(context, styleResId)
applyGenericViewCustomStyle(context, view, typedArray)
if (view is TextView) {
applyTextViewSpecificCustomStyle(view, typedArray)
}
typedArray.recycle()
}

private fun applyGenericViewCustomStyle(context: Context, view: View, typedArray: TypedArray) {
for (i in 0 until typedArray.indexCount) {
when (typedArray.getIndex(i)) {
CustomStyleViewAttributes.BACKGROUND.attrId -> {
val backgroundColor =
typedArray.getColor(i, ContextCompat.getColor(context, android.R.color.transparent))
view.setBackgroundColor(backgroundColor)
}
}
}
}

private fun applyTextViewSpecificCustomStyle(
textView: TextView,
typedArray: TypedArray,
) {
for (i in 0 until typedArray.indexCount) {
when (typedArray.getIndex(i)) {
CustomStyleViewAttributes.TEXT_APPEARANCE.attrId -> {
val textAppearance = typedArray.getResourceId(i, -1)
if (textAppearance != -1) {
textView.setTextAppearance(textAppearance)
}
}
}
}
}
Loading
Loading