Skip to content

Commit 55a8956

Browse files
committed
Remove one-to-one relationship between provider and ownership
1 parent fed889e commit 55a8956

File tree

20 files changed

+212
-318
lines changed

20 files changed

+212
-318
lines changed

android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/data/DummyRelayItems.kt

+4-5
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import net.mullvad.mullvadvpn.lib.model.CustomListName
66
import net.mullvad.mullvadvpn.lib.model.GeoLocationId
77
import net.mullvad.mullvadvpn.lib.model.Ownership
88
import net.mullvad.mullvadvpn.lib.model.PortRange
9-
import net.mullvad.mullvadvpn.lib.model.Provider
109
import net.mullvad.mullvadvpn.lib.model.ProviderId
1110
import net.mullvad.mullvadvpn.lib.model.RelayItem
1211
import net.mullvad.mullvadvpn.lib.model.RelayList
@@ -20,8 +19,8 @@ private val DUMMY_RELAY_1 =
2019
"Relay host 1",
2120
),
2221
active = true,
23-
provider =
24-
Provider(providerId = ProviderId("PROVIDER RENTED"), ownership = Ownership.Rented),
22+
provider = ProviderId("PROVIDER RENTED"),
23+
ownership = Ownership.Rented,
2524
daita = false,
2625
)
2726
private val DUMMY_RELAY_2 =
@@ -32,8 +31,8 @@ private val DUMMY_RELAY_2 =
3231
"Relay host 2",
3332
),
3433
active = true,
35-
provider =
36-
Provider(providerId = ProviderId("PROVIDER OWNED"), ownership = Ownership.MullvadOwned),
34+
provider = ProviderId("PROVIDER OWNED"),
35+
ownership = Ownership.MullvadOwned,
3736
daita = false,
3837
)
3938
private val DUMMY_RELAY_CITY_1 =

android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/FilterScreenTest.kt

+27-48
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import net.mullvad.mullvadvpn.compose.createEdgeToEdgeComposeExtension
1111
import net.mullvad.mullvadvpn.compose.setContentWithTheme
1212
import net.mullvad.mullvadvpn.compose.state.RelayFilterUiState
1313
import net.mullvad.mullvadvpn.lib.model.Ownership
14-
import net.mullvad.mullvadvpn.lib.model.Provider
1514
import net.mullvad.mullvadvpn.lib.model.ProviderId
1615
import org.junit.jupiter.api.Test
1716
import org.junit.jupiter.api.extension.RegisterExtension
@@ -30,7 +29,7 @@ class FilterScreenTest {
3029
onApplyClick: () -> Unit = {},
3130
onSelectedOwnership: (ownership: Ownership?) -> Unit = {},
3231
onAllProviderCheckChange: (isChecked: Boolean) -> Unit = {},
33-
onSelectedProvider: (checked: Boolean, provider: Provider) -> Unit = { _, _ -> },
32+
onSelectedProvider: (checked: Boolean, provider: ProviderId) -> Unit = { _, _ -> },
3433
) {
3534
setContentWithTheme {
3635
FilterScreen(
@@ -50,7 +49,7 @@ class FilterScreenTest {
5049
initScreen(
5150
state =
5251
RelayFilterUiState(
53-
allProviders = DUMMY_RELAY_ALL_PROVIDERS,
52+
providerToOwnerships = DUMMY_RELAY_ALL_PROVIDERS,
5453
selectedOwnership = null,
5554
selectedProviders = DUMMY_SELECTED_PROVIDERS,
5655
)
@@ -65,7 +64,7 @@ class FilterScreenTest {
6564
initScreen(
6665
state =
6766
RelayFilterUiState(
68-
allProviders = DUMMY_RELAY_ALL_PROVIDERS,
67+
providerToOwnerships = DUMMY_RELAY_ALL_PROVIDERS,
6968
selectedOwnership = null,
7069
selectedProviders = DUMMY_SELECTED_PROVIDERS,
7170
)
@@ -80,7 +79,7 @@ class FilterScreenTest {
8079
initScreen(
8180
state =
8281
RelayFilterUiState(
83-
allProviders = DUMMY_RELAY_ALL_PROVIDERS,
82+
providerToOwnerships = DUMMY_RELAY_ALL_PROVIDERS,
8483
selectedOwnership = Ownership.MullvadOwned,
8584
selectedProviders = DUMMY_SELECTED_PROVIDERS,
8685
)
@@ -95,7 +94,7 @@ class FilterScreenTest {
9594
initScreen(
9695
state =
9796
RelayFilterUiState(
98-
allProviders = DUMMY_RELAY_ALL_PROVIDERS,
97+
providerToOwnerships = DUMMY_RELAY_ALL_PROVIDERS,
9998
selectedOwnership = Ownership.Rented,
10099
selectedProviders = DUMMY_SELECTED_PROVIDERS,
101100
)
@@ -110,7 +109,7 @@ class FilterScreenTest {
110109
initScreen(
111110
state =
112111
RelayFilterUiState(
113-
allProviders = DUMMY_RELAY_ALL_PROVIDERS,
112+
providerToOwnerships = DUMMY_RELAY_ALL_PROVIDERS,
114113
selectedOwnership = null,
115114
selectedProviders = DUMMY_SELECTED_PROVIDERS,
116115
)
@@ -128,10 +127,9 @@ class FilterScreenTest {
128127
initScreen(
129128
state =
130129
RelayFilterUiState(
131-
allProviders = listOf(),
130+
providerToOwnerships = DUMMY_RELAY_ALL_PROVIDERS,
132131
selectedOwnership = null,
133-
selectedProviders =
134-
listOf(Provider(ProviderId("31173"), Ownership.MullvadOwned)),
132+
selectedProviders = listOf(ProviderId("31173")),
135133
),
136134
onApplyClick = mockClickListener,
137135
)
@@ -141,45 +139,26 @@ class FilterScreenTest {
141139

142140
companion object {
143141
private val DUMMY_RELAY_ALL_PROVIDERS =
144-
listOf(
145-
Provider(ProviderId("31173"), Ownership.MullvadOwned),
146-
Provider(ProviderId("100TB"), Ownership.Rented),
147-
Provider(ProviderId("Blix"), Ownership.MullvadOwned),
148-
Provider(ProviderId("Creanova"), Ownership.MullvadOwned),
149-
Provider(ProviderId("DataPacket"), Ownership.Rented),
150-
Provider(ProviderId("HostRoyale"), Ownership.Rented),
151-
Provider(ProviderId("hostuniversal"), Ownership.Rented),
152-
Provider(ProviderId("iRegister"), Ownership.Rented),
153-
Provider(ProviderId("M247"), Ownership.Rented),
154-
Provider(ProviderId("Makonix"), Ownership.Rented),
155-
Provider(ProviderId("PrivateLayer"), Ownership.Rented),
156-
Provider(ProviderId("ptisp"), Ownership.Rented),
157-
Provider(ProviderId("Qnax"), Ownership.Rented),
158-
Provider(ProviderId("Quadranet"), Ownership.Rented),
159-
Provider(ProviderId("techfutures"), Ownership.Rented),
160-
Provider(ProviderId("Tzulo"), Ownership.Rented),
161-
Provider(ProviderId("xtom"), Ownership.Rented),
142+
mapOf(
143+
ProviderId("31173") to setOf(Ownership.MullvadOwned),
144+
ProviderId("100TB") to setOf(Ownership.Rented),
145+
ProviderId("Blix") to setOf(Ownership.MullvadOwned),
146+
ProviderId("Creanova") to setOf(Ownership.MullvadOwned),
147+
ProviderId("DataPacket") to setOf(Ownership.Rented),
148+
ProviderId("HostRoyale") to setOf(Ownership.Rented),
149+
ProviderId("hostuniversal") to setOf(Ownership.Rented),
150+
ProviderId("iRegister") to setOf(Ownership.Rented),
151+
ProviderId("M247") to setOf(Ownership.Rented),
152+
ProviderId("Makonix") to setOf(Ownership.Rented),
153+
ProviderId("PrivateLayer") to setOf(Ownership.Rented),
154+
ProviderId("ptisp") to setOf(Ownership.Rented),
155+
ProviderId("Qnax") to setOf(Ownership.Rented),
156+
ProviderId("Quadranet") to setOf(Ownership.Rented),
157+
ProviderId("techfutures") to setOf(Ownership.Rented),
158+
ProviderId("Tzulo") to setOf(Ownership.Rented),
159+
ProviderId("xtom") to setOf(Ownership.Rented),
162160
)
163161

164-
private val DUMMY_SELECTED_PROVIDERS =
165-
listOf(
166-
Provider(ProviderId("31173"), Ownership.MullvadOwned),
167-
Provider(ProviderId("100TB"), Ownership.Rented),
168-
Provider(ProviderId("Blix"), Ownership.MullvadOwned),
169-
Provider(ProviderId("Creanova"), Ownership.MullvadOwned),
170-
Provider(ProviderId("DataPacket"), Ownership.Rented),
171-
Provider(ProviderId("HostRoyale"), Ownership.Rented),
172-
Provider(ProviderId("hostuniversal"), Ownership.Rented),
173-
Provider(ProviderId("iRegister"), Ownership.Rented),
174-
Provider(ProviderId("M247"), Ownership.Rented),
175-
Provider(ProviderId("Makonix"), Ownership.Rented),
176-
Provider(ProviderId("PrivateLayer"), Ownership.Rented),
177-
Provider(ProviderId("ptisp"), Ownership.Rented),
178-
Provider(ProviderId("Qnax"), Ownership.Rented),
179-
Provider(ProviderId("Quadranet"), Ownership.Rented),
180-
Provider(ProviderId("techfutures"), Ownership.Rented),
181-
Provider(ProviderId("Tzulo"), Ownership.Rented),
182-
Provider(ProviderId("xtom"), Ownership.Rented),
183-
)
162+
private val DUMMY_SELECTED_PROVIDERS = DUMMY_RELAY_ALL_PROVIDERS.keys.toList()
184163
}
185164
}

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

+3-5
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,17 @@ package net.mullvad.mullvadvpn.compose.preview
33
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
44
import net.mullvad.mullvadvpn.compose.state.RelayFilterUiState
55
import net.mullvad.mullvadvpn.lib.model.Ownership
6-
import net.mullvad.mullvadvpn.lib.model.Provider
76
import net.mullvad.mullvadvpn.lib.model.ProviderId
87

9-
private val PROVIDER =
10-
Provider(providerId = ProviderId("provider1"), ownership = Ownership.MullvadOwned)
8+
private val PROVIDER_TO_OWNERSHIPS = mapOf(ProviderId("provider1") to setOf(Ownership.MullvadOwned))
119

1210
class FilterUiStatePreviewParameterProvider : PreviewParameterProvider<RelayFilterUiState> {
1311
override val values =
1412
sequenceOf(
1513
RelayFilterUiState(
14+
providerToOwnerships = PROVIDER_TO_OWNERSHIPS,
1615
selectedOwnership = Ownership.MullvadOwned,
17-
allProviders = listOf(PROVIDER),
18-
selectedProviders = listOf(PROVIDER),
16+
selectedProviders = PROVIDER_TO_OWNERSHIPS.keys.toList(),
1917
)
2018
)
2119
}

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/preview/SelectLocationsUiStatePreviewParameterProvider.kt

-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ package net.mullvad.mullvadvpn.compose.preview
33
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
44
import net.mullvad.mullvadvpn.compose.state.RelayListType
55
import net.mullvad.mullvadvpn.compose.state.SelectLocationUiState
6-
import net.mullvad.mullvadvpn.lib.model.Ownership
7-
import net.mullvad.mullvadvpn.lib.model.Provider
86
import net.mullvad.mullvadvpn.usecase.FilterChip
97
import net.mullvad.mullvadvpn.usecase.ModelOwnership
108

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

+10-10
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ import net.mullvad.mullvadvpn.compose.state.RelayFilterUiState
4646
import net.mullvad.mullvadvpn.compose.transitions.SlideInFromRightTransition
4747
import net.mullvad.mullvadvpn.compose.util.CollectSideEffectWithLifecycle
4848
import net.mullvad.mullvadvpn.lib.model.Ownership
49-
import net.mullvad.mullvadvpn.lib.model.Provider
49+
import net.mullvad.mullvadvpn.lib.model.ProviderId
5050
import net.mullvad.mullvadvpn.lib.theme.AppTheme
5151
import net.mullvad.mullvadvpn.lib.theme.Dimens
5252
import net.mullvad.mullvadvpn.viewmodel.FilterScreenSideEffect
@@ -98,7 +98,7 @@ fun FilterScreen(
9898
onApplyClick: () -> Unit,
9999
onSelectedOwnership: (ownership: Ownership?) -> Unit,
100100
onAllProviderCheckChange: (isChecked: Boolean) -> Unit,
101-
onSelectedProvider: (checked: Boolean, provider: Provider) -> Unit,
101+
onSelectedProvider: (checked: Boolean, provider: ProviderId) -> Unit,
102102
) {
103103
var providerExpanded by rememberSaveable { mutableStateOf(false) }
104104
var ownershipExpanded by rememberSaveable { mutableStateOf(false) }
@@ -126,7 +126,7 @@ fun FilterScreen(
126126
itemsWithDivider(
127127
key = { it.name },
128128
contentType = { ContentType.ITEM },
129-
items = state.filteredOwnershipByProviders,
129+
items = state.selectableOwnerships,
130130
) { ownership ->
131131
Ownership(ownership, state, onSelectedOwnership)
132132
}
@@ -139,9 +139,9 @@ fun FilterScreen(
139139
AllProviders(state, onAllProviderCheckChange)
140140
}
141141
itemsWithDivider(
142-
key = { it.providerId.value },
142+
key = { it.value },
143143
contentType = { ContentType.ITEM },
144-
items = state.filteredProvidersByOwnership,
144+
items = state.selectableProviders,
145145
) { provider ->
146146
Provider(provider, state, onSelectedProvider)
147147
}
@@ -216,14 +216,14 @@ private fun LazyItemScope.AllProviders(
216216

217217
@Composable
218218
private fun LazyItemScope.Provider(
219-
provider: Provider,
219+
providerId: ProviderId,
220220
state: RelayFilterUiState,
221-
onSelectedProvider: (checked: Boolean, provider: Provider) -> Unit,
221+
onSelectedProvider: (checked: Boolean, providerId: ProviderId) -> Unit,
222222
) {
223223
CheckboxCell(
224-
title = provider.providerId.value,
225-
checked = provider in state.selectedProviders,
226-
onCheckedChange = { checked -> onSelectedProvider(checked, provider) },
224+
title = providerId.value,
225+
checked = providerId in state.selectedProviders,
226+
onCheckedChange = { checked -> onSelectedProvider(checked, providerId) },
227227
modifier = Modifier.animateItem(),
228228
)
229229
}

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

+5-8
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package net.mullvad.mullvadvpn.compose.state
22

33
import net.mullvad.mullvadvpn.lib.model.Constraint
44
import net.mullvad.mullvadvpn.lib.model.Ownership
5-
import net.mullvad.mullvadvpn.lib.model.Provider
5+
import net.mullvad.mullvadvpn.lib.model.ProviderId
66
import net.mullvad.mullvadvpn.lib.model.Providers
77

88
fun Ownership?.toOwnershipConstraint(): Constraint<Ownership> =
@@ -11,18 +11,15 @@ fun Ownership?.toOwnershipConstraint(): Constraint<Ownership> =
1111
else -> Constraint.Only(this)
1212
}
1313

14-
fun Constraint<Providers>.toSelectedProviders(allProviders: List<Provider>): List<Provider> =
14+
fun Constraint<Providers>.toSelectedProviders(allProviders: List<ProviderId>): List<ProviderId> =
1515
when (this) {
1616
Constraint.Any -> allProviders
17-
is Constraint.Only ->
18-
value.providers.toList().mapNotNull { provider ->
19-
allProviders.firstOrNull { it.providerId == provider }
20-
}
17+
is Constraint.Only -> value.providers.toList()
2118
}
2219

23-
fun List<Provider>.toConstraintProviders(allProviders: List<Provider>): Constraint<Providers> =
20+
fun List<ProviderId>.toConstraintProviders(allProviders: List<ProviderId>): Constraint<Providers> =
2421
if (size == allProviders.size) {
2522
Constraint.Any
2623
} else {
27-
Constraint.Only(Providers(map { provider -> provider.providerId }.toHashSet()))
24+
Constraint.Only(Providers(toHashSet()))
2825
}
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,33 @@
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+
private val providerToOwnerships: Map<ProviderId, Set<Ownership>> = emptyMap(),
78
val selectedOwnership: Ownership? = null,
8-
val allProviders: List<Provider> = emptyList(),
9-
val selectedProviders: List<Provider> = allProviders,
9+
val selectedProviders: List<ProviderId> = emptyList(),
1010
) {
11-
val isApplyButtonEnabled = selectedProviders.isNotEmpty()
12-
13-
val filteredOwnershipByProviders =
11+
val selectableOwnerships: List<Ownership> =
1412
if (selectedProviders.isEmpty()) {
15-
Ownership.entries
16-
} else {
17-
Ownership.entries.filter { ownership ->
18-
selectedProviders.any { provider -> provider.ownership == ownership }
13+
Ownership.entries
14+
} else {
15+
providerToOwnerships
16+
.filterKeys { it in selectedProviders }
17+
.values
18+
.flatten()
19+
.distinct()
1920
}
20-
}
21-
val filteredProvidersByOwnership =
22-
if (selectedOwnership == null) allProviders
23-
else allProviders.filter { provider -> provider.ownership == selectedOwnership }
21+
.sorted()
22+
23+
val selectableProviders: List<ProviderId> =
24+
if (selectedOwnership != null)
25+
providerToOwnerships.filterValues { selectedOwnership in it }.keys.toList()
26+
else providerToOwnerships.keys.toList()
27+
28+
val allProviders: List<ProviderId> = providerToOwnerships.keys.toList()
29+
30+
val isApplyButtonEnabled = selectedProviders.isNotEmpty()
2431

2532
val isAllProvidersChecked = allProviders.size == selectedProviders.size
2633
}

android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ import net.mullvad.mullvadvpn.ui.MainActivity
3737
import net.mullvad.mullvadvpn.ui.serviceconnection.AppVersionInfoRepository
3838
import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionManager
3939
import net.mullvad.mullvadvpn.usecase.AccountExpiryInAppNotificationUseCase
40-
import net.mullvad.mullvadvpn.usecase.AvailableProvidersUseCase
4140
import net.mullvad.mullvadvpn.usecase.EmptyPaymentUseCase
4241
import net.mullvad.mullvadvpn.usecase.FilterChipUseCase
4342
import net.mullvad.mullvadvpn.usecase.FilteredRelayListUseCase
@@ -47,6 +46,7 @@ import net.mullvad.mullvadvpn.usecase.NewDeviceNotificationUseCase
4746
import net.mullvad.mullvadvpn.usecase.OutOfTimeUseCase
4847
import net.mullvad.mullvadvpn.usecase.PaymentUseCase
4948
import net.mullvad.mullvadvpn.usecase.PlayPaymentUseCase
49+
import net.mullvad.mullvadvpn.usecase.ProviderToOwnershipsUseCase
5050
import net.mullvad.mullvadvpn.usecase.SelectedLocationTitleUseCase
5151
import net.mullvad.mullvadvpn.usecase.SelectedLocationUseCase
5252
import net.mullvad.mullvadvpn.usecase.SystemVpnSettingsAvailableUseCase
@@ -156,7 +156,7 @@ val uiModule = module {
156156
single { SystemVpnSettingsAvailableUseCase(androidContext()) }
157157
single { CustomListActionUseCase(get(), get()) }
158158
single { SelectedLocationTitleUseCase(get(), get()) }
159-
single { AvailableProvidersUseCase(get()) }
159+
single { ProviderToOwnershipsUseCase(get()) }
160160
single { FilterCustomListsRelayItemUseCase(get(), get(), get(), get()) }
161161
single { CustomListsRelayItemUseCase(get(), get()) }
162162
single { CustomListRelayItemsUseCase(get(), get()) }

0 commit comments

Comments
 (0)