Skip to content

Commit

Permalink
Animate chips
Browse files Browse the repository at this point in the history
  • Loading branch information
Rawa committed Jul 23, 2024
1 parent bd27b43 commit 0d38d7f
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package net.mullvad.mullvadvpn.compose.cell

import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
Expand Down Expand Up @@ -40,9 +41,9 @@ fun FilterRow(
horizontal = Dimens.searchFieldHorizontalPadding,
)
.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(Dimens.chipSpace)
) {
Text(
modifier = Modifier.padding(end = Dimens.filterTittlePadding),
text = stringResource(id = R.string.filtered),
color = MaterialTheme.colorScheme.onPrimary,
style = MaterialTheme.typography.labelMedium)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package net.mullvad.mullvadvpn.compose.screen

import android.content.Context
import androidx.compose.animation.AnimatedContent
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.animateScrollBy
Expand Down Expand Up @@ -47,6 +48,8 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.compose.dropUnlessResumed
import arrow.core.toNonEmptyListOrNull
import co.touchlab.kermit.Logger
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.generated.destinations.CreateCustomListDestination
Expand Down Expand Up @@ -88,14 +91,14 @@ import net.mullvad.mullvadvpn.compose.screen.BottomSheetState.ShowEditCustomList
import net.mullvad.mullvadvpn.compose.screen.BottomSheetState.ShowLocationBottomSheet
import net.mullvad.mullvadvpn.compose.state.RelayListItem
import net.mullvad.mullvadvpn.compose.state.SelectLocationUiState
import net.mullvad.mullvadvpn.compose.state.SelectLocationUiState.Content
import net.mullvad.mullvadvpn.compose.test.CIRCULAR_PROGRESS_INDICATOR
import net.mullvad.mullvadvpn.compose.test.SELECT_LOCATION_CUSTOM_LIST_BOTTOM_SHEET_TEST_TAG
import net.mullvad.mullvadvpn.compose.test.SELECT_LOCATION_CUSTOM_LIST_HEADER_TEST_TAG
import net.mullvad.mullvadvpn.compose.test.SELECT_LOCATION_LOCATION_BOTTOM_SHEET_TEST_TAG
import net.mullvad.mullvadvpn.compose.textfield.SearchTextField
import net.mullvad.mullvadvpn.compose.transitions.SelectLocationTransition
import net.mullvad.mullvadvpn.compose.util.CollectSideEffectWithLifecycle
import net.mullvad.mullvadvpn.compose.util.RunOnKeyChange
import net.mullvad.mullvadvpn.compose.util.showSnackbarImmediately
import net.mullvad.mullvadvpn.lib.model.CustomList
import net.mullvad.mullvadvpn.lib.model.CustomListId
Expand All @@ -120,7 +123,7 @@ private fun PreviewSelectLocationScreen() {
emptyList(),
relayListItems = emptyList(),
customLists = emptyList(),
)
)
AppTheme {
SelectLocationScreen(
state = state,
Expand All @@ -147,6 +150,8 @@ fun SelectLocation(
val snackbarHostState = remember { SnackbarHostState() }
val context = LocalContext.current

val lazyListState = rememberLazyListState()

CollectSideEffectWithLifecycle(vm.uiSideEffect) {
when (it) {
SelectLocationSideEffect.CloseScreen -> backNavigator.navigateBack(result = true)
Expand All @@ -166,6 +171,16 @@ fun SelectLocation(
message = context.getString(R.string.error_occurred),
duration = SnackbarDuration.Short)
}

is SelectLocationSideEffect.CenterOnItem -> {
val index = state.indexOfSelectedRelayItem()
Logger.d("CENTER ON ITEM $index")

if (index >= 0) {
lazyListState.scrollToItem(index)
lazyListState.animateScrollAndCentralizeItem(index)
}
}
}
}

Expand All @@ -182,6 +197,7 @@ fun SelectLocation(

SelectLocationScreen(
state = state,
lazyListState = lazyListState,
snackbarHostState = snackbarHostState,
onSelectRelay = vm::selectRelay,
onSearchTermInput = vm::onSearchTermInput,
Expand Down Expand Up @@ -226,6 +242,7 @@ fun SelectLocation(
@Composable
fun SelectLocationScreen(
state: SelectLocationUiState,
lazyListState: LazyListState = rememberLazyListState(),
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
onSelectRelay: (item: RelayItem) -> Unit = {},
onSearchTermInput: (searchTerm: String) -> Unit = {},
Expand Down Expand Up @@ -269,15 +286,11 @@ fun SelectLocationScreen(
Column(modifier = Modifier.padding(it).background(backgroundColor).fillMaxSize()) {
SelectLocationTopBar(onBackClick = onBackClick, onFilterClick = onFilterClick)

when (state) {
SelectLocationUiState.Loading -> {}
is SelectLocationUiState.Content -> {
if (state.filterChips.isNotEmpty()) {
FilterRow(
filters = state.filterChips,
removeOwnershipFilter,
removeProviderFilter)
}
val filterChips = (state as? Content)?.filterChips?.toNonEmptyListOrNull()
AnimatedContent(filterChips) {
if (it != null) {
FilterRow(
filters = it.toList(), removeOwnershipFilter, removeProviderFilter)
}
}

Expand All @@ -292,17 +305,6 @@ fun SelectLocationScreen(
onSearchTermInput.invoke(searchString)
}
Spacer(modifier = Modifier.height(height = Dimens.verticalSpace))
val lazyListState = rememberLazyListState()

// val selectedItemCode = (state as? SelectLocationUiState.Content)?.selectedItem ?: ""
// RunOnKeyChange(key = selectedItemCode) {
// val index = state.indexOfSelectedRelayItem()
//
// if (index >= 0) {
// lazyListState.scrollToItem(index)
// lazyListState.animateScrollAndCentralizeItem(index)
// }
// }

LazyColumn(
modifier =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,17 @@ package net.mullvad.mullvadvpn.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import arrow.core.raise.either
import co.touchlab.kermit.Logger
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flatMap
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.receiveAsFlow
Expand All @@ -18,6 +25,7 @@ import net.mullvad.mullvadvpn.compose.communication.LocationsChanged
import net.mullvad.mullvadvpn.compose.state.RelayListItem
import net.mullvad.mullvadvpn.compose.state.RelayListItem.CustomListHeader
import net.mullvad.mullvadvpn.compose.state.SelectLocationUiState
import net.mullvad.mullvadvpn.compose.state.SelectLocationUiState.Content
import net.mullvad.mullvadvpn.compose.state.toNullableOwnership
import net.mullvad.mullvadvpn.compose.state.toSelectedProviders
import net.mullvad.mullvadvpn.lib.model.Constraint
Expand Down Expand Up @@ -144,7 +152,7 @@ class SelectLocationViewModel(
relayListItems,
filterChips,
customLists ->
SelectLocationUiState.Content(
Content(
searchTerm = searchTerm,
filterChips = filterChips,
relayListItems = relayListItems,
Expand All @@ -159,6 +167,22 @@ class SelectLocationViewModel(
private val _uiSideEffect = Channel<SelectLocationSideEffect>()
val uiSideEffect = _uiSideEffect.receiveAsFlow()

init {
viewModelScope.launch {
uiState
.map { it is Content }
.filter { it }
.distinctUntilChanged()
.flatMapLatest { relayListRepository.selectedLocation.filterNotNull() }
.filterIsInstance<Constraint.Only<RelayItemId>>()
.map { it.value }
.collect {
Logger.d("SELECTED LOCATION CHANGED!")
_uiSideEffect.send(SelectLocationSideEffect.CenterOnItem(it))
}
}
}

fun createRelayListItems(
isSearching: Boolean,
selectedItem: RelayItemId?,
Expand Down Expand Up @@ -386,4 +410,6 @@ sealed interface SelectLocationSideEffect {
class LocationRemovedFromCustomList(val result: LocationsChanged) : SelectLocationSideEffect

data object GenericError : SelectLocationSideEffect

data class CenterOnItem(val selectedItem: RelayItemId?) : SelectLocationSideEffect
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ data class Dimensions(
val dropdownMenuVerticalPadding: Dp = 8.dp, // Used to remove padding from dropdown menu
val dropdownMenuBorder: Dp = 1.dp,
val expandableCellChevronSize: Dp = 30.dp,
val filterTittlePadding: Dp = 4.dp,
val filterTitlePadding: Dp = 4.dp,
val formTextFieldMinHeight: Dp = 72.dp,
val iconFailSuccessTopMargin: Dp = 30.dp,
val iconHeight: Dp = 44.dp,
Expand Down

0 comments on commit 0d38d7f

Please sign in to comment.