summaryrefslogtreecommitdiffhomepage
path: root/android/lib/shared/src
diff options
context:
space:
mode:
authorAlbin <albin@mullvad.net>2024-08-21 11:54:17 +0200
committerAlbin <albin@mullvad.net>2024-08-21 11:54:17 +0200
commitd6771c29ed0b7a9df53d67a736e49a6f671c6981 (patch)
tree0494de3c25aa8b101c0d099189672d6490c90d94 /android/lib/shared/src
parent26e03f20c8ee93303cd9afb2432601651571dc05 (diff)
parent8a9c8b1a53567bc5ae655f1069c3e908ae17e801 (diff)
downloadmullvadvpn-d6771c29ed0b7a9df53d67a736e49a6f671c6981.tar.xz
mullvadvpn-d6771c29ed0b7a9df53d67a736e49a6f671c6981.zip
Merge branch 'translate-location-names-droid-432'
Diffstat (limited to 'android/lib/shared/src')
-rw-r--r--android/lib/shared/src/main/kotlin/net/mullvad/mullvadvpn/lib/shared/ConnectionProxy.kt24
-rw-r--r--android/lib/shared/src/main/kotlin/net/mullvad/mullvadvpn/lib/shared/LocaleRepository.kt19
-rw-r--r--android/lib/shared/src/main/kotlin/net/mullvad/mullvadvpn/lib/shared/RelayLocationTranslationRepository.kt61
-rw-r--r--android/lib/shared/src/test/kotlin/net/mullvad/mullvadvpn/lib/shared/ConnectionProxyTest.kt5
4 files changed, 107 insertions, 2 deletions
diff --git a/android/lib/shared/src/main/kotlin/net/mullvad/mullvadvpn/lib/shared/ConnectionProxy.kt b/android/lib/shared/src/main/kotlin/net/mullvad/mullvadvpn/lib/shared/ConnectionProxy.kt
index 6ea373e426..13d668b65b 100644
--- a/android/lib/shared/src/main/kotlin/net/mullvad/mullvadvpn/lib/shared/ConnectionProxy.kt
+++ b/android/lib/shared/src/main/kotlin/net/mullvad/mullvadvpn/lib/shared/ConnectionProxy.kt
@@ -3,14 +3,36 @@ package net.mullvad.mullvadvpn.lib.shared
import arrow.core.Either
import arrow.core.raise.either
import arrow.core.raise.ensure
+import kotlinx.coroutines.flow.combine
import net.mullvad.mullvadvpn.lib.daemon.grpc.ManagementService
import net.mullvad.mullvadvpn.lib.model.ConnectError
+import net.mullvad.mullvadvpn.lib.model.GeoIpLocation
+import net.mullvad.mullvadvpn.lib.model.TunnelState
class ConnectionProxy(
private val managementService: ManagementService,
+ translationRepository: RelayLocationTranslationRepository,
private val vpnPermissionRepository: VpnPermissionRepository
) {
- val tunnelState = managementService.tunnelState
+ val tunnelState =
+ combine(managementService.tunnelState, translationRepository.translations) {
+ tunnelState,
+ translations ->
+ tunnelState.translateLocations(translations)
+ }
+
+ private fun TunnelState.translateLocations(translations: Map<String, String>): TunnelState {
+ return when (this) {
+ is TunnelState.Connecting -> copy(location = location?.translate(translations))
+ is TunnelState.Disconnected -> copy(location = location?.translate(translations))
+ is TunnelState.Disconnecting -> this
+ is TunnelState.Error -> this
+ is TunnelState.Connected -> copy(location = location?.translate(translations))
+ }
+ }
+
+ private fun GeoIpLocation.translate(translations: Map<String, String>): GeoIpLocation =
+ copy(city = translations[city] ?: city, country = translations[country] ?: country)
suspend fun connect(): Either<ConnectError, Boolean> = either {
ensure(vpnPermissionRepository.hasVpnPermission()) { ConnectError.NoVpnPermission }
diff --git a/android/lib/shared/src/main/kotlin/net/mullvad/mullvadvpn/lib/shared/LocaleRepository.kt b/android/lib/shared/src/main/kotlin/net/mullvad/mullvadvpn/lib/shared/LocaleRepository.kt
new file mode 100644
index 0000000000..4e5628d214
--- /dev/null
+++ b/android/lib/shared/src/main/kotlin/net/mullvad/mullvadvpn/lib/shared/LocaleRepository.kt
@@ -0,0 +1,19 @@
+package net.mullvad.mullvadvpn.lib.shared
+
+import android.content.res.Resources
+import co.touchlab.kermit.Logger
+import java.util.Locale
+import kotlin.also
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+
+class LocaleRepository(val resources: Resources) {
+ private val _currentLocale = MutableStateFlow(getLocale())
+ val currentLocale: StateFlow<Locale?> = _currentLocale
+
+ private fun getLocale(): Locale? = resources.configuration.locales.get(0)
+
+ fun refreshLocale() {
+ _currentLocale.value = getLocale().also { Logger.d("New locale: $it") }
+ }
+}
diff --git a/android/lib/shared/src/main/kotlin/net/mullvad/mullvadvpn/lib/shared/RelayLocationTranslationRepository.kt b/android/lib/shared/src/main/kotlin/net/mullvad/mullvadvpn/lib/shared/RelayLocationTranslationRepository.kt
new file mode 100644
index 0000000000..edaa0c1ebc
--- /dev/null
+++ b/android/lib/shared/src/main/kotlin/net/mullvad/mullvadvpn/lib/shared/RelayLocationTranslationRepository.kt
@@ -0,0 +1,61 @@
+package net.mullvad.mullvadvpn.lib.shared
+
+import android.content.Context
+import android.content.res.XmlResourceParser
+import co.touchlab.kermit.Logger
+import java.util.Locale
+import kotlin.collections.set
+import kotlin.collections.toMap
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.withContext
+
+typealias Translations = Map<String, String>
+
+class RelayLocationTranslationRepository(
+ val context: Context,
+ val localeRepository: LocaleRepository,
+ externalScope: CoroutineScope = MainScope(),
+ val dispatcher: CoroutineDispatcher = Dispatchers.IO
+) {
+ val translations: StateFlow<Translations> =
+ localeRepository.currentLocale
+ .filterNotNull()
+ .map { loadTranslations(it) }
+ .stateIn(externalScope, SharingStarted.Eagerly, emptyMap())
+
+ private suspend fun loadTranslations(locale: Locale): Translations =
+ withContext(dispatcher) {
+ Logger.d("Updating translations based on $locale")
+ if (locale.language == DEFAULT_LANGUAGE) emptyMap()
+ else {
+ // Load current translations
+ val xml = context.resources.getXml(R.xml.relay_locations)
+ xml.loadRelayTranslation()
+ }
+ }
+
+ private fun XmlResourceParser.loadRelayTranslation(): Map<String, String> {
+ val translation = mutableMapOf<String, String>()
+ while (this.eventType != XmlResourceParser.END_DOCUMENT) {
+ if (this.eventType == XmlResourceParser.START_TAG && this.name == "string") {
+ val key = this.getAttributeValue(null, "name")
+ val value = this.nextText()
+ translation[key] = value
+ }
+ this.next()
+ }
+ return translation.toMap()
+ }
+
+ companion object {
+ private const val DEFAULT_LANGUAGE = "en"
+ }
+}
diff --git a/android/lib/shared/src/test/kotlin/net/mullvad/mullvadvpn/lib/shared/ConnectionProxyTest.kt b/android/lib/shared/src/test/kotlin/net/mullvad/mullvadvpn/lib/shared/ConnectionProxyTest.kt
index 74ab4f6b64..138d0f5a41 100644
--- a/android/lib/shared/src/test/kotlin/net/mullvad/mullvadvpn/lib/shared/ConnectionProxyTest.kt
+++ b/android/lib/shared/src/test/kotlin/net/mullvad/mullvadvpn/lib/shared/ConnectionProxyTest.kt
@@ -13,11 +13,14 @@ class ConnectionProxyTest {
private val mockManagementService: ManagementService = mockk(relaxed = true)
private val mockVpnPermissionRepository: VpnPermissionRepository = mockk()
+ private val mockTranslationRepository: RelayLocationTranslationRepository =
+ mockk(relaxed = true)
private val connectionProxy: ConnectionProxy =
ConnectionProxy(
managementService = mockManagementService,
- vpnPermissionRepository = mockVpnPermissionRepository
+ vpnPermissionRepository = mockVpnPermissionRepository,
+ translationRepository = mockTranslationRepository
)
@Test