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
24 changes: 19 additions & 5 deletions app/src/main/kotlin/ee/ria/DigiDoc/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,29 @@ import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.runtime.getValue
import androidx.core.app.ActivityCompat
import androidx.core.net.toUri
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import androidx.preference.PreferenceManager
import com.google.firebase.Firebase
import com.google.firebase.crashlytics.crashlytics
import dagger.hilt.android.AndroidEntryPoint
import ee.ria.DigiDoc.common.model.AppState
import ee.ria.DigiDoc.configuration.loader.ConfigurationLoader
import ee.ria.DigiDoc.domain.model.theme.ThemeSetting
import ee.ria.DigiDoc.domain.preferences.DataStore
import ee.ria.DigiDoc.fragment.RootFragment
import ee.ria.DigiDoc.fragment.UnsupportedVersionFragment
import ee.ria.DigiDoc.init.LibrarySetup
import ee.ria.DigiDoc.manager.ActivityManager
import ee.ria.DigiDoc.root.RootChecker
import ee.ria.DigiDoc.ui.theme.RIADigiDocTheme
import ee.ria.DigiDoc.utils.VersionUtil
import ee.ria.DigiDoc.utils.WebEidUriUtil
import ee.ria.DigiDoc.utils.locale.LocaleUtil
import ee.ria.DigiDoc.utils.locale.LocaleUtilImpl
Expand Down Expand Up @@ -73,6 +78,9 @@ class MainActivity :
@Inject
lateinit var secureUtil: SecureUtil

@Inject
lateinit var configurationLoader: ConfigurationLoader

private val logTag = "MainActivity"

private var isAppReady = false
Expand Down Expand Up @@ -163,13 +171,19 @@ class MainActivity :
isAppReady = true
}

val appVersion = "${BuildConfig.VERSION_NAME}.${BuildConfig.VERSION_CODE}"
setContent {
val configuration by configurationLoader.getConfigurationFlow().collectAsStateWithLifecycle()
RIADigiDocTheme(darkTheme = useDarkMode) {
RIADigiDocAppScreen(
externalFileUris = externalFileUris,
webEidUri = webEidUri,
browserPackage = browserPackage,
)
if (VersionUtil.isLowerThan(appVersion, configuration?.riaddUnsupported)) {
UnsupportedVersionFragment()
} else {
RIADigiDocAppScreen(
externalFileUris = externalFileUris,
webEidUri = webEidUri,
browserPackage = browserPackage,
)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// SPDX-FileCopyrightText: Estonian Information System Authority
// SPDX-License-Identifier: LGPL-2.1-or-later

@file:Suppress("PackageName", "FunctionName")

package ee.ria.DigiDoc.fragment

import android.content.res.Configuration
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.testTagsAsResourceId
import androidx.compose.ui.tooling.preview.Preview
import ee.ria.DigiDoc.fragment.screen.UnsupportedVersionScreen
import ee.ria.DigiDoc.ui.theme.RIADigiDocTheme

@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun UnsupportedVersionFragment(modifier: Modifier = Modifier) {
Surface(
modifier =
modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
.semantics {
testTagsAsResourceId = true
}.testTag("unsupportedVersionFragment"),
color = MaterialTheme.colorScheme.background,
) {
UnsupportedVersionScreen(
modifier = modifier,
)
}
}

@Preview(showBackground = true)
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
fun UnsupportedVersionFragmentPreview() {
RIADigiDocTheme {
UnsupportedVersionFragment()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// SPDX-FileCopyrightText: Estonian Information System Authority
// SPDX-License-Identifier: LGPL-2.1-or-later

@file:Suppress("PackageName", "FunctionName")

package ee.ria.DigiDoc.fragment.screen

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.testTagsAsResourceId
import androidx.compose.ui.text.LinkAnnotation
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextLinkStyles
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import ee.ria.DigiDoc.R
import ee.ria.DigiDoc.ui.component.shared.InvisibleElement
import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding

@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun UnsupportedVersionScreen(modifier: Modifier = Modifier) {
val linkText = stringResource(R.string.unsupported_version_link_text)
val message = stringResource(R.string.unsupported_version_message, linkText)
val url = stringResource(R.string.unsupported_version_url)
val linkColor = MaterialTheme.colorScheme.primary

val annotatedMessage =
buildAnnotatedString {
append(message)
val linkStart = message.indexOf(linkText)
if (linkStart >= 0) {
addLink(
LinkAnnotation.Url(
url = url,
styles =
TextLinkStyles(
style =
SpanStyle(
color = linkColor,
textDecoration = TextDecoration.Underline,
),
),
),
linkStart,
linkStart + linkText.length,
)
}
}

Scaffold(
modifier =
modifier
.semantics {
testTagsAsResourceId = true
}.testTag("unsupportedVersionScreen"),
) { innerPadding ->
Column(
modifier = modifier.padding(innerPadding),
) {
Box(
modifier =
modifier
.padding(SPadding)
.fillMaxSize()
.verticalScroll(rememberScrollState())
.testTag("scrollView"),
contentAlignment = Alignment.Center,
) {
Text(
text = annotatedMessage,
style = MaterialTheme.typography.bodyLarge,
modifier =
modifier
.padding(vertical = SPadding)
.testTag("unsupportedVersionMessage"),
textAlign = TextAlign.Center,
color = MaterialTheme.colorScheme.onSurface,
)
InvisibleElement(modifier = modifier)
}
}
}
}
39 changes: 39 additions & 0 deletions app/src/main/kotlin/ee/ria/DigiDoc/utils/VersionUtil.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-FileCopyrightText: Estonian Information System Authority
// SPDX-License-Identifier: LGPL-2.1-or-later

@file:Suppress("PackageName")

package ee.ria.DigiDoc.utils

object VersionUtil {
fun isLowerThan(
version: String,
otherVersion: String?,
): Boolean {
val segments = segments(version)
val otherSegments = segments(otherVersion.orEmpty())
if (segments.isEmpty() || otherSegments.isEmpty()) {
return false
}

val length = maxOf(segments.size, otherSegments.size)
for (index in 0 until length) {
val segment = segments.getOrElse(index) { 0 }
val otherSegment = otherSegments.getOrElse(index) { 0 }
if (segment != otherSegment) {
return segment < otherSegment
}
}
return false
}

private fun segments(version: String): List<Int> =
version
.trim()
.split('.')
.asSequence()
.map { it.toIntOrNull() }
.takeWhile { it != null && it >= 0 }
.filterNotNull()
.toList()
}
2 changes: 2 additions & 0 deletions app/src/main/res/values-et/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
<string name="action_continue">Jätka</string>

<string name="rooted_device">Seda rakendust ei saa kasutada turvamata (ingl rooted) seadmes.</string>
<string name="unsupported_version_message">Sinu nutiseadmes olev ID-tarkvara ei ole toetatud. RIA Digidoc kasutamiseks pead ID-tarkvara uuendama. Paigalda uus ID-tarkvara veebilehelt %1$s.</string>
<string name="unsupported_version_url">https://www.id.ee/artikkel/paigalda-id-tarkvara/</string>

<string name="configuration_initialization_failed">Konfiguratsiooni initsialiseerimine ebaõnnestus</string>
<string name="error_general_client">Midagi läks valesti, proovi uuesti</string>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/donottranslate.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<string name="init_lang_locale_en">English</string>

<string name="last_invisible_element_name">Invisible element</string>
<string name="unsupported_version_link_text">www.id.ee</string>

<!-- Main About -->
<string name="main_about_libdigidocpp_title">libdigidocpp</string>
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
<string name="action_continue">Continue</string>

<string name="rooted_device">This app cannot be used in rooted device.</string>
<string name="unsupported_version_message">This version of ID-software on your computer is unsupported. RIA DigiDoc cannot be used until you update ID-software. Install new ID-software from %1$s.</string>
<string name="unsupported_version_url">https://www.id.ee/en/article/install-id-software/</string>

<string name="configuration_initialization_failed">Failed to initialize configuration</string>
<string name="error_general_client">Something went wrong, try again</string>
Expand Down
71 changes: 71 additions & 0 deletions app/src/test/kotlin/ee/ria/DigiDoc/utils/VersionUtilTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// SPDX-FileCopyrightText: Estonian Information System Authority
// SPDX-License-Identifier: LGPL-2.1-or-later

@file:Suppress("PackageName")

package ee.ria.DigiDoc.utils

import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test

class VersionUtilTest {
@Test
fun versionUtil_isLowerThan_returnTrueWhenBuildNumberIsLower() {
assertTrue(VersionUtil.isLowerThan("3.2.0.100", "3.2.0.101"))
}

@Test
fun versionUtil_isLowerThan_returnTrueWhenMinorIsLowerDespiteHigherBuildNumber() {
assertTrue(VersionUtil.isLowerThan("3.1.9.999", "3.2.0.1"))
}

@Test
fun versionUtil_isLowerThan_comparesSegmentsNumericallyNotLexically() {
assertTrue(VersionUtil.isLowerThan("3.9.0.1", "3.10.0.1"))
assertFalse(VersionUtil.isLowerThan("3.10.0.1", "3.9.0.1"))
}

@Test
fun versionUtil_isLowerThan_returnFalseWhenEqual() {
assertFalse(VersionUtil.isLowerThan("3.2.0.100", "3.2.0.100"))
}

@Test
fun versionUtil_isLowerThan_returnFalseWhenHigher() {
assertFalse(VersionUtil.isLowerThan("3.2.1.1", "3.2.0.500"))
}

@Test
fun versionUtil_isLowerThan_treatsMissingSegmentsAsZero() {
assertTrue(VersionUtil.isLowerThan("3.2", "3.2.0.1"))
assertFalse(VersionUtil.isLowerThan("3.2.0.0", "3.2"))
assertFalse(VersionUtil.isLowerThan("3.2.0.1", "3.2"))
}

@Test
fun versionUtil_isLowerThan_returnFalseWhenOtherVersionIsNull() {
assertFalse(VersionUtil.isLowerThan("3.2.0.100", null))
}

@Test
fun versionUtil_isLowerThan_returnFalseWhenOtherVersionIsBlank() {
assertFalse(VersionUtil.isLowerThan("3.2.0.100", " "))
}

@Test
fun versionUtil_isLowerThan_returnFalseWhenOtherVersionIsNotNumeric() {
assertFalse(VersionUtil.isLowerThan("3.2.0.100", "latest"))
}

@Test
fun versionUtil_isLowerThan_ignoresTrailingNonNumericSuffix() {
assertTrue(VersionUtil.isLowerThan("3.2.0.100", "3.3.0-beta"))
assertFalse(VersionUtil.isLowerThan("3.3.0.1", "3.3.0-beta"))
}

@Test
fun versionUtil_isLowerThan_trimsWhitespace() {
assertTrue(VersionUtil.isLowerThan("3.2.0.100", " 3.2.0.101 "))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ data class ConfigurationProvider(
@SerializedName("LDAP-CERTS") val ldapCerts: List<String> = listOf(),
var configurationLastUpdateCheckDate: Date?,
var configurationUpdateDate: Date?,
@SerializedName("RIADD-UNSUPPORTED") val riaddUnsupported: String? = null,
) {
data class MetaInf(
@SerializedName("URL") val url: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// SPDX-FileCopyrightText: Estonian Information System Authority
// SPDX-License-Identifier: LGPL-2.1-or-later

@file:Suppress("PackageName")

package ee.ria.DigiDoc.configuration.provider

import com.google.gson.Gson
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Test

class ConfigurationProviderTest {
@Test
fun configurationProvider_deserialize_readsRiaddUnsupported() {
val configuration =
Gson().fromJson(
"""{"RIADD-UNSUPPORTED":"3.2.0.100","QDIGIDOC4-UNSUPPORTED":"4.8.0.0"}""",
ConfigurationProvider::class.java,
)

assertEquals("3.2.0.100", configuration.riaddUnsupported)
}

@Test
fun configurationProvider_deserialize_riaddUnsupportedIsNullWhenMissing() {
val configuration =
Gson().fromJson(
"""{"QDIGIDOC4-UNSUPPORTED":"4.8.0.0"}""",
ConfigurationProvider::class.java,
)

assertNull(configuration.riaddUnsupported)
}
}
Loading