Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -62,6 +64,14 @@ internal class SyncInfoFragment : Fragment(R.layout.fragment_sync_info) {
setupClickListeners()
observeUI()

findNavController().handleResult<ModuleSelectorResult>(
viewLifecycleOwner,
getCurrentDestinationId(),
ModuleSelectorContract.DESTINATION,
) {
if (it.isConfirmed) viewModel.forceEventSync(false)
}

findNavController().handleResult(
viewLifecycleOwner,
getCurrentDestinationId(),
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand Down
18 changes: 8 additions & 10 deletions feature/dashboard/src/main/res/navigation/graph_dashboard.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<include app:graph="@navigation/graph_privacy" />
<include app:graph="@navigation/graph_login" />
<include app:graph="@navigation/graph_troubleshooting" />
<include app:graph="@navigation/graph_module_selection" />

<fragment
android:id="@+id/requestLoginFragment"
Expand Down Expand Up @@ -54,8 +55,8 @@
android:id="@+id/action_mainFragment_to_syncInfoFragment"
app:destination="@id/syncInfoFragment" />
<action
android:id="@+id/action_mainFragment_to_moduleSelectionFragment"
app:destination="@id/moduleSelectionFragment" />
android:id="@+id/action_syncInfoFragment_to_moduleSelection"
app:destination="@id/graph_module_selection" />
<action
android:id="@+id/action_mainFragment_to_privacyNoticesFragment"
app:destination="@id/graph_privacy" />
Expand Down Expand Up @@ -102,16 +103,13 @@
android:label="fragment_sync_info"
tools:layout="@layout/fragment_sync_info">
<action
android:id="@+id/action_syncInfoFragment_to_moduleSelectionFragment"
app:destination="@id/moduleSelectionFragment" />
android:id="@+id/action_syncInfoFragment_to_moduleSelection"
app:destination="@id/graph_module_selection" />
<action
android:id="@+id/action_syncInfoFragment_to_login"
app:destination="@id/graph_login" />
</fragment>
<fragment
android:id="@+id/moduleSelectionFragment"
android:name="com.simprints.feature.moduleselector.ModuleSelectorFragment"
android:label="ModuleSelectionFragment" />

<fragment
android:id="@+id/fingerSelectionFragment"
android:name="com.simprints.feature.dashboard.settings.fingerselection.FingerSelectionFragment"
Expand All @@ -131,8 +129,8 @@
android:id="@+id/action_logoutSyncFragment_to_logoutSyncDeclineFragment"
app:destination="@id/logOutSyncDeclineFragment" />
<action
android:id="@+id/action_logoutSyncFragment_to_moduleSelectionFragment"
app:destination="@id/moduleSelectionFragment" />
android:id="@+id/action_syncInfoFragment_to_moduleSelection"
app:destination="@id/graph_module_selection" />
<action
android:id="@+id/action_logOutSyncFragment_to_login"
app:destination="@id/graph_login" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.simprints.feature.moduleselector

import com.simprints.feature.module.selector.R

object ModuleSelectorContract {
val DESTINATION = R.id.moduleSelectionFragment
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -67,7 +68,7 @@ internal class ModuleSelectorFragment : Fragment(R.layout.fragment_module_select
onSuccess = { viewModel.onAction(ModuleSelectorAction.UnlockScreen) },
)
moduleSelectionToolbar.setNavigationOnClickListener {
findNavController().popBackStack()
finishWithResult(false)
}
Comment thread
luhmirin-s marked this conversation as resolved.
moduleSelectionCancelButton.setOnClickListener {
viewModel.onAction(ModuleSelectorAction.CancelClicked)
Expand Down Expand Up @@ -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))
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ internal data class ModuleSelectorState(
}

internal sealed interface ModuleSelectorEffects {
data object Confirmed : ModuleSelectorEffects

data object Dismiss : ModuleSelectorEffects

data class ShowPassword(
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand Down Expand Up @@ -124,9 +121,8 @@ 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)
}
Comment thread
luhmirin-s marked this conversation as resolved.
emitEffect(ModuleSelectorEffects.Dismiss)
}

private fun updateState(block: (currentState: ModuleSelectorState) -> ModuleSelectorState) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/graph_module_selection"
app:startDestination="@id/moduleSelectionFragment">

<fragment
android:id="@+id/moduleSelectionFragment"
android:name="com.simprints.feature.moduleselector.ModuleSelectorFragment"
android:label="ModuleSelectionFragment"
tools:layout="@layout/fragment_module_selector" />

</navigation>
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand Down Expand Up @@ -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),
Expand All @@ -231,14 +226,13 @@ internal class ModuleSelectorViewModelTest {

viewModel.effects.test {
viewModel.onAction(ModuleSelectorAction.SaveClicked)
assertThat(awaitItem()).isEqualTo(ModuleSelectorEffects.Dismiss)
assertThat(awaitItem()).isEqualTo(ModuleSelectorEffects.Confirmed)
cancelAndIgnoreRemainingEvents()
}
advanceUntilIdle()

val saveSlot = slot<List<SelectableModule>>()
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),
Expand Down Expand Up @@ -287,7 +281,6 @@ internal class ModuleSelectorViewModelTest {

private fun createViewModel() = ModuleSelectorViewModel(
moduleRepository = moduleRepository,
syncOrchestrator = syncOrchestrator,
configRepository = configRepository,
tokenizationProcessor = tokenizationProcessor,
externalScope = CoroutineScope(testCoroutineRule.testCoroutineDispatcher),
Expand Down
1 change: 1 addition & 0 deletions feature/validate-subject-pool/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ android {
}

dependencies {
implementation(project(":feature:module-selector"))

implementation(project(":infra:enrolment-records:repository"))
implementation(project(":infra:config-store"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@ 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
import com.simprints.feature.validatepool.ValidateSubjectPoolResult
import com.simprints.feature.validatepool.databinding.FragmentValidateSubjectPoolBinding
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
Expand All @@ -35,6 +39,16 @@ internal class ValidateSubjectPoolFragment : Fragment(R.layout.fragment_validate
applySystemBarInsets(view)
Simber.i("ValidateSubjectPoolFragment started", tag = ORCHESTRATION)

findNavController().handleResult<ModuleSelectorResult>(
viewLifecycleOwner,
R.id.validateSubjectPoolFragment,
ModuleSelectorContract.DESTINATION,
) {
if (it.isConfirmed) {
viewModel.startSync(params.enrolmentRecordQuery, params.mode)
}
}

viewModel.state.observe(viewLifecycleOwner, LiveDataEventWithContentObserver(::renderState))

viewModel.lastSyncLabel.observe(
Expand All @@ -47,7 +61,12 @@ 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,
ValidateSubjectPoolFragmentDirections.actionValidateSubjectPoolFragmentToModuleSelection(),
)
}
viewModel.checkIdentificationPool(params.enrolmentRecordQuery, params.mode)
}

Expand All @@ -64,6 +83,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(
Expand All @@ -87,6 +107,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
Expand All @@ -98,7 +119,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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,18 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/validationIssueDescriptionBlock">

<com.google.android.material.button.MaterialButton
android:id="@+id/validationActionsSelectModules"
style="@style/Widget.Simprints.Button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/id_pool_validation_action_select_modules"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="gone" />

<com.google.android.material.button.MaterialButton
android:id="@+id/validationActionsSync"
style="@style/Widget.Simprints.Button.Green"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,18 @@
app:layout_constraintTop_toBottomOf="@id/validationIssueDescriptionBlock"
tools:visibility="visible">

<com.google.android.material.button.MaterialButton
android:id="@+id/validationActionsSelectModules"
style="@style/Widget.Simprints.Button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/id_pool_validation_action_select_modules"
android:visibility="gone"
tools:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<com.google.android.material.button.MaterialButton
android:id="@+id/validationActionsSync"
style="@style/Widget.Simprints.Button.Green"
Expand Down
Loading