Skip to content

Commit

Permalink
Integrate GeoWidget (#1548)
Browse files Browse the repository at this point in the history
* Add Geowidget module

- Integrate into Quest
- Add Geowidget debug build variant that enables running quest with Geowidget
- Implement displaying families with locations on Quest
- Implement family registration with location from geowidget

* Zoom to registered families & remove register family btn

* Fix Kujaku version and add turf dependency

- Turf is used for measurements and calculations but a runtime dependency on Mapbox SDK

* Connect maps menu to Geowidget

- Remove hardcoded Geowidget menu
- Remove geowidget module from FHIR Core engine
- Move kujaku dependency to deps.gradle file
- Update naming in fhircore_style.json
- Add GEOWIDGET_ENABLED BuildConfig to disable the maps menu
- Fix maps English translation for configurable menu
- Code cleanup

* Disable  maps menu when geowidgetEnabled config is false

* Update eCBIS geowidget questionnaire to work with non-geowidget versions

* Add empty action when family is clicked

- Add family-id to feature JSON
- Cleanup code in GeowidgetActivity
- Comment out hardcoded questionnaire and structure-map

* Enable syncing of Locations in quest

* Enable saving new points into Location boundary extension

- Enable parsing feature from the Location Boundary GeoJSON extension
- Refactor code in GeowidgetActivity
- Code reformat
- Move strings to strings.xml

* Add Geowidget module tests & spotless checks to CI

- Add jacoco report generation to the Geowidget module
- Add licenses to the Geowidget module files
- Fix wildcard imports in Geowidget tests

* Move data from AppMainActivity

* Add KujakuFhirCoreConverterTest

- Rename KujakuConversionInterface to KujakuFhirCoreConverter
- Code cleanup

* Add GeowidgetViewModel tests

* GeowidgetActivity tests

* Re-enable removed sync configs

* Fix quest sync config failing test

* Exclude META-INF/sun-jaxb.episode from packing in Geowidget module

- This fixes the build failure

* Exclude META-INF files causing build failure in geowidget

- Fix codacy reported issues

* Set application flavor for geowidget

Refactor the implementation for navigating to maps UI to use the
Navigation configs. Also fix sync location by organization.

Signed-off-by: Elly Kitoto <junkmailstoelly@gmail.com>

* Navigate to profile from geowidget

Introduce GeoWidgetConfiguration which will be used to configure the
map.

Signed-off-by: Elly Kitoto <junkmailstoelly@gmail.com>

* Refactor GeoWidgetActivity to a Fragement

In order to honor the single Activtivity architecture, the GeoWidgetActivity
has been converted to a Fragment and all the composable screens are now wrapped
in a Fragment. Using a Fragment allows for a more hybrid approach that will
also take care of other custom views that are still using XML layout at the
same time be able to render composable views.

Instead of using Composable (MainScreen) as the NavigationHost, we now use the
AppMainActivity as the Host, with NavHostFragment as the container for the
fragments.

UserProfileScreen has also been renamed to UserSettingScreen and it is now rendered
in the UserSettingFragment.

The application side menu (drawer navigation) has been moved to RegisterFragement setContent
method. It makes sense to be able to access the drawer via the registers. MainScreen is therefore
no longer needed so it has been deleted.

GeoWidgetViewModel is now instantiated in the GeoWidgetFragement with the activityViewModels
extension function. This is to allow the activity to access the geoWidgetEventLiveData to
react to the events created via the GeoWidgetFragment.

Signed-off-by: Elly Kitoto <junkmailstoelly@gmail.com>

* Setup toolbar on map view

Signed-off-by: Elly Kitoto <junkmailstoelly@gmail.com>

* Remove P2P menu for Geowidget NavMenu

* Delete irrelevant test

Signed-off-by: Elly Kitoto <junkmailstoelly@gmail.com>

* Fix failing tests across modules

Signed-off-by: Elly Kitoto <junkmailstoelly@gmail.com>

* Fix GeoWidgeViewModelTest

Signed-off-by: Elly Kitoto <junkmailstoelly@gmail.com>

* Fix permissions request from GeoWidgetFragment

Signed-off-by: Elly Kitoto <junkmailstoelly@gmail.com>

* Set test logs

Indicate tests that are passing, skipped or failed

Signed-off-by: Elly Kitoto <junkmailstoelly@gmail.com>

Signed-off-by: Elly Kitoto <junkmailstoelly@gmail.com>
Co-authored-by: Elly Kitoto <junkmailstoelly@gmail.com>
Co-authored-by: Francis Odhiambo Otieno <4540684+f-odhiambo@users.noreply.github.com>
  • Loading branch information
3 people authored Sep 7, 2022
1 parent 98f2c5e commit 0ffd664
Show file tree
Hide file tree
Showing 98 changed files with 16,117 additions and 669 deletions.
72 changes: 72 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,78 @@ jobs:
working-directory: android
run: bash <(curl -s https://codecov.io/bash) -F engine -f "engine/build/reports/jacoco/fhircoreJacocoReport/fhircoreJacocoReport.xml"

geowidget-tests:
runs-on: macos-latest
strategy:
matrix:
api-level: [30]
steps:
- name: Cancel Previous workflow runs
uses: styfle/cancel-workflow-action@0.9.1
with:
access_token: ${{ github.token }}

- name: Checkout 🛎️
uses: actions/checkout@v2
with:
fetch-depth: 2

- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11

- name: Grant execute permission for gradlew
run: chmod +x gradlew
working-directory: android

- name: Copy CI gradle.properties
run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties && cat ~/.gradle/gradle.properties

- name: Setup Gradle cache
uses: gradle/gradle-build-action@v2

- name: Spotless check geowidget module
run: ./gradlew :geowidget:spotlessCheck --stacktrace
working-directory: android

- name: Load AVD cache
uses: actions/cache@v2
id: avd-cache
with:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-${{ matrix.api-level }}

- name: Create AVD and generate snapshot for caching
if: steps.avd-cache.outputs.cache-hit != 'true'
uses: reactivecircus/android-emulator-runner@v2
with:
working-directory: android
api-level: ${{ matrix.api-level }}
arch: x86_64
force-avd-creation: false
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: false
script: echo "Generated AVD snapshot for caching."

- name: Run Geowidget module unit and instrumentation tests and generate coverage report
uses: reactivecircus/android-emulator-runner@v2
with:
working-directory: android
api-level: ${{ matrix.api-level }}
arch: x86_64
force-avd-creation: true
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true
script: ./gradlew :geowidget:clean && ./gradlew :geowidget:fhircoreJacocoReport --stacktrace

- name: Upload Geowidget module test coverage report to Codecov
if: matrix.api-level == 30 # Only upload coverage on API level 30
working-directory: android
run: bash <(curl -s https://codecov.io/bash) -F geowidget -f "geowidget/build/reports/jacoco/fhircoreJacocoReport/fhircoreJacocoReport.xml"

quest-tests:
runs-on: macos-latest
strategy:
Expand Down
15 changes: 12 additions & 3 deletions android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
apply from: 'deps.gradle'
apply from: 'configs.gradle'

ext.composeVersion = "1.2.1"
ext.navigationVersion = "2.5.1"

repositories {
google()
maven { url "https://plugins.gradle.org/m2/" }
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }

}

dependencies {
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10'
classpath "org.jetbrains.kotlin:kotlin-serialization:1.6.21"
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10'
classpath "org.jetbrains.kotlin:kotlin-serialization:1.7.10"
classpath 'com.google.dagger:hilt-android-gradle-plugin:2.42'
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.5.1"
classpath deps.spotless
classpath deps.kotlin_coveralls_plugin
classpath deps.junit5_plugin
Expand All @@ -32,6 +38,9 @@ allprojects {
name = "fhirsdk"
url = uri("/Users/ndegwamartin/.m2.dev/fhirsdk")
}
maven {
url 'https://jcenter.bintray.com/'
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions android/configs.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def geowidgetEnabled = true
ext.geowidgetEnabled = geowidgetEnabled
8 changes: 6 additions & 2 deletions android/deps.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,17 @@ versions.coroutines = '1.6.0'
versions.core = '1.7.0'
versions.cql_engine = '1.3.14-SNAPSHOT'
versions.desugar = '1.1.5'
versions.fragment = '1.4.1'
versions.fragment = '1.5.2'
versions.fhir_protos = '0.6.1'
versions.guava = '28.2-android'
versions.hapi_r4 = '5.3.0'
versions.junit5_api = '5.8.2'
versions.junit5_plugin = '1.8.2.0'
versions.kotlin = '1.6.10'
versions.kotlin = '1.7.10'
versions.kujaku_library = '0.9.0'
versions.lifecycle = '2.2.0'
versions.material = '1.5.0'
versions.mapbox_sdk_turf = '4.8.0'
versions.okhttp_logging_interceptor = '4.0.0'
versions.recyclerview = '1.1.0'
versions.retrofit = '2.7.2'
Expand Down Expand Up @@ -89,6 +91,8 @@ deps.junit5_plugin = "de.mannodermaus.gradle.plugins:android-junit5:$versions.ju
deps.junit5_api = "org.junit.jupiter:junit-jupiter-api:$versions.junit5_api"
deps.junit5_engine = "org.junit.jupiter:junit-jupiter-engine:$versions.junit5_api"
deps.junit5_engine_vintage = "org.junit.vintage:junit-vintage-engine:$versions.junit5_api"
deps.kujaku_library = "io.ona.kujaku:library:$versions.kujaku_library"
deps.mapbox_sdk_turf = "com.mapbox.mapboxsdk:mapbox-sdk-turf:$versions.mapbox_sdk_turf"
deps.mockk = "io.mockk:mockk:$versions.mockk"
deps.mockk_android = "io.mockk:mockk-android:$versions.mockk"
deps.dokka_plugin = "org.jetbrains.dokka:dokka-gradle-plugin:$versions.dokka"
Expand Down
34 changes: 22 additions & 12 deletions android/engine/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ plugins {
id 'de.mannodermaus.android-junit5'
id 'jacoco'
id 'dagger.hilt.android.plugin'
id 'androidx.navigation.safeargs'
}

apply from: '../jacoco.gradle'
apply from: '../configs.gradle'

android {

Expand All @@ -18,6 +20,7 @@ android {
dataBinding {
enabled true
}

defaultConfig {
minSdkVersion sdk_versions.min_sdk
targetSdkVersion sdk_versions.target_sdk
Expand All @@ -41,14 +44,14 @@ android {
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
freeCompilerArgs = ['-Xjvm-default=compatibility']
freeCompilerArgs = ['-Xjvm-default=all-compatibility']
}
buildFeatures {
compose true
viewBinding true
}
composeOptions {
kotlinCompilerExtensionVersion '1.1.1'
kotlinCompilerExtensionVersion '1.3.0'
}

packagingOptions {
Expand Down Expand Up @@ -81,14 +84,18 @@ android {
all {
minHeapSize = "4608m"
maxHeapSize = "4608m"
beforeTest { testDescriptor ->
println "${testDescriptor.className} > ${testDescriptor.name} STARTED"
}
}
}
}
}

// Test Logging
tasks.withType(Test) {
testLogging {
events "passed", "skipped", "failed"
}
}

// CQL
configurations {
all*.exclude group: 'org.eclipse.persistence'
Expand Down Expand Up @@ -152,28 +159,29 @@ dependencies {
implementation "com.google.dagger:hilt-android:$hiltVersion"
kapt "com.google.dagger:hilt-compiler:$hiltVersion"

def lifecycleKtxVersion = '2.5.0'
def lifecycleKtxVersion = '2.5.1'
api "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleKtxVersion"
api "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleKtxVersion"

// P2P dependency
implementation('org.smartregister:p2p-lib:0.4.0-SNAPSHOT')

// Configure Jetpack Compose
def composeVersion = "1.3.0-alpha01"
//Configure Jetpack Compose and navigation
api("androidx.compose.ui:ui:$composeVersion")
api("androidx.compose.ui:ui-tooling:$composeVersion")
api("androidx.compose.foundation:foundation:$composeVersion")
api("androidx.compose.material:material:$composeVersion")
api("androidx.compose.material:material-icons-core:$composeVersion")
api("androidx.compose.material:material-icons-extended:$composeVersion")
api("androidx.compose.runtime:runtime-livedata:$composeVersion")
api("androidx.navigation:navigation-compose:2.5.0")
api ("androidx.navigation:navigation-fragment-ktx:$navigationVersion")
api ("androidx.navigation:navigation-ui-ktx:$navigationVersion")
api("androidx.navigation:navigation-compose:$navigationVersion")
api("androidx.hilt:hilt-navigation-compose:1.0.0")
api("androidx.lifecycle:lifecycle-viewmodel-compose:2.5.0")
api("androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1")
api("androidx.paging:paging-compose:1.0.0-alpha15")
api("androidx.activity:activity-compose:1.5.0")
api 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.2'
api("androidx.activity:activity-compose:1.5.1")
api 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2'
api ("com.google.accompanist:accompanist-flowlayout:0.23.1")
api("androidx.work:work-runtime-ktx:2.7.1")
api("org.ocpsoft.prettytime:prettytime:5.0.2.Final")
Expand All @@ -190,6 +198,8 @@ dependencies {
exclude group: 'com.sun.xml.bind', module: 'jaxb-core'
exclude group: 'com.sun.activation', module: 'javax.activation'
exclude group: 'com.google.android.fhir', module: 'common'
exclude group: 'ca.uhn.hapi.fhir'
exclude group: 'org.opencds.cqf.cql'
}

api('org.smartregister:common:0.1.0-alpha03-preview3-SNAPSHOT') {
Expand Down
3 changes: 2 additions & 1 deletion android/engine/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@

<uses-permission android:name="android.permission.CALL_PHONE" />

<application>
<application
xmlns:tools="http://schemas.android.com/tools">

<activity
android:name=".ui.appsetting.AppSettingActivity"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,5 @@ sealed class ConfigType(
object Register : ConfigType("register", multiConfig = true)
object MeasureReport : ConfigType("measureReport")
object Profile : ConfigType("profile", multiConfig = true)
object GeoWidget : ConfigType("geoWidget", multiConfig = true)
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ package org.smartregister.fhircore.engine.configuration
* @property appId Unique identifier for the application to which this configurations is applied
* @property configType Used to categorize multiple configurations of the same type. E.g. two
* RegisterViewConfigurations used in an application with two registers.
* @property resourceType Optional FHIR resource type
*/
abstract class Configuration {
open lateinit var appId: String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,6 @@ interface ConfigService {
)
}

fun unschedulePlan(context: Context) {
WorkManager.getInstance(context).cancelUniqueWork(FhirTaskPlanWorker.WORK_ID)
}

/** Retrieve registry sync params */
fun loadRegistrySyncParams(
configurationRegistry: ConfigurationRegistry,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2021 Ona Systems, Inc
*
* 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 org.smartregister.fhircore.engine.configuration.geowidget

import kotlinx.serialization.Serializable
import org.smartregister.fhircore.engine.configuration.ConfigType
import org.smartregister.fhircore.engine.configuration.Configuration
import org.smartregister.fhircore.engine.configuration.QuestionnaireConfig

@Serializable
data class GeoWidgetConfiguration(
override var appId: String,
override var configType: String = ConfigType.GeoWidget.name,
val id: String,
val profileId: String,
val registrationQuestionnaire: QuestionnaireConfig
) : Configuration()
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,14 @@ constructor(
val baseResourceClass = baseResourceConfig.resource.resourceClassType()
val baseResourceType = baseResourceClass.newInstance().resourceType

// Some resource id maybe in the format Group/1be72fc8-5e5c-4f90-a37d-739c73fc4bdf/_history/7
val parsedResourceId =
if (resourceId.startsWith(baseResourceType.name))
resourceId.substringAfter("/").substringBefore("/")
else resourceId

val baseResource: Resource =
withContext(dispatcherProvider.io()) { fhirEngine.get(baseResourceType, resourceId) }
withContext(dispatcherProvider.io()) { fhirEngine.get(baseResourceType, parsedResourceId) }

return retrieveRelatedResources(
relatedResourcesConfig = relatedResourcesConfig,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,13 +170,15 @@ open class QuestionnaireActivity : BaseMultiLanguageActivity(), View.OnClickList

if (clientIdentifier != null) {
setBarcode(questionnaire, clientIdentifier!!, true)
questionnaireResponse =
questionnaireViewModel.generateQuestionnaireResponse(questionnaire, intent)
this.putString(
QuestionnaireFragment.EXTRA_QUESTIONNAIRE_RESPONSE_JSON_STRING,
questionnaireResponse.encodeResourceToString()
)
}

questionnaireResponse =
questionnaireViewModel.generateQuestionnaireResponse(questionnaire, intent)

this.putString(
QuestionnaireFragment.EXTRA_QUESTIONNAIRE_RESPONSE_JSON_STRING,
questionnaireResponse.encodeResourceToString()
)
}
}
supportFragmentManager.commit { add(R.id.container, fragment, QUESTIONNAIRE_FRAGMENT_TAG) }
Expand Down Expand Up @@ -374,6 +376,10 @@ open class QuestionnaireActivity : BaseMultiLanguageActivity(), View.OnClickList
}
}

override fun onResume() {
super.onResume()
}

open fun getDismissDialogMessage() = R.string.questionnaire_alert_back_pressed_message

companion object {
Expand Down
Loading

0 comments on commit 0ffd664

Please sign in to comment.