Skip to content

Commit c74dcaf

Browse files
committed
Fixed all the things
1 parent 07c68a6 commit c74dcaf

29 files changed

+526
-448
lines changed

android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/RelayLocationCell.kt

+11-17
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,15 @@ import androidx.compose.ui.Alignment
2727
import androidx.compose.ui.Modifier
2828
import androidx.compose.ui.draw.alpha
2929
import androidx.compose.ui.graphics.Color
30-
import androidx.compose.ui.graphics.compositeOver
3130
import androidx.compose.ui.res.painterResource
3231
import androidx.compose.ui.tooling.preview.Preview
32+
import androidx.compose.ui.unit.Dp
3333
import net.mullvad.mullvadvpn.R
3434
import net.mullvad.mullvadvpn.compose.component.ChevronView
3535
import net.mullvad.mullvadvpn.compose.component.MullvadCheckbox
3636
import net.mullvad.mullvadvpn.compose.component.VerticalDivider
3737
import net.mullvad.mullvadvpn.lib.theme.AppTheme
3838
import net.mullvad.mullvadvpn.lib.theme.Dimens
39-
import net.mullvad.mullvadvpn.lib.theme.color.Alpha40
4039
import net.mullvad.mullvadvpn.lib.theme.color.AlphaInactive
4140
import net.mullvad.mullvadvpn.lib.theme.color.AlphaInvisible
4241
import net.mullvad.mullvadvpn.lib.theme.color.AlphaVisible
@@ -328,6 +327,7 @@ fun CheckableRelayLocationCell(
328327
onCheckedChange = { isChecked -> onRelayCheckedChange(relayItem, isChecked) }
329328
)
330329
},
330+
leadingContentStartPadding = Dimens.cellStartPaddingInteractive,
331331
modifier = modifier,
332332
onClick = { onRelayCheckedChange(it, !selectedRelays.contains(it)) },
333333
onLongClick = {},
@@ -341,18 +341,14 @@ private fun RelayLocationCell(
341341
relay: RelayItem,
342342
leadingContent: @Composable BoxScope.(relay: RelayItem) -> Unit,
343343
modifier: Modifier = Modifier,
344+
leadingContentStartPadding: Dp = Dimens.cellStartPadding,
345+
leadingContentStarPaddingModifier: Dp = Dimens.mediumPadding,
344346
specialBackgroundColor: @Composable (relayItem: RelayItem) -> Color? = { null },
345347
onClick: (item: RelayItem) -> Unit,
346348
onLongClick: (item: RelayItem) -> Unit,
347349
depth: Int
348350
) {
349-
val startPadding =
350-
when (depth) {
351-
0 -> Dimens.countryRowPadding
352-
1 -> Dimens.cityRowPadding
353-
2 -> Dimens.relayRowPadding
354-
else -> Dimens.relayRowPaddingExtra
355-
}
351+
val startPadding = leadingContentStartPadding + leadingContentStarPaddingModifier * depth
356352
val expanded =
357353
rememberSaveable(key = relay.expanded.toString()) { mutableStateOf(relay.expanded) }
358354
Column(
@@ -371,14 +367,12 @@ private fun RelayLocationCell(
371367
.fillMaxWidth()
372368
.background(
373369
specialBackgroundColor.invoke(relay)
374-
?: when (relay) {
375-
is RelayItem.Country -> MaterialTheme.colorScheme.primary
376-
is RelayItem.City ->
377-
MaterialTheme.colorScheme.primary
378-
.copy(alpha = Alpha40)
379-
.compositeOver(MaterialTheme.colorScheme.background)
380-
is RelayItem.Relay -> MaterialTheme.colorScheme.secondaryContainer
381-
else -> MaterialTheme.colorScheme.primary
370+
?: when (depth) {
371+
0 -> MaterialTheme.colorScheme.surfaceContainerHighest
372+
1 -> MaterialTheme.colorScheme.surfaceContainerHigh
373+
2 -> MaterialTheme.colorScheme.surfaceContainerLow
374+
3 -> MaterialTheme.colorScheme.surfaceContainerLowest
375+
else -> MaterialTheme.colorScheme.surfaceContainerLowest
382376
}
383377
)
384378
) {
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,36 @@
11
package net.mullvad.mullvadvpn.compose.communication
22

3-
import net.mullvad.mullvadvpn.relaylist.Location
3+
import android.os.Parcelable
4+
import kotlinx.parcelize.Parcelize
45

5-
sealed interface CustomListAction {
6+
sealed interface CustomListAction : Parcelable {
7+
8+
@Parcelize
69
data class Rename(val customListId: String, val name: String) : CustomListAction {
7-
fun not(oldName: String): CustomListAction = this.copy(name = oldName)
10+
fun not(): CustomListAction = this
811
}
912

10-
data class Delete(val customListId: String) : CustomListAction {
11-
fun not(name: String, locations: List<Location>): CustomListAction = Create(name, locations)
13+
@Parcelize
14+
data class Delete(val customListId: String, val name: String) : CustomListAction {
15+
fun not(locations: List<String>): CustomListAction = Create(name, locations)
1216
}
1317

14-
data class Create(val name: String, val locations: List<Location> = emptyList()) :
15-
CustomListAction {
16-
fun not(customListId: String) = Delete(customListId)
18+
@Parcelize
19+
data class Create(
20+
val name: String = "",
21+
val locations: List<String> = emptyList(),
22+
val locationNames: List<String> = emptyList()
23+
) : CustomListAction, Parcelable {
24+
fun not(customListId: String) = Delete(customListId, name)
1725
}
1826

19-
data class UpdateLocations(val customListId: String, val newList: Boolean) : CustomListAction {
20-
fun not(locations: List<Location>): CustomListAction =
21-
RemoveLocations(customListId, locations)
27+
@Parcelize
28+
data class UpdateLocations(
29+
val customListId: String,
30+
val newList: Boolean = false,
31+
val locations: List<String> = emptyList()
32+
) : CustomListAction {
33+
fun not(locations: List<String>): CustomListAction =
34+
UpdateLocations(customListId = customListId, locations = locations)
2235
}
23-
24-
data class RemoveLocations(val customListId: String, val locations: List<Location>) :
25-
CustomListAction
2636
}
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
package net.mullvad.mullvadvpn.compose.communication
22

3-
sealed interface CustomListRequest {
4-
}
3+
import android.os.Parcelable
4+
import kotlinx.parcelize.Parcelize
5+
6+
@Parcelize @JvmInline value class CustomListRequest(val action: CustomListAction) : Parcelable
7+
8+
inline fun <reified T> CustomListRequest.parsedAction(): T = action as T
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package net.mullvad.mullvadvpn.compose.communication
2+
3+
import android.os.Parcelable
4+
import kotlinx.parcelize.Parcelize
5+
6+
sealed interface CustomListResult : Parcelable {
7+
val reverseAction: CustomListAction
8+
9+
@Parcelize
10+
data class ListCreated(
11+
val locationName: String,
12+
val customListName: String,
13+
override val reverseAction: CustomListAction
14+
) : CustomListResult
15+
16+
@Parcelize
17+
data class ListDeleted(val name: String, override val reverseAction: CustomListAction) :
18+
CustomListResult
19+
20+
@Parcelize
21+
data class ListRenamed(val name: String, override val reverseAction: CustomListAction) :
22+
CustomListResult
23+
24+
@Parcelize
25+
data class ListUpdated(val name: String, override val reverseAction: CustomListAction) :
26+
CustomListResult
27+
}

android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/communication/Request.kt

-3
This file was deleted.

android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/communication/Result.kt

-3
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package net.mullvad.mullvadvpn.compose.component
2+
3+
import androidx.compose.foundation.layout.ColumnScope
4+
import androidx.compose.material3.BottomSheetDefaults
5+
import androidx.compose.material3.ExperimentalMaterial3Api
6+
import androidx.compose.material3.HorizontalDivider
7+
import androidx.compose.material3.MaterialTheme
8+
import androidx.compose.material3.ModalBottomSheet
9+
import androidx.compose.material3.rememberModalBottomSheetState
10+
import androidx.compose.runtime.Composable
11+
import androidx.compose.runtime.rememberCoroutineScope
12+
import androidx.compose.ui.Modifier
13+
import androidx.compose.ui.graphics.Color
14+
import androidx.compose.ui.tooling.preview.Preview
15+
import kotlinx.coroutines.launch
16+
import net.mullvad.mullvadvpn.compose.cell.HeaderCell
17+
import net.mullvad.mullvadvpn.compose.cell.IconCell
18+
import net.mullvad.mullvadvpn.lib.theme.AppTheme
19+
20+
@Preview
21+
@Composable
22+
fun PreviewMullvadModalBottomSheet() {
23+
AppTheme {
24+
MullvadModalBottomSheet(
25+
sheetContent = { _, _ ->
26+
HeaderCell(
27+
text = "Title",
28+
)
29+
HorizontalDivider()
30+
IconCell(
31+
iconId = null,
32+
title = "Select",
33+
)
34+
},
35+
closeBottomSheet = {}
36+
)
37+
}
38+
}
39+
40+
@OptIn(ExperimentalMaterial3Api::class)
41+
@Composable
42+
fun MullvadModalBottomSheet(
43+
modifier: Modifier = Modifier,
44+
backgroundColor: Color = MaterialTheme.colorScheme.surfaceContainer,
45+
onBackgroundColor: Color = MaterialTheme.colorScheme.onSurface,
46+
closeBottomSheet: () -> Unit,
47+
sheetContent: @Composable ColumnScope.(onBackgroundColor: Color, onClose: () -> Unit) -> Unit
48+
) {
49+
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
50+
val scope = rememberCoroutineScope()
51+
52+
ModalBottomSheet(
53+
onDismissRequest = closeBottomSheet,
54+
sheetState = sheetState,
55+
containerColor = backgroundColor,
56+
modifier = modifier,
57+
dragHandle = { BottomSheetDefaults.DragHandle(color = onBackgroundColor) }
58+
) {
59+
sheetContent(onBackgroundColor) {
60+
scope
61+
.launch { sheetState.hide() }
62+
.invokeOnCompletion {
63+
if (!sheetState.isVisible) {
64+
closeBottomSheet()
65+
}
66+
}
67+
}
68+
}
69+
}

android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/CreateCustomListDialog.kt

+9-6
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,9 @@ import com.ramcosta.composedestinations.spec.DestinationStyle
2424
import net.mullvad.mullvadvpn.R
2525
import net.mullvad.mullvadvpn.compose.button.PrimaryButton
2626
import net.mullvad.mullvadvpn.compose.communication.CustomListAction
27-
import net.mullvad.mullvadvpn.compose.communication.Request
28-
import net.mullvad.mullvadvpn.compose.communication.Result
27+
import net.mullvad.mullvadvpn.compose.communication.CustomListRequest
28+
import net.mullvad.mullvadvpn.compose.communication.CustomListResult
29+
import net.mullvad.mullvadvpn.compose.communication.parsedAction
2930
import net.mullvad.mullvadvpn.compose.destinations.CustomListLocationsDestination
3031
import net.mullvad.mullvadvpn.compose.state.CreateCustomListUiState
3132
import net.mullvad.mullvadvpn.compose.textfield.CustomTextField
@@ -56,11 +57,13 @@ fun PreviewCreateCustomListDialogError() {
5657
@Destination(style = DestinationStyle.Dialog::class)
5758
fun CreateCustomList(
5859
navigator: DestinationsNavigator,
59-
backNavigator: ResultBackNavigator<Result<CustomListAction.Delete>>,
60-
request: Request<CustomListAction.Create>
60+
backNavigator: ResultBackNavigator<CustomListResult.ListCreated>,
61+
request: CustomListRequest
6162
) {
6263
val vm: CreateCustomListDialogViewModel =
63-
koinViewModel(parameters = { parametersOf(request.action.locations) })
64+
koinViewModel(
65+
parameters = { parametersOf(request.parsedAction<CustomListAction.Create>()) }
66+
)
6467
LaunchedEffect(key1 = Unit) {
6568
vm.uiSideEffect.collect { sideEffect ->
6669
when (sideEffect) {
@@ -69,7 +72,7 @@ fun CreateCustomList(
6972
navigator.navigate(
7073
CustomListLocationsDestination(
7174
request =
72-
Request(
75+
CustomListRequest(
7376
action =
7477
CustomListAction.UpdateLocations(
7578
customListId = sideEffect.customListId,

android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/DeleteCustomListConfirmationDialog.kt

+12-5
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ import com.ramcosta.composedestinations.spec.DestinationStyle
2121
import net.mullvad.mullvadvpn.R
2222
import net.mullvad.mullvadvpn.compose.button.NegativeButton
2323
import net.mullvad.mullvadvpn.compose.button.PrimaryButton
24+
import net.mullvad.mullvadvpn.compose.communication.CustomListAction
25+
import net.mullvad.mullvadvpn.compose.communication.CustomListRequest
26+
import net.mullvad.mullvadvpn.compose.communication.CustomListResult
27+
import net.mullvad.mullvadvpn.compose.communication.parsedAction
2428
import net.mullvad.mullvadvpn.lib.theme.AppTheme
2529
import net.mullvad.mullvadvpn.lib.theme.Dimens
2630
import net.mullvad.mullvadvpn.viewmodel.DeleteCustomListConfirmationSideEffect
@@ -36,21 +40,24 @@ private fun PreviewRemoveDeviceConfirmationDialog() {
3640

3741
@Composable
3842
@Destination(style = DestinationStyle.Dialog::class)
39-
fun DeleteCustomList(navigator: ResultBackNavigator<String>, id: String, name: String) {
43+
fun DeleteCustomList(
44+
navigator: ResultBackNavigator<CustomListResult.ListDeleted>,
45+
request: CustomListRequest
46+
) {
4047
val viewModel: DeleteCustomListConfirmationViewModel =
41-
koinViewModel(parameters = { parametersOf(id) })
48+
koinViewModel(parameters = { parametersOf(request.parsedAction()) })
4249

4350
LaunchedEffect(Unit) {
4451
viewModel.uiSideEffect.collect {
4552
when (it) {
46-
is DeleteCustomListConfirmationSideEffect.CloseDialog ->
47-
navigator.navigateBack(result = name)
53+
is DeleteCustomListConfirmationSideEffect.ReturnWithResult ->
54+
navigator.navigateBack(result = it.result)
4855
}
4956
}
5057
}
5158

5259
DeleteCustomListConfirmationDialog(
53-
name = name,
60+
name = request.parsedAction<CustomListAction.Delete>().name,
5461
onDelete = viewModel::deleteCustomList,
5562
onBack = { navigator.navigateBack() }
5663
)

android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/EditCustomListNameDialog.kt

+6-5
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ import com.ramcosta.composedestinations.result.ResultBackNavigator
2222
import com.ramcosta.composedestinations.spec.DestinationStyle
2323
import net.mullvad.mullvadvpn.R
2424
import net.mullvad.mullvadvpn.compose.button.PrimaryButton
25-
import net.mullvad.mullvadvpn.compose.communication.EditCustomListNameDialogRequest
26-
import net.mullvad.mullvadvpn.compose.communication.EditCustomListNameDialogResult
25+
import net.mullvad.mullvadvpn.compose.communication.CustomListRequest
26+
import net.mullvad.mullvadvpn.compose.communication.CustomListResult
27+
import net.mullvad.mullvadvpn.compose.communication.parsedAction
2728
import net.mullvad.mullvadvpn.compose.state.UpdateCustomListUiState
2829
import net.mullvad.mullvadvpn.compose.textfield.CustomTextField
2930
import net.mullvad.mullvadvpn.lib.theme.AppTheme
@@ -42,11 +43,11 @@ fun PreviewEditCustomListNameDialog() {
4243
@Composable
4344
@Destination(style = DestinationStyle.Dialog::class)
4445
fun EditCustomListName(
45-
backNavigator: ResultBackNavigator<EditCustomListNameDialogResult>,
46-
request: EditCustomListNameDialogRequest
46+
backNavigator: ResultBackNavigator<CustomListResult.ListRenamed>,
47+
request: CustomListRequest
4748
) {
4849
val vm: EditCustomListNameDialogViewModel =
49-
koinViewModel(parameters = { parametersOf(request.customListId, request.name) })
50+
koinViewModel(parameters = { parametersOf(request.parsedAction()) })
5051
LaunchedEffect(Unit) {
5152
vm.uiSideEffect.collect { sideEffect ->
5253
when (sideEffect) {

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

+9-8
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ import com.ramcosta.composedestinations.result.ResultBackNavigator
2828
import com.ramcosta.composedestinations.result.ResultRecipient
2929
import net.mullvad.mullvadvpn.R
3030
import net.mullvad.mullvadvpn.compose.cell.CheckableRelayLocationCell
31-
import net.mullvad.mullvadvpn.compose.communication.CustomListLocationScreenRequest
32-
import net.mullvad.mullvadvpn.compose.communication.CustomListLocationScreenResult
31+
import net.mullvad.mullvadvpn.compose.communication.CustomListRequest
32+
import net.mullvad.mullvadvpn.compose.communication.CustomListResult
33+
import net.mullvad.mullvadvpn.compose.communication.parsedAction
3334
import net.mullvad.mullvadvpn.compose.component.LocationsEmptyText
3435
import net.mullvad.mullvadvpn.compose.component.MullvadCircularProgressIndicatorLarge
3536
import net.mullvad.mullvadvpn.compose.component.NavigateBackIconButton
@@ -58,13 +59,13 @@ fun PreviewCustomListLocationScreen() {
5859
@Destination(style = SlideInFromRightTransition::class)
5960
fun CustomListLocations(
6061
navigator: DestinationsNavigator,
61-
backNavigator: ResultBackNavigator<CustomListLocationScreenResult>,
62-
request: CustomListLocationScreenRequest,
62+
backNavigator: ResultBackNavigator<CustomListResult.ListUpdated>,
63+
request: CustomListRequest,
6364
discardChangesResultRecipient: ResultRecipient<DiscardChangesDialogDestination, Boolean>
6465
) {
6566
val customListsViewModel =
6667
koinViewModel<CustomListLocationsViewModel>(
67-
parameters = { parametersOf(request.customListKey, request.newList) }
68+
parameters = { parametersOf(request.parsedAction()) }
6869
)
6970

7071
discardChangesResultRecipient.onNavResult(
@@ -96,10 +97,10 @@ fun CustomListLocations(
9697
onSaveClick = customListsViewModel::save,
9798
onRelaySelectionClick = customListsViewModel::onRelaySelectionClick,
9899
onBackClick = {
99-
if (state.saveEnabled.not()) {
100-
backNavigator.navigateBack()
100+
if (state.willDiscardChanges) {
101+
navigator.navigate(DiscardChangesDialogDestination) { launchSingleTop = true }
101102
} else {
102-
navigator.navigate(DiscardChangesDialogDestination) {}
103+
backNavigator.navigateBack()
103104
}
104105
}
105106
)

0 commit comments

Comments
 (0)