summaryrefslogtreecommitdiffhomepage
path: root/android
diff options
context:
space:
mode:
Diffstat (limited to 'android')
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/communication/CustomListAction.kt33
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/communication/CustomListResult.kt34
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/RelayListUseCase.kt7
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/customlists/CustomListActionUseCase.kt117
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/customlists/CustomListsException.kt5
5 files changed, 195 insertions, 1 deletions
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/communication/CustomListAction.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/communication/CustomListAction.kt
new file mode 100644
index 0000000000..0b478f5272
--- /dev/null
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/communication/CustomListAction.kt
@@ -0,0 +1,33 @@
+package net.mullvad.mullvadvpn.compose.communication
+
+import android.os.Parcelable
+import kotlinx.parcelize.Parcelize
+
+sealed interface CustomListAction : Parcelable {
+
+ @Parcelize
+ data class Rename(val customListId: String, val name: String, val newName: String) :
+ CustomListAction {
+ fun not() = this.copy(name = newName, newName = name)
+ }
+
+ @Parcelize
+ data class Delete(val customListId: String) : CustomListAction {
+ fun not(name: String, locations: List<String>) = Create(name, locations)
+ }
+
+ @Parcelize
+ data class Create(val name: String = "", val locations: List<String> = emptyList()) :
+ CustomListAction, Parcelable {
+ fun not(customListId: String) = Delete(customListId)
+ }
+
+ @Parcelize
+ data class UpdateLocations(
+ val customListId: String,
+ val locations: List<String> = emptyList()
+ ) : CustomListAction {
+ fun not(locations: List<String>): UpdateLocations =
+ UpdateLocations(customListId = customListId, locations = locations)
+ }
+}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/communication/CustomListResult.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/communication/CustomListResult.kt
new file mode 100644
index 0000000000..32fa077a7f
--- /dev/null
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/communication/CustomListResult.kt
@@ -0,0 +1,34 @@
+package net.mullvad.mullvadvpn.compose.communication
+
+import android.os.Parcelable
+import kotlinx.parcelize.Parcelize
+
+sealed interface CustomListResult : Parcelable {
+ val undo: CustomListAction
+
+ @Parcelize
+ data class Created(
+ val id: String,
+ val name: String,
+ val locationName: String?,
+ override val undo: CustomListAction.Delete
+ ) : CustomListResult
+
+ @Parcelize
+ data class Deleted(override val undo: CustomListAction.Create) : CustomListResult {
+ val name
+ get() = undo.name
+ }
+
+ @Parcelize
+ data class Renamed(override val undo: CustomListAction.Rename) : CustomListResult {
+ val name: String
+ get() = undo.name
+ }
+
+ @Parcelize
+ data class LocationsChanged(
+ val name: String,
+ override val undo: CustomListAction.UpdateLocations
+ ) : CustomListResult
+}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/RelayListUseCase.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/RelayListUseCase.kt
index ab3d93e06e..4957818283 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/RelayListUseCase.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/RelayListUseCase.kt
@@ -44,13 +44,18 @@ class RelayListUseCase(
findSelectedRelayItem(
relaySettings = settings?.relaySettings,
relayCountries = relayCountries,
- customLists = customLists
+ customLists = customLists,
)
RelayList(customLists, relayCountries, selectedItem)
}
fun selectedRelayItem(): Flow<RelayItem?> = relayListWithSelection().map { it.selectedItem }
+ fun relayList(): Flow<List<RelayItem.Country>> = relayListWithSelection().map { it.country }
+
+ fun customLists(): Flow<List<RelayItem.CustomList>> =
+ relayListWithSelection().map { it.customLists }
+
fun fetchRelayList() {
relayListListener.fetchRelayList()
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/customlists/CustomListActionUseCase.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/customlists/CustomListActionUseCase.kt
new file mode 100644
index 0000000000..7b2e5a43aa
--- /dev/null
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/customlists/CustomListActionUseCase.kt
@@ -0,0 +1,117 @@
+package net.mullvad.mullvadvpn.usecase.customlists
+
+import kotlinx.coroutines.flow.firstOrNull
+import net.mullvad.mullvadvpn.compose.communication.CustomListAction
+import net.mullvad.mullvadvpn.compose.communication.CustomListResult
+import net.mullvad.mullvadvpn.model.CreateCustomListResult
+import net.mullvad.mullvadvpn.model.CustomList
+import net.mullvad.mullvadvpn.model.GeographicLocationConstraint
+import net.mullvad.mullvadvpn.model.UpdateCustomListResult
+import net.mullvad.mullvadvpn.relaylist.getRelayItemsByCodes
+import net.mullvad.mullvadvpn.repository.CustomListsRepository
+import net.mullvad.mullvadvpn.usecase.RelayListUseCase
+
+class CustomListActionUseCase(
+ private val customListsRepository: CustomListsRepository,
+ private val relayListUseCase: RelayListUseCase
+) {
+ suspend fun performAction(action: CustomListAction): Result<CustomListResult> {
+ return when (action) {
+ is CustomListAction.Create -> {
+ performAction(action)
+ }
+ is CustomListAction.Rename -> {
+ performAction(action)
+ }
+ is CustomListAction.Delete -> {
+ performAction(action)
+ }
+ is CustomListAction.UpdateLocations -> {
+ performAction(action)
+ }
+ }
+ }
+
+ suspend fun performAction(action: CustomListAction.Rename): Result<CustomListResult.Renamed> =
+ when (
+ val result =
+ customListsRepository.updateCustomListName(action.customListId, action.newName)
+ ) {
+ is UpdateCustomListResult.Ok ->
+ Result.success(CustomListResult.Renamed(undo = action.not()))
+ is UpdateCustomListResult.Error -> Result.failure(CustomListsException(result.error))
+ }
+
+ suspend fun performAction(action: CustomListAction.Create): Result<CustomListResult.Created> =
+ when (val result = customListsRepository.createCustomList(action.name)) {
+ is CreateCustomListResult.Ok -> {
+ if (action.locations.isNotEmpty()) {
+ customListsRepository.updateCustomListLocationsFromCodes(
+ result.id,
+ action.locations
+ )
+ val locationNames =
+ relayListUseCase
+ .relayList()
+ .firstOrNull()
+ ?.getRelayItemsByCodes(action.locations)
+ ?.map { it.name }
+ Result.success(
+ CustomListResult.Created(
+ id = result.id,
+ name = action.name,
+ locationName = locationNames?.first(),
+ undo = action.not(result.id)
+ )
+ )
+ } else {
+ Result.success(
+ CustomListResult.Created(
+ id = result.id,
+ name = action.name,
+ locationName = null,
+ undo = action.not(result.id)
+ )
+ )
+ }
+ }
+ is CreateCustomListResult.Error -> Result.failure(CustomListsException(result.error))
+ }
+
+ fun performAction(action: CustomListAction.Delete): Result<CustomListResult.Deleted> {
+ val customList: CustomList? = customListsRepository.getCustomListById(action.customListId)
+ val oldLocations = customList.locations()
+ val name = customList?.name ?: ""
+ customListsRepository.deleteCustomList(action.customListId)
+ return Result.success(
+ CustomListResult.Deleted(undo = action.not(locations = oldLocations, name = name))
+ )
+ }
+
+ suspend fun performAction(
+ action: CustomListAction.UpdateLocations
+ ): Result<CustomListResult.LocationsChanged> {
+ val customList: CustomList? = customListsRepository.getCustomListById(action.customListId)
+ val oldLocations = customList.locations()
+ val name = customList?.name ?: ""
+ customListsRepository.updateCustomListLocationsFromCodes(
+ action.customListId,
+ action.locations
+ )
+ return Result.success(
+ CustomListResult.LocationsChanged(
+ name = name,
+ undo = action.not(locations = oldLocations)
+ )
+ )
+ }
+
+ private fun CustomList?.locations(): List<String> =
+ this?.locations?.map {
+ when (it) {
+ is GeographicLocationConstraint.City -> it.cityCode
+ is GeographicLocationConstraint.Country -> it.countryCode
+ is GeographicLocationConstraint.Hostname -> it.hostname
+ }
+ } ?: emptyList()
+}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/customlists/CustomListsException.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/customlists/CustomListsException.kt
new file mode 100644
index 0000000000..07c37f7333
--- /dev/null
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/customlists/CustomListsException.kt
@@ -0,0 +1,5 @@
+package net.mullvad.mullvadvpn.usecase.customlists
+
+import net.mullvad.mullvadvpn.model.CustomListsError
+
+class CustomListsException(val error: CustomListsError) : Throwable()