summaryrefslogtreecommitdiffhomepage
path: root/android/app
diff options
context:
space:
mode:
authorDavid Göransson <david.goransson@mullvad.net>2024-08-07 18:49:46 +0200
committerAlbin <albin@mullvad.net>2024-08-21 11:52:30 +0200
commit7e2015962384cd87af823570c9dab7f3fcaf49b7 (patch)
treee8d81b1e8c3dca781a3e952ba406cfef26f7d32f /android/app
parentb905cd0204ee6481375b957ef0ef7516016f0345 (diff)
downloadmullvadvpn-7e2015962384cd87af823570c9dab7f3fcaf49b7.tar.xz
mullvadvpn-7e2015962384cd87af823570c9dab7f3fcaf49b7.zip
Add support for translated location names
Diffstat (limited to 'android/app')
-rw-r--r--android/app/build.gradle.kts1
-rw-r--r--android/app/src/main/AndroidManifest.xml6
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/AppModule.kt6
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/receiver/LocaleChangedBroadcastReceiver.kt18
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayListExtensions.kt3
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/RelayListRepository.kt41
7 files changed, 70 insertions, 7 deletions
diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts
index ecde2e9132..f8c92c9849 100644
--- a/android/app/build.gradle.kts
+++ b/android/app/build.gradle.kts
@@ -337,6 +337,7 @@ dependencies {
implementation(libs.androidx.lifecycle.viewmodel)
implementation(libs.androidx.lifecycle.runtime.compose)
implementation(libs.arrow)
+ implementation(libs.arrow.optics)
implementation(libs.arrow.resilience)
implementation(libs.compose.constrainlayout)
implementation(libs.compose.foundation)
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 9247112466..28d6a17ed1 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -106,5 +106,11 @@
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
+ <receiver android:name=".receiver.LocaleChangedBroadcastReceiver"
+ android:exported="false">
+ <intent-filter>
+ <action android:name="android.intent.action.LOCALE_CHANGED" />
+ </intent-filter>
+ </receiver>
</application>
</manifest>
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/AppModule.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/AppModule.kt
index 6af9ff57cb..e4722094f9 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/AppModule.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/AppModule.kt
@@ -11,6 +11,8 @@ import net.mullvad.mullvadvpn.lib.model.BuildVersion
import net.mullvad.mullvadvpn.lib.shared.AccountRepository
import net.mullvad.mullvadvpn.lib.shared.ConnectionProxy
import net.mullvad.mullvadvpn.lib.shared.DeviceRepository
+import net.mullvad.mullvadvpn.lib.shared.LocaleRepository
+import net.mullvad.mullvadvpn.lib.shared.RelayLocationTranslationRepository
import net.mullvad.mullvadvpn.lib.shared.VpnPermissionRepository
import org.koin.android.ext.koin.androidContext
import org.koin.core.qualifier.named
@@ -32,5 +34,7 @@ val appModule = module {
single { AccountRepository(get(), get(), MainScope()) }
single { DeviceRepository(get()) }
single { VpnPermissionRepository(androidContext()) }
- single { ConnectionProxy(get(), get()) }
+ single { ConnectionProxy(get(), get(), get()) }
+ single { LocaleRepository(get()) }
+ single { RelayLocationTranslationRepository(get(), get(), MainScope()) }
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt
index 6494cbb167..929d1e3b99 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt
@@ -117,7 +117,7 @@ val uiModule = module {
single { MullvadProblemReport(get()) }
single { RelayOverridesRepository(get()) }
single { CustomListsRepository(get()) }
- single { RelayListRepository(get()) }
+ single { RelayListRepository(get(), get()) }
single { RelayListFilterRepository(get()) }
single { VoucherRepository(get(), get()) }
single { SplitTunnelingRepository(get()) }
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/receiver/LocaleChangedBroadcastReceiver.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/receiver/LocaleChangedBroadcastReceiver.kt
new file mode 100644
index 0000000000..8969ffd14c
--- /dev/null
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/receiver/LocaleChangedBroadcastReceiver.kt
@@ -0,0 +1,18 @@
+package net.mullvad.mullvadvpn.receiver
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import net.mullvad.mullvadvpn.lib.shared.LocaleRepository
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.inject
+
+class LocaleChangedBroadcastReceiver : BroadcastReceiver(), KoinComponent {
+ private val localeRepository by inject<LocaleRepository>()
+
+ override fun onReceive(context: Context?, intent: Intent?) {
+ if (intent?.action == Intent.ACTION_LOCALE_CHANGED) {
+ localeRepository.refreshLocale()
+ }
+ }
+}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayListExtensions.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayListExtensions.kt
index ea017339f6..6d308e3b26 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayListExtensions.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayListExtensions.kt
@@ -55,3 +55,6 @@ fun List<RelayItem.Location.Country>.getRelayItemsByCodes(
): List<RelayItem.Location> =
this.filter { codes.contains(it.id) } +
this.flatMap { it.descendants() }.filter { codes.contains(it.id) }
+
+fun <T : RelayItem> List<T>.sortedByName() =
+ this.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.name })
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/RelayListRepository.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/RelayListRepository.kt
index ce41b57c4c..69a35c406b 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/RelayListRepository.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/RelayListRepository.kt
@@ -1,11 +1,15 @@
package net.mullvad.mullvadvpn.repository
+import arrow.optics.Every
+import arrow.optics.copy
+import arrow.optics.dsl.every
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
@@ -17,18 +21,45 @@ import net.mullvad.mullvadvpn.lib.model.RelayItem
import net.mullvad.mullvadvpn.lib.model.RelayItemId
import net.mullvad.mullvadvpn.lib.model.WireguardConstraints
import net.mullvad.mullvadvpn.lib.model.WireguardEndpointData
+import net.mullvad.mullvadvpn.lib.model.cities
+import net.mullvad.mullvadvpn.lib.model.name
+import net.mullvad.mullvadvpn.lib.shared.RelayLocationTranslationRepository
import net.mullvad.mullvadvpn.relaylist.findByGeoLocationId
+import net.mullvad.mullvadvpn.relaylist.sortedByName
class RelayListRepository(
private val managementService: ManagementService,
+ private val translationRepository: RelayLocationTranslationRepository,
dispatcher: CoroutineDispatcher = Dispatchers.IO
) {
val relayList: StateFlow<List<RelayItem.Location.Country>> =
- managementService.relayCountries.stateIn(
- CoroutineScope(dispatcher),
- SharingStarted.WhileSubscribed(),
- emptyList()
- )
+ combine(managementService.relayCountries, translationRepository.translations) {
+ countries,
+ translations ->
+ countries.translateRelays(translations)
+ }
+ .stateIn(CoroutineScope(dispatcher), SharingStarted.WhileSubscribed(), emptyList())
+
+ private fun List<RelayItem.Location.Country>.translateRelays(
+ translations: Map<String, String>
+ ): List<RelayItem.Location.Country> {
+ if (translations.isEmpty()) {
+ return this
+ }
+
+ return Every.list<RelayItem.Location.Country>()
+ .modify(this) {
+ it.copy {
+ RelayItem.Location.Country.name set translations.getOrDefault(it.name, it.name)
+ RelayItem.Location.Country.cities.every(Every.list()).name transform
+ { cityName ->
+ translations.getOrDefault(cityName, cityName)
+ }
+ RelayItem.Location.Country.cities transform { cities -> cities.sortedByName() }
+ }
+ }
+ .sortedByName()
+ }
val wireguardEndpointData: StateFlow<WireguardEndpointData> =
managementService.wireguardEndpointData.stateIn(