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 filter for ownership and providers #5506

Merged
merged 7 commits into from
Dec 4, 2023
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,191 @@
package net.mullvad.mullvadvpn.compose.screen

import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import io.mockk.MockKAnnotations
import io.mockk.mockk
import io.mockk.verify
import kotlinx.coroutines.flow.MutableSharedFlow
import net.mullvad.mullvadvpn.compose.setContentWithTheme
import net.mullvad.mullvadvpn.compose.state.RelayFilterState
import net.mullvad.mullvadvpn.model.Ownership
import net.mullvad.mullvadvpn.relaylist.Provider
import org.junit.Rule
import org.junit.Test

class FilterScreenTest {
@get:Rule val composeTestRule = createComposeRule()

fun setup() {
MockKAnnotations.init(this)
}

@Test
fun testDefaultState() {
composeTestRule.setContentWithTheme {
FilterScreen(
uiState =
RelayFilterState(
allProviders = DUMMY_RELAY_ALL_PROVIDERS,
selectedOwnership = null,
selectedProviders = DUMMY_SELECTED_PROVIDERS,
),
uiCloseAction = MutableSharedFlow(),
onSelectedProviders = { _, _ -> }
)
}
composeTestRule.apply {
onNodeWithText("Ownership").assertExists()
onNodeWithText("Providers").assertExists()
}
}

@Test
fun testIsAnyCellShowing() {
composeTestRule.setContentWithTheme {
FilterScreen(
uiState =
RelayFilterState(
allProviders = DUMMY_RELAY_ALL_PROVIDERS,
selectedOwnership = null,
selectedProviders = DUMMY_SELECTED_PROVIDERS
),
uiCloseAction = MutableSharedFlow(),
onSelectedProviders = { _, _ -> }
)
}
composeTestRule.apply {
onNodeWithText("Ownership").performClick()
onNodeWithText("Any").assertExists()
}
}

@Test
fun testIsMullvadCellShowing() {
composeTestRule.setContentWithTheme {
FilterScreen(
uiState =
RelayFilterState(
allProviders = DUMMY_RELAY_ALL_PROVIDERS,
selectedOwnership = Ownership.MullvadOwned,
selectedProviders = DUMMY_SELECTED_PROVIDERS
),
uiCloseAction = MutableSharedFlow(),
onSelectedProviders = { _, _ -> }
)
}
composeTestRule.apply {
onNodeWithText("Ownership").performClick()
onNodeWithText("Mullvad owned only").assertExists()
}
}

@Test
fun testIsRentedCellShowing() {
composeTestRule.setContentWithTheme {
FilterScreen(
uiState =
RelayFilterState(
allProviders = DUMMY_RELAY_ALL_PROVIDERS,
selectedOwnership = Ownership.Rented,
selectedProviders = DUMMY_SELECTED_PROVIDERS
),
uiCloseAction = MutableSharedFlow(),
onSelectedProviders = { _, _ -> }
)
}
composeTestRule.apply {
onNodeWithText("Ownership").performClick()
onNodeWithText("Rented only").assertExists()
}
}

@Test
fun testShowProviders() {
composeTestRule.setContentWithTheme {
FilterScreen(
uiState =
RelayFilterState(
allProviders = DUMMY_RELAY_ALL_PROVIDERS,
selectedOwnership = null,
selectedProviders = DUMMY_SELECTED_PROVIDERS
),
uiCloseAction = MutableSharedFlow(),
onSelectedProviders = { _, _ -> }
)
}

composeTestRule.apply {
onNodeWithText("Providers").performClick()
onNodeWithText("Creanova").assertExists()
onNodeWithText("Creanova").assertExists()
onNodeWithText("100TB").assertExists()
}
}

@Test
fun testApplyButtonClick() {
val mockClickListener: () -> Unit = mockk(relaxed = true)
composeTestRule.setContentWithTheme {
FilterScreen(
uiState =
RelayFilterState(
allProviders = listOf(),
selectedOwnership = null,
selectedProviders = listOf(Provider("31173", true))
),
uiCloseAction = MutableSharedFlow(),
onSelectedProviders = { _, _ -> },
onApplyClick = mockClickListener
)
}
composeTestRule.onNodeWithText("Apply").performClick()
verify { mockClickListener() }
}

companion object {

private val DUMMY_RELAY_ALL_PROVIDERS =
listOf(
Provider("31173", true),
Provider("100TB", false),
Provider("Blix", true),
Provider("Creanova", true),
Provider("DataPacket", false),
Provider("HostRoyale", false),
Provider("hostuniversal", false),
Provider("iRegister", false),
Provider("M247", false),
Provider("Makonix", false),
Provider("PrivateLayer", false),
Provider("ptisp", false),
Provider("Qnax", false),
Provider("Quadranet", false),
Provider("techfutures", false),
Provider("Tzulo", false),
Provider("xtom", false)
)

private val DUMMY_SELECTED_PROVIDERS =
listOf(
Provider("31173", true),
Provider("100TB", false),
Provider("Blix", true),
Provider("Creanova", true),
Provider("DataPacket", false),
Provider("HostRoyale", false),
Provider("hostuniversal", false),
Provider("iRegister", false),
Provider("M247", false),
Provider("Makonix", false),
Provider("PrivateLayer", false),
Provider("ptisp", false),
Provider("Qnax", false),
Provider("Quadranet", false),
Provider("techfutures", false),
Provider("Tzulo", false),
Provider("xtom", false)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@ class SelectLocationScreenTest {
uiState =
SelectLocationUiState.ShowData(
countries = DUMMY_RELAY_COUNTRIES,
selectedRelay = null
selectedRelay = null,
selectedOwnership = null,
selectedProvidersCount = 0,
searchTerm = ""
),
uiCloseAction = MutableSharedFlow(),
enterTransitionEndAction = MutableSharedFlow<Unit>().asSharedFlow()
Expand Down Expand Up @@ -93,7 +96,10 @@ class SelectLocationScreenTest {
uiState =
SelectLocationUiState.ShowData(
countries = updatedDummyList,
selectedRelay = updatedDummyList[0].cities[0].relays[0]
selectedRelay = updatedDummyList[0].cities[0].relays[0],
selectedOwnership = null,
selectedProvidersCount = 0,
searchTerm = ""
),
uiCloseAction = MutableSharedFlow(),
enterTransitionEndAction = MutableSharedFlow<Unit>().asSharedFlow()
Expand All @@ -118,7 +124,13 @@ class SelectLocationScreenTest {
composeTestRule.setContentWithTheme {
SelectLocationScreen(
uiState =
SelectLocationUiState.ShowData(countries = emptyList(), selectedRelay = null),
SelectLocationUiState.ShowData(
countries = emptyList(),
selectedRelay = null,
selectedOwnership = null,
selectedProvidersCount = 0,
searchTerm = ""
),
uiCloseAction = MutableSharedFlow(),
enterTransitionEndAction = MutableSharedFlow<Unit>().asSharedFlow(),
onSearchTermInput = mockedSearchTermInput
Expand All @@ -140,7 +152,14 @@ class SelectLocationScreenTest {
val mockSearchString = "SEARCH"
composeTestRule.setContentWithTheme {
SelectLocationScreen(
uiState = SelectLocationUiState.NoSearchResultFound(searchTerm = mockSearchString),
uiState =
SelectLocationUiState.ShowData(
countries = emptyList(),
selectedRelay = null,
selectedOwnership = null,
selectedProvidersCount = 0,
searchTerm = mockSearchString
),
uiCloseAction = MutableSharedFlow(),
enterTransitionEndAction = MutableSharedFlow<Unit>().asSharedFlow(),
onSearchTermInput = mockedSearchTermInput
Expand Down Expand Up @@ -187,7 +206,7 @@ class SelectLocationScreenTest {
private val DUMMY_RELAY_COUNTRIES =
RelayList(
arrayListOf(DUMMY_RELAY_COUNTRY_1, DUMMY_RELAY_COUNTRY_2),
DUMMY_WIREGUARD_ENDPOINT_DATA
DUMMY_WIREGUARD_ENDPOINT_DATA,
)
.toRelayCountries(ownership = Constraint.Any(), providers = Constraint.Any())
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package net.mullvad.mullvadvpn.compose.button

import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.compose.component.SpacedColumn
import net.mullvad.mullvadvpn.lib.theme.AppTheme

@Preview
@Composable
private fun PreviewApplyButton() {
AppTheme {
SpacedColumn {
ApplyButton(onClick = {}, isEnabled = true)
ApplyButton(onClick = {}, isEnabled = false)
}
}
}

@Composable
fun ApplyButton(
modifier: Modifier = Modifier,
background: Color = MaterialTheme.colorScheme.background,
onClick: () -> Unit,
isEnabled: Boolean
) {
VariantButton(
background = background,
text = stringResource(id = R.string.apply),
onClick = onClick,
modifier = modifier,
isEnabled = isEnabled,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package net.mullvad.mullvadvpn.compose.cell

import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Checkbox
import androidx.compose.material3.CheckboxDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import net.mullvad.mullvadvpn.lib.theme.AppTheme
import net.mullvad.mullvadvpn.lib.theme.Dimens
import net.mullvad.mullvadvpn.lib.theme.color.MullvadGreen

@Preview
@Composable
private fun PreviewCheckboxCell() {
AppTheme { CheckboxCell(providerName = "", checked = false, onCheckedChange = {}) }
}

@Composable
internal fun CheckboxCell(
modifier: Modifier = Modifier,
providerName: String,
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
background: Color = MaterialTheme.colorScheme.secondaryContainer,
startPadding: Dp = Dimens.cellStartPadding,
endPadding: Dp = Dimens.cellEndPadding,
minHeight: Dp = Dimens.cellHeight
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier =
modifier
.clickable { onCheckedChange(!checked) }
.defaultMinSize(minHeight = minHeight)
.fillMaxWidth()
.background(background)
.padding(start = startPadding, end = endPadding)
) {
Box(
modifier =
Modifier.size(Dimens.checkBoxSize)
.background(Color.White, MaterialTheme.shapes.small)
) {
Checkbox(
modifier = Modifier.fillMaxSize(),
checked = checked,
onCheckedChange = onCheckedChange,
colors =
CheckboxDefaults.colors(
checkedColor = Color.Transparent,
uncheckedColor = Color.Transparent,
checkmarkColor = MullvadGreen
),
)
}

Spacer(modifier = Modifier.size(Dimens.mediumPadding))

Text(
text = providerName,
style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.onSecondary,
modifier =
Modifier.weight(1f)
.padding(top = Dimens.mediumPadding, bottom = Dimens.mediumPadding)
)
}
}
Loading
Loading