Skip to content

Commit 17a8988

Browse files
committed
Add animations to filter screen
1 parent 7af6b25 commit 17a8988

File tree

3 files changed

+55
-22
lines changed

3 files changed

+55
-22
lines changed

Diff for: android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ExpandableComposeCell.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ private fun PreviewExpandedEnabledExpandableComposeCell() {
4646
fun ExpandableComposeCell(
4747
title: String,
4848
isExpanded: Boolean,
49+
modifier: Modifier = Modifier,
4950
isEnabled: Boolean = true,
5051
testTag: String = "",
5152
onCellClicked: (Boolean) -> Unit = {},
@@ -55,7 +56,7 @@ fun ExpandableComposeCell(
5556
val bodyViewModifier = Modifier
5657

5758
BaseCell(
58-
modifier = Modifier.testTag(testTag).focusProperties { canFocus = false },
59+
modifier = modifier.testTag(testTag).focusProperties { canFocus = false },
5960
headlineContent = {
6061
BaseCellTitle(
6162
title = title,

Diff for: android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SelectableCell.kt

+2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ private fun PreviewSelectableCell() {
3737
fun SelectableCell(
3838
title: String,
3939
isSelected: Boolean,
40+
modifier: Modifier = Modifier,
4041
isEnabled: Boolean = true,
4142
iconContentDescription: String? = null,
4243
selectedIcon: @Composable RowScope.() -> Unit = {
@@ -60,6 +61,7 @@ fun SelectableCell(
6061
testTag: String = ""
6162
) {
6263
BaseCell(
64+
modifier = modifier,
6365
onCellClicked = onCellClicked,
6466
isRowEnabled = isEnabled,
6567
headlineContent = {

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

+51-21
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
99
import androidx.compose.foundation.layout.padding
1010
import androidx.compose.foundation.layout.systemBarsPadding
1111
import androidx.compose.foundation.lazy.LazyColumn
12+
import androidx.compose.foundation.lazy.LazyItemScope
1213
import androidx.compose.material3.Icon
1314
import androidx.compose.material3.IconButton
1415
import androidx.compose.material3.MaterialTheme
@@ -36,6 +37,7 @@ import net.mullvad.mullvadvpn.compose.button.ApplyButton
3637
import net.mullvad.mullvadvpn.compose.cell.CheckboxCell
3738
import net.mullvad.mullvadvpn.compose.cell.ExpandableComposeCell
3839
import net.mullvad.mullvadvpn.compose.cell.SelectableCell
40+
import net.mullvad.mullvadvpn.compose.constant.ContentType
3941
import net.mullvad.mullvadvpn.compose.extensions.itemWithDivider
4042
import net.mullvad.mullvadvpn.compose.extensions.itemsWithDivider
4143
import net.mullvad.mullvadvpn.compose.state.RelayFilterState
@@ -102,7 +104,6 @@ fun FilterScreen(
102104
var ownershipExpanded by rememberSaveable { mutableStateOf(false) }
103105

104106
val backgroundColor = MaterialTheme.colorScheme.background
105-
106107
Scaffold(
107108
modifier = Modifier.background(backgroundColor).systemBarsPadding().fillMaxSize(),
108109
topBar = {
@@ -127,9 +128,9 @@ fun FilterScreen(
127128
Box(
128129
modifier =
129130
Modifier.fillMaxWidth()
130-
.padding(top = Dimens.screenVerticalMargin)
131131
.clickable(enabled = false, onClick = onApplyClick)
132-
.background(color = backgroundColor),
132+
.background(color = backgroundColor)
133+
.padding(top = Dimens.screenVerticalMargin),
133134
contentAlignment = Alignment.BottomCenter
134135
) {
135136
ApplyButton(
@@ -146,17 +147,33 @@ fun FilterScreen(
146147
},
147148
) { contentPadding ->
148149
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+
}
150153
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 ->
153162
Ownership(ownership, state, onSelectedOwnership)
154163
}
155164
}
156-
itemWithDivider { ProvidersHeader(providerExpanded) { providerExpanded = it } }
165+
itemWithDivider(key = Keys.PROVIDERS_TITLE, contentType = ContentType.HEADER) {
166+
ProvidersHeader(providerExpanded) { providerExpanded = it }
167+
}
157168
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 ->
160177
Provider(provider, state, onSelectedProvider)
161178
}
162179
}
@@ -165,74 +182,80 @@ fun FilterScreen(
165182
}
166183

167184
@Composable
168-
private fun OwnershipHeader(expanded: Boolean, onToggleExpanded: (Boolean) -> Unit) {
185+
private fun LazyItemScope.OwnershipHeader(expanded: Boolean, onToggleExpanded: (Boolean) -> Unit) {
169186
ExpandableComposeCell(
170187
title = stringResource(R.string.ownership),
171188
isExpanded = expanded,
172189
isEnabled = true,
173190
onInfoClicked = null,
174-
onCellClicked = { onToggleExpanded(!expanded) }
191+
onCellClicked = { onToggleExpanded(!expanded) },
192+
modifier = Modifier.animateItem()
175193
)
176194
}
177195

178196
@Composable
179-
private fun AnyOwnership(
197+
private fun LazyItemScope.AnyOwnership(
180198
state: RelayFilterState,
181199
onSelectedOwnership: (ownership: Ownership?) -> Unit
182200
) {
183201
SelectableCell(
184202
title = stringResource(id = R.string.any),
185203
isSelected = state.selectedOwnership == null,
186-
onCellClicked = { onSelectedOwnership(null) }
204+
onCellClicked = { onSelectedOwnership(null) },
205+
modifier = Modifier.animateItem()
187206
)
188207
}
189208

190209
@Composable
191-
private fun Ownership(
210+
private fun LazyItemScope.Ownership(
192211
ownership: Ownership,
193212
state: RelayFilterState,
194213
onSelectedOwnership: (ownership: Ownership?) -> Unit
195214
) {
196215
SelectableCell(
197216
title = stringResource(id = ownership.stringResource()),
198217
isSelected = ownership == state.selectedOwnership,
199-
onCellClicked = { onSelectedOwnership(ownership) }
218+
onCellClicked = { onSelectedOwnership(ownership) },
219+
modifier = Modifier.animateItem()
200220
)
201221
}
202222

203223
@Composable
204-
private fun ProvidersHeader(expanded: Boolean, onToggleExpanded: (Boolean) -> Unit) {
224+
private fun LazyItemScope.ProvidersHeader(expanded: Boolean, onToggleExpanded: (Boolean) -> Unit) {
205225
ExpandableComposeCell(
206226
title = stringResource(R.string.providers),
207227
isExpanded = expanded,
208228
isEnabled = true,
209229
onInfoClicked = null,
210-
onCellClicked = { onToggleExpanded(!expanded) }
230+
onCellClicked = { onToggleExpanded(!expanded) },
231+
modifier = Modifier.animateItem()
211232
)
212233
}
213234

214235
@Composable
215-
private fun AllProviders(
236+
private fun LazyItemScope.AllProviders(
216237
state: RelayFilterState,
217238
onAllProviderCheckChange: (isChecked: Boolean) -> Unit
218239
) {
219240
CheckboxCell(
220241
title = stringResource(R.string.all_providers),
221242
checked = state.isAllProvidersChecked,
222-
onCheckedChange = { isChecked -> onAllProviderCheckChange(isChecked) }
243+
onCheckedChange = { isChecked -> onAllProviderCheckChange(isChecked) },
244+
modifier = Modifier.animateItem()
223245
)
224246
}
225247

226248
@Composable
227-
private fun Provider(
249+
private fun LazyItemScope.Provider(
228250
provider: Provider,
229251
state: RelayFilterState,
230252
onSelectedProvider: (checked: Boolean, provider: Provider) -> Unit
231253
) {
232254
CheckboxCell(
233255
title = provider.providerId.value,
234256
checked = provider in state.selectedProviders,
235-
onCheckedChange = { checked -> onSelectedProvider(checked, provider) }
257+
onCheckedChange = { checked -> onSelectedProvider(checked, provider) },
258+
modifier = Modifier.animateItem()
236259
)
237260
}
238261

@@ -241,3 +264,10 @@ private fun Ownership.stringResource(): Int =
241264
Ownership.MullvadOwned -> R.string.mullvad_owned_only
242265
Ownership.Rented -> R.string.rented_only
243266
}
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

Comments
 (0)