Skip to content

Commit 3c4b4a8

Browse files
authored
Merge pull request #270 from open-eid/MOPPAND-1635
Open file without context menu
2 parents 3dcaf1a + 167811a commit 3c4b4a8

File tree

13 files changed

+497
-260
lines changed

13 files changed

+497
-260
lines changed

app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/shared/SharedContainerViewModelTest.kt

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ import androidx.activity.result.ActivityResult
1010
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
1111
import androidx.test.platform.app.InstrumentationRegistry
1212
import com.google.gson.Gson
13+
import ee.ria.DigiDoc.common.R
1314
import ee.ria.DigiDoc.common.testfiles.asset.AssetFile
15+
import ee.ria.DigiDoc.common.testfiles.asset.AssetFile.Companion.getResourceFileAsFile
1416
import ee.ria.DigiDoc.configuration.ConfigurationProperty
1517
import ee.ria.DigiDoc.configuration.ConfigurationSignatureVerifierImpl
1618
import ee.ria.DigiDoc.configuration.loader.ConfigurationLoader
@@ -20,8 +22,10 @@ import ee.ria.DigiDoc.configuration.repository.CentralConfigurationRepositoryImp
2022
import ee.ria.DigiDoc.configuration.repository.ConfigurationRepository
2123
import ee.ria.DigiDoc.configuration.repository.ConfigurationRepositoryImpl
2224
import ee.ria.DigiDoc.configuration.service.CentralConfigurationServiceImpl
25+
import ee.ria.DigiDoc.domain.model.ContainerFileOpeningResult
2326
import ee.ria.DigiDoc.domain.repository.fileopening.FileOpeningRepository
2427
import ee.ria.DigiDoc.libdigidoclib.SignedContainer
28+
import ee.ria.DigiDoc.libdigidoclib.domain.model.DataFileInterface
2529
import ee.ria.DigiDoc.libdigidoclib.exceptions.ContainerDataFilesEmptyException
2630
import ee.ria.DigiDoc.libdigidoclib.init.Initialization
2731
import ee.ria.DigiDoc.network.mid.dto.response.MobileCreateSignatureProcessStatus
@@ -609,6 +613,69 @@ class SharedContainerViewModelTest {
609613
assertTrue(viewModel.addedFilesCount.value == 0)
610614
}
611615

616+
@Test
617+
fun sharedContainerViewModel_openContainerDataFile_returnOpenNestedFileResultWhenFileIsContainer() {
618+
runTest {
619+
val file =
620+
getResourceFileAsFile(
621+
context,
622+
"example_nested_container.asice",
623+
R.raw.example_nested_container,
624+
)
625+
626+
val signedContainer = SignedContainer.openOrCreate(context, file, listOf(file), true)
627+
628+
val dataFile = signedContainer.getDataFiles().first()
629+
630+
val result = viewModel.openContainerDataFile(signedContainer, dataFile, context)
631+
assertTrue(result is ContainerFileOpeningResult.OpenNestedFile)
632+
}
633+
}
634+
635+
@Test
636+
fun sharedContainerViewModel_openContainerDataFile_returnOpenWithFileResultWhenFileIsNotAContainer() {
637+
runTest {
638+
val file =
639+
getResourceFileAsFile(
640+
context,
641+
"example_no_signatures.asice",
642+
R.raw.example_no_signatures,
643+
)
644+
645+
val signedContainer = SignedContainer.openOrCreate(context, file, listOf(file), true)
646+
647+
val dataFile = signedContainer.getDataFiles().first()
648+
649+
val result = viewModel.openContainerDataFile(signedContainer, dataFile, context)
650+
assertTrue(result is ContainerFileOpeningResult.OpenWithFile)
651+
}
652+
}
653+
654+
@Test
655+
fun sharedContainerViewModel_openContainerDataFile_returnErrorResultWhenParametersAreNull() {
656+
val result = viewModel.openContainerDataFile(null, null, context)
657+
assertTrue(result is ContainerFileOpeningResult.Error)
658+
}
659+
660+
@Test
661+
fun sharedContainerViewModel_openContainerDataFile_returnErrorResultWhenFileDoesntExistInContainer() {
662+
runTest {
663+
val mockDataFile = mock(DataFileInterface::class.java)
664+
665+
val file =
666+
getResourceFileAsFile(
667+
context,
668+
"example_nested_container.asice",
669+
R.raw.example_nested_container,
670+
)
671+
672+
val signedContainer = SignedContainer.openOrCreate(context, file, listOf(file), true)
673+
674+
val result = viewModel.openContainerDataFile(signedContainer, mockDataFile, context)
675+
assertTrue(result is ContainerFileOpeningResult.Error)
676+
}
677+
}
678+
612679
private fun createTempFileWithStringContent(
613680
filename: String,
614681
content: String,
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
@file:Suppress("PackageName")
2+
3+
package ee.ria.DigiDoc.domain.model
4+
5+
import java.io.File
6+
7+
sealed class ContainerFileOpeningResult {
8+
data class OpenNestedFile(
9+
val file: File,
10+
val needsSivaDialog: Boolean,
11+
) : ContainerFileOpeningResult()
12+
13+
data class OpenWithFile(
14+
val file: File,
15+
) : ContainerFileOpeningResult()
16+
17+
data class Error(
18+
val throwable: Throwable,
19+
) : ContainerFileOpeningResult()
20+
}

app/src/main/kotlin/ee/ria/DigiDoc/ui/component/crypto/EncryptNavigation.kt

Lines changed: 121 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ import ee.ria.DigiDoc.ui.component.shared.MessageDialog
8585
import ee.ria.DigiDoc.ui.component.shared.TabView
8686
import ee.ria.DigiDoc.ui.component.shared.TopBar
8787
import ee.ria.DigiDoc.ui.component.shared.dialog.SivaConfirmationDialog
88+
import ee.ria.DigiDoc.ui.component.shared.handler.containerFileOpeningHandler
8889
import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding
8990
import ee.ria.DigiDoc.ui.theme.Dimensions.XLPadding
9091
import ee.ria.DigiDoc.ui.theme.Dimensions.XSPadding
@@ -250,7 +251,99 @@ fun EncryptNavigation(
250251
val showDataFileBottomSheet = remember { mutableStateOf(false) }
251252
val showRecipientBottomSheet = remember { mutableStateOf(false) }
252253

254+
val showSivaDialog = remember { mutableStateOf(false) }
255+
val nestedFile = rememberSaveable { mutableStateOf<File?>(null) }
256+
257+
val openNestedContainer: (nestedContainer: File, isSivaConfirmed: Boolean) -> Unit =
258+
{ nestedContainer, isSivaConfirmed ->
259+
scope.launch(IO) {
260+
try {
261+
val isSigningContainer = nestedContainer.isContainer(context)
262+
263+
if (isSigningContainer) {
264+
signingViewModel.openNestedContainer(
265+
context,
266+
nestedContainer,
267+
sharedContainerViewModel,
268+
isSivaConfirmed,
269+
)
270+
271+
withContext(Main) {
272+
sharedContainerViewModel.setIsSivaConfirmed(isSivaConfirmed)
273+
navController.navigate(Route.Signing.route)
274+
}
275+
} else {
276+
encryptViewModel.openNestedContainer(
277+
context,
278+
nestedContainer,
279+
sharedContainerViewModel,
280+
)
281+
}
282+
showLoadingScreen.value = false
283+
} catch (ex: Exception) {
284+
withContext(Main) {
285+
errorLog(
286+
this.javaClass.simpleName,
287+
"Unable to open nested container",
288+
ex,
289+
)
290+
showLoadingScreen.value = false
291+
Toast
292+
.makeText(
293+
context,
294+
ex.localizedMessage,
295+
Toast.LENGTH_LONG,
296+
).show()
297+
}
298+
}
299+
}
300+
}
301+
302+
val handleSivaCancel: () -> Unit = {
303+
showSivaDialog.value = false
304+
nestedFile.value?.let { file ->
305+
if (DDOC_MIMETYPE != file.mimeType(context)) {
306+
openNestedContainer(file, false)
307+
}
308+
}
309+
}
310+
311+
val handleSivaConfirmation: () -> Unit = {
312+
showSivaDialog.value = false
313+
nestedFile.value?.let { file ->
314+
openNestedContainer(file, true)
315+
}
316+
}
317+
318+
val handleResult: (Boolean) -> Unit = { isSivaConfirmed ->
319+
if (isSivaConfirmed) {
320+
handleSivaConfirmation()
321+
} else {
322+
handleSivaCancel()
323+
}
324+
}
325+
253326
val onDataFileClick: (File) -> Unit = { file ->
327+
showDataFileBottomSheet.value = false
328+
showLoadingScreen.value = true
329+
val result =
330+
sharedContainerViewModel.openCryptoContainerDataFile(
331+
cryptoContainer = cryptoContainer,
332+
dataFile = file,
333+
)
334+
containerFileOpeningHandler(
335+
result = result,
336+
nestedFile = nestedFile,
337+
showSivaDialog = showSivaDialog,
338+
showLoadingScreen = showLoadingScreen,
339+
context = context,
340+
signingViewModel = null,
341+
encryptViewModel = encryptViewModel,
342+
handleSivaConfirmation = handleSivaConfirmation,
343+
)
344+
}
345+
346+
val onDataFileMoreOptionsActionButtonClick: (File) -> Unit = { file ->
254347
showDataFileBottomSheet.value = true
255348
clickedFile.value = file
256349
}
@@ -499,7 +592,10 @@ fun EncryptNavigation(
499592
TopBar(
500593
modifier = modifier,
501594
sharedMenuViewModel = sharedMenuViewModel,
502-
title = null,
595+
title =
596+
cryptoContainer
597+
?.takeIf { it.encrypted || it.decrypted }
598+
?.let { R.string.signing_container_documents_title },
503599
leftIcon =
504600
when {
505601
isNestedContainer -> R.drawable.ic_m3_arrow_back_48dp_wght400
@@ -578,78 +674,6 @@ fun EncryptNavigation(
578674
) {
579675
var actionRecipient by remember { mutableStateOf<Addressee?>(null) }
580676

581-
val showSivaDialog = remember { mutableStateOf(false) }
582-
val nestedFile = rememberSaveable { mutableStateOf<File?>(null) }
583-
584-
val openNestedContainer: (nestedContainer: File, isSivaConfirmed: Boolean) -> Unit =
585-
{ nestedContainer, isSivaConfirmed ->
586-
scope.launch(IO) {
587-
try {
588-
val isSigningContainer = nestedContainer.isContainer(context)
589-
590-
if (isSigningContainer) {
591-
signingViewModel.openNestedContainer(
592-
context,
593-
nestedContainer,
594-
sharedContainerViewModel,
595-
isSivaConfirmed,
596-
)
597-
598-
withContext(Main) {
599-
sharedContainerViewModel.setIsSivaConfirmed(isSivaConfirmed)
600-
navController.navigate(Route.Signing.route)
601-
}
602-
} else {
603-
encryptViewModel.openNestedContainer(
604-
context,
605-
nestedContainer,
606-
sharedContainerViewModel,
607-
)
608-
}
609-
showLoadingScreen.value = false
610-
} catch (ex: Exception) {
611-
withContext(Main) {
612-
errorLog(
613-
this.javaClass.simpleName,
614-
"Unable to open nested container",
615-
ex,
616-
)
617-
showLoadingScreen.value = false
618-
Toast
619-
.makeText(
620-
context,
621-
ex.localizedMessage,
622-
Toast.LENGTH_LONG,
623-
).show()
624-
}
625-
}
626-
}
627-
}
628-
629-
val handleSivaCancel: () -> Unit = {
630-
showSivaDialog.value = false
631-
nestedFile.value?.let { file ->
632-
if (DDOC_MIMETYPE != file.mimeType(context)) {
633-
openNestedContainer(file, false)
634-
}
635-
}
636-
}
637-
638-
val handleSivaConfirmation: () -> Unit = {
639-
showSivaDialog.value = false
640-
nestedFile.value?.let { file ->
641-
openNestedContainer(file, true)
642-
}
643-
}
644-
645-
val handleResult: (Boolean) -> Unit = { isSivaConfirmed ->
646-
if (isSivaConfirmed) {
647-
handleSivaConfirmation()
648-
} else {
649-
handleSivaCancel()
650-
}
651-
}
652-
653677
Column(
654678
modifier =
655679
modifier
@@ -685,27 +709,28 @@ fun EncryptNavigation(
685709
text = removeExtensionFromContainerFilename(cryptoContainerName),
686710
)
687711
cryptoContainer?.let {
688-
val isNoRecipientsContainer =
689-
!encryptViewModel.isContainerWithoutRecipients(cryptoContainer) &&
690-
!isNestedContainer
691-
val title =
692-
if (!isNoRecipientsContainer) {
693-
stringResource(R.string.crypto_new_title)
694-
} else {
695-
stringResource(R.string.crypto_view_title)
712+
val isInitialCryptoContainer =
713+
with(encryptViewModel) {
714+
isContainerWithoutRecipients(cryptoContainer) &&
715+
!isEncryptedContainer(cryptoContainer) &&
716+
!isDecryptedContainer(cryptoContainer) &&
717+
!isNestedContainer
696718
}
697-
Text(
698-
modifier =
699-
modifier
700-
.padding(bottom = SPadding)
701-
.semantics {
702-
heading()
703-
testTagsAsResourceId = true
704-
}.testTag("encryptionTitle"),
705-
text = title,
706-
style = MaterialTheme.typography.headlineMedium,
707-
textAlign = TextAlign.Start,
708-
)
719+
720+
if (isInitialCryptoContainer) {
721+
Text(
722+
modifier =
723+
modifier
724+
.padding(bottom = SPadding)
725+
.semantics {
726+
heading()
727+
testTagsAsResourceId = true
728+
}.testTag("encryptionTitle"),
729+
text = stringResource(R.string.crypto_new_title),
730+
style = MaterialTheme.typography.headlineMedium,
731+
textAlign = TextAlign.Start,
732+
)
733+
}
709734
val rightActionButtonName =
710735
if (encryptViewModel.isDecryptButtonShown(cryptoContainer, isNestedContainer)) {
711736
R.string.decrypt_button
@@ -806,6 +831,7 @@ fun EncryptNavigation(
806831
dataFiles = dataFiles,
807832
isMoreOptionsButtonShown = true,
808833
onClick = onDataFileClick,
834+
onDataFileMoreOptionsActionButtonClick = onDataFileMoreOptionsActionButtonClick,
809835
)
810836
}
811837
} else {
@@ -830,6 +856,8 @@ fun EncryptNavigation(
830856
cryptoContainer,
831857
),
832858
onClick = onDataFileClick,
859+
onDataFileMoreOptionsActionButtonClick =
860+
onDataFileMoreOptionsActionButtonClick,
833861
)
834862
} else {
835863
CryptoDataFilesLocked(modifier = modifier)

0 commit comments

Comments
 (0)