From 032ccfd90b370cd74b37f3e4dc36c335306d6cfd Mon Sep 17 00:00:00 2001 From: Sergejs Luhmirins Date: Thu, 3 Sep 2026 15:39:05 +0300 Subject: [PATCH 1/4] MS-1547 Add finish result to module selection --- .../moduleselector/ModuleSelectorFragment.kt | 9 +++++++-- .../feature/moduleselector/ModuleSelectorMvi.kt | 2 ++ .../feature/moduleselector/ModuleSelectorResult.kt | 13 +++++++++++++ .../moduleselector/ModuleSelectorViewModel.kt | 2 +- .../moduleselector/ModuleSelectorViewModelTest.kt | 2 +- 5 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 feature/module-selector/src/main/java/com/simprints/feature/moduleselector/ModuleSelectorResult.kt diff --git a/feature/module-selector/src/main/java/com/simprints/feature/moduleselector/ModuleSelectorFragment.kt b/feature/module-selector/src/main/java/com/simprints/feature/moduleselector/ModuleSelectorFragment.kt index 8c641db38e..f7a2cbaf06 100644 --- a/feature/module-selector/src/main/java/com/simprints/feature/moduleselector/ModuleSelectorFragment.kt +++ b/feature/module-selector/src/main/java/com/simprints/feature/moduleselector/ModuleSelectorFragment.kt @@ -15,6 +15,7 @@ import com.simprints.feature.module.selector.R import com.simprints.feature.module.selector.databinding.FragmentModuleSelectorBinding import com.simprints.feature.moduleselector.ModuleSelectorState.SelectionError import com.simprints.feature.moduleselector.adapter.ModuleSelectorAdapter +import com.simprints.infra.uibase.navigation.finishWithResult import com.simprints.infra.uibase.password.SettingsPasswordDialogFragment import com.simprints.infra.uibase.view.applySystemBarInsets import com.simprints.infra.uibase.viewbinding.viewBinding @@ -67,7 +68,7 @@ internal class ModuleSelectorFragment : Fragment(R.layout.fragment_module_select onSuccess = { viewModel.onAction(ModuleSelectorAction.UnlockScreen) }, ) moduleSelectionToolbar.setNavigationOnClickListener { - findNavController().popBackStack() + finishWithResult(false) } moduleSelectionCancelButton.setOnClickListener { viewModel.onAction(ModuleSelectorAction.CancelClicked) @@ -108,11 +109,15 @@ internal class ModuleSelectorFragment : Fragment(R.layout.fragment_module_select } private fun handleEffect(effect: ModuleSelectorEffects) = when (effect) { - ModuleSelectorEffects.Dismiss -> findNavController().popBackStack() + ModuleSelectorEffects.Confirmed -> finishWithResult(true) + ModuleSelectorEffects.Dismiss -> finishWithResult(false) is ModuleSelectorEffects.ShowPassword -> { SettingsPasswordDialogFragment .newInstance(passwordToMatch = effect.password) .show(childFragmentManager, SettingsPasswordDialogFragment.TAG) } } + + private fun finishWithResult(isConfirmed: Boolean): Boolean = findNavController() + .finishWithResult(this, ModuleSelectorResult(isConfirmed)) } diff --git a/feature/module-selector/src/main/java/com/simprints/feature/moduleselector/ModuleSelectorMvi.kt b/feature/module-selector/src/main/java/com/simprints/feature/moduleselector/ModuleSelectorMvi.kt index 7f98e91726..2c9fe5f1dd 100644 --- a/feature/module-selector/src/main/java/com/simprints/feature/moduleselector/ModuleSelectorMvi.kt +++ b/feature/module-selector/src/main/java/com/simprints/feature/moduleselector/ModuleSelectorMvi.kt @@ -20,6 +20,8 @@ internal data class ModuleSelectorState( } internal sealed interface ModuleSelectorEffects { + data object Confirmed : ModuleSelectorEffects + data object Dismiss : ModuleSelectorEffects data class ShowPassword( diff --git a/feature/module-selector/src/main/java/com/simprints/feature/moduleselector/ModuleSelectorResult.kt b/feature/module-selector/src/main/java/com/simprints/feature/moduleselector/ModuleSelectorResult.kt new file mode 100644 index 0000000000..61ab3275bd --- /dev/null +++ b/feature/module-selector/src/main/java/com/simprints/feature/moduleselector/ModuleSelectorResult.kt @@ -0,0 +1,13 @@ +package com.simprints.feature.moduleselector + +import androidx.annotation.Keep +import com.simprints.core.domain.step.StepResult +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Keep +@Serializable +@SerialName("ModuleSelectorResult") +data class ModuleSelectorResult( + val isConfirmed: Boolean, +) : StepResult diff --git a/feature/module-selector/src/main/java/com/simprints/feature/moduleselector/ModuleSelectorViewModel.kt b/feature/module-selector/src/main/java/com/simprints/feature/moduleselector/ModuleSelectorViewModel.kt index ac89457086..72e356b55f 100644 --- a/feature/module-selector/src/main/java/com/simprints/feature/moduleselector/ModuleSelectorViewModel.kt +++ b/feature/module-selector/src/main/java/com/simprints/feature/moduleselector/ModuleSelectorViewModel.kt @@ -125,8 +125,8 @@ internal class ModuleSelectorViewModel @Inject constructor( externalScope.launch { moduleRepository.saveModules(allModules.map { module -> SelectableModule(module.tokenizedName, module.isSelected) }) syncOrchestrator.execute(OneTime.Events.restart()) + emitEffect(ModuleSelectorEffects.Confirmed) } - emitEffect(ModuleSelectorEffects.Dismiss) } private fun updateState(block: (currentState: ModuleSelectorState) -> ModuleSelectorState) { diff --git a/feature/module-selector/src/test/java/com/simprints/feature/moduleselector/ModuleSelectorViewModelTest.kt b/feature/module-selector/src/test/java/com/simprints/feature/moduleselector/ModuleSelectorViewModelTest.kt index 7800f6d435..0c571a2417 100644 --- a/feature/module-selector/src/test/java/com/simprints/feature/moduleselector/ModuleSelectorViewModelTest.kt +++ b/feature/module-selector/src/test/java/com/simprints/feature/moduleselector/ModuleSelectorViewModelTest.kt @@ -231,7 +231,7 @@ internal class ModuleSelectorViewModelTest { viewModel.effects.test { viewModel.onAction(ModuleSelectorAction.SaveClicked) - assertThat(awaitItem()).isEqualTo(ModuleSelectorEffects.Dismiss) + assertThat(awaitItem()).isEqualTo(ModuleSelectorEffects.Confirmed) cancelAndIgnoreRemainingEvents() } advanceUntilIdle() From e75fc8250a1e88dbe823e274769199e1c1a799d3 Mon Sep 17 00:00:00 2001 From: Sergejs Luhmirins Date: Thu, 3 Sep 2026 15:45:32 +0300 Subject: [PATCH 2/4] MS-1547 Add the "Select modules" button to "module mismatch" state in subject validation screen --- .../validate-subject-pool/build.gradle.kts | 1 + .../screen/ValidateSubjectPoolFragment.kt | 22 +++++++++++++++++-- .../fragment_validate_subject_pool.xml | 12 ++++++++++ .../layout/fragment_validate_subject_pool.xml | 12 ++++++++++ .../graph_validate_subject_pool.xml | 9 ++++++++ .../src/main/res/values-am-rET/strings.xml | 1 + .../src/main/res/values-fr/strings.xml | 1 + .../resources/src/main/res/values/strings.xml | 1 + 8 files changed, 57 insertions(+), 2 deletions(-) diff --git a/feature/validate-subject-pool/build.gradle.kts b/feature/validate-subject-pool/build.gradle.kts index 1dc0958367..d73bf8d8dc 100644 --- a/feature/validate-subject-pool/build.gradle.kts +++ b/feature/validate-subject-pool/build.gradle.kts @@ -9,6 +9,7 @@ android { } dependencies { + implementation(project(":feature:module-selector")) implementation(project(":infra:enrolment-records:repository")) implementation(project(":infra:config-store")) diff --git a/feature/validate-subject-pool/src/main/java/com/simprints/feature/validatepool/screen/ValidateSubjectPoolFragment.kt b/feature/validate-subject-pool/src/main/java/com/simprints/feature/validatepool/screen/ValidateSubjectPoolFragment.kt index 2a587125e2..0a99ecdcfa 100644 --- a/feature/validate-subject-pool/src/main/java/com/simprints/feature/validatepool/screen/ValidateSubjectPoolFragment.kt +++ b/feature/validate-subject-pool/src/main/java/com/simprints/feature/validatepool/screen/ValidateSubjectPoolFragment.kt @@ -8,6 +8,7 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import com.simprints.core.livedata.LiveDataEventWithContentObserver +import com.simprints.feature.moduleselector.ModuleSelectorResult import com.simprints.feature.validatepool.R import com.simprints.feature.validatepool.ValidateSubjectPoolFragmentParams import com.simprints.feature.validatepool.ValidateSubjectPoolResult @@ -15,6 +16,8 @@ import com.simprints.feature.validatepool.databinding.FragmentValidateSubjectPoo import com.simprints.infra.logging.LoggingConstants.CrashReportTag.ORCHESTRATION import com.simprints.infra.logging.Simber import com.simprints.infra.uibase.navigation.finishWithResult +import com.simprints.infra.uibase.navigation.handleResult +import com.simprints.infra.uibase.navigation.navigateSafely import com.simprints.infra.uibase.navigation.navigationParams import com.simprints.infra.uibase.view.applySystemBarInsets import com.simprints.infra.uibase.viewbinding.viewBinding @@ -35,6 +38,16 @@ internal class ValidateSubjectPoolFragment : Fragment(R.layout.fragment_validate applySystemBarInsets(view) Simber.i("ValidateSubjectPoolFragment started", tag = ORCHESTRATION) + findNavController().handleResult( + viewLifecycleOwner, + R.id.validateSubjectPoolFragment, + R.id.moduleSelectionFragment, + ) { + if (it.isConfirmed) { + viewModel.startSync(params.enrolmentRecordQuery, params.mode) + } + } + viewModel.state.observe(viewLifecycleOwner, LiveDataEventWithContentObserver(::renderState)) viewModel.lastSyncLabel.observe( @@ -47,7 +60,9 @@ internal class ValidateSubjectPoolFragment : Fragment(R.layout.fragment_validate binding.validationActionsClose.setOnClickListener { finishWithResult(false) } binding.validationActionsContinue.setOnClickListener { finishWithResult(true) } binding.validationActionsSync.setOnClickListener { viewModel.startSync(params.enrolmentRecordQuery, params.mode) } - + binding.validationActionsSelectModules.setOnClickListener { + findNavController().navigateSafely(this, R.id.action_validateSubjectPoolFragment_to_moduleSelectionFragment) + } viewModel.checkIdentificationPool(params.enrolmentRecordQuery, params.mode) } @@ -64,6 +79,7 @@ internal class ValidateSubjectPoolFragment : Fragment(R.layout.fragment_validate ValidateSubjectPoolState.ModuleMismatch -> setViews( descriptionRes = IDR.string.id_pool_validation_module_mismatch_message, + showSelectModules = true, ) ValidateSubjectPoolState.RequiresSync -> setViews( @@ -87,6 +103,7 @@ internal class ValidateSubjectPoolFragment : Fragment(R.layout.fragment_validate showValidating: Boolean = false, showProgress: Boolean = false, showSyncBlock: Boolean = false, + showSelectModules: Boolean = false, ) = with(binding) { validationValidating.isVisible = showValidating validationMainCard.isVisible = !showValidating @@ -98,7 +115,8 @@ internal class ValidateSubjectPoolFragment : Fragment(R.layout.fragment_validate validationIssueLastSynced.isVisible = showSyncBlock // Loading - validationLoadingBlock.isVisible = showSyncBlock + validationLoadingBlock.isVisible = showSyncBlock || showSelectModules + validationActionsSelectModules.isVisible = showSelectModules validationActionsSync.isVisible = showSyncBlock && !showProgress validationLoadingIndicator.isVisible = showProgress && showSyncBlock validationLoadingIndicatorText.isVisible = showProgress && showSyncBlock diff --git a/feature/validate-subject-pool/src/main/res/layout-land/fragment_validate_subject_pool.xml b/feature/validate-subject-pool/src/main/res/layout-land/fragment_validate_subject_pool.xml index fcfe491148..e1cf038ef4 100644 --- a/feature/validate-subject-pool/src/main/res/layout-land/fragment_validate_subject_pool.xml +++ b/feature/validate-subject-pool/src/main/res/layout-land/fragment_validate_subject_pool.xml @@ -120,6 +120,18 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/validationIssueDescriptionBlock"> + + + + + + + + diff --git a/infra/resources/src/main/res/values-am-rET/strings.xml b/infra/resources/src/main/res/values-am-rET/strings.xml index 64c5b28516..070f20d6ca 100644 --- a/infra/resources/src/main/res/values-am-rET/strings.xml +++ b/infra/resources/src/main/res/values-am-rET/strings.xml @@ -485,6 +485,7 @@ ስልኩ ላይ ምንም መረጃ የለም ዝጋ ሲንከ አድርግና እና እንደገና ሞክር + ሞጁሎችን ይምረጡ የተጠቃሚውን የእድሜ ክልል ምረጥ diff --git a/infra/resources/src/main/res/values-fr/strings.xml b/infra/resources/src/main/res/values-fr/strings.xml index e48e754e70..5efff361c0 100644 --- a/infra/resources/src/main/res/values-fr/strings.xml +++ b/infra/resources/src/main/res/values-fr/strings.xml @@ -495,6 +495,7 @@ Dernière synchro: %1$s Synchronisation en cours... Synchroniser et réessayer + Sélectionner les modules Fermer Continuer diff --git a/infra/resources/src/main/res/values/strings.xml b/infra/resources/src/main/res/values/strings.xml index 3e689d8e7b..29d8f4c5ec 100644 --- a/infra/resources/src/main/res/values/strings.xml +++ b/infra/resources/src/main/res/values/strings.xml @@ -490,6 +490,7 @@ Last sync: %1$s Sync in progress… Sync and retry + Select modules Close Continue From 2a3590f82d12558041a7def0ab3d2c46afaa9517 Mon Sep 17 00:00:00 2001 From: Sergejs Luhmirins Date: Mon, 7 Sep 2026 13:16:12 +0300 Subject: [PATCH 3/4] MS-1547 Move the sync call out of the module selection to the caller side --- .../settings/syncinfo/SyncInfoFragment.kt | 24 +++++++++++++++---- .../main/res/navigation/graph_dashboard.xml | 18 +++++++------- .../moduleselector/ModuleSelectorContract.kt | 7 ++++++ .../moduleselector/ModuleSelectorViewModel.kt | 4 ---- .../res/navigation/graph_module_selection.xml | 14 +++++++++++ .../ModuleSelectorViewModelTest.kt | 9 +------ .../screen/ValidateSubjectPoolFragment.kt | 8 +++++-- .../graph_validate_subject_pool.xml | 11 ++++----- 8 files changed, 59 insertions(+), 36 deletions(-) create mode 100644 feature/module-selector/src/main/java/com/simprints/feature/moduleselector/ModuleSelectorContract.kt create mode 100644 feature/module-selector/src/main/res/navigation/graph_module_selection.xml diff --git a/feature/dashboard/src/main/java/com/simprints/feature/dashboard/settings/syncinfo/SyncInfoFragment.kt b/feature/dashboard/src/main/java/com/simprints/feature/dashboard/settings/syncinfo/SyncInfoFragment.kt index 9057e277fa..1f9bc49108 100644 --- a/feature/dashboard/src/main/java/com/simprints/feature/dashboard/settings/syncinfo/SyncInfoFragment.kt +++ b/feature/dashboard/src/main/java/com/simprints/feature/dashboard/settings/syncinfo/SyncInfoFragment.kt @@ -22,6 +22,8 @@ import com.simprints.feature.dashboard.databinding.FragmentSyncInfoBinding import com.simprints.feature.dashboard.settings.syncinfo.modulecount.ModuleCountAdapter import com.simprints.feature.dashboard.view.ConfigurableSyncInfoFragmentContainer import com.simprints.feature.login.LoginContract +import com.simprints.feature.moduleselector.ModuleSelectorContract +import com.simprints.feature.moduleselector.ModuleSelectorResult import com.simprints.infra.uibase.navigation.handleResult import com.simprints.infra.uibase.navigation.toBundle import com.simprints.infra.uibase.view.applySystemBarInsets @@ -62,6 +64,14 @@ internal class SyncInfoFragment : Fragment(R.layout.fragment_sync_info) { setupClickListeners() observeUI() + findNavController().handleResult( + viewLifecycleOwner, + getCurrentDestinationId(), + ModuleSelectorContract.DESTINATION, + ) { + if (it.isConfirmed) viewModel.forceEventSync(false) + } + findNavController().handleResult( viewLifecycleOwner, getCurrentDestinationId(), @@ -79,10 +89,10 @@ internal class SyncInfoFragment : Fragment(R.layout.fragment_sync_info) { private fun setupClickListeners() { binding.buttonSelectModules.setOnClickListener { - findNavController().navigate(R.id.moduleSelectionFragment) + findNavController().navigate(R.id.action_syncInfoFragment_to_moduleSelection) } binding.textEventSyncInstructionsNoModules.setOnClickListener { - findNavController().navigate(R.id.moduleSelectionFragment) + findNavController().navigate(R.id.action_syncInfoFragment_to_moduleSelection) } binding.syncSettingsButton.setOnClickListener { findNavController().navigate(R.id.syncInfoFragment) @@ -347,9 +357,13 @@ internal class SyncInfoFragment : Fragment(R.layout.fragment_sync_info) { textView.text = progressText } - private fun getCurrentDestinationId() = - parentFragment?.takeIf { !syncInfoConfig.isSyncInfoToolbarVisible }?.id // parent if this isn't standalone - ?: id + // Being run withing a nested NavFragment sometimes messes up the "parent" resolution and breaks the navigation result handling, + // so we have to find the correct destination manually using the UI clues. + private fun getCurrentDestinationId(): Int = when { + syncInfoConfig.isSyncInfoLogoutOnComplete -> R.id.logOutSyncFragment // if logging out on complete, we are at logout screen + syncInfoConfig.isSyncInfoToolbarVisible -> R.id.syncInfoFragment // if shown toolbar, we are in standalone sync info fragment + else -> R.id.mainFragment // otherwise we are in main fragment + } private companion object { private const val MAX_MODULE_LIST_HEIGHT_ITEMS = 5 diff --git a/feature/dashboard/src/main/res/navigation/graph_dashboard.xml b/feature/dashboard/src/main/res/navigation/graph_dashboard.xml index f4f43e5951..30a2e4d5b8 100644 --- a/feature/dashboard/src/main/res/navigation/graph_dashboard.xml +++ b/feature/dashboard/src/main/res/navigation/graph_dashboard.xml @@ -8,6 +8,7 @@ + + android:id="@+id/action_syncInfoFragment_to_moduleSelection" + app:destination="@id/graph_module_selection" /> @@ -102,16 +103,13 @@ android:label="fragment_sync_info" tools:layout="@layout/fragment_sync_info"> + android:id="@+id/action_syncInfoFragment_to_moduleSelection" + app:destination="@id/graph_module_selection" /> - + + android:id="@+id/action_syncInfoFragment_to_moduleSelection" + app:destination="@id/graph_module_selection" /> diff --git a/feature/module-selector/src/main/java/com/simprints/feature/moduleselector/ModuleSelectorContract.kt b/feature/module-selector/src/main/java/com/simprints/feature/moduleselector/ModuleSelectorContract.kt new file mode 100644 index 0000000000..fd6a34123f --- /dev/null +++ b/feature/module-selector/src/main/java/com/simprints/feature/moduleselector/ModuleSelectorContract.kt @@ -0,0 +1,7 @@ +package com.simprints.feature.moduleselector + +import com.simprints.feature.module.selector.R + +object ModuleSelectorContract { + val DESTINATION = R.id.moduleSelectionFragment +} diff --git a/feature/module-selector/src/main/java/com/simprints/feature/moduleselector/ModuleSelectorViewModel.kt b/feature/module-selector/src/main/java/com/simprints/feature/moduleselector/ModuleSelectorViewModel.kt index 72e356b55f..8b918e232b 100644 --- a/feature/module-selector/src/main/java/com/simprints/feature/moduleselector/ModuleSelectorViewModel.kt +++ b/feature/module-selector/src/main/java/com/simprints/feature/moduleselector/ModuleSelectorViewModel.kt @@ -11,8 +11,6 @@ import com.simprints.infra.config.store.models.TokenKeyType import com.simprints.infra.config.store.tokenization.TokenizationProcessor import com.simprints.infra.eventsync.module.ModuleSelectionRepository import com.simprints.infra.eventsync.module.SelectableModule -import com.simprints.infra.sync.OneTime -import com.simprints.infra.sync.SyncOrchestrator import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableSharedFlow @@ -25,7 +23,6 @@ import javax.inject.Inject @HiltViewModel internal class ModuleSelectorViewModel @Inject constructor( private val moduleRepository: ModuleSelectionRepository, - private val syncOrchestrator: SyncOrchestrator, private val configRepository: ConfigRepository, private val tokenizationProcessor: TokenizationProcessor, @param:ExternalScope private val externalScope: CoroutineScope, @@ -124,7 +121,6 @@ internal class ModuleSelectorViewModel @Inject constructor( private fun saveModules() { externalScope.launch { moduleRepository.saveModules(allModules.map { module -> SelectableModule(module.tokenizedName, module.isSelected) }) - syncOrchestrator.execute(OneTime.Events.restart()) emitEffect(ModuleSelectorEffects.Confirmed) } } diff --git a/feature/module-selector/src/main/res/navigation/graph_module_selection.xml b/feature/module-selector/src/main/res/navigation/graph_module_selection.xml new file mode 100644 index 0000000000..29f8cdd187 --- /dev/null +++ b/feature/module-selector/src/main/res/navigation/graph_module_selection.xml @@ -0,0 +1,14 @@ + + + + + + diff --git a/feature/module-selector/src/test/java/com/simprints/feature/moduleselector/ModuleSelectorViewModelTest.kt b/feature/module-selector/src/test/java/com/simprints/feature/moduleselector/ModuleSelectorViewModelTest.kt index 0c571a2417..3ee3991eed 100644 --- a/feature/module-selector/src/test/java/com/simprints/feature/moduleselector/ModuleSelectorViewModelTest.kt +++ b/feature/module-selector/src/test/java/com/simprints/feature/moduleselector/ModuleSelectorViewModelTest.kt @@ -14,8 +14,6 @@ import com.simprints.infra.config.store.models.TokenKeyType import com.simprints.infra.config.store.tokenization.TokenizationProcessor import com.simprints.infra.eventsync.module.ModuleSelectionRepository import com.simprints.infra.eventsync.module.SelectableModule -import com.simprints.infra.sync.OneTime -import com.simprints.infra.sync.SyncOrchestrator import com.simprints.testtools.common.coroutines.TestCoroutineRule import io.mockk.* import io.mockk.impl.annotations.MockK @@ -36,9 +34,6 @@ internal class ModuleSelectorViewModelTest { @MockK private lateinit var moduleRepository: ModuleSelectionRepository - @MockK - private lateinit var syncOrchestrator: SyncOrchestrator - @MockK private lateinit var configRepository: ConfigRepository @@ -218,7 +213,7 @@ internal class ModuleSelectorViewModelTest { } @Test - fun `save action persists modules and triggers sync then emits dismiss effect`() = runTest { + fun `save action persists modules then emits dismiss effect`() = runTest { coEvery { moduleRepository.getMaxNumberOfModules() } returns 2 coEvery { moduleRepository.getModules() } returns listOf( SelectableModule(name = "Alpha".asTokenizableRaw(), isSelected = true), @@ -238,7 +233,6 @@ internal class ModuleSelectorViewModelTest { val saveSlot = slot>() coVerify(exactly = 1) { moduleRepository.saveModules(capture(saveSlot)) } - coVerify(exactly = 1) { syncOrchestrator.execute(OneTime.Events.restart()) } assertThat(saveSlot.captured) .containsExactly( SelectableModule(name = "Alpha".asTokenizableRaw(), isSelected = true), @@ -287,7 +281,6 @@ internal class ModuleSelectorViewModelTest { private fun createViewModel() = ModuleSelectorViewModel( moduleRepository = moduleRepository, - syncOrchestrator = syncOrchestrator, configRepository = configRepository, tokenizationProcessor = tokenizationProcessor, externalScope = CoroutineScope(testCoroutineRule.testCoroutineDispatcher), diff --git a/feature/validate-subject-pool/src/main/java/com/simprints/feature/validatepool/screen/ValidateSubjectPoolFragment.kt b/feature/validate-subject-pool/src/main/java/com/simprints/feature/validatepool/screen/ValidateSubjectPoolFragment.kt index 0a99ecdcfa..c7568ba325 100644 --- a/feature/validate-subject-pool/src/main/java/com/simprints/feature/validatepool/screen/ValidateSubjectPoolFragment.kt +++ b/feature/validate-subject-pool/src/main/java/com/simprints/feature/validatepool/screen/ValidateSubjectPoolFragment.kt @@ -8,6 +8,7 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import com.simprints.core.livedata.LiveDataEventWithContentObserver +import com.simprints.feature.moduleselector.ModuleSelectorContract import com.simprints.feature.moduleselector.ModuleSelectorResult import com.simprints.feature.validatepool.R import com.simprints.feature.validatepool.ValidateSubjectPoolFragmentParams @@ -41,7 +42,7 @@ internal class ValidateSubjectPoolFragment : Fragment(R.layout.fragment_validate findNavController().handleResult( viewLifecycleOwner, R.id.validateSubjectPoolFragment, - R.id.moduleSelectionFragment, + ModuleSelectorContract.DESTINATION, ) { if (it.isConfirmed) { viewModel.startSync(params.enrolmentRecordQuery, params.mode) @@ -61,7 +62,10 @@ internal class ValidateSubjectPoolFragment : Fragment(R.layout.fragment_validate binding.validationActionsContinue.setOnClickListener { finishWithResult(true) } binding.validationActionsSync.setOnClickListener { viewModel.startSync(params.enrolmentRecordQuery, params.mode) } binding.validationActionsSelectModules.setOnClickListener { - findNavController().navigateSafely(this, R.id.action_validateSubjectPoolFragment_to_moduleSelectionFragment) + findNavController().navigateSafely( + this, + ValidateSubjectPoolFragmentDirections.actionValidateSubjectPoolFragmentToModuleSelection(), + ) } viewModel.checkIdentificationPool(params.enrolmentRecordQuery, params.mode) } diff --git a/feature/validate-subject-pool/src/main/res/navigation/graph_validate_subject_pool.xml b/feature/validate-subject-pool/src/main/res/navigation/graph_validate_subject_pool.xml index 8680ed8318..b5509ed70e 100644 --- a/feature/validate-subject-pool/src/main/res/navigation/graph_validate_subject_pool.xml +++ b/feature/validate-subject-pool/src/main/res/navigation/graph_validate_subject_pool.xml @@ -5,6 +5,8 @@ android:id="@+id/graph_validate_subject_pool" app:startDestination="@id/validateSubjectPoolFragment"> + + + android:id="@+id/action_validateSubjectPoolFragment_to_moduleSelection" + app:destination="@id/graph_module_selection" /> - - From b1a727aeb06501d447d2b87c048fdc0e2e7d9749 Mon Sep 17 00:00:00 2001 From: Sergejs Luhmirins Date: Mon, 14 Sep 2026 18:08:56 +0300 Subject: [PATCH 4/4] MS-1547 Avoid crashing when setting user property on debug build --- .../infra/eventsync/module/ModuleSelectionRepository.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/infra/event-sync/src/main/java/com/simprints/infra/eventsync/module/ModuleSelectionRepository.kt b/infra/event-sync/src/main/java/com/simprints/infra/eventsync/module/ModuleSelectionRepository.kt index 06185640a5..0b039e6b25 100644 --- a/infra/event-sync/src/main/java/com/simprints/infra/eventsync/module/ModuleSelectionRepository.kt +++ b/infra/event-sync/src/main/java/com/simprints/infra/eventsync/module/ModuleSelectionRepository.kt @@ -11,6 +11,7 @@ import com.simprints.infra.logging.LoggingConstants.CrashReportTag.SETTINGS import com.simprints.infra.logging.LoggingConstants.CrashReportingCustomKeys.MODULE_IDS import com.simprints.infra.logging.Simber import javax.inject.Inject +import kotlin.collections.take class ModuleSelectionRepository @Inject internal constructor( private val configRepository: ConfigRepository, @@ -85,7 +86,8 @@ class ModuleSelectionRepository @Inject internal constructor( } private fun setCrashlyticsKeyForModules(modules: List) { - Simber.setUserProperty(MODULE_IDS, modules.toString()) + // Ensure that user property is within the allowed string limit to avoid crashing in debug + Simber.setUserProperty(MODULE_IDS, modules.toString().take(99)) } private fun logMessageForCrashReport(message: String) {