diff --git a/rqes-ui-sdk/src/main/java/eu/europa/ec/eudi/rqesui/presentation/ui/options_selection/OptionsSelectionViewModel.kt b/rqes-ui-sdk/src/main/java/eu/europa/ec/eudi/rqesui/presentation/ui/options_selection/OptionsSelectionViewModel.kt index adef7e6..2e7e8aa 100644 --- a/rqes-ui-sdk/src/main/java/eu/europa/ec/eudi/rqesui/presentation/ui/options_selection/OptionsSelectionViewModel.kt +++ b/rqes-ui-sdk/src/main/java/eu/europa/ec/eudi/rqesui/presentation/ui/options_selection/OptionsSelectionViewModel.kt @@ -56,7 +56,6 @@ import org.koin.core.annotation.InjectedParam internal data class State( val isLoading: Boolean = false, val config: OptionsSelectionUiConfig, - val currentScreenSelectionState: String = QTSP_SELECTION_STATE, val documentSelectionItem: SelectionOptionUi? = null, val qtspServiceSelectionItem: SelectionOptionUi? = null, diff --git a/rqes-ui-sdk/src/main/java/eu/europa/ec/eudi/rqesui/presentation/ui/success/SuccessScreen.kt b/rqes-ui-sdk/src/main/java/eu/europa/ec/eudi/rqesui/presentation/ui/success/SuccessScreen.kt index da66bae..9d55400 100644 --- a/rqes-ui-sdk/src/main/java/eu/europa/ec/eudi/rqesui/presentation/ui/success/SuccessScreen.kt +++ b/rqes-ui-sdk/src/main/java/eu/europa/ec/eudi/rqesui/presentation/ui/success/SuccessScreen.kt @@ -104,7 +104,10 @@ internal fun SuccessScreen( onEventSend = { viewModel.setEvent(it) }, onNavigationRequested = { navigationEffect -> when (navigationEffect) { - is Effect.Navigation.SwitchScreen -> navController.navigate(navigationEffect.screenRoute) + is Effect.Navigation.SwitchScreen -> { + navController.navigate(navigationEffect.screenRoute) + } + is Effect.Navigation.Finish -> context.finish() } }, @@ -116,7 +119,9 @@ internal fun SuccessScreen( state.selectionItem?.let { safeSelectionItem -> WrapModalBottomSheet( onDismissRequest = { - viewModel.setEvent(Event.BottomSheet.UpdateBottomSheetState(isOpen = false)) + viewModel.setEvent( + Event.BottomSheet.UpdateBottomSheetState(isOpen = false) + ) }, sheetState = bottomSheetState ) { @@ -197,7 +202,9 @@ private fun Content( modalBottomSheetState.hide() }.invokeOnCompletion { if (!modalBottomSheetState.isVisible) { - onEventSend(Event.BottomSheet.UpdateBottomSheetState(isOpen = false)) + onEventSend( + Event.BottomSheet.UpdateBottomSheetState(isOpen = false) + ) } } } @@ -262,9 +269,6 @@ private fun SuccessScreenPreview() { PreviewTheme { Content( state = State( - title = "Sign document", - headline = "Success", - subtitle = "You successfully signed your document", selectionItem = SelectionOptionUi( mainText = "Document name.PDF", actionText = "VIEW", diff --git a/rqes-ui-sdk/src/main/java/eu/europa/ec/eudi/rqesui/presentation/ui/success/SuccessViewModel.kt b/rqes-ui-sdk/src/main/java/eu/europa/ec/eudi/rqesui/presentation/ui/success/SuccessViewModel.kt index 8da3ba8..c349aec 100644 --- a/rqes-ui-sdk/src/main/java/eu/europa/ec/eudi/rqesui/presentation/ui/success/SuccessViewModel.kt +++ b/rqes-ui-sdk/src/main/java/eu/europa/ec/eudi/rqesui/presentation/ui/success/SuccessViewModel.kt @@ -56,12 +56,7 @@ internal data class State( val error: ContentErrorConfig? = null, val isBottomSheetOpen: Boolean = false, val isBottomBarButtonEnabled: Boolean = false, - - val title: String, - val headline: String? = null, - val subtitle: String? = null, val bottomBarButtonText: String, - val sheetContent: SuccessBottomSheetContent, ) : ViewState @@ -126,7 +121,6 @@ internal class SuccessViewModel( override fun setInitialState(): State { return State( - title = resourceProvider.getLocalizedString(LocalizableKey.SignDocument), bottomBarButtonText = resourceProvider.getLocalizedString(LocalizableKey.Close), sheetContent = SuccessBottomSheetContent.ShareDocument(bottomSheetTextData = getShareDocumentTextData()), ) @@ -249,8 +243,6 @@ internal class SuccessViewModel( } ), selectionItem = null, - headline = null, - subtitle = null, isBottomBarButtonEnabled = false, isLoading = false, ) @@ -276,8 +268,6 @@ internal class SuccessViewModel( copy( headerConfig = headerConfig, selectionItem = selectionItem, - headline = resourceProvider.getLocalizedString(LocalizableKey.Success), - subtitle = resourceProvider.getLocalizedString(LocalizableKey.SuccessfullySignedDocument), isBottomBarButtonEnabled = true, isLoading = false, ) diff --git a/rqes-ui-sdk/src/test/java/eu/europa/ec/eudi/rqesui/presentation/ui/success/TestSuccessViewModel.kt b/rqes-ui-sdk/src/test/java/eu/europa/ec/eudi/rqesui/presentation/ui/success/TestSuccessViewModel.kt index 37c50b9..5c988b0 100644 --- a/rqes-ui-sdk/src/test/java/eu/europa/ec/eudi/rqesui/presentation/ui/success/TestSuccessViewModel.kt +++ b/rqes-ui-sdk/src/test/java/eu/europa/ec/eudi/rqesui/presentation/ui/success/TestSuccessViewModel.kt @@ -14,7 +14,6 @@ * governing permissions and limitations under the Licence. */ -/* package eu.europa.ec.eudi.rqesui.presentation.ui.success import android.net.Uri @@ -28,10 +27,16 @@ import eu.europa.ec.eudi.rqesui.domain.serializer.UiSerializer import eu.europa.ec.eudi.rqesui.infrastructure.config.data.DocumentData import eu.europa.ec.eudi.rqesui.infrastructure.config.data.QtspData import eu.europa.ec.eudi.rqesui.infrastructure.provider.ResourceProvider +import eu.europa.ec.eudi.rqesui.infrastructure.theme.values.ThemeColors +import eu.europa.ec.eudi.rqesui.presentation.entities.SelectionOptionUi import eu.europa.ec.eudi.rqesui.presentation.entities.config.ViewDocumentUiConfig import eu.europa.ec.eudi.rqesui.presentation.navigation.SdkScreens import eu.europa.ec.eudi.rqesui.presentation.navigation.helper.generateComposableArguments import eu.europa.ec.eudi.rqesui.presentation.navigation.helper.generateComposableNavigationLink +import eu.europa.ec.eudi.rqesui.presentation.ui.component.AppIconAndTextData +import eu.europa.ec.eudi.rqesui.presentation.ui.component.AppIcons +import eu.europa.ec.eudi.rqesui.presentation.ui.component.RelyingPartyData +import eu.europa.ec.eudi.rqesui.presentation.ui.component.content.ContentHeaderConfig import eu.europa.ec.eudi.rqesui.presentation.ui.component.wrap.BottomSheetTextData import eu.europa.ec.eudi.rqesui.util.CoroutineTestRule import eu.europa.ec.eudi.rqesui.util.mockedDocumentName @@ -96,8 +101,8 @@ class TestSuccessViewModel { // Case 1 // Function setInitialState() is called to initialize the ViewModel state. // Case 1 Expected Result: - // 1. The ViewModel's initialState should be correctly initialized with a title, a bottom bar - // and the related wordings for the bottom sheet. + // 1. The ViewModel's initialState should be correctly initialized with a ContentHeader showing + // the app icon, a bottom bar and the related wordings for the bottom sheet. @Test fun `Given Case 1, When setInitialState is called, Then the expected result is returned`() { // Act @@ -112,9 +117,14 @@ class TestSuccessViewModel { negativeButtonText = resourceProvider.getLocalizedString(LocalizableKey.Close), ) ) + val expectedHeaderConfig = ContentHeaderConfig( + appIconAndTextData = AppIconAndTextData(), + description = null, + ) + assertEquals( - resourceProvider.getLocalizedString(LocalizableKey.SignDocument), - initialState.title + expectedHeaderConfig, + initialState.headerConfig ) assertEquals( resourceProvider.getLocalizedString(LocalizableKey.Close), @@ -126,10 +136,11 @@ class TestSuccessViewModel { //region setEvent // Case 1 - // Function setEvent(Event.Init) is called to initialize the ViewModel with selected file and QTSP data. + // Function setEvent(Event.Initialize) is called to initialize the ViewModel with selected file and QTSP data. // Case 1 Expected Result: // 1. The mocked response contains the selected file (document name and Uri) and QTSP data. - // 2. When the Event.Init event is triggered, the ViewModel should emit the Effect.OnSelectedFileAndQtspGot effect. + // 2. When the Event.Initialize event is triggered, the ViewModel should emit the + // Effect.OnSelectedFileAndQtspGot effect. @Test fun `Given Case 1, When setEvent is called, Then the expected result is returned`() = coroutineRule.runTest { @@ -138,16 +149,19 @@ class TestSuccessViewModel { selectedFile = DocumentData(mockedDocumentName, uri = documentFileUri), selectedQtsp = qtspData ) - mockQTSPData(qtspData) + mockQTSPData(qtspData = qtspData) mockGetSelectedFileAndQtspCall(response = response) // Act - viewModel.setEvent(Event.Init) + viewModel.setEvent(Event.Initialize) // Assert viewModel.effect.runFlowTest { val expectedEffect = Effect.OnSelectedFileAndQtspGot( - selectedFile = DocumentData(mockedDocumentName, uri = documentFileUri), + selectedFile = DocumentData( + documentName = mockedDocumentName, + uri = documentFileUri + ), selectedQtsp = qtspData ) assertEquals(expectedEffect, awaitItem()) @@ -159,55 +173,65 @@ class TestSuccessViewModel { // Case 2 Expected Result: // 1. The mocked response simulates a successfully signed and saved document with a text prefix. // 2. When the event is triggered, the ViewModel updates its state to reflect success. - // This includes the updated selection item, title, subtitle, bottom bar button text and bottom sheet content. + // This includes the updated selection item, contentHeader, bottom bar button text and + // bottom sheet content. @Test fun `Given Case 2, When setEvent is called, Then the expected result is returned`() = coroutineRule.runTest { // Arrange val event = Event.SignAndSaveDocument(mockedDocumentName, mockedQtspName) + val signedDocumentPrefix = "signed_0" + val selectionItem = SelectionOptionUi( + leadingIcon = AppIcons.Verified, + leadingIconTint = ThemeColors.success, + mainText = "${signedDocumentPrefix}_$mockedDocumentName", + actionText = resourceProvider.getLocalizedString(LocalizableKey.View), + event = Event.ViewDocumentItemPressed( + documentData = DocumentData( + documentName = "${signedDocumentPrefix}_$mockedDocumentName", + uri = documentFileUri + ) + ), + ) + val title = resourceProvider.getLocalizedString(LocalizableKey.SharingDocument) val message = resourceProvider.getLocalizedString(LocalizableKey.CloseSharingMessage) - val signDocument = resourceProvider.getLocalizedString(LocalizableKey.SignDocument) - val signedDocumentPrefix = "signed_0" - val selectionITem = SelectionItemUi( - action = resourceProvider.getLocalizedString(LocalizableKey.View), - documentData = DocumentData( - documentName = "${signedDocumentPrefix}_$mockedDocumentName", - uri = documentFileUri - ) + val headerConfig = ContentHeaderConfig( + appIconAndTextData = AppIconAndTextData(), + description = resourceProvider.getLocalizedString(LocalizableKey.SuccessDescription), + relyingPartyData = RelyingPartyData(isVerified = true, name = mockedQtspName) ) val expectedState = State( isLoading = false, - headline = resourceProvider.getLocalizedString(LocalizableKey.Success), - selectionItem = selectionITem, + headerConfig = headerConfig, + selectionItem = selectionItem, error = null, isBottomSheetOpen = false, isBottomBarButtonEnabled = true, - title = signDocument, - subtitle = resourceProvider.getLocalizedString(LocalizableKey.SuccessfullySignedDocument), bottomBarButtonText = resourceProvider.getLocalizedString(LocalizableKey.Close), sheetContent = SuccessBottomSheetContent.ShareDocument( bottomSheetTextData = BottomSheetTextData( title = title, message = message, - resourceProvider.getLocalizedString(LocalizableKey.Share), - resourceProvider.getLocalizedString(LocalizableKey.Close) + positiveButtonText = resourceProvider.getLocalizedString(LocalizableKey.Share), + negativeButtonText = resourceProvider.getLocalizedString(LocalizableKey.Close) ) ) ) - whenever(successInteractor.signAndSaveDocument(originalDocumentName = mockedDocumentName)) - .thenReturn( - SuccessInteractorSignAndSaveDocumentPartialState.Success( - savedDocument = DocumentData( - documentName = "${signedDocumentPrefix}_$mockedDocumentName", - uri = documentFileUri - ) - ) + val response = SuccessInteractorSignAndSaveDocumentPartialState.Success( + savedDocument = DocumentData( + documentName = "${signedDocumentPrefix}_$mockedDocumentName", + uri = documentFileUri ) + ) + mockSignAndSaveDocumentCall( + documentName = mockedDocumentName, + response = response + ) // Act viewModel.setEvent(event) @@ -229,8 +253,7 @@ class TestSuccessViewModel { val errorResponse = SuccessInteractorSignAndSaveDocumentPartialState.Failure( error = EudiRQESUiError(mockedPlainFailureMessage) ) - whenever(successInteractor.signAndSaveDocument(mockedDocumentName)) - .thenReturn(errorResponse) + mockSignAndSaveDocumentCall(documentName = mockedDocumentName, response = errorResponse) // Act viewModel.setEvent(event) @@ -255,7 +278,9 @@ class TestSuccessViewModel { val expectedState = viewModel.viewState.value.copy(isBottomSheetOpen = true) // Act - viewModel.setEvent(Event.BottomSheet.UpdateBottomSheetState(true)) + viewModel.setEvent( + Event.BottomSheet.UpdateBottomSheetState(isOpen = true) + ) // Assert assertEquals( @@ -265,7 +290,7 @@ class TestSuccessViewModel { } // Case 5 - // Function setEvent(Event.ViewDocument) is called to handle navigation to the ViewDocument screen. + // Function setEvent(Event.ViewDocumentItemPressed) is called to handle navigation to the ViewDocument screen. // Case 5 Expected Result: // 1. The correct screen route is generated based on the document data. // 2. The ViewModel emits an Effect.Navigation.SwitchScreen to navigate to next screen. @@ -277,7 +302,7 @@ class TestSuccessViewModel { // Act viewModel.setEvent( - Event.ViewDocument(documentData) + Event.ViewDocumentItemPressed(documentData = documentData) ) // Assert @@ -418,6 +443,13 @@ class TestSuccessViewModel { whenever(successInteractor.getSelectedFileAndQtsp()) .thenReturn(response) } + + private suspend fun mockSignAndSaveDocumentCall( + documentName: String, + response: SuccessInteractorSignAndSaveDocumentPartialState + ) { + whenever(successInteractor.signAndSaveDocument(originalDocumentName = documentName)) + .thenReturn(response) + } //endregion -} -*/ \ No newline at end of file +} \ No newline at end of file