diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2957759873..b230321631 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -255,7 +255,7 @@ dependencies { implementation(project(":stock-usecase")) implementation(project(":dhis2-mobile-program-rules")) implementation(project(":tracker")) - implementation(project(":support-module")) + implementation(libs.security.conscrypt) implementation(libs.security.rootbeer) diff --git a/app/src/main/java/org/dhis2/data/dhislogic/DhisProgramUtils.kt b/app/src/main/java/org/dhis2/data/dhislogic/DhisProgramUtils.kt index 882e6f9101..ca28d953ae 100644 --- a/app/src/main/java/org/dhis2/data/dhislogic/DhisProgramUtils.kt +++ b/app/src/main/java/org/dhis2/data/dhislogic/DhisProgramUtils.kt @@ -2,7 +2,6 @@ package org.dhis2.data.dhislogic import io.reactivex.Flowable import org.hisp.dhis.android.core.D2 -import org.hisp.dhis.android.core.arch.repositories.scope.RepositoryScope import org.hisp.dhis.android.core.common.State import org.hisp.dhis.android.core.enrollment.EnrollmentCollectionRepository import org.hisp.dhis.android.core.event.EventCollectionRepository @@ -10,7 +9,6 @@ import org.hisp.dhis.android.core.organisationunit.OrganisationUnit import org.hisp.dhis.android.core.program.Program import org.hisp.dhis.android.core.program.ProgramType import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceCollectionRepository -import org.saudigitus.rei.utils.Utils.datastorePrograms import javax.inject.Inject class DhisProgramUtils @Inject constructor(val d2: D2) { @@ -45,7 +43,6 @@ class DhisProgramUtils @Inject constructor(val d2: D2) { fun getProgramsInCaptureOrgUnits(): Flowable> { return d2.programModule().programs() - .byUid().`in`(datastorePrograms(d2)) .withTrackedEntityType() .byOrganisationUnitScope(OrganisationUnit.Scope.SCOPE_DATA_CAPTURE) .get().toFlowable() diff --git a/app/src/main/java/org/dhis2/usescases/main/HomeNavigator.kt b/app/src/main/java/org/dhis2/usescases/main/HomeNavigator.kt index dabf807a65..b4b98baeba 100644 --- a/app/src/main/java/org/dhis2/usescases/main/HomeNavigator.kt +++ b/app/src/main/java/org/dhis2/usescases/main/HomeNavigator.kt @@ -12,6 +12,7 @@ import org.dhis2.usescases.main.program.ProgramUiModel import org.dhis2.usescases.programEventDetail.ProgramEventDetailActivity import org.dhis2.usescases.searchTrackEntity.SearchTEActivity import org.hisp.dhis.android.core.program.ProgramType +import org.saudigitus.rei.ReiActivity sealed class HomeItemData( open val uid: String, @@ -24,6 +25,7 @@ sealed class HomeItemData( override val accessDataWrite: Boolean, val trackedEntityType: String, val stockConfig: AppConfig?, + val isRei: Boolean, ) : HomeItemData(uid, label, accessDataWrite) data class EventProgram( @@ -55,6 +57,7 @@ fun ProgramUiModel.toHomeItemData(): HomeItemData { accessDataWrite, type!!, stockConfig, + isRei, ) else -> HomeItemData.DataSet( @@ -94,7 +97,12 @@ fun ActivityResultLauncher.navigateTo(context: Context, homeItemData: Ho } is HomeItemData.TrackerProgram -> { - if (homeItemData.stockConfig != null) { + if (homeItemData.isRei) { + Intent(context, ReiActivity::class.java).apply { + putExtras(bundle) + launch(this) + } + } else if (homeItemData.stockConfig != null) { Intent(context, HomeActivity::class.java).apply { putExtra( org.dhis2.android.rtsm.commons.Constants.INTENT_EXTRA_APP_CONFIG, diff --git a/app/src/main/java/org/dhis2/usescases/main/HomeRepositoryImpl.kt b/app/src/main/java/org/dhis2/usescases/main/HomeRepositoryImpl.kt index 5f303caf7b..0c4b333394 100644 --- a/app/src/main/java/org/dhis2/usescases/main/HomeRepositoryImpl.kt +++ b/app/src/main/java/org/dhis2/usescases/main/HomeRepositoryImpl.kt @@ -17,6 +17,7 @@ import org.hisp.dhis.android.core.category.CategoryOptionCombo import org.hisp.dhis.android.core.program.ProgramType import org.hisp.dhis.android.core.systeminfo.SystemInfo import org.hisp.dhis.android.core.user.User +import org.saudigitus.rei.utils.Utils.isRei class HomeRepositoryImpl( private val d2: D2, @@ -81,6 +82,7 @@ class HomeRepositoryImpl( } else { null }, + isRei = isRei(d2, program.uid()), ) program?.programType() == ProgramType.WITHOUT_REGISTRATION -> diff --git a/app/src/main/java/org/dhis2/usescases/main/program/ProgramFragment.kt b/app/src/main/java/org/dhis2/usescases/main/program/ProgramFragment.kt index 0a90005674..6824d4ffe7 100644 --- a/app/src/main/java/org/dhis2/usescases/main/program/ProgramFragment.kt +++ b/app/src/main/java/org/dhis2/usescases/main/program/ProgramFragment.kt @@ -31,8 +31,6 @@ import org.dhis2.utils.HelpManager import org.dhis2.utils.analytics.SELECT_PROGRAM import org.dhis2.utils.analytics.TYPE_PROGRAM_SELECTED import org.dhis2.utils.granularsync.SyncStatusDialog -import org.saudigitus.rei.ui.stages.StageViewModel -import org.saudigitus.rei.ui.stages.StageViewModelFactory import timber.log.Timber import javax.inject.Inject @@ -41,17 +39,10 @@ class ProgramFragment : FragmentGlobalAbstract(), ProgramView { @Inject lateinit var programViewModelFactory: ProgramViewModelFactory - @Inject - lateinit var stageViewModelFactory: StageViewModelFactory - val programViewModel: ProgramViewModel by viewModels { programViewModelFactory } - val stageViewModel: StageViewModel by viewModels { - stageViewModelFactory - } - @Inject lateinit var animation: ProgramAnimation @@ -86,7 +77,6 @@ class ProgramFragment : FragmentGlobalAbstract(), ProgramView { programViewModel.setIsDownloading() } ProgramList( - stageViewModel = stageViewModel, downLoadState = state, programs = items, onItemClick = { diff --git a/app/src/main/java/org/dhis2/usescases/main/program/ProgramModule.kt b/app/src/main/java/org/dhis2/usescases/main/program/ProgramModule.kt index b8fd5b51e4..7354edf05c 100644 --- a/app/src/main/java/org/dhis2/usescases/main/program/ProgramModule.kt +++ b/app/src/main/java/org/dhis2/usescases/main/program/ProgramModule.kt @@ -16,7 +16,6 @@ import org.dhis2.data.service.SyncStatusController import org.hisp.dhis.android.core.D2 import org.saudigitus.rei.data.source.DataManager import org.saudigitus.rei.data.source.repository.DataManagerImpl -import org.saudigitus.rei.ui.stages.StageViewModelFactory @Module class ProgramModule(private val view: ProgramView) { @@ -40,12 +39,6 @@ class ProgramModule(private val view: ProgramView) { ) } - @Provides - @PerFragment - internal fun stageViewModelFactory(dataManager: DataManager): StageViewModelFactory { - return StageViewModelFactory(dataManager) - } - @Provides @PerFragment internal fun homeRepository( diff --git a/app/src/main/java/org/dhis2/usescases/main/program/ProgramRepositoryImpl.kt b/app/src/main/java/org/dhis2/usescases/main/program/ProgramRepositoryImpl.kt index c5749790ea..4581ea6089 100644 --- a/app/src/main/java/org/dhis2/usescases/main/program/ProgramRepositoryImpl.kt +++ b/app/src/main/java/org/dhis2/usescases/main/program/ProgramRepositoryImpl.kt @@ -17,6 +17,7 @@ import org.hisp.dhis.android.core.program.Program import org.hisp.dhis.android.core.program.ProgramType.WITHOUT_REGISTRATION import org.hisp.dhis.android.core.program.ProgramType.WITH_REGISTRATION import org.hisp.dhis.mobile.ui.designsystem.theme.SurfaceColor +import org.saudigitus.rei.utils.Utils.isRei internal class ProgramRepositoryImpl( private val d2: D2, @@ -115,6 +116,7 @@ internal class ProgramRepositoryImpl( } else { null }, + isRei = isRei(d2, program.uid()), ) }.toList().toFlowable().blockingFirst() } diff --git a/app/src/main/java/org/dhis2/usescases/main/program/ProgramUi.kt b/app/src/main/java/org/dhis2/usescases/main/program/ProgramUi.kt index f79df6e726..1c7810289e 100644 --- a/app/src/main/java/org/dhis2/usescases/main/program/ProgramUi.kt +++ b/app/src/main/java/org/dhis2/usescases/main/program/ProgramUi.kt @@ -11,15 +11,12 @@ import androidx.compose.foundation.layout.Arrangement.Absolute.spacedBy import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.verticalScroll import androidx.compose.material.Card import androidx.compose.material.CircularProgressIndicator import androidx.compose.material.Icon @@ -51,13 +48,10 @@ import androidx.compose.ui.semantics.SemanticsPropertyReceiver import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.font.FontFamily -import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import com.saudigitus.support_module.ui.MenuScreen import org.dhis2.R import org.dhis2.commons.bindings.addIf import org.dhis2.commons.date.toDateSpan @@ -89,8 +83,6 @@ import org.hisp.dhis.mobile.ui.designsystem.component.state.rememberListCardStat import org.hisp.dhis.mobile.ui.designsystem.theme.Spacing import org.hisp.dhis.mobile.ui.designsystem.theme.SurfaceColor import org.hisp.dhis.mobile.ui.designsystem.theme.TextColor -import org.saudigitus.rei.ui.stages.StageScreen -import org.saudigitus.rei.ui.stages.StageViewModel import java.util.Date enum class ProgramLayout { @@ -105,7 +97,6 @@ enum class ProgramLayout { @Composable fun ProgramList( - stageViewModel: StageViewModel? = null, programs: List?, onItemClick: (programUiModel: ProgramUiModel) -> Unit, onGranularSyncClick: (programUiModel: ProgramUiModel) -> Unit, @@ -114,7 +105,6 @@ fun ProgramList( Column( modifier = Modifier .fillMaxSize() - .verticalScroll(rememberScrollState()) .testTag(HOME_ITEMS) .semantics { HasPrograms = programs?.isNotEmpty() ?: false @@ -129,8 +119,7 @@ fun ProgramList( ExpandableItemColumn( modifier = Modifier - .fillMaxWidth() - .height(300.dp), + .fillMaxSize(), itemList = programs, ) { program, verticalPadding, onSizeChanged -> @@ -152,19 +141,6 @@ fun ProgramList( ?: run { {} }, ) } - if (stageViewModel != null) { - StageScreen(stageViewModel) - } - Spacer(modifier = Modifier.height(16.dp)) - - Text( - text = "Suporte ao utilizador", - modifier = Modifier.padding(horizontal = 16.dp), - fontSize = 16.sp, - fontWeight = FontWeight.Bold, - color = Color.Black.copy(.5f), - ) - MenuScreen(context = LocalContext.current) } ?: run { Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { ProgressIndicator(type = ProgressIndicatorType.CIRCULAR_SMALL) @@ -693,6 +669,7 @@ private fun testingProgramModel() = ProgramUiModel( state = State.SYNCED, downloadState = ProgramDownloadState.NONE, stockConfig = null, + isRei = false, lastUpdated = Date(), ) diff --git a/app/src/main/java/org/dhis2/usescases/main/program/ProgramUiModel.kt b/app/src/main/java/org/dhis2/usescases/main/program/ProgramUiModel.kt index c1440bcf30..38cba1dcb9 100644 --- a/app/src/main/java/org/dhis2/usescases/main/program/ProgramUiModel.kt +++ b/app/src/main/java/org/dhis2/usescases/main/program/ProgramUiModel.kt @@ -20,6 +20,7 @@ data class ProgramUiModel( val downloadState: ProgramDownloadState, val downloadActive: Boolean = false, val stockConfig: AppConfig?, + val isRei: Boolean, val lastUpdated: Date, ) { fun countDescription() = "%s %s".format(count, typeName) diff --git a/app/src/main/java/org/dhis2/usescases/main/program/ProgramViewModelMapper.kt b/app/src/main/java/org/dhis2/usescases/main/program/ProgramViewModelMapper.kt index a632bfdf50..50ab41094e 100644 --- a/app/src/main/java/org/dhis2/usescases/main/program/ProgramViewModelMapper.kt +++ b/app/src/main/java/org/dhis2/usescases/main/program/ProgramViewModelMapper.kt @@ -33,6 +33,7 @@ class ProgramViewModelMapper() { state = State.valueOf(state.name), downloadState = ProgramDownloadState.NONE, stockConfig = null, + isRei = false, lastUpdated = program.lastUpdated() ?: Date(), ) } @@ -58,6 +59,7 @@ class ProgramViewModelMapper() { state = dataSetInstanceSummary.state(), downloadState = ProgramDownloadState.NONE, stockConfig = null, + isRei = false, lastUpdated = dataSet.lastUpdated() ?: Date(), ) } diff --git a/app/src/main/java/org/dhis2/usescases/searchTrackEntity/adapters/SearchTeiLiveAdapter.kt b/app/src/main/java/org/dhis2/usescases/searchTrackEntity/adapters/SearchTeiLiveAdapter.kt index 02b46780db..2fa4fc2e74 100644 --- a/app/src/main/java/org/dhis2/usescases/searchTrackEntity/adapters/SearchTeiLiveAdapter.kt +++ b/app/src/main/java/org/dhis2/usescases/searchTrackEntity/adapters/SearchTeiLiveAdapter.kt @@ -102,6 +102,7 @@ class SearchTeiLiveAdapter( var cardHeightDp by remember { mutableStateOf(0.dp) } val card = cardMapper.map( + searchTEIModel = it, onSyncIconClick = { onSyncIconClick.invoke(it.selectedEnrollment.uid()) diff --git a/app/src/main/java/org/dhis2/usescases/searchTrackEntity/ui/mapper/TEICardMapper.kt b/app/src/main/java/org/dhis2/usescases/searchTrackEntity/ui/mapper/TEICardMapper.kt index 3ced2908cf..9088eb5894 100644 --- a/app/src/main/java/org/dhis2/usescases/searchTrackEntity/ui/mapper/TEICardMapper.kt +++ b/app/src/main/java/org/dhis2/usescases/searchTrackEntity/ui/mapper/TEICardMapper.kt @@ -62,7 +62,7 @@ class TEICardMapper( actionButton = { ProvideSyncButton(searchTEIModel, onSyncIconClick) }, expandLabelText = resourceManager.getString(R.string.show_more), shrinkLabelText = resourceManager.getString(R.string.show_less), - status = style.first, + status = context.getString(style.first), onCardCLick = onCardClick, ) } diff --git a/app/src/main/java/org/dhis2/usescases/teiDashboard/teiProgramList/ui/EnrollToProgram.kt b/app/src/main/java/org/dhis2/usescases/teiDashboard/teiProgramList/ui/EnrollToProgram.kt index 1228649038..62a03864dd 100644 --- a/app/src/main/java/org/dhis2/usescases/teiDashboard/teiProgramList/ui/EnrollToProgram.kt +++ b/app/src/main/java/org/dhis2/usescases/teiDashboard/teiProgramList/ui/EnrollToProgram.kt @@ -112,6 +112,7 @@ private fun testingProgramModel(downloadState: ProgramDownloadState) = ProgramUi state = State.SYNCED, downloadState = downloadState, stockConfig = null, + isRei = false, lastUpdated = Date(), ) diff --git a/rei/build.gradle.kts b/rei/build.gradle.kts index 7142921dc4..83e8be9dbf 100644 --- a/rei/build.gradle.kts +++ b/rei/build.gradle.kts @@ -46,6 +46,7 @@ kotlin { dependencies { implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar")))) implementation(project(":commons")) + implementation(project(":support-module")) implementation(libs.dagger.hilt.android) implementation(libs.androidx.compose.lifecycle) implementation(libs.androidx.hilt.navigation.compose) diff --git a/rei/src/main/AndroidManifest.xml b/rei/src/main/AndroidManifest.xml index a5918e68ab..dcf84d0dff 100644 --- a/rei/src/main/AndroidManifest.xml +++ b/rei/src/main/AndroidManifest.xml @@ -1,4 +1,6 @@ - + + + \ No newline at end of file diff --git a/rei/src/main/java/org/saudigitus/rei/ReiActivity.kt b/rei/src/main/java/org/saudigitus/rei/ReiActivity.kt new file mode 100644 index 0000000000..4d6791e1c6 --- /dev/null +++ b/rei/src/main/java/org/saudigitus/rei/ReiActivity.kt @@ -0,0 +1,62 @@ +package org.saudigitus.rei + +import android.os.Bundle +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.activity.viewModels +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.fragment.app.FragmentActivity +import com.saudigitus.support_module.ui.MenuScreen +import dagger.hilt.android.AndroidEntryPoint +import org.dhis2.commons.Constants +import org.dhis2.ui.theme.Dhis2Theme +import org.saudigitus.rei.ui.stages.StageScreen +import org.saudigitus.rei.ui.stages.StageViewModel + +@AndroidEntryPoint +class ReiActivity : FragmentActivity() { + + private val viewModel: StageViewModel by viewModels() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + + setContent { + Dhis2Theme { + viewModel.setProgram(intent?.extras?.getString(Constants.PROGRAM_UID) ?: "") + + Surface(modifier = Modifier.fillMaxSize()) { + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.Top, + horizontalAlignment = Alignment.CenterHorizontally, + ) { + StageScreen(viewModel) + + Text( + text = "Suporte ao utilizador", + modifier = Modifier.padding(horizontal = 16.dp), + fontSize = 16.sp, + fontWeight = FontWeight.Bold, + color = Color.Black.copy(.5f), + ) + + MenuScreen(context = this@ReiActivity) + } + } + } + } + } +} diff --git a/rei/src/main/java/org/saudigitus/rei/data/model/AppConfig.kt b/rei/src/main/java/org/saudigitus/rei/data/model/AppConfig.kt index d92a971dcf..718a904d1b 100644 --- a/rei/src/main/java/org/saudigitus/rei/data/model/AppConfig.kt +++ b/rei/src/main/java/org/saudigitus/rei/data/model/AppConfig.kt @@ -1,19 +1,7 @@ package org.saudigitus.rei.data.model -import com.fasterxml.jackson.annotation.JsonIgnoreProperties -import com.fasterxml.jackson.annotation.JsonProperty import org.saudigitus.rei.utils.Utils.toJson -@JsonIgnoreProperties(ignoreUnknown = true) -data class AppConfig( - @JsonProperty("stageProgram") - val stageProgram: String, - @JsonProperty("programs") - val programs: List, - @JsonProperty("stageVaccination") - val stageVaccination: String, - @JsonProperty("ccvDataElement") - val ccvDataElement: String, -) { +class AppConfig { override fun toString() = this.toJson() } diff --git a/rei/src/main/java/org/saudigitus/rei/data/model/AppConfigItem.kt b/rei/src/main/java/org/saudigitus/rei/data/model/AppConfigItem.kt new file mode 100644 index 0000000000..4fbb471c9c --- /dev/null +++ b/rei/src/main/java/org/saudigitus/rei/data/model/AppConfigItem.kt @@ -0,0 +1,16 @@ +package org.saudigitus.rei.data.model + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties +import com.fasterxml.jackson.annotation.JsonProperty + +@JsonIgnoreProperties(ignoreUnknown = true) +data class AppConfigItem( + @JsonProperty("defaults") + val defaults: Defaults, + @JsonProperty("lineListing") + val lineListing: LineListing, + @JsonProperty("program") + val program: String, + @JsonProperty("stageItems") + val stageItems: List, +) diff --git a/rei/src/main/java/org/saudigitus/rei/data/model/Defaults.kt b/rei/src/main/java/org/saudigitus/rei/data/model/Defaults.kt new file mode 100644 index 0000000000..af25b31935 --- /dev/null +++ b/rei/src/main/java/org/saudigitus/rei/data/model/Defaults.kt @@ -0,0 +1,12 @@ +package org.saudigitus.rei.data.model + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties +import com.fasterxml.jackson.annotation.JsonProperty + +@JsonIgnoreProperties(ignoreUnknown = true) +data class Defaults( + @JsonProperty("displayStages") + val displayStages: Boolean, + @JsonProperty("displaySupport") + val displaySupport: Boolean, +) diff --git a/rei/src/main/java/org/saudigitus/rei/data/model/LineListing.kt b/rei/src/main/java/org/saudigitus/rei/data/model/LineListing.kt new file mode 100644 index 0000000000..4f06969fde --- /dev/null +++ b/rei/src/main/java/org/saudigitus/rei/data/model/LineListing.kt @@ -0,0 +1,14 @@ +package org.saudigitus.rei.data.model + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties +import com.fasterxml.jackson.annotation.JsonProperty + +@JsonIgnoreProperties(ignoreUnknown = true) +data class LineListing( + @JsonProperty("ccvDataElement") + val ccvDataElement: String, + @JsonProperty("stageVaccination") + val stageVaccination: String, + @JsonProperty("status") + val status: List, +) diff --git a/rei/src/main/java/org/saudigitus/rei/data/model/StageItem.kt b/rei/src/main/java/org/saudigitus/rei/data/model/StageItem.kt new file mode 100644 index 0000000000..b4bd9c31fd --- /dev/null +++ b/rei/src/main/java/org/saudigitus/rei/data/model/StageItem.kt @@ -0,0 +1,12 @@ +package org.saudigitus.rei.data.model + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties +import com.fasterxml.jackson.annotation.JsonProperty + +@JsonIgnoreProperties(ignoreUnknown = true) +data class StageItem( + @JsonProperty("color") + val color: String, + @JsonProperty("label") + val label: String, +) diff --git a/rei/src/main/java/org/saudigitus/rei/data/model/Status.kt b/rei/src/main/java/org/saudigitus/rei/data/model/Status.kt new file mode 100644 index 0000000000..3f137e0486 --- /dev/null +++ b/rei/src/main/java/org/saudigitus/rei/data/model/Status.kt @@ -0,0 +1,12 @@ +package org.saudigitus.rei.data.model + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties +import com.fasterxml.jackson.annotation.JsonProperty + +@JsonIgnoreProperties(ignoreUnknown = true) +data class Status( + @JsonProperty("color") + val color: String, + @JsonProperty("label") + val label: String, +) diff --git a/rei/src/main/java/org/saudigitus/rei/data/source/DataManager.kt b/rei/src/main/java/org/saudigitus/rei/data/source/DataManager.kt index bca9cd53af..70104878bf 100644 --- a/rei/src/main/java/org/saudigitus/rei/data/source/DataManager.kt +++ b/rei/src/main/java/org/saudigitus/rei/data/source/DataManager.kt @@ -1,11 +1,11 @@ package org.saudigitus.rei.data.source import androidx.compose.ui.graphics.Color -import org.saudigitus.rei.data.model.AppConfig +import org.saudigitus.rei.data.model.AppConfigItem import org.saudigitus.rei.data.model.Stage interface DataManager { - suspend fun loadConfig(): AppConfig? + suspend fun loadConfig(): List suspend fun getStages( program: String, diff --git a/rei/src/main/java/org/saudigitus/rei/ui/stages/StageScreen.kt b/rei/src/main/java/org/saudigitus/rei/ui/stages/StageScreen.kt index 9ae9e2305d..9bcf442af9 100644 --- a/rei/src/main/java/org/saudigitus/rei/ui/stages/StageScreen.kt +++ b/rei/src/main/java/org/saudigitus/rei/ui/stages/StageScreen.kt @@ -1,5 +1,6 @@ package org.saudigitus.rei.ui.stages +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -11,7 +12,8 @@ fun StageScreen(viewModel: StageViewModel) { val state by viewModel.uiState.collectAsStateWithLifecycle() StageTab( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier.fillMaxWidth() + .fillMaxSize(.3f), state = state, onAction = viewModel::loadStageData, ) diff --git a/rei/src/main/java/org/saudigitus/rei/ui/stages/StageViewModel.kt b/rei/src/main/java/org/saudigitus/rei/ui/stages/StageViewModel.kt index e27d50c601..4f3012d3fe 100644 --- a/rei/src/main/java/org/saudigitus/rei/ui/stages/StageViewModel.kt +++ b/rei/src/main/java/org/saudigitus/rei/ui/stages/StageViewModel.kt @@ -1,16 +1,20 @@ package org.saudigitus.rei.ui.stages import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import org.saudigitus.rei.data.model.AppConfigItem import org.saudigitus.rei.data.source.DataManager +import javax.inject.Inject -class StageViewModel( +@HiltViewModel +class StageViewModel @Inject constructor( private val dataManager: DataManager, ) : ViewModel() { @@ -23,20 +27,32 @@ class StageViewModel( viewModelState.value, ) + private val _config = MutableStateFlow>(emptyList()) + private val config: StateFlow> = _config + + private val _program = MutableStateFlow("") + private val program: StateFlow = _program + init { + loadConfig() loadStages() } + private fun loadConfig() { + viewModelScope.launch { + _config.value = dataManager.loadConfig() + } + } + private fun loadStages() { viewModelScope.launch { - val program = dataManager.loadConfig()?.stageProgram - val stages = dataManager.getStages(program ?: "") + val stages = dataManager.getStages(program.value) viewModelState.update { it.copy( stages = stages, stagesData = dataManager.getStageEventData( - program ?: "", + program.value, stages.firstOrNull()?.uid ?: "", ), ) @@ -44,22 +60,15 @@ class StageViewModel( } } + fun setProgram(program: String) { + _program.value = program + } + fun loadStageData(stage: String) { viewModelScope.launch { - val program = dataManager.loadConfig()?.stageProgram - viewModelState.update { - it.copy(stagesData = dataManager.getStageEventData("$program", stage)) + it.copy(stagesData = dataManager.getStageEventData(program.value, stage)) } } } } - -@Suppress("UNCHECKED_CAST") -class StageViewModelFactory( - private val dataManager: DataManager, -) : ViewModelProvider.Factory { - override fun create(modelClass: Class): T { - return StageViewModel(dataManager) as T - } -} diff --git a/rei/src/main/java/org/saudigitus/rei/utils/Extensions.kt b/rei/src/main/java/org/saudigitus/rei/utils/Extensions.kt index 489d4ba98b..c82498ef3e 100644 --- a/rei/src/main/java/org/saudigitus/rei/utils/Extensions.kt +++ b/rei/src/main/java/org/saudigitus/rei/utils/Extensions.kt @@ -4,8 +4,8 @@ import org.dhis2.commons.date.DateUtils import org.hisp.dhis.android.core.D2 import org.hisp.dhis.android.core.arch.repositories.scope.RepositoryScope import org.hisp.dhis.android.core.event.EventStatus -import org.saudigitus.rei.data.model.AppConfig -import org.saudigitus.rei.utils.Utils.fromJson +import org.saudigitus.rei.data.model.AppConfigItem +import org.saudigitus.rei.utils.Utils.buildListFromJson import java.util.Locale fun String.capital() = this.replaceFirstChar { @@ -29,7 +29,6 @@ fun D2.countEventsByStatusToday( .byStatus().eq(eventStatus) .blockingCount() - fun D2.overdueEventCount( program: String, stage: String, @@ -44,20 +43,19 @@ fun D2.eventOrderedByDateDesc(enrollment: String) = eventModule().events() .orderByEventDate(RepositoryScope.OrderByDirection.DESC) .one().blockingGet() - -fun D2.reiModuleDatastore(): AppConfig? { +fun D2.reiModuleDatastore(): List { val datastore = dataStoreModule().dataStore() .byNamespace().eq(Constants.NAMESPACE) .byKey().eq(Constants.KEY) .one().blockingGet() - return fromJson(datastore?.value()) + return buildListFromJson(datastore?.value()) ?: emptyList() } fun D2.isEventOverdue( enrollment: String, - stage: String + stage: String, ) = eventModule().events() .byEnrollmentUid().eq(enrollment) .byProgramStageUid().eq(stage) .byDueDate().before(DateUtils.getInstance().today) - .blockingCount() > 0 \ No newline at end of file + .blockingCount() > 0 diff --git a/rei/src/main/java/org/saudigitus/rei/utils/SearchTeiStyle.kt b/rei/src/main/java/org/saudigitus/rei/utils/SearchTeiStyle.kt index 781ba86b49..4ffb54b7a2 100644 --- a/rei/src/main/java/org/saudigitus/rei/utils/SearchTeiStyle.kt +++ b/rei/src/main/java/org/saudigitus/rei/utils/SearchTeiStyle.kt @@ -4,25 +4,26 @@ import androidx.compose.ui.graphics.Color import org.dhis2.commons.data.SearchTeiModel import org.hisp.dhis.android.core.D2 import org.saudigitus.rei.R -import org.saudigitus.rei.data.model.AppConfig +import org.saudigitus.rei.data.model.AppConfigItem +import org.saudigitus.rei.data.model.LineListing import org.saudigitus.rei.ui.theme.Light_Error import org.saudigitus.rei.ui.theme.Light_Success import org.saudigitus.rei.ui.theme.Light_Warning class SearchTeiStyle(private val d2: D2) { - private var appConfig: AppConfig? = null + private var appConfigs: List = emptyList() init { - appConfig = d2.reiModuleDatastore() + appConfigs = d2.reiModuleDatastore() } - private fun isCompletelyVaccinated(enrollment: String): Boolean { + private fun isCompletelyVaccinated(enrollment: String, lineListing: LineListing): Boolean { val event = d2.eventOrderedByDateDesc(enrollment) val eventValue = d2.trackedEntityModule().trackedEntityDataValues() .byEvent().eq(event?.uid()) - .byDataElement().eq(appConfig?.ccvDataElement) + .byDataElement().eq(lineListing.ccvDataElement) .one().blockingGet() return eventValue?.value()?.toBoolean() == true @@ -30,18 +31,18 @@ class SearchTeiStyle(private val d2: D2) { fun getTeiCardBackground(searchTeiModel: SearchTeiModel): Pair { val enrollment = searchTeiModel.enrollments.getOrNull(0) + val lineListing = appConfigs[0].lineListing return if (enrollment != null) { - val isOverdue = d2.isEventOverdue(enrollment.uid(), appConfig?.stageVaccination ?: "") + val isOverdue = d2.isEventOverdue(enrollment.uid(), lineListing.stageVaccination) if (isOverdue) { Pair(R.string.overdue, Light_Warning.copy(.2f)) - } else if (isCompletelyVaccinated(enrollment.uid())) { + } else if (isCompletelyVaccinated(enrollment.uid(), lineListing)) { Pair(R.string.vaccinated, Light_Success.copy(.2f)) } else { Pair(R.string.not_vaccinated, Light_Error.copy(.2f)) } - } else { Pair(R.string.active, Color.Transparent) } diff --git a/rei/src/main/java/org/saudigitus/rei/utils/Utils.kt b/rei/src/main/java/org/saudigitus/rei/utils/Utils.kt index 4b8ea66a37..3bcd524d63 100644 --- a/rei/src/main/java/org/saudigitus/rei/utils/Utils.kt +++ b/rei/src/main/java/org/saudigitus/rei/utils/Utils.kt @@ -1,5 +1,6 @@ package org.saudigitus.rei.utils +import com.fasterxml.jackson.databind.ObjectMapper import org.hisp.dhis.android.core.D2 import org.saudigitus.rei.utils.ObjectMapper.translateJsonToObject @@ -14,9 +15,27 @@ object Utils { null } + inline fun buildListFromJson(json: String?): List? = if (json != null) { + val mapper = ObjectMapper() + + translateJsonToObject() + .readValue( + json, + mapper.typeFactory.constructCollectionType( + List::class.java, + T::class.java, + ), + ) + } else { + null + } + fun T.toJson(): String = translateJsonToObject().writeValueAsString(this) - fun datastorePrograms(d2: D2): List { - return d2.reiModuleDatastore()?.programs?.map { it.uid } ?: emptyList() + fun isRei(d2: D2, program: String): Boolean { + val config = d2.reiModuleDatastore() + .find { it.program == program } + + return config != null && (config.defaults.displayStages || config.defaults.displaySupport) } }