Skip to content

Commit f041976

Browse files
committed
Disconnect provider and ownership
1 parent 1e100f9 commit f041976

File tree

12 files changed

+73
-60
lines changed

12 files changed

+73
-60
lines changed

android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/FilterUiStatePreviewParameterProvider.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ import net.mullvad.mullvadvpn.lib.model.Provider
77
import net.mullvad.mullvadvpn.lib.model.ProviderId
88

99
private val PROVIDER =
10-
Provider(providerId = ProviderId("provider1"), ownership = Ownership.MullvadOwned)
10+
Provider(providerId = ProviderId("provider1"), ownership = setOf(Ownership.MullvadOwned))
1111

1212
class FilterUiStatePreviewParameterProvider : PreviewParameterProvider<RelayFilterUiState> {
1313
override val values =
1414
sequenceOf(
1515
RelayFilterUiState(
1616
selectedOwnership = Ownership.MullvadOwned,
17-
allProviders = listOf(PROVIDER),
18-
selectedProviders = listOf(PROVIDER),
17+
filteredProvidersByOwnership = listOf(PROVIDER.providerId),
18+
selectedProviders = listOf(PROVIDER.providerId),
1919
)
2020
)
2121
}

android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/RelayItemPreviewData.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package net.mullvad.mullvadvpn.compose.preview
22

33
import net.mullvad.mullvadvpn.lib.model.GeoLocationId
44
import net.mullvad.mullvadvpn.lib.model.Ownership
5-
import net.mullvad.mullvadvpn.lib.model.Provider
65
import net.mullvad.mullvadvpn.lib.model.ProviderId
76
import net.mullvad.mullvadvpn.lib.model.RelayItem
87

@@ -56,7 +55,8 @@ private fun generateRelayItemRelay(
5655
RelayItem.Location.Relay(
5756
id = GeoLocationId.Hostname(city = cityCode, code = hostName),
5857
active = active,
59-
provider = Provider(ProviderId("Provider"), Ownership.MullvadOwned),
58+
provider = ProviderId("Provider"),
59+
ownership = Ownership.MullvadOwned,
6060
daita = daita,
6161
)
6262

android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/FilterScreen.kt

+8-7
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import net.mullvad.mullvadvpn.compose.transitions.SlideInFromRightTransition
4747
import net.mullvad.mullvadvpn.compose.util.CollectSideEffectWithLifecycle
4848
import net.mullvad.mullvadvpn.lib.model.Ownership
4949
import net.mullvad.mullvadvpn.lib.model.Provider
50+
import net.mullvad.mullvadvpn.lib.model.ProviderId
5051
import net.mullvad.mullvadvpn.lib.theme.AppTheme
5152
import net.mullvad.mullvadvpn.lib.theme.Dimens
5253
import net.mullvad.mullvadvpn.viewmodel.FilterScreenSideEffect
@@ -98,7 +99,7 @@ fun FilterScreen(
9899
onApplyClick: () -> Unit,
99100
onSelectedOwnership: (ownership: Ownership?) -> Unit,
100101
onAllProviderCheckChange: (isChecked: Boolean) -> Unit,
101-
onSelectedProvider: (checked: Boolean, provider: Provider) -> Unit,
102+
onSelectedProvider: (checked: Boolean, provider: ProviderId) -> Unit,
102103
) {
103104
var providerExpanded by rememberSaveable { mutableStateOf(false) }
104105
var ownershipExpanded by rememberSaveable { mutableStateOf(false) }
@@ -139,7 +140,7 @@ fun FilterScreen(
139140
AllProviders(state, onAllProviderCheckChange)
140141
}
141142
itemsWithDivider(
142-
key = { it.providerId.value },
143+
key = { it.value },
143144
contentType = { ContentType.ITEM },
144145
items = state.filteredProvidersByOwnership,
145146
) { provider ->
@@ -216,14 +217,14 @@ private fun LazyItemScope.AllProviders(
216217

217218
@Composable
218219
private fun LazyItemScope.Provider(
219-
provider: Provider,
220+
providerId: ProviderId,
220221
state: RelayFilterUiState,
221-
onSelectedProvider: (checked: Boolean, provider: Provider) -> Unit,
222+
onSelectedProvider: (checked: Boolean, providerId: ProviderId) -> Unit,
222223
) {
223224
CheckboxCell(
224-
title = provider.providerId.value,
225-
checked = provider in state.selectedProviders,
226-
onCheckedChange = { checked -> onSelectedProvider(checked, provider) },
225+
title = providerId.value,
226+
checked = providerId in state.selectedProviders,
227+
onCheckedChange = { checked -> onSelectedProvider(checked, providerId) },
227228
modifier = Modifier.animateItem(),
228229
)
229230
}

android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/FilterConstrainExtensions.kt

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package net.mullvad.mullvadvpn.compose.state
33
import net.mullvad.mullvadvpn.lib.model.Constraint
44
import net.mullvad.mullvadvpn.lib.model.Ownership
55
import net.mullvad.mullvadvpn.lib.model.Provider
6+
import net.mullvad.mullvadvpn.lib.model.ProviderId
67
import net.mullvad.mullvadvpn.lib.model.Providers
78

89
fun Ownership?.toOwnershipConstraint(): Constraint<Ownership> =
@@ -20,9 +21,9 @@ fun Constraint<Providers>.toSelectedProviders(allProviders: List<Provider>): Lis
2021
}
2122
}
2223

23-
fun List<Provider>.toConstraintProviders(allProviders: List<Provider>): Constraint<Providers> =
24+
fun List<ProviderId>.toConstraintProviders(allProviders: List<ProviderId>): Constraint<Providers> =
2425
if (size == allProviders.size) {
2526
Constraint.Any
2627
} else {
27-
Constraint.Only(Providers(map { provider -> provider.providerId }.toHashSet()))
28+
Constraint.Only(Providers(toHashSet()))
2829
}
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,16 @@
11
package net.mullvad.mullvadvpn.compose.state
22

33
import net.mullvad.mullvadvpn.lib.model.Ownership
4-
import net.mullvad.mullvadvpn.lib.model.Provider
4+
import net.mullvad.mullvadvpn.lib.model.ProviderId
55

66
data class RelayFilterUiState(
7+
val filteredOwnershipByProviders: List<Ownership> = Ownership.entries,
78
val selectedOwnership: Ownership? = null,
8-
val allProviders: List<Provider> = emptyList(),
9-
val selectedProviders: List<Provider> = allProviders,
9+
val filteredProvidersByOwnership: List<ProviderId> = listOf(),
10+
val allProviders: List<ProviderId> = emptyList(),
11+
val selectedProviders: List<ProviderId> = filteredProvidersByOwnership,
1012
) {
1113
val isApplyButtonEnabled = selectedProviders.isNotEmpty()
1214

13-
val filteredOwnershipByProviders =
14-
if (selectedProviders.isEmpty()) {
15-
Ownership.entries
16-
} else {
17-
Ownership.entries.filter { ownership ->
18-
selectedProviders.any { provider -> provider.ownership == ownership }
19-
}
20-
}
21-
val filteredProvidersByOwnership =
22-
if (selectedOwnership == null) allProviders
23-
else allProviders.filter { provider -> provider.ownership == selectedOwnership }
24-
2515
val isAllProvidersChecked = allProviders.size == selectedProviders.size
2616
}

android/app/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemExtensions.kt

+2-3
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ private fun RelayItem.Location.hasOwnership(ownershipConstraint: Constraint<Owne
3535
when (this) {
3636
is RelayItem.Location.Country -> cities.any { it.hasOwnership(ownershipConstraint) }
3737
is RelayItem.Location.City -> relays.any { it.hasOwnership(ownershipConstraint) }
38-
is RelayItem.Location.Relay -> this.provider.ownership == ownershipConstraint.value
38+
is RelayItem.Location.Relay -> ownershipConstraint.value == ownership
3939
}
4040
} else {
4141
true
@@ -46,8 +46,7 @@ private fun RelayItem.Location.hasProvider(providersConstraint: Constraint<Provi
4646
when (this) {
4747
is RelayItem.Location.Country -> cities.any { it.hasProvider(providersConstraint) }
4848
is RelayItem.Location.City -> relays.any { it.hasProvider(providersConstraint) }
49-
is RelayItem.Location.Relay ->
50-
providersConstraint.value.providers.contains(provider.providerId)
49+
is RelayItem.Location.Relay -> providersConstraint.value.providers.contains(provider)
5150
}
5251
} else {
5352
true

android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/AvailableProvidersUseCase.kt

+3-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ class AvailableProvidersUseCase(private val relayListRepository: RelayListReposi
1313
relayList
1414
.flatMap(RelayItem.Location.Country::cities)
1515
.flatMap(RelayItem.Location.City::relays)
16-
.map(RelayItem.Location.Relay::provider)
17-
.distinct()
16+
.groupBy({ it.provider }, { it.ownership })
17+
.map { (provider, ownerships) -> Provider(provider, ownerships.toSet()) }
18+
.sortedBy { it.providerId.value.uppercase() }
1819
}
1920
}

android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/FilterChipUseCase.kt

+5-2
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,11 @@ class FilterChipUseCase(
8787
selectedProviders: List<Provider>,
8888
selectedOwnership: Ownership?,
8989
): List<Provider> =
90-
if (selectedOwnership == null) selectedProviders
91-
else selectedProviders.filter { it.ownership == selectedOwnership }
90+
if (selectedOwnership != null) {
91+
selectedProviders.filter { it.ownership.contains(selectedOwnership) }
92+
} else {
93+
selectedProviders
94+
}
9295

9396
private fun Settings.daitaAndDirectOnly() =
9497
tunnelOptions.wireguard.daitaSettings.enabled &&

android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/FilterViewModel.kt

+31-16
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import net.mullvad.mullvadvpn.compose.state.toConstraintProviders
1616
import net.mullvad.mullvadvpn.compose.state.toOwnershipConstraint
1717
import net.mullvad.mullvadvpn.compose.state.toSelectedProviders
1818
import net.mullvad.mullvadvpn.lib.model.Ownership
19-
import net.mullvad.mullvadvpn.lib.model.Provider
19+
import net.mullvad.mullvadvpn.lib.model.ProviderId
2020
import net.mullvad.mullvadvpn.repository.RelayListFilterRepository
2121
import net.mullvad.mullvadvpn.usecase.AvailableProvidersUseCase
2222

@@ -28,15 +28,17 @@ class FilterViewModel(
2828
val uiSideEffect = _uiSideEffect.receiveAsFlow()
2929

3030
private val selectedOwnership = MutableStateFlow<Ownership?>(null)
31-
private val selectedProviders = MutableStateFlow<List<Provider>>(emptyList())
31+
private val selectedProviders = MutableStateFlow<List<ProviderId>>(emptyList())
3232

3333
init {
3434
viewModelScope.launch {
3535
selectedProviders.value =
3636
combine(availableProvidersUseCase(), relayListFilterRepository.selectedProviders) {
3737
allProviders,
3838
selectedConstraintProviders ->
39-
selectedConstraintProviders.toSelectedProviders(allProviders)
39+
selectedConstraintProviders.toSelectedProviders(allProviders).map {
40+
it.providerId
41+
}
4042
}
4143
.first()
4244

@@ -51,26 +53,36 @@ class FilterViewModel(
5153
allProviders,
5254
selectedProviders ->
5355
RelayFilterUiState(
56+
filteredOwnershipByProviders =
57+
if (selectedProviders.isEmpty()) {
58+
Ownership.entries
59+
} else {
60+
Ownership.entries.filter { ownership ->
61+
selectedProviders.any { providerId ->
62+
allProviders.any {
63+
it.providerId == providerId && ownership in it.ownership
64+
}
65+
}
66+
}
67+
},
5468
selectedOwnership = selectedOwnership,
55-
allProviders = allProviders,
69+
filteredProvidersByOwnership =
70+
if (selectedOwnership != null)
71+
allProviders
72+
.filter { provider -> selectedOwnership in provider.ownership }
73+
.map { it.providerId }
74+
else allProviders.map { it.providerId },
75+
allProviders = allProviders.map { it.providerId },
5676
selectedProviders = selectedProviders,
5777
)
5878
}
59-
.stateIn(
60-
viewModelScope,
61-
SharingStarted.WhileSubscribed(),
62-
RelayFilterUiState(
63-
allProviders = emptyList(),
64-
selectedOwnership = null,
65-
selectedProviders = emptyList(),
66-
),
67-
)
79+
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), RelayFilterUiState())
6880

6981
fun setSelectedOwnership(ownership: Ownership?) {
7082
selectedOwnership.value = ownership
7183
}
7284

73-
fun setSelectedProvider(checked: Boolean, provider: Provider) {
85+
fun setSelectedProvider(checked: Boolean, provider: ProviderId) {
7486
selectedProviders.value =
7587
if (checked) {
7688
selectedProviders.value + provider
@@ -83,7 +95,7 @@ class FilterViewModel(
8395
viewModelScope.launch {
8496
selectedProviders.value =
8597
if (isChecked) {
86-
availableProvidersUseCase().first()
98+
availableProvidersUseCase().first().map { it.providerId }
8799
} else {
88100
emptyList()
89101
}
@@ -92,8 +104,11 @@ class FilterViewModel(
92104

93105
fun onApplyButtonClicked() {
94106
val newSelectedOwnership = selectedOwnership.value.toOwnershipConstraint()
107+
// TODO should be all providers?!
95108
val newSelectedProviders =
96-
selectedProviders.value.toConstraintProviders(uiState.value.allProviders)
109+
selectedProviders.value.toConstraintProviders(
110+
uiState.value.filteredProvidersByOwnership
111+
)
97112

98113
viewModelScope.launch {
99114
relayListFilterRepository.updateSelectedOwnershipAndProviderFilter(

android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/ToDomain.kt

+2-6
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ import net.mullvad.mullvadvpn.lib.model.ParameterGenerationError
5252
import net.mullvad.mullvadvpn.lib.model.PlayPurchasePaymentToken
5353
import net.mullvad.mullvadvpn.lib.model.Port
5454
import net.mullvad.mullvadvpn.lib.model.PortRange
55-
import net.mullvad.mullvadvpn.lib.model.Provider
5655
import net.mullvad.mullvadvpn.lib.model.ProviderId
5756
import net.mullvad.mullvadvpn.lib.model.Providers
5857
import net.mullvad.mullvadvpn.lib.model.QuantumResistantState
@@ -565,11 +564,8 @@ internal fun ManagementInterface.Relay.toDomain(
565564
RelayItem.Location.Relay(
566565
id = GeoLocationId.Hostname(cityCode, hostname),
567566
active = active,
568-
provider =
569-
Provider(
570-
ProviderId(provider),
571-
ownership = if (owned) Ownership.MullvadOwned else Ownership.Rented,
572-
),
567+
provider = ProviderId(provider),
568+
ownership = if (owned) Ownership.MullvadOwned else Ownership.Rented,
573569
daita =
574570
if (
575571
hasEndpointData() && endpointType == ManagementInterface.Relay.RelayType.WIREGUARD
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
package net.mullvad.mullvadvpn.lib.model
22

3-
data class Provider(val providerId: ProviderId, val ownership: Ownership)
3+
import android.os.Parcelable
4+
import kotlinx.parcelize.Parcelize
5+
import kotlinx.parcelize.RawValue
6+
7+
@Parcelize
8+
data class Provider(val providerId: @RawValue ProviderId, val ownership: Set<Ownership>) :
9+
Parcelable

android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/RelayItem.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ sealed interface RelayItem {
5656
@optics
5757
data class Relay(
5858
override val id: GeoLocationId.Hostname,
59-
val provider: Provider,
59+
val provider: ProviderId,
60+
val ownership: Ownership,
6061
override val active: Boolean,
6162
val daita: Boolean,
6263
) : Location {

0 commit comments

Comments
 (0)