Skip to content
Open
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* License: LGPL 2.1
* © Estonian Information System Authority

# RIA-DigiDoc-Android v3
# RIA-DigiDoc-Android

Android application that allows signing containers with ID-card via USB reader, ID-card via NFC, Mobile-ID and Smart-ID.

Expand Down
28 changes: 15 additions & 13 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import com.google.firebase.crashlytics.buildtools.gradle.CrashlyticsExtension
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

val appAbiFilters = "arm64-v8a;armeabi-v7a;x86_64"
val appAbiFilters = "arm64-v8a;armeabi-v7a;x86_64".split(';').map { it.trim() }

plugins {
jacoco
alias(libs.plugins.androidApplication)
alias(libs.plugins.jetbrainsKotlinAndroid)
alias(libs.plugins.compose.compiler)
kotlin("kapt")
alias(libs.plugins.ksp)
id("com.google.dagger.hilt.android")
alias(libs.plugins.google.services)
alias(libs.plugins.google.firebase.crashlytics)
Expand All @@ -20,6 +19,8 @@ tasks.register<JacocoReport>("jacocoFilteredReport") {
group = "Reporting"
description = "Generates filtered JaCoCo report excluding UI package and other noise"

val buildDir = layout.buildDirectory.get().asFile

val coverageFiles =
fileTree("$buildDir/outputs/code_coverage/debugAndroidTest/connected") {
include("**/coverage.ec")
Expand Down Expand Up @@ -85,7 +86,7 @@ android {

ndk {
abiFilters.clear()
abiFilters.addAll(appAbiFilters.split(';').map { it.trim() })
abiFilters.addAll(appAbiFilters)
}
}

Expand Down Expand Up @@ -132,14 +133,8 @@ android {
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}

kotlin {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_17)
}
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}

buildFeatures {
Expand All @@ -157,6 +152,12 @@ android {
}
}

kotlin {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_21)
}
}

dependencies {

implementation(libs.androidx.core.ktx)
Expand All @@ -166,6 +167,7 @@ dependencies {
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.material.icons.core)
implementation(libs.androidx.ui)
implementation(libs.androidx.ui.graphics)
implementation(libs.androidx.ui.tooling.preview)
Expand All @@ -179,7 +181,7 @@ dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.google.dagger.hilt.android)
implementation(libs.firebase.crashlytics.ktx)
kapt(libs.google.dagger.hilt.android.compile)
ksp(libs.google.dagger.hilt.android.compile)
implementation(libs.androidx.hilt)
implementation(libs.kotlinx.coroutines.rx3)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import org.mockito.junit.MockitoJUnitRunner
import org.mockito.kotlin.whenever
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileNotFoundException
import java.nio.charset.Charset
Expand Down Expand Up @@ -332,7 +334,9 @@ class DiagnosticsViewModelTest {
fun diagnosticsViewModel_saveFile_success() {
val file = createTempFileWithStringContent("test", "Test content")
val intent = Intent()
intent.data = Uri.fromFile(file)
val uri = Uri.fromFile(file)
intent.data = uri
whenever(contentResolver.openOutputStream(uri)).thenReturn(ByteArrayOutputStream())
val activityResult = ActivityResult(-1, intent)
viewModel.saveFile(file, activityResult)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ import org.mockito.Mockito.mock
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
import org.mockito.junit.MockitoJUnitRunner
import org.mockito.kotlin.whenever
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileNotFoundException
import java.nio.charset.Charset
Expand Down Expand Up @@ -127,7 +129,9 @@ class SharedContainerViewModelTest {
fun sharedContainerViewModel_saveContainerFile_success() {
val file = createTempFileWithStringContent("test", "Test content")
val intent = Intent()
intent.data = Uri.fromFile(file)
val uri = Uri.fromFile(file)
intent.data = uri
whenever(contentResolver.openOutputStream(uri)).thenReturn(ByteArrayOutputStream())
val activityResult = ActivityResult(-1, intent)
viewModel.saveContainerFile(file, activityResult)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import org.mockito.junit.MockitoJUnitRunner
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import java.io.File
import java.io.InputStream
import java.nio.charset.Charset
Expand Down Expand Up @@ -266,6 +267,7 @@ class SharedSettingsViewModelTest {
ee.ria.DigiDoc.common.R.raw.siva,
)
val uri = Uri.fromFile(file)
whenever(contentResolver.openInputStream(uri)).thenReturn(file.inputStream())
viewModel.handleSivaFile(uri)

val validUrl = "https://valid-siva-url.com"
Expand Down Expand Up @@ -299,6 +301,7 @@ class SharedSettingsViewModelTest {
ee.ria.DigiDoc.common.R.raw.siva,
)
val uri = Uri.fromFile(file)
whenever(contentResolver.openInputStream(uri)).thenReturn(file.inputStream())
viewModel.handleTsaFile(uri)

val validUrl = "https://valid-tsa-url.com"
Expand Down Expand Up @@ -332,6 +335,7 @@ class SharedSettingsViewModelTest {
)

val uri = Uri.fromFile(file)
whenever(contentResolver.openInputStream(uri)).thenReturn(file.inputStream())
viewModel.handleSivaFile(uri)
assertEquals("sivaCert", dataStore.getSettingsSivaCertName())
}
Expand All @@ -353,6 +357,7 @@ class SharedSettingsViewModelTest {
)

val uri = Uri.fromFile(file)
whenever(contentResolver.openInputStream(uri)).thenReturn(file.inputStream())
viewModel.handleTsaFile(uri)
assertEquals("tsaCert", dataStore.getTSACertName())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,7 @@ class FileOpeningRepositoryImpl
override fun isFileAlreadyInContainer(
file: File,
container: CryptoContainer,
): Boolean =
container.dataFiles?.any { it?.name == file.name }
?: false
): Boolean = container.dataFiles.any { it.name == file.name }

override fun isSivaConfirmationNeeded(
context: Context,
Expand Down Expand Up @@ -272,10 +270,8 @@ class FileOpeningRepositoryImpl
val dataFiles =
cryptoContainer.dataFiles

if (dataFiles != null) {
for (i in dataFiles.indices) {
dataFiles[i]?.name?.let { containerFileNames.add(it) }
}
for (i in dataFiles.indices) {
dataFiles[i].name.let { containerFileNames.add(it) }
}

return containerFileNames
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,13 @@ class FileOpeningServiceImpl : FileOpeningService {
displayName = it
.getString(0)
?.let { name ->
sanitizeString(name, "")?.trim()?.let {
if (it.isEmpty() || it.startsWith(".")) {
"$DEFAULT_FILENAME$it"
} else if (it.endsWith(".")) {
sanitizeString(name, "").trim().let { sanitizedString ->
if (sanitizedString.isEmpty() || sanitizedString.startsWith(".")) {
"$DEFAULT_FILENAME$sanitizedString"
} else if (sanitizedString.endsWith(".")) {
DEFAULT_FILENAME
} else {
it
sanitizedString
}
}
}?.let { sanitized ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ fun ProxyServicesSettingsScreen(
.clickable {
settingsProxyChoice.value = ProxySetting.NO_PROXY.name
setProxySetting(ProxySetting.NO_PROXY)
sharedSettingsViewModel.saveProxySettings(true, ManualProxy("", 80, "", ""))
},
verticalAlignment = Alignment.CenterVertically,
) {
Expand All @@ -302,6 +303,7 @@ fun ProxyServicesSettingsScreen(
onClick = {
settingsProxyChoice.value = ProxySetting.NO_PROXY.name
setProxySetting(ProxySetting.NO_PROXY)
sharedSettingsViewModel.saveProxySettings(true, ManualProxy("", 80, "", ""))
},
)
}
Expand All @@ -328,6 +330,7 @@ fun ProxyServicesSettingsScreen(
.clickable {
settingsProxyChoice.value = ProxySetting.SYSTEM_PROXY.name
setProxySetting(ProxySetting.SYSTEM_PROXY)
sharedSettingsViewModel.saveProxySettings(true, ManualProxy("", 80, "", ""))
},
verticalAlignment = Alignment.CenterVertically,
) {
Expand All @@ -348,6 +351,7 @@ fun ProxyServicesSettingsScreen(
onClick = {
settingsProxyChoice.value = ProxySetting.SYSTEM_PROXY.name
setProxySetting(ProxySetting.SYSTEM_PROXY)
sharedSettingsViewModel.saveProxySettings(true, ManualProxy("", 80, "", ""))
},
)
}
Expand All @@ -372,8 +376,18 @@ fun ProxyServicesSettingsScreen(
.fillMaxWidth()
.padding(SPadding)
.clickable {
val proxyPortValue = proxyPort.text.toIntOrNull() ?: 80
settingsProxyChoice.value = ProxySetting.MANUAL_PROXY.name
setProxySetting(ProxySetting.MANUAL_PROXY)
sharedSettingsViewModel.saveProxySettings(
false,
ManualProxy(
host = proxyHost.text,
port = proxyPortValue,
username = proxyUsername.text,
password = proxyPassword.text,
),
)
},
verticalAlignment = Alignment.CenterVertically,
) {
Expand All @@ -393,8 +407,18 @@ fun ProxyServicesSettingsScreen(
},
selected = settingsProxyChoice.value == ProxySetting.MANUAL_PROXY.name,
onClick = {
val proxyPortValue = proxyPort.text.toIntOrNull() ?: 80
settingsProxyChoice.value = ProxySetting.MANUAL_PROXY.name
setProxySetting(ProxySetting.MANUAL_PROXY)
sharedSettingsViewModel.saveProxySettings(
false,
ManualProxy(
host = proxyHost.text,
port = proxyPortValue,
username = proxyUsername.text,
password = proxyPassword.text,
),
)
},
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,13 @@
package ee.ria.DigiDoc.ui.component.menu

import androidx.annotation.StringRes
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Home
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import ee.ria.DigiDoc.R
import ee.ria.DigiDoc.utils.Language

data class LanguageChoiceButtonItem(
@param:StringRes val label: Int = 0,
val icon: ImageVector = Icons.Filled.Home,
val locale: String = "",
val contentDescription: String = "",
val testTag: String = "",
Expand Down
12 changes: 2 additions & 10 deletions app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/TabView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,8 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SecondaryTabRow
import androidx.compose.material3.Tab
import androidx.compose.material3.TabRow
import androidx.compose.material3.TabRowDefaults
import androidx.compose.material3.TabRowDefaults.tabIndicatorOffset
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
Expand Down Expand Up @@ -59,14 +57,8 @@ fun TabView(
}.testTag(testTag)
.fillMaxSize(),
) {
TabRow(
SecondaryTabRow(
selectedTabIndex = selectedTabIndex,
indicator = { tabPositions ->
TabRowDefaults.SecondaryIndicator(
modifier = modifier.tabIndicatorOffset(tabPositions[selectedTabIndex]),
color = MaterialTheme.colorScheme.primary,
)
},
) {
tabItems.forEachIndexed { index, (title, _) ->
val isSelected = selectedTabIndex == index
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,13 @@
package ee.ria.DigiDoc.ui.component.signing

import androidx.annotation.StringRes
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Home
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import ee.ria.DigiDoc.R
import ee.ria.DigiDoc.domain.model.methods.SigningMethod

data class SignatureAddRadioItem(
@param:StringRes val label: Int = 0,
val icon: ImageVector = Icons.Filled.Home,
val method: SigningMethod = SigningMethod.NFC,
val contentDescription: String = "",
val testTag: String = "",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,6 @@ class LocaleUtilImpl
val config = context.resources.configuration
config.setLocale(locale)
config.setLayoutDirection(locale)
val configurationContext = context.createConfigurationContext(config)
context.resources.updateConfiguration(config, context.resources.displayMetrics)
return configurationContext
return context.createConfigurationContext(config)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,8 @@ class DiagnosticsViewModel
contentResolver
.openOutputStream(it)
.use { outputStream ->
if (outputStream != null) {
ByteStreams.copy(inputStream, outputStream)
}
outputStream ?: throw FileNotFoundException("Unable to open output stream for URI: $it")
ByteStreams.copy(inputStream, outputStream)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,8 @@ class SigningViewModel
ContainerUtil.getContainerDataFilesDir(context, it)
}

dataFiles.mapNotNullTo(uris) { dataFile ->
container.getDataFile(dataFile, dataFilesDir)?.toUri()
dataFiles.mapTo(uris) { dataFile ->
container.getDataFile(dataFile, dataFilesDir).toUri()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,9 +339,8 @@ class SharedContainerViewModel
contentResolver
.openOutputStream(it)
.use { outputStream ->
if (outputStream != null) {
ByteStreams.copy(inputStream, outputStream)
}
outputStream ?: throw FileNotFoundException("Unable to open output stream for URI: $it")
ByteStreams.copy(inputStream, outputStream)
}
}
}
Expand Down
Loading
Loading