Skip to content

Commit

Permalink
Merge branch 'master' into 2561-fix-sqlite-crash
Browse files Browse the repository at this point in the history
  • Loading branch information
LZRS authored Jun 26, 2024
2 parents 0264816 + e192970 commit d9e6d03
Show file tree
Hide file tree
Showing 22 changed files with 215 additions and 300 deletions.
54 changes: 0 additions & 54 deletions buildSrc/src/main/kotlin/Dependencies.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,6 @@ import org.gradle.api.artifacts.DependencyConstraint
import org.gradle.kotlin.dsl.exclude

object Dependencies {

object Androidx {
const val activity = "androidx.activity:activity:${Versions.Androidx.activity}"
const val appCompat = "androidx.appcompat:appcompat:${Versions.Androidx.appCompat}"
const val constraintLayout =
"androidx.constraintlayout:constraintlayout:${Versions.Androidx.constraintLayout}"
const val coreKtx = "androidx.core:core-ktx:${Versions.Androidx.coreKtx}"
const val datastorePref =
"androidx.datastore:datastore-preferences:${Versions.Androidx.datastorePref}"
const val fragmentKtx = "androidx.fragment:fragment-ktx:${Versions.Androidx.fragmentKtx}"
const val recyclerView = "androidx.recyclerview:recyclerview:${Versions.Androidx.recyclerView}"
const val sqliteKtx = "androidx.sqlite:sqlite-ktx:${Versions.Androidx.sqliteKtx}"
const val workRuntimeKtx = "androidx.work:work-runtime-ktx:${Versions.Androidx.workRuntimeKtx}"
}

object Cql {
const val evaluator = "org.opencds.cqf.fhir:cqf-fhir-cr:${Versions.Cql.clinicalReasoning}"
const val evaluatorFhirJackson =
Expand Down Expand Up @@ -106,32 +91,11 @@ object Dependencies {
const val stdlib = "org.jetbrains.kotlin:kotlin-stdlib:${Versions.Kotlin.stdlib}"
}

object Lifecycle {
const val liveDataKtx =
"androidx.lifecycle:lifecycle-livedata-ktx:${Versions.Androidx.lifecycle}"
const val runtime = "androidx.lifecycle:lifecycle-runtime:${Versions.Androidx.lifecycle}"
const val viewModelKtx =
"androidx.lifecycle:lifecycle-viewmodel-ktx:${Versions.Androidx.lifecycle}"
}

object Navigation {
const val navFragmentKtx =
"androidx.navigation:navigation-fragment-ktx:${Versions.Androidx.navigation}"
const val navUiKtx = "androidx.navigation:navigation-ui-ktx:${Versions.Androidx.navigation}"
}

object Retrofit {
const val coreRetrofit = "com.squareup.retrofit2:retrofit:${Versions.retrofit}"
const val gsonConverter = "com.squareup.retrofit2:converter-gson:${Versions.retrofit}"
}

object Room {
const val compiler = "androidx.room:room-compiler:${Versions.Androidx.room}"
const val ktx = "androidx.room:room-ktx:${Versions.Androidx.room}"
const val runtime = "androidx.room:room-runtime:${Versions.Androidx.room}"
const val testing = "androidx.room:room-testing:${Versions.Androidx.room}"
}

object Mlkit {
const val barcodeScanning =
"com.google.mlkit:barcode-scanning:${Versions.Mlkit.barcodeScanning}"
Expand All @@ -157,7 +121,6 @@ object Dependencies {

const val desugarJdkLibs = "com.android.tools:desugar_jdk_libs:${Versions.desugarJdkLibs}"
const val fhirUcum = "org.fhir:ucum:${Versions.fhirUcum}"
const val gson = "com.google.code.gson:gson:${Versions.gson}"

const val guavaModule = "com.google.guava:guava"
const val guava = "$guavaModule:${Versions.guava}"
Expand Down Expand Up @@ -188,8 +151,6 @@ object Dependencies {
"androidx.fragment:fragment-testing:${Versions.AndroidxTest.fragmentVersion}"
const val rules = "androidx.test:rules:${Versions.AndroidxTest.rules}"
const val runner = "androidx.test:runner:${Versions.AndroidxTest.runner}"
const val workTestingRuntimeKtx =
"androidx.work:work-testing:${Versions.Androidx.workRuntimeKtx}"
}

object Espresso {
Expand All @@ -212,20 +173,6 @@ object Dependencies {
const val xmlUnit = "org.xmlunit:xmlunit-core:${Versions.xmlUnit}"

object Versions {
object Androidx {
const val activity = "1.7.2"
const val appCompat = "1.6.1"
const val constraintLayout = "2.1.4"
const val coreKtx = "1.10.1"
const val datastorePref = "1.0.0"
const val fragmentKtx = "1.6.0"
const val lifecycle = "2.6.1"
const val navigation = "2.6.0"
const val recyclerView = "1.3.0"
const val room = "2.5.2"
const val sqliteKtx = "2.3.1"
const val workRuntimeKtx = "2.8.1"
}

object Cql {
const val clinicalReasoning = "3.0.0-PRE9-SNAPSHOT"
Expand All @@ -243,7 +190,6 @@ object Dependencies {
const val desugarJdkLibs = "2.0.3"
const val caffeine = "2.9.1"
const val fhirUcum = "1.0.3"
const val gson = "2.9.1"
const val guava = "32.1.3-android"

const val hapiFhir = "6.8.0"
Expand Down
3 changes: 1 addition & 2 deletions buildSrc/src/main/kotlin/Plugins.kt
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ object Plugins {
"androidx.benchmark:benchmark-gradle-plugin:${Versions.benchmarkPlugin}"
const val kotlinGradlePlugin =
"org.jetbrains.kotlin:kotlin-gradle-plugin:${Dependencies.Versions.Kotlin.stdlib}"
const val navSafeArgsGradlePlugin =
"androidx.navigation:navigation-safe-args-gradle-plugin:${Dependencies.Versions.Androidx.navigation}"
const val navSafeArgsGradlePlugin = "androidx.navigation:navigation-safe-args-gradle-plugin:2.6.0"
const val rulerGradlePlugin = "com.spotify.ruler:ruler-gradle-plugin:1.2.1"
const val flankGradlePlugin = "com.osacky.flank.gradle:fladle:0.17.4"
const val kspGradlePlugin =
Expand Down
12 changes: 6 additions & 6 deletions catalog/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@ dependencies {

coreLibraryDesugaring(Dependencies.desugarJdkLibs)

implementation(Dependencies.Androidx.appCompat)
implementation(Dependencies.Androidx.constraintLayout)
implementation(Dependencies.Androidx.coreKtx)
implementation(Dependencies.Androidx.fragmentKtx)
implementation(Dependencies.material)
implementation(Dependencies.Kotlin.stdlib)
implementation(Dependencies.Navigation.navFragmentKtx)
implementation(Dependencies.Navigation.navUiKtx)
implementation(libs.androidx.appcompat)
implementation(libs.androidx.constraintlayout)
implementation(libs.androidx.core)
implementation(libs.androidx.fragment)
implementation(libs.androidx.navigation.fragment)
implementation(libs.androidx.navigation.ui)

implementation(project(path = ":datacapture"))
implementation(project(path = ":engine"))
Expand Down

This file was deleted.

6 changes: 3 additions & 3 deletions contrib/barcode/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,14 @@ dependencies {
androidTestImplementation(Dependencies.truth)

implementation(project(":datacapture"))
implementation(Dependencies.Androidx.coreKtx)
implementation(Dependencies.Androidx.fragmentKtx)
implementation(Dependencies.Mlkit.barcodeScanning)
implementation(Dependencies.Mlkit.objectDetection)
implementation(Dependencies.Mlkit.objectDetectionCustom)
implementation(Dependencies.material)
implementation(Dependencies.timber)
implementation(Dependencies.Androidx.appCompat)
implementation(libs.androidx.appcompat)
implementation(libs.androidx.core)
implementation(libs.androidx.fragment)

testImplementation(Dependencies.AndroidxTest.core)
testImplementation(Dependencies.AndroidxTest.fragmentTesting)
Expand Down
6 changes: 3 additions & 3 deletions contrib/locationwidget/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ configurations { all { removeIncompatibleDependencies() } }

dependencies {
implementation(project(":datacapture"))
implementation(Dependencies.Androidx.coreKtx)
implementation(Dependencies.Androidx.fragmentKtx)
implementation(Dependencies.playServicesLocation)
implementation(Dependencies.Kotlin.kotlinCoroutinesPlay)
implementation(Dependencies.material)
implementation(Dependencies.timber)
implementation(Dependencies.Androidx.appCompat)
implementation(libs.androidx.appcompat)
implementation(libs.androidx.core)
implementation(libs.androidx.fragment)

testImplementation(Dependencies.AndroidxTest.fragmentTesting)
testImplementation(Dependencies.Kotlin.kotlinTestJunit)
Expand Down
12 changes: 6 additions & 6 deletions datacapture/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -84,22 +84,22 @@ dependencies {

coreLibraryDesugaring(Dependencies.desugarJdkLibs)

implementation(Dependencies.Androidx.appCompat)
implementation(Dependencies.Androidx.constraintLayout)
implementation(Dependencies.Androidx.coreKtx)
implementation(Dependencies.Androidx.fragmentKtx)
implementation(libs.glide)
implementation(Dependencies.HapiFhir.guavaCaching)
implementation(Dependencies.HapiFhir.validation) {
exclude(module = "commons-logging")
exclude(module = "httpclient")
}
implementation(Dependencies.Kotlin.kotlinCoroutinesCore)
implementation(Dependencies.Kotlin.stdlib)
implementation(Dependencies.Lifecycle.viewModelKtx)
implementation(Dependencies.androidFhirCommon)
implementation(Dependencies.material)
implementation(Dependencies.timber)
implementation(libs.androidx.appcompat)
implementation(libs.androidx.constraintlayout)
implementation(libs.androidx.core)
implementation(libs.androidx.fragment)
implementation(libs.androidx.lifecycle.viewmodel)
implementation(libs.glide)

testImplementation(Dependencies.AndroidxTest.core)
testImplementation(Dependencies.AndroidxTest.fragmentTesting)
Expand Down
24 changes: 12 additions & 12 deletions demo/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -43,23 +43,23 @@ dependencies {

coreLibraryDesugaring(Dependencies.desugarJdkLibs)

implementation(Dependencies.Androidx.activity)
implementation(Dependencies.Androidx.appCompat)
implementation(Dependencies.Androidx.constraintLayout)
implementation(Dependencies.Androidx.datastorePref)
implementation(Dependencies.Androidx.fragmentKtx)
implementation(Dependencies.Androidx.recyclerView)
implementation(Dependencies.Androidx.workRuntimeKtx)
implementation(Dependencies.Kotlin.kotlinCoroutinesAndroid)
implementation(Dependencies.Kotlin.kotlinCoroutinesCore)
implementation(Dependencies.Kotlin.stdlib)
implementation(Dependencies.Lifecycle.liveDataKtx)
implementation(Dependencies.Lifecycle.runtime)
implementation(Dependencies.Lifecycle.viewModelKtx)
implementation(Dependencies.Navigation.navFragmentKtx)
implementation(Dependencies.Navigation.navUiKtx)
implementation(Dependencies.material)
implementation(Dependencies.timber)
implementation(libs.androidx.activity)
implementation(libs.androidx.appcompat)
implementation(libs.androidx.constraintlayout)
implementation(libs.androidx.datastore.preferences)
implementation(libs.androidx.fragment)
implementation(libs.androidx.lifecycle.livedata)
implementation(libs.androidx.lifecycle.runtime)
implementation(libs.androidx.lifecycle.viewmodel)
implementation(libs.androidx.navigation.fragment)
implementation(libs.androidx.navigation.ui)
implementation(libs.androidx.recyclerview)
implementation(libs.androidx.work.runtime)
implementation(project(":datacapture")) {
exclude(group = Dependencies.androidFhirGroup, module = Dependencies.androidFhirEngineModule)
}
Expand Down
98 changes: 55 additions & 43 deletions docs/use/SDCL/Customize-how-a-Questionnaire-is-displayed.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,53 +79,65 @@ component.

### Create a custom component

In order to create a custom component:

1. Create a layout for the custom component
([example](https://github.com/google/android-fhir/blob/master/catalog/src/main/res/layout/custom_number_picker_layout.xml)).
2. Create a class for your component that implements
`QuestionnaireItemViewHolderFactory`
([example](https://github.com/google/android-fhir/blob/master/catalog/src/main/java/com/google/android/fhir/catalog/CustomNumberPickerFactory.kt)).
In that class:
1. Pass the layout resource for your custom component in the constructor of
your custom factory.
2. Override the `getQuestionnaireItemViewHolderDelegate()` function. It
must return a `QuestionnaireItemViewHolderDelegate` which implements the
following functions:
3. `init`: a delegate function for the `init` function of
`RecyclerView.ViewHolder`
4. `bind`: a delegate function for the `bind` function of
`RecyclerView.ViewHolder`
5. `displayValidationResult`: displays the validation result for the answer(s)
provided by the user
6. `setReadOnly`: configures the UI based on the read-only status of the
questionnaire item

### Apply a custom component to questions

Now that you have defined the custom widget and its behavior, it is time to
configure the Structured Data Capture Library in order for the custom widget to
be applied to the appropriate questions.

1. Create a QuestionnaireFragment.QuestionnaireItemViewHolderFactoryMatcher
([example](https://github.com/google/android-fhir/blob/master/catalog/src/main/java/com/google/android/fhir/catalog/CustomQuestionnaireFragment.kt#L26))
that defines:
1. factory: The custom component factory to use.
2. matches: A predicate function which, given a
[`Questionnaire.QuestionnaireItemComponent`](https://hapifhir.io/hapi-fhir/apidocs/hapi-fhir-structures-r4/org/hl7/fhir/r4/model/Questionnaire.QuestionnaireItemComponent.html),
returns true if the factory should apply to that item.
2. Create a custom implementation of `QuestionnaireFragment` that
overrides `getCustomQuestionnaireItemViewHolderFactoryMatchers`
([example](https://github.com/google/android-fhir/blob/master/catalog/src/main/java/com/google/android/fhir/catalog/CustomQuestionnaireFragment.kt#L22)).
It should return a list that contains your
`QuestionnaireItemViewHolderFactoryMatcher`.
3. When rendering your questionnaire, use your custom implementation of
<code>QuestionnaireFragment</code> instead.
This guide outlines the step-by-step process to create and incorporate custom widgets into FHIR questionnaires using the Android FHIR SDK.

Note: Examples given below are all from the [catalog](https://github.com/google/android-fhir/tree/master/catalog) application in this repository. We recommend you try out the application to see these concepts in action.

1. Create a layout for the Custom Component

Design an XML layout file to define the visual structure and appearance of your custom widget.

* Example: See this [example location_widget_view.xml](https://github.com/google/android-fhir/blob/master/contrib/locationwidget/src/main/res/layout/location_widget_view.xml).

2. Create a `QuestionnaireItemViewHolderFactory` class

Implement a class that extends [QuestionnaireItemViewHolderFactory](https://github.com/google/android-fhir/blob/master/datacapture/src/main/java/com/google/android/fhir/datacapture/views/factories/QuestionnaireItemViewHolderFactory.kt#L35). This class will be responsible for creating and managing the view holder for your custom component.

* Example: Check out this [example LocationWidgetViewHolderFactory](https://github.com/google/android-fhir/blob/master/contrib/locationwidget/src/main/java/com/google/android/fhir/datacapture/contrib/views/locationwidget/LocationWidgetViewHolderFactory.kt#L29).

Within this class:

* Pass the layout resource ID to the constructor.
* Override `getQuestionnaireItemViewHolderDelegate()` to return a `QuestionnaireItemViewHolderDelegate` implementation. This delegate should include:
* `init`: Initializes the `RecyclerView.ViewHolder`.
* `bind`: Binds data to the `RecyclerView.ViewHolder`.
* `displayValidationResult`: Displays validation feedback for user input.
* `setReadOnly`: Configures the UI for read-only mode.

3. Create `QuestionnaireItemViewHolderFactoryMatcher` Objects

For each custom `ViewHolderFactory`, create a corresponding factory matcher object - [QuestionnaireItemViewHolderFactoryMatcher](https://github.com/google/android-fhir/blob/master/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireFragment.kt#L538)

* Example: Refer to these [matcher examples](https://github.com/google/android-fhir/blob/master/catalog/src/main/java/com/google/android/fhir/catalog/ContribQuestionnaireItemViewHolderFactoryMatchersProviderFactory.kt#L38C15-L45C16).

Each matcher should define:

* `factory`: The custom `ViewHolderFactory` instance.
* `matches`: A predicate function that takes a [`Questionnaire.QuestionnaireItemComponent`](https://hapifhir.io/hapi-fhir/apidocs/hapi-fhir-structures-r4/org/hl7/fhir/r4/model/Questionnaire.QuestionnaireItemComponent.html) and returns `true` if this factory is suitable for rendering that item.

4. Create a `QuestionnaireItemViewHolderFactoryMatchersProviderFactory`

Create a factory class that implements this interface. It acts as a central registry for your custom widget associations.

* Example: This [example factory class](https://github.com/google/android-fhir/blob/master/catalog/src/main/java/com/google/android/fhir/catalog/ContribQuestionnaireItemViewHolderFactoryMatchersProviderFactory.kt) demonstrates this.

5. Register the Factory in `DataCaptureConfig`

In your `DataCaptureConfig` object, set the `questionnaireItemViewHolderFactoryMatchersProviderFactory` property to your custom factory instance.

* Example: See how this is done in [this code](https://github.com/google/android-fhir/blob/master/catalog/src/main/java/com/google/android/fhir/catalog/CatalogApplication.kt#L42C5-L47C8).

6. Use the Custom Widget in Your Questionnaire Fragment

When building your `QuestionnaireFragment`, call the `setCustomQuestionnaireItemViewHolderFactoryMatchersProvider` method on the builder, providing the string identifier associated with your custom widget.

* Example: This [usage example](https://github.com/google/android-fhir/blob/master/catalog/src/main/java/com/google/android/fhir/catalog/DemoQuestionnaireFragment.kt#L142C13-L150C23) shows how to set up the fragment.


## Localize questionnaires

When rendering your questionnaire, the library will look for the
[translation extension](http://hl7.org/fhir/extension-translation.html), and if
[translation extension](https://www.hl7.org/fhir/R4/languages.html##ext), and if
the lang element matches the application default locale, will use the value of
the content element of the extension instead of the text element of the
questionnaire item. You can also use the
Expand Down
Loading

0 comments on commit d9e6d03

Please sign in to comment.