@@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
9
9
import androidx.compose.foundation.layout.padding
10
10
import androidx.compose.foundation.layout.systemBarsPadding
11
11
import androidx.compose.foundation.lazy.LazyColumn
12
+ import androidx.compose.foundation.lazy.LazyItemScope
12
13
import androidx.compose.material3.Icon
13
14
import androidx.compose.material3.IconButton
14
15
import androidx.compose.material3.MaterialTheme
@@ -36,6 +37,7 @@ import net.mullvad.mullvadvpn.compose.button.ApplyButton
36
37
import net.mullvad.mullvadvpn.compose.cell.CheckboxCell
37
38
import net.mullvad.mullvadvpn.compose.cell.ExpandableComposeCell
38
39
import net.mullvad.mullvadvpn.compose.cell.SelectableCell
40
+ import net.mullvad.mullvadvpn.compose.constant.ContentType
39
41
import net.mullvad.mullvadvpn.compose.extensions.itemWithDivider
40
42
import net.mullvad.mullvadvpn.compose.extensions.itemsWithDivider
41
43
import net.mullvad.mullvadvpn.compose.state.RelayFilterState
@@ -102,7 +104,6 @@ fun FilterScreen(
102
104
var ownershipExpanded by rememberSaveable { mutableStateOf(false ) }
103
105
104
106
val backgroundColor = MaterialTheme .colorScheme.background
105
-
106
107
Scaffold (
107
108
modifier = Modifier .background(backgroundColor).systemBarsPadding().fillMaxSize(),
108
109
topBar = {
@@ -127,9 +128,9 @@ fun FilterScreen(
127
128
Box (
128
129
modifier =
129
130
Modifier .fillMaxWidth()
130
- .padding(top = Dimens .screenVerticalMargin)
131
131
.clickable(enabled = false , onClick = onApplyClick)
132
- .background(color = backgroundColor),
132
+ .background(color = backgroundColor)
133
+ .padding(top = Dimens .screenVerticalMargin),
133
134
contentAlignment = Alignment .BottomCenter
134
135
) {
135
136
ApplyButton (
@@ -146,17 +147,33 @@ fun FilterScreen(
146
147
},
147
148
) { contentPadding ->
148
149
LazyColumn (modifier = Modifier .padding(contentPadding).fillMaxSize()) {
149
- itemWithDivider { OwnershipHeader (ownershipExpanded) { ownershipExpanded = it } }
150
+ itemWithDivider(key = Keys .OWNERSHIP_TITLE , contentType = ContentType .HEADER ) {
151
+ OwnershipHeader (ownershipExpanded) { ownershipExpanded = it }
152
+ }
150
153
if (ownershipExpanded) {
151
- item { AnyOwnership (state, onSelectedOwnership) }
152
- itemsWithDivider(state.filteredOwnershipByProviders) { ownership ->
154
+ item(key = Keys .OWNERSHIP_ALL , contentType = ContentType .ITEM ) {
155
+ AnyOwnership (state, onSelectedOwnership)
156
+ }
157
+ itemsWithDivider(
158
+ key = { it.name },
159
+ contentType = { ContentType .ITEM },
160
+ items = state.filteredOwnershipByProviders
161
+ ) { ownership ->
153
162
Ownership (ownership, state, onSelectedOwnership)
154
163
}
155
164
}
156
- itemWithDivider { ProvidersHeader (providerExpanded) { providerExpanded = it } }
165
+ itemWithDivider(key = Keys .PROVIDERS_TITLE , contentType = ContentType .HEADER ) {
166
+ ProvidersHeader (providerExpanded) { providerExpanded = it }
167
+ }
157
168
if (providerExpanded) {
158
- itemWithDivider { AllProviders (state, onAllProviderCheckChange) }
159
- itemsWithDivider(state.filteredProvidersByOwnership) { provider ->
169
+ itemWithDivider(key = Keys .PROVIDERS_ALL , contentType = ContentType .ITEM ) {
170
+ AllProviders (state, onAllProviderCheckChange)
171
+ }
172
+ itemsWithDivider(
173
+ key = { it.providerId.value },
174
+ contentType = { ContentType .ITEM },
175
+ items = state.filteredProvidersByOwnership
176
+ ) { provider ->
160
177
Provider (provider, state, onSelectedProvider)
161
178
}
162
179
}
@@ -165,74 +182,80 @@ fun FilterScreen(
165
182
}
166
183
167
184
@Composable
168
- private fun OwnershipHeader (expanded : Boolean , onToggleExpanded : (Boolean ) -> Unit ) {
185
+ private fun LazyItemScope. OwnershipHeader (expanded : Boolean , onToggleExpanded : (Boolean ) -> Unit ) {
169
186
ExpandableComposeCell (
170
187
title = stringResource(R .string.ownership),
171
188
isExpanded = expanded,
172
189
isEnabled = true ,
173
190
onInfoClicked = null ,
174
- onCellClicked = { onToggleExpanded(! expanded) }
191
+ onCellClicked = { onToggleExpanded(! expanded) },
192
+ modifier = Modifier .animateItem()
175
193
)
176
194
}
177
195
178
196
@Composable
179
- private fun AnyOwnership (
197
+ private fun LazyItemScope. AnyOwnership (
180
198
state : RelayFilterState ,
181
199
onSelectedOwnership : (ownership: Ownership ? ) -> Unit
182
200
) {
183
201
SelectableCell (
184
202
title = stringResource(id = R .string.any),
185
203
isSelected = state.selectedOwnership == null ,
186
- onCellClicked = { onSelectedOwnership(null ) }
204
+ onCellClicked = { onSelectedOwnership(null ) },
205
+ modifier = Modifier .animateItem()
187
206
)
188
207
}
189
208
190
209
@Composable
191
- private fun Ownership (
210
+ private fun LazyItemScope. Ownership (
192
211
ownership : Ownership ,
193
212
state : RelayFilterState ,
194
213
onSelectedOwnership : (ownership: Ownership ? ) -> Unit
195
214
) {
196
215
SelectableCell (
197
216
title = stringResource(id = ownership.stringResource()),
198
217
isSelected = ownership == state.selectedOwnership,
199
- onCellClicked = { onSelectedOwnership(ownership) }
218
+ onCellClicked = { onSelectedOwnership(ownership) },
219
+ modifier = Modifier .animateItem()
200
220
)
201
221
}
202
222
203
223
@Composable
204
- private fun ProvidersHeader (expanded : Boolean , onToggleExpanded : (Boolean ) -> Unit ) {
224
+ private fun LazyItemScope. ProvidersHeader (expanded : Boolean , onToggleExpanded : (Boolean ) -> Unit ) {
205
225
ExpandableComposeCell (
206
226
title = stringResource(R .string.providers),
207
227
isExpanded = expanded,
208
228
isEnabled = true ,
209
229
onInfoClicked = null ,
210
- onCellClicked = { onToggleExpanded(! expanded) }
230
+ onCellClicked = { onToggleExpanded(! expanded) },
231
+ modifier = Modifier .animateItem()
211
232
)
212
233
}
213
234
214
235
@Composable
215
- private fun AllProviders (
236
+ private fun LazyItemScope. AllProviders (
216
237
state : RelayFilterState ,
217
238
onAllProviderCheckChange : (isChecked: Boolean ) -> Unit
218
239
) {
219
240
CheckboxCell (
220
241
title = stringResource(R .string.all_providers),
221
242
checked = state.isAllProvidersChecked,
222
- onCheckedChange = { isChecked -> onAllProviderCheckChange(isChecked) }
243
+ onCheckedChange = { isChecked -> onAllProviderCheckChange(isChecked) },
244
+ modifier = Modifier .animateItem()
223
245
)
224
246
}
225
247
226
248
@Composable
227
- private fun Provider (
249
+ private fun LazyItemScope. Provider (
228
250
provider : Provider ,
229
251
state : RelayFilterState ,
230
252
onSelectedProvider : (checked: Boolean , provider: Provider ) -> Unit
231
253
) {
232
254
CheckboxCell (
233
255
title = provider.providerId.value,
234
256
checked = provider in state.selectedProviders,
235
- onCheckedChange = { checked -> onSelectedProvider(checked, provider) }
257
+ onCheckedChange = { checked -> onSelectedProvider(checked, provider) },
258
+ modifier = Modifier .animateItem()
236
259
)
237
260
}
238
261
@@ -241,3 +264,10 @@ private fun Ownership.stringResource(): Int =
241
264
Ownership .MullvadOwned -> R .string.mullvad_owned_only
242
265
Ownership .Rented -> R .string.rented_only
243
266
}
267
+
268
+ private object Keys {
269
+ const val OWNERSHIP_TITLE = " ownership-title"
270
+ const val OWNERSHIP_ALL = " ownership-all"
271
+ const val PROVIDERS_TITLE = " providers-title"
272
+ const val PROVIDERS_ALL = " providers_all"
273
+ }
0 commit comments