From c15fa5f9dc9b040d88e0630509f15a0f19f71033 Mon Sep 17 00:00:00 2001 From: Comfort Mwalija Date: Tue, 26 Nov 2024 18:21:55 +0200 Subject: [PATCH] Performance improvements for large facilities :v3 -> Bug fixes when syncing --- .../syncStrategy/SyncStrategyCacheDao.kt | 33 ++++++- .../syncStrategy/SyncStrategyCacheEntity.kt | 2 + .../remote/resource/syncStrategy/Utils.kt | 52 ++++++----- .../syncStrategy/fhir/IdentifierSyncParams.kt | 18 +++- .../fhir/LogicalIdSyncParamsBased.kt | 15 ++- .../fhir/ResourceParamsBasedDownload.kt | 8 ++ .../fhircore/engine/sync/AppSyncWorker.kt | 93 ++++++++++++------- .../fhircore/quest/ui/main/AppMainActivity.kt | 12 +-- .../register/PatientRegisterViewModel.kt | 30 +++--- 9 files changed, 175 insertions(+), 88 deletions(-) diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/data/local/syncStrategy/SyncStrategyCacheDao.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/data/local/syncStrategy/SyncStrategyCacheDao.kt index e0f25ba0fc..f5b04d11ee 100644 --- a/android/engine/src/main/java/org/smartregister/fhircore/engine/data/local/syncStrategy/SyncStrategyCacheDao.kt +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/data/local/syncStrategy/SyncStrategyCacheDao.kt @@ -24,11 +24,40 @@ import androidx.room.Query @Dao abstract class SyncStrategyCacheDao { + suspend fun upsert(logicalId: String) = + with(get(logicalId)) { + if (this == null) { + insert(logicalId.toEntity()) + } else { + update(this.logicalId) + } + } + + suspend fun upsert(logicalIds: List) = + logicalIds.onEach { logicalId -> + with(get(logicalId)) { + if (this == null) { + insert(logicalId.toEntity()) + } else { + update(this.logicalId) + } + } + } + + @Insert(onConflict = OnConflictStrategy.REPLACE) + abstract suspend fun insert(syncStrategyCacheEntity: List) + @Insert(onConflict = OnConflictStrategy.REPLACE) - abstract suspend fun upsert(syncStrategyCacheEntity: List) + abstract suspend fun insert(syncStrategyCacheEntity: SyncStrategyCacheEntity) @Query("DELETE FROM syncstrategycacheentity") abstract suspend fun deleteAll() - @Query("SELECT * FROM syncstrategycacheentity") + @Query("SELECT * FROM syncstrategycacheentity WHERE shouldSync = 0") abstract suspend fun query(): List + + @Query("SELECT * FROM syncstrategycacheentity WHERE logicalId = :logicalId") + abstract suspend fun get(logicalId: String): SyncStrategyCacheEntity? + + @Query("UPDATE syncstrategycacheentity SET shouldSync = 1 WHERE logicalId = :logicalId") + abstract suspend fun update(logicalId: String) } diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/data/local/syncStrategy/SyncStrategyCacheEntity.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/data/local/syncStrategy/SyncStrategyCacheEntity.kt index a2ebdb8592..c8d70aaa08 100644 --- a/android/engine/src/main/java/org/smartregister/fhircore/engine/data/local/syncStrategy/SyncStrategyCacheEntity.kt +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/data/local/syncStrategy/SyncStrategyCacheEntity.kt @@ -27,3 +27,5 @@ data class SyncStrategyCacheEntity( ) fun List.toEntity() = map { SyncStrategyCacheEntity(logicalId = it) } + +fun String.toEntity() = SyncStrategyCacheEntity(logicalId = this) diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/data/remote/resource/syncStrategy/Utils.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/data/remote/resource/syncStrategy/Utils.kt index c2298ce9b7..633bfe1297 100644 --- a/android/engine/src/main/java/org/smartregister/fhircore/engine/data/remote/resource/syncStrategy/Utils.kt +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/data/remote/resource/syncStrategy/Utils.kt @@ -16,45 +16,29 @@ package org.smartregister.fhircore.engine.data.remote.resource.syncStrategy +import android.content.Intent +import androidx.localbroadcastmanager.content.LocalBroadcastManager import com.google.android.fhir.FhirEngine import com.google.android.fhir.search.search import java.util.concurrent.TimeUnit -import kotlinx.coroutines.runBlocking import org.hl7.fhir.r4.model.ListResource -import org.hl7.fhir.r4.model.Patient import org.smartregister.fhircore.engine.configuration.ConfigurationRegistry import org.smartregister.fhircore.engine.configuration.Item import org.smartregister.fhircore.engine.data.local.syncStrategy.SyncStrategyCacheDao +import org.smartregister.fhircore.engine.data.remote.resource.syncStrategy.broadcast.SYNC_STATUS_BROADCAST_RECEIVER_KEY +import org.smartregister.fhircore.engine.data.remote.resource.syncStrategy.broadcast.SyncStatusBroadcastReceiver +import org.smartregister.fhircore.engine.data.remote.resource.syncStrategy.fhir.ParamSyncStatus import org.smartregister.fhircore.engine.data.remote.resource.syncStrategy.utils.SyncState import org.smartregister.fhircore.engine.util.SharedPreferenceKey import org.smartregister.fhircore.engine.util.SharedPreferenceKey.SYNC_STATUS import org.smartregister.fhircore.engine.util.SharedPreferencesHelper -fun logicalIds(fhirEngine: FhirEngine) = runBlocking { - fhirEngine - .search { filter(Patient.ACTIVE, { value = of(true) }) } - .map { it.resource.idPart } -} - -fun List.subListIds(syncStrategyCacheDao: SyncStrategyCacheDao): List { - return runBlocking { - val cachedIds = syncStrategyCacheDao.query().map { it.logicalId } - ((cachedIds union this@subListIds) - (cachedIds intersect this@subListIds.toSet())).toList() - } -} +suspend fun logicalIds(syncStrategyCacheDao: SyncStrategyCacheDao) = + syncStrategyCacheDao.query().map { it.logicalId } fun hasCompletedInitialSync(sharedPreferencesHelper: SharedPreferencesHelper) = getSyncState(sharedPreferencesHelper) < SyncState.CompletedInitialSync.value -fun setSubSequentSync(sharedPreferencesHelper: SharedPreferencesHelper) = - sharedPreferencesHelper.write(SYNC_STATUS.name, SyncState.SubSequentSync.value) - -fun isSubSequentSync(sharedPreferencesHelper: SharedPreferencesHelper) = - getSyncState(sharedPreferencesHelper) == SyncState.SubSequentSync.value - -fun isRunSyncNow(sharedPreferencesHelper: SharedPreferencesHelper) = - getSyncState(sharedPreferencesHelper) == SyncState.RunSyncNow.value - fun getSyncState(sharedPreferencesHelper: SharedPreferencesHelper) = sharedPreferencesHelper.read(SYNC_STATUS.name, SyncState.InitialSync.value) @@ -84,10 +68,30 @@ data class IdTimestamp( val timestamp: Long, ) -fun perOrgSyncConfig( +fun onPerOrgSyncConfigItem( configurationRegistry: ConfigurationRegistry, sharedPreferencesHelper: SharedPreferencesHelper, ): Item? = configurationRegistry.getPerOrgSyncConfigs()?.items?.find { it.id == sharedPreferencesHelper.organisationCode() } + +fun syncConfigOfflineFirst( + configurationRegistry: ConfigurationRegistry, + sharedPreferencesHelper: SharedPreferencesHelper, +): Boolean { + val configs = + onPerOrgSyncConfigItem(configurationRegistry, sharedPreferencesHelper) ?: return false + return !configs.offlineFirst +} + +fun onSendBroadcast( + broadcaster: LocalBroadcastManager, + paramSyncStatus: ParamSyncStatus, +) { + val broadcastIntent = + Intent(SyncStatusBroadcastReceiver::class.java.name).apply { + putExtra(SYNC_STATUS_BROADCAST_RECEIVER_KEY, paramSyncStatus) + } + broadcaster.sendBroadcast(broadcastIntent) +} diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/data/remote/resource/syncStrategy/fhir/IdentifierSyncParams.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/data/remote/resource/syncStrategy/fhir/IdentifierSyncParams.kt index 21bf958d6c..9af7aa364b 100644 --- a/android/engine/src/main/java/org/smartregister/fhircore/engine/data/remote/resource/syncStrategy/fhir/IdentifierSyncParams.kt +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/data/remote/resource/syncStrategy/fhir/IdentifierSyncParams.kt @@ -31,7 +31,7 @@ class IdentifierSyncParams( ) : DownloadWorkManager { private val urlOfTheNextPagesToDownloadForAResource = LinkedList() - private val resourcesToDownloadWithSearchParams = LinkedList(identifiers.chunked(12)) + private val resourcesToDownloadWithSearchParams = LinkedList(identifiers.chunked(32)) private var patientPosition = 0 override suspend fun getNextRequest(): DownloadRequest? { @@ -62,11 +62,21 @@ class IdentifierSyncParams( .mapNotNull { it.resource as Bundle } .map { it.entry.map { it.resource } } .flatten() - .also { catchIds() } + .also(::catchIds) } - private fun catchIds() = - callback(ParamSyncStatus(identifiers.map { it.toString() }, identifiers.size, patientPosition)) + private fun catchIds(resources: List) = + resources + .filter { it.resourceType == ResourceType.Patient } + .also { patients -> + callback( + ParamSyncStatus( + logicalId = patients.map { it.idPart }, + idsTotal = identifiers.size, + patientPositionAt = patientPosition, + ), + ) + } private fun List.bundleOf(): Bundle { return Bundle().apply { diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/data/remote/resource/syncStrategy/fhir/LogicalIdSyncParamsBased.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/data/remote/resource/syncStrategy/fhir/LogicalIdSyncParamsBased.kt index 11f07c7427..5148f88fce 100644 --- a/android/engine/src/main/java/org/smartregister/fhircore/engine/data/remote/resource/syncStrategy/fhir/LogicalIdSyncParamsBased.kt +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/data/remote/resource/syncStrategy/fhir/LogicalIdSyncParamsBased.kt @@ -62,10 +62,21 @@ class LogicalIdSyncParamsBased( .mapNotNull { it.resource as Bundle } .map { it.entry.map { it.resource } } .flatten() - .also { catchIds() } + .also(::catchIds) } - private fun catchIds() = callback(ParamSyncStatus(logicalIds, logicalIds.size, patientPosition)) + private fun catchIds(resources: List) = + resources + .filter { it.resourceType == ResourceType.Patient } + .also { patients -> + callback( + ParamSyncStatus( + logicalId = patients.map { it.idPart }, + idsTotal = logicalIds.size, + patientPositionAt = patientPosition, + ), + ) + } private fun List.bundleOf(): Bundle { return Bundle().apply { diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/data/remote/resource/syncStrategy/fhir/ResourceParamsBasedDownload.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/data/remote/resource/syncStrategy/fhir/ResourceParamsBasedDownload.kt index 4860ab31f0..54bebe43ef 100644 --- a/android/engine/src/main/java/org/smartregister/fhircore/engine/data/remote/resource/syncStrategy/fhir/ResourceParamsBasedDownload.kt +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/data/remote/resource/syncStrategy/fhir/ResourceParamsBasedDownload.kt @@ -37,6 +37,7 @@ typealias ResourceSearchParams = Map class ResourceParamsBasedDownload( syncParams: ResourceSearchParams, val context: TimestampContext, + private val callback: (List) -> Unit, ) : DownloadWorkManager { private val resourcesToDownloadWithSearchParams = LinkedList(syncParams.entries) private val urlOfTheNextPagesToDownloadForAResource = LinkedList() @@ -117,6 +118,7 @@ class ResourceParamsBasedDownload( return response.entry .map { it.resource } + .also(::catchIds) .also { resources -> resources .groupBy { it.resourceType } @@ -133,6 +135,12 @@ class ResourceParamsBasedDownload( } } } + + private fun catchIds(resources: List) = + resources + .filter { it.resourceType == ResourceType.Patient } + .map { it.idPart } + .also { callback(it) } } interface TimestampContext { diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/sync/AppSyncWorker.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/sync/AppSyncWorker.kt index 5914c43e14..5aed9c4112 100644 --- a/android/engine/src/main/java/org/smartregister/fhircore/engine/sync/AppSyncWorker.kt +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/sync/AppSyncWorker.kt @@ -17,10 +17,11 @@ package org.smartregister.fhircore.engine.sync import android.content.Context -import android.content.Intent import androidx.hilt.work.HiltWorker +import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.work.WorkerParameters import com.google.android.fhir.FhirEngine +import com.google.android.fhir.search.search import com.google.android.fhir.sync.AcceptLocalConflictResolver import com.google.android.fhir.sync.ConflictResolver import com.google.android.fhir.sync.DownloadWorkManager @@ -30,22 +31,23 @@ import dagger.assisted.Assisted import dagger.assisted.AssistedInject import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext +import org.hl7.fhir.r4.model.ListResource import org.hl7.fhir.r4.model.ResourceType import org.smartregister.fhircore.engine.configuration.ConfigurationRegistry import org.smartregister.fhircore.engine.configuration.preferences.SyncUploadStrategy import org.smartregister.fhircore.engine.data.local.TingatheDatabase import org.smartregister.fhircore.engine.data.local.syncStrategy.toEntity import org.smartregister.fhircore.engine.data.remote.resource.syncStrategy.SyncParamStrategy -import org.smartregister.fhircore.engine.data.remote.resource.syncStrategy.broadcast.SYNC_STATUS_BROADCAST_RECEIVER_KEY -import org.smartregister.fhircore.engine.data.remote.resource.syncStrategy.broadcast.SyncStatusBroadcastReceiver +import org.smartregister.fhircore.engine.data.remote.resource.syncStrategy.fhir.IdentifierSyncParams import org.smartregister.fhircore.engine.data.remote.resource.syncStrategy.fhir.LogicalIdSyncParamsBased import org.smartregister.fhircore.engine.data.remote.resource.syncStrategy.fhir.ResourceParamsBasedDownload import org.smartregister.fhircore.engine.data.remote.resource.syncStrategy.fhir.TimestampContext +import org.smartregister.fhircore.engine.data.remote.resource.syncStrategy.getIdentifiers import org.smartregister.fhircore.engine.data.remote.resource.syncStrategy.hasCompletedInitialSync import org.smartregister.fhircore.engine.data.remote.resource.syncStrategy.logicalIds -import org.smartregister.fhircore.engine.data.remote.resource.syncStrategy.perOrgSyncConfig +import org.smartregister.fhircore.engine.data.remote.resource.syncStrategy.onSendBroadcast import org.smartregister.fhircore.engine.data.remote.resource.syncStrategy.saveLastUpdatedTimestamp -import org.smartregister.fhircore.engine.data.remote.resource.syncStrategy.subListIds +import org.smartregister.fhircore.engine.data.remote.resource.syncStrategy.syncConfigOfflineFirst import org.smartregister.fhircore.engine.ui.questionnaire.ContentCache import org.smartregister.fhircore.engine.util.AppDataStore import org.smartregister.fhircore.engine.util.DispatcherProvider @@ -70,40 +72,65 @@ constructor( ) : FhirSyncWorker(appContext, workerParams) { private val syncStrategyCacheDao = database.syncStrategyCacheDao - - private fun downloadWorkManager(): DownloadWorkManager { - return when { - hasCompletedInitialSync(preference) -> defaultDownloadManager() - else -> { - val subList = logicalIds(engine).subListIds(syncStrategyCacheDao) - return if (subList.isNotEmpty()) { - LogicalIdSyncParamsBased(subList) { - Timber.tag("TAG") - .e("downloadWorkManager: " + it.patientPositionAt + " of " + it.idsTotal) + private val broadcaster = LocalBroadcastManager.getInstance(dataStore.context.applicationContext) + private val listResourceTitle = "Patient Identifier List" + + private fun downloadWorkManager(): DownloadWorkManager = runBlocking { + syncConfigOfflineFirst(configurationRegistry, preference) + .takeIf { it } + ?.let { + getIdentifiers(engine)?.let { item -> + return@runBlocking IdentifierSyncParams(item.data) { runBlocking { - syncStrategyCacheDao.upsert(it.logicalId.toEntity()) - saveLastUpdatedTimestamp(dataStore) - } - val broadcastIntent = - Intent(SyncStatusBroadcastReceiver::class.java.name).apply { - putExtra(SYNC_STATUS_BROADCAST_RECEIVER_KEY, it) + onSendBroadcast(broadcaster, it) + syncStrategyCacheDao.insert(it.logicalId.toEntity()) + if (it.patientPositionAt == item.data.size) { + purgeListResource() } - dataStore.context.sendBroadcast(broadcastIntent) + } } - } else { - defaultDownloadManager() } } + + val logicalIds = logicalIds(syncStrategyCacheDao) + + return@runBlocking if (logicalIds.isNotEmpty()) { + LogicalIdSyncParamsBased(logicalIds) { + Timber.e("${it.patientPositionAt} of ${logicalIds.size}") + runBlocking { + it.logicalId + .toEntity() + .map { catchEntity -> catchEntity.copy(shouldSync = true) } + .also { syncStrategyCacheDao.upsert(it.map { it.logicalId }) } + saveLastUpdatedTimestamp(dataStore) + onSendBroadcast(broadcaster, it) + } + } + } else { + defaultDownloadManager() } } - private fun syncParams(): Map> { - val configs = - perOrgSyncConfig(configurationRegistry, preference) - ?: return syncListenerManager.loadSyncParams() - - if (configs.offlineFirst) return syncListenerManager.loadSyncParams() + private suspend fun purgeListResource() { + engine + .search { filter(ListResource.TITLE, { value = listResourceTitle }) } + .map { it.resource } + .firstOrNull() + ?.let { + runCatching { engine.purge(ResourceType.List, it.idPart) }.onFailure { Timber.e(it) } + } + } + private fun syncParams(): Map> { + if ( + syncConfigOfflineFirst( + configurationRegistry, + preference, + ) + .not() + ) { + return syncListenerManager.loadSyncParams() + } return when { hasCompletedInitialSync(preference) -> SyncParamStrategy(preference).syncParams() else -> syncListenerManager.loadSyncParams() @@ -125,7 +152,11 @@ constructor( timestamp?.let { dataStore.saveLastUpdatedTimestamp(resourceType, timestamp) } } }, - ) + ) { ids -> + if (syncConfigOfflineFirst(configurationRegistry, preference)) { + runBlocking { syncStrategyCacheDao.upsert(ids) } + } + } override fun getConflictResolver(): ConflictResolver = AcceptLocalConflictResolver diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/main/AppMainActivity.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/main/AppMainActivity.kt index 97a8b6da34..668d455598 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/main/AppMainActivity.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/main/AppMainActivity.kt @@ -19,13 +19,13 @@ package org.smartregister.fhircore.quest.ui.main import android.app.Activity import android.content.Intent import android.content.IntentFilter -import android.os.Build import android.os.Bundle import androidx.activity.compose.setContent import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.viewModels import androidx.compose.material.ExperimentalMaterialApi import androidx.lifecycle.lifecycleScope +import androidx.localbroadcastmanager.content.LocalBroadcastManager import com.google.android.fhir.sync.SyncJobStatus import dagger.hilt.android.AndroidEntryPoint import javax.inject.Inject @@ -68,6 +68,7 @@ open class AppMainActivity : BaseMultiLanguageActivity(), OnSyncListener { val appMainViewModel by viewModels() private lateinit var syncStatusBroadcastReceiver: SyncStatusBroadcastReceiver + private lateinit var localBroadcastManager: LocalBroadcastManager private val authActivityLauncherForResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { res -> @@ -80,16 +81,13 @@ open class AppMainActivity : BaseMultiLanguageActivity(), OnSyncListener { super.onCreate(savedInstanceState) setupTimeOutListener() val paramSyncStatus = MutableStateFlow(null) + localBroadcastManager = LocalBroadcastManager.getInstance(this) syncStatusBroadcastReceiver = SyncStatusBroadcastReceiver { showToast("Syncing ${it.patientPositionAt} of ${it.idsTotal}") paramSyncStatus.value = it } val intentFilter = IntentFilter(SyncStatusBroadcastReceiver::class.java.name) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - registerReceiver(syncStatusBroadcastReceiver, intentFilter, RECEIVER_NOT_EXPORTED) - } else { - registerReceiver(syncStatusBroadcastReceiver, intentFilter) - } + localBroadcastManager.registerReceiver(syncStatusBroadcastReceiver, intentFilter) setContent { AppTheme { @@ -105,7 +103,7 @@ open class AppMainActivity : BaseMultiLanguageActivity(), OnSyncListener { override fun onDestroy() { super.onDestroy() - unregisterReceiver(syncStatusBroadcastReceiver) + localBroadcastManager.unregisterReceiver(syncStatusBroadcastReceiver) } override fun onResume() { diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/register/PatientRegisterViewModel.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/register/PatientRegisterViewModel.kt index aa24e22414..c32a35c0c5 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/register/PatientRegisterViewModel.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/patient/register/PatientRegisterViewModel.kt @@ -54,8 +54,7 @@ import org.smartregister.fhircore.engine.configuration.ConfigurationRegistry import org.smartregister.fhircore.engine.data.local.TingatheDatabase import org.smartregister.fhircore.engine.data.local.register.AppRegisterRepository import org.smartregister.fhircore.engine.data.remote.resource.syncStrategy.logicalIds -import org.smartregister.fhircore.engine.data.remote.resource.syncStrategy.perOrgSyncConfig -import org.smartregister.fhircore.engine.data.remote.resource.syncStrategy.subListIds +import org.smartregister.fhircore.engine.data.remote.resource.syncStrategy.syncConfigOfflineFirst import org.smartregister.fhircore.engine.data.remote.resource.syncStrategy.utils.SyncState import org.smartregister.fhircore.engine.domain.util.PaginationConstant import org.smartregister.fhircore.engine.sync.SyncBroadcaster @@ -86,13 +85,12 @@ constructor( val appFeatureManager: AppFeatureManager, val dispatcherProvider: DispatcherProvider, val sharedPreferencesHelper: SharedPreferencesHelper, - database: TingatheDatabase, + private val database: TingatheDatabase, ) : ViewModel() { private val appFeatureName = savedStateHandle.get(NavigationArg.FEATURE) private val healthModule = savedStateHandle.get(NavigationArg.HEALTH_MODULE) ?: HealthModule.DEFAULT - private val dao = database.syncStrategyCacheDao private val _isRefreshing = MutableStateFlow(false) @@ -197,10 +195,15 @@ constructor( refresh() _firstTimeSyncState.value = false viewModelScope.launch(Dispatchers.IO) { - val configs = - perOrgSyncConfig(configurationRegistry, sharedPreferencesHelper) ?: return@launch - - if (configs.offlineFirst) return@launch + if ( + syncConfigOfflineFirst( + configurationRegistry, + sharedPreferencesHelper, + ) + .not() + ) { + return@launch + } if (getSyncState() == SyncState.InitialSync.value) { sharedPreferencesHelper.write( @@ -210,16 +213,7 @@ constructor( syncBroadcaster.runSync() } - if (getSyncState() < SyncState.SubSequentSync.value) { - if (logicalIds(syncBroadcaster.fhirEngine).subListIds(dao).isNotEmpty()) { - syncBroadcaster.runSync() - } else { - sharedPreferencesHelper.write( - SharedPreferenceKey.SYNC_STATUS.name, - SyncState.SubSequentSync.value, - ) - } - } + if (logicalIds(database.syncStrategyCacheDao).isNotEmpty()) syncBroadcaster.runSync() } } is SyncJobStatus.InProgress -> {