Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more detailed snackbars when adding and removing a location in a custom list #6380

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package net.mullvad.mullvadvpn.compose.communication

import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import net.mullvad.mullvadvpn.lib.model.CustomListName

sealed interface CustomListActionResultData : Parcelable {

sealed interface Success : CustomListActionResultData, Parcelable {
val undo: CustomListAction

@Parcelize
data class CreatedWithLocations(
val customListName: CustomListName,
val locationNames: List<String>,
override val undo: CustomListAction
) : Success

@Parcelize
data class Deleted(
val customListName: CustomListName,
override val undo: CustomListAction.Create
) : Success

@Parcelize
data class Renamed(
val newName: CustomListName,
override val undo: CustomListAction.Rename
) : Success

@Parcelize
data class LocationAdded(
val customListName: CustomListName,
val locationName: String,
override val undo: CustomListAction
) : Success

@Parcelize
data class LocationRemoved(
val customListName: CustomListName,
val locationName: String,
override val undo: CustomListAction
) : Success

@Parcelize
data class LocationChanged(
val customListName: CustomListName,
override val undo: CustomListAction
) : Success
}

@Parcelize data object GenericError : CustomListActionResultData
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package net.mullvad.mullvadvpn.compose.communication

import android.os.Parcelable
import kotlinx.parcelize.IgnoredOnParcel
import kotlinx.parcelize.Parcelize
import net.mullvad.mullvadvpn.lib.model.CustomListId
import net.mullvad.mullvadvpn.lib.model.CustomListName
import net.mullvad.mullvadvpn.lib.model.GeoLocationId

sealed interface CustomListSuccess : Parcelable {
val undo: CustomListAction
Expand Down Expand Up @@ -31,6 +33,14 @@ data class Renamed(override val undo: CustomListAction.Rename) : CustomListSucce

@Parcelize
data class LocationsChanged(
val id: CustomListId,
val name: CustomListName,
val locations: List<GeoLocationId>,
val oldLocations: List<GeoLocationId>,
) : CustomListSuccess {
override val undo: CustomListAction.UpdateLocations
) : CustomListSuccess
get() = CustomListAction.UpdateLocations(id, oldLocations)

@IgnoredOnParcel val addedLocations = locations - oldLocations
@IgnoredOnParcel val removedLocations = oldLocations - locations
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import com.ramcosta.composedestinations.result.ResultBackNavigator
import com.ramcosta.composedestinations.spec.DestinationStyle
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.compose.button.PrimaryButton
import net.mullvad.mullvadvpn.compose.communication.Created
import net.mullvad.mullvadvpn.compose.communication.CustomListActionResultData
import net.mullvad.mullvadvpn.compose.component.CustomListNameTextField
import net.mullvad.mullvadvpn.compose.state.CreateCustomListUiState
import net.mullvad.mullvadvpn.compose.test.CREATE_CUSTOM_LIST_DIALOG_INPUT_TEST_TAG
Expand Down Expand Up @@ -63,7 +63,7 @@ data class CreateCustomListNavArgs(val locationCode: GeoLocationId?)
)
fun CreateCustomList(
navigator: DestinationsNavigator,
backNavigator: ResultBackNavigator<Created>,
backNavigator: ResultBackNavigator<CustomListActionResultData.Success.CreatedWithLocations>,
) {
val vm: CreateCustomListDialogViewModel = koinViewModel()
LaunchedEffect(key1 = Unit) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.result.ResultBackNavigator
import com.ramcosta.composedestinations.spec.DestinationStyle
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.compose.communication.Deleted
import net.mullvad.mullvadvpn.compose.communication.CustomListActionResultData
import net.mullvad.mullvadvpn.compose.state.DeleteCustomListUiState
import net.mullvad.mullvadvpn.compose.util.LaunchedEffectCollect
import net.mullvad.mullvadvpn.lib.model.CustomListId
Expand Down Expand Up @@ -39,7 +39,7 @@ data class DeleteCustomListNavArgs(val customListId: CustomListId, val name: Cus
navArgs = DeleteCustomListNavArgs::class
)
fun DeleteCustomList(
navigator: ResultBackNavigator<Deleted>,
navigator: ResultBackNavigator<CustomListActionResultData.Success.Deleted>,
) {
val viewModel: DeleteCustomListConfirmationViewModel = koinViewModel()
val state by viewModel.uiState.collectAsStateWithLifecycle()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import com.ramcosta.composedestinations.result.ResultBackNavigator
import com.ramcosta.composedestinations.spec.DestinationStyle
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.compose.button.PrimaryButton
import net.mullvad.mullvadvpn.compose.communication.Renamed
import net.mullvad.mullvadvpn.compose.communication.CustomListActionResultData
import net.mullvad.mullvadvpn.compose.component.CustomListNameTextField
import net.mullvad.mullvadvpn.compose.state.EditCustomListNameUiState
import net.mullvad.mullvadvpn.compose.test.EDIT_CUSTOM_LIST_DIALOG_INPUT_TEST_TAG
Expand Down Expand Up @@ -50,7 +50,7 @@ data class EditCustomListNameNavArgs(
navArgs = EditCustomListNameNavArgs::class
)
fun EditCustomListName(
backNavigator: ResultBackNavigator<Renamed>,
backNavigator: ResultBackNavigator<CustomListActionResultData.Success.Renamed>,
) {
val vm: EditCustomListNameDialogViewModel = koinViewModel()
LaunchedEffectCollect(vm.uiSideEffect) { sideEffect ->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package net.mullvad.mullvadvpn.compose.screen

import android.content.Context
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
Expand All @@ -13,16 +12,12 @@ import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
Expand All @@ -35,10 +30,9 @@ import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.result.NavResult
import com.ramcosta.composedestinations.result.ResultBackNavigator
import com.ramcosta.composedestinations.result.ResultRecipient
import kotlinx.coroutines.launch
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.compose.cell.CheckableRelayLocationCell
import net.mullvad.mullvadvpn.compose.communication.LocationsChanged
import net.mullvad.mullvadvpn.compose.communication.CustomListActionResultData
import net.mullvad.mullvadvpn.compose.component.LocationsEmptyText
import net.mullvad.mullvadvpn.compose.component.MullvadCircularProgressIndicatorLarge
import net.mullvad.mullvadvpn.compose.component.NavigateBackIconButton
Expand All @@ -52,7 +46,6 @@ import net.mullvad.mullvadvpn.compose.test.SAVE_BUTTON_TEST_TAG
import net.mullvad.mullvadvpn.compose.textfield.SearchTextField
import net.mullvad.mullvadvpn.compose.transitions.SlideInFromRightTransition
import net.mullvad.mullvadvpn.compose.util.LaunchedEffectCollect
import net.mullvad.mullvadvpn.compose.util.showSnackbarImmediately
import net.mullvad.mullvadvpn.lib.model.CustomListId
import net.mullvad.mullvadvpn.lib.model.RelayItem
import net.mullvad.mullvadvpn.lib.theme.Dimens
Expand All @@ -79,7 +72,7 @@ data class CustomListLocationsNavArgs(
)
fun CustomListLocations(
navigator: DestinationsNavigator,
backNavigator: ResultBackNavigator<LocationsChanged>,
backNavigator: ResultBackNavigator<CustomListActionResultData>,
discardChangesResultRecipient: ResultRecipient<DiscardChangesDestination, Boolean>,
) {
val customListsViewModel = koinViewModel<CustomListLocationsViewModel>()
Expand All @@ -95,27 +88,16 @@ fun CustomListLocations(
}
}

val snackbarHostState = remember { SnackbarHostState() }
val context: Context = LocalContext.current
LaunchedEffectCollect(customListsViewModel.uiSideEffect) { sideEffect ->
when (sideEffect) {
is CustomListLocationsSideEffect.ReturnWithResult ->
is CustomListLocationsSideEffect.ReturnWithResultData ->
backNavigator.navigateBack(result = sideEffect.result)
CustomListLocationsSideEffect.CloseScreen -> backNavigator.navigateBack()
CustomListLocationsSideEffect.Error ->
launch {
snackbarHostState.showSnackbarImmediately(
message = context.getString(R.string.error_occurred),
duration = SnackbarDuration.Short
)
}
}
}

val state by customListsViewModel.uiState.collectAsStateWithLifecycle()
CustomListLocationsScreen(
state = state,
snackbarHostState = snackbarHostState,
onSearchTermInput = customListsViewModel::onSearchTermInput,
onSaveClick = customListsViewModel::save,
onRelaySelectionClick = customListsViewModel::onRelaySelectionClick,
Expand All @@ -134,15 +116,13 @@ fun CustomListLocations(
@Composable
fun CustomListLocationsScreen(
state: CustomListLocationsUiState,
snackbarHostState: SnackbarHostState = SnackbarHostState(),
onSearchTermInput: (String) -> Unit = {},
onSaveClick: () -> Unit = {},
onRelaySelectionClick: (RelayItem.Location, selected: Boolean) -> Unit = { _, _ -> },
onExpand: (RelayItem.Location, selected: Boolean) -> Unit = { _, _ -> },
onBackClick: () -> Unit = {}
) {
ScaffoldWithSmallTopBar(
snackbarHostState = snackbarHostState,
appBarTitle =
stringResource(
if (state.newList) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import com.ramcosta.composedestinations.result.ResultRecipient
import kotlinx.coroutines.launch
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.compose.cell.NavigationComposeCell
import net.mullvad.mullvadvpn.compose.communication.CustomListActionResultData
import net.mullvad.mullvadvpn.compose.communication.Deleted
import net.mullvad.mullvadvpn.compose.component.MullvadCircularProgressIndicatorLarge
import net.mullvad.mullvadvpn.compose.component.NavigateBackIconButton
Expand Down Expand Up @@ -63,7 +64,8 @@ private fun PreviewCustomListsScreen() {
@Destination<RootGraph>(style = SlideInFromRightTransition::class)
fun CustomLists(
navigator: DestinationsNavigator,
editCustomListResultRecipient: ResultRecipient<EditCustomListDestination, Deleted>
editCustomListResultRecipient:
ResultRecipient<EditCustomListDestination, CustomListActionResultData.Success.Deleted>
) {
val viewModel = koinViewModel<CustomListsViewModel>()
val state by viewModel.uiState.collectAsStateWithLifecycle()
Expand All @@ -82,7 +84,7 @@ fun CustomLists(
message =
context.getString(
R.string.delete_custom_list_message,
result.value.name
result.value.customListName
),
actionLabel = context.getString(R.string.undo),
duration = SnackbarDuration.Long,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import com.ramcosta.composedestinations.result.ResultBackNavigator
import com.ramcosta.composedestinations.result.ResultRecipient
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.compose.cell.TwoRowCell
import net.mullvad.mullvadvpn.compose.communication.CustomListActionResultData
import net.mullvad.mullvadvpn.compose.communication.Deleted
import net.mullvad.mullvadvpn.compose.component.MullvadCircularProgressIndicatorLarge
import net.mullvad.mullvadvpn.compose.component.NavigateBackIconButton
Expand Down Expand Up @@ -83,8 +84,9 @@ data class EditCustomListNavArgs(val customListId: CustomListId)
)
fun EditCustomList(
navigator: DestinationsNavigator,
backNavigator: ResultBackNavigator<Deleted>,
confirmDeleteListResultRecipient: ResultRecipient<DeleteCustomListDestination, Deleted>
backNavigator: ResultBackNavigator<CustomListActionResultData.Success.Deleted>,
confirmDeleteListResultRecipient:
ResultRecipient<DeleteCustomListDestination, CustomListActionResultData.Success.Deleted>
) {
val viewModel = koinViewModel<EditCustomListViewModel>()

Expand Down
Loading
Loading