Skip to content

Commit

Permalink
Fixed some more ui issues
Browse files Browse the repository at this point in the history
  • Loading branch information
Pururun committed Jun 11, 2024
1 parent 47db813 commit 37a919f
Show file tree
Hide file tree
Showing 21 changed files with 155 additions and 143 deletions.
Original file line number Diff line number Diff line change
@@ -1,82 +1,36 @@
package net.mullvad.mullvadvpn.compose.button

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.compose.component.MullvadCircularProgressIndicatorSmall
import net.mullvad.mullvadvpn.compose.preview.TestMethodButtonPreviewParameterProvider
import net.mullvad.mullvadvpn.lib.model.TestApiAccessMethodState
import net.mullvad.mullvadvpn.lib.theme.AppTheme
import net.mullvad.mullvadvpn.lib.theme.Dimens
import net.mullvad.mullvadvpn.lib.theme.color.selected

@Preview
@Composable
private fun PreviewTestMethodButton(
@PreviewParameter(provider = TestMethodButtonPreviewParameterProvider::class)
state: TestApiAccessMethodState?
@PreviewParameter(provider = TestMethodButtonPreviewParameterProvider::class) isTesting: Boolean
) {
AppTheme { TestMethodButton(testMethodState = state, onTestMethod = {}) }
AppTheme { TestMethodButton(isTesting = isTesting, onTestMethod = {}) }
}

@Composable
fun TestMethodButton(
modifier: Modifier = Modifier,
testMethodState: TestApiAccessMethodState?,
onTestMethod: () -> Unit
) {
fun TestMethodButton(modifier: Modifier = Modifier, isTesting: Boolean, onTestMethod: () -> Unit) {
PrimaryButton(
modifier = modifier,
leadingIcon = { Icon(testMethodState = testMethodState) },
onClick = onTestMethod,
isEnabled = testMethodState !is TestApiAccessMethodState.Testing,
isEnabled = !isTesting,
text =
stringResource(
id =
when (testMethodState) {
TestApiAccessMethodState.Result.Successful -> R.string.api_reachable
TestApiAccessMethodState.Result.Failure -> R.string.api_unreachable
TestApiAccessMethodState.Testing -> R.string.testing
null -> R.string.test_method
if (isTesting) {
R.string.testing
} else {
R.string.test_method
}
),
)
}

@Composable
private fun Icon(testMethodState: TestApiAccessMethodState?) {
when (testMethodState) {
TestApiAccessMethodState.Result.Failure ->
Box(
modifier =
Modifier.padding(start = Dimens.mediumPadding)
.size(Dimens.relayCircleSize)
.background(color = MaterialTheme.colorScheme.error, shape = CircleShape)
)
TestApiAccessMethodState.Result.Successful -> {
Box(
modifier =
Modifier.padding(start = Dimens.mediumPadding)
.size(Dimens.relayCircleSize)
.background(color = MaterialTheme.colorScheme.selected, shape = CircleShape)
)
}
TestApiAccessMethodState.Testing -> {
MullvadCircularProgressIndicatorSmall(
modifier = Modifier.padding(start = Dimens.mediumPadding)
)
}
null -> {
/*Show nothing*/
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ fun MullvadExposedDropdownMenuBox(
modifier = Modifier.fillMaxWidth().menuAnchor(),
readOnly = true,
value = title,
onValueChange = { /* Do nothing */ },
onValueChange = { /* Do nothing */},
label = { Text(text = label) },
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
colors = colors,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ import net.mullvad.mullvadvpn.compose.button.PrimaryButton
import net.mullvad.mullvadvpn.compose.component.MullvadCircularProgressIndicatorMedium
import net.mullvad.mullvadvpn.compose.preview.SaveApiAccessMethodUiStatePreviewParameterProvider
import net.mullvad.mullvadvpn.compose.state.SaveApiAccessMethodUiState
import net.mullvad.mullvadvpn.compose.state.TestApiAccessMethodState
import net.mullvad.mullvadvpn.compose.test.SAVE_API_ACCESS_METHOD_CANCEL_BUTTON_TEST_TAG
import net.mullvad.mullvadvpn.compose.test.SAVE_API_ACCESS_METHOD_LOADING_SPINNER_TEST_TAG
import net.mullvad.mullvadvpn.compose.test.SAVE_API_ACCESS_METHOD_SAVE_BUTTON_TEST_TAG
import net.mullvad.mullvadvpn.compose.util.LaunchedEffectCollect
import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodId
import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodName
import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodType
import net.mullvad.mullvadvpn.lib.model.TestApiAccessMethodState
import net.mullvad.mullvadvpn.lib.theme.AppTheme
import net.mullvad.mullvadvpn.viewmodel.SaveApiAccessMethodSideEffect
import net.mullvad.mullvadvpn.viewmodel.SaveApiAccessMethodViewModel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class ApiAccessMethodDetailsUiStatePreviewParameterProvider :
isEditable = false,
isCurrentMethod = false,
isDisableable = true,
testApiAccessMethodState = null
isTestingAccessMethod = false
)
},
// Editable api access type, current method, can not be disabled
Expand All @@ -29,7 +29,7 @@ class ApiAccessMethodDetailsUiStatePreviewParameterProvider :
isEditable = true,
isCurrentMethod = true,
isDisableable = false,
testApiAccessMethodState = null
isTestingAccessMethod = false
)
}
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import net.mullvad.mullvadvpn.compose.state.EditApiAccessFormData
import net.mullvad.mullvadvpn.compose.state.EditApiAccessMethodUiState
import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodType
import net.mullvad.mullvadvpn.lib.model.InvalidDataError
import net.mullvad.mullvadvpn.lib.model.TestApiAccessMethodState

class EditApiAccessMethodUiStateParameterProvider :
PreviewParameterProvider<EditApiAccessMethodUiState> {
Expand All @@ -18,7 +17,7 @@ class EditApiAccessMethodUiStateParameterProvider :
editMode = false,
formData = EditApiAccessFormData.empty(),
hasChanges = false,
testMethodState = null
isTestingApiAccessMethod = false
),
// Shadowsocks, no errors
EditApiAccessMethodUiState.Content(
Expand All @@ -37,7 +36,7 @@ class EditApiAccessMethodUiStateParameterProvider :
username = ""
)
},
testMethodState = null
isTestingApiAccessMethod = false
),
// Socks5 Remote, no errors, testing method
EditApiAccessMethodUiState.Content(
Expand All @@ -56,7 +55,7 @@ class EditApiAccessMethodUiStateParameterProvider :
password = data.auth?.password ?: ""
)
},
testMethodState = TestApiAccessMethodState.Testing
isTestingApiAccessMethod = true
),
// Socks 5 remote, required errors
EditApiAccessMethodUiState.Content(
Expand All @@ -74,7 +73,7 @@ class EditApiAccessMethodUiStateParameterProvider :
InvalidDataError.PasswordError.Required
)
),
testMethodState = null
isTestingApiAccessMethod = false
)
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package net.mullvad.mullvadvpn.compose.preview

import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import net.mullvad.mullvadvpn.compose.state.SaveApiAccessMethodUiState
import net.mullvad.mullvadvpn.lib.model.TestApiAccessMethodState
import net.mullvad.mullvadvpn.compose.state.TestApiAccessMethodState

class SaveApiAccessMethodUiStatePreviewParameterProvider :
PreviewParameterProvider<SaveApiAccessMethodUiState> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
package net.mullvad.mullvadvpn.compose.preview

import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import net.mullvad.mullvadvpn.lib.model.TestApiAccessMethodState

class TestMethodButtonPreviewParameterProvider :
PreviewParameterProvider<TestApiAccessMethodState?> {
override val values: Sequence<TestApiAccessMethodState?> =
sequenceOf(
null,
TestApiAccessMethodState.Testing,
TestApiAccessMethodState.Result.Successful,
TestApiAccessMethodState.Result.Failure
)
class TestMethodButtonPreviewParameterProvider : PreviewParameterProvider<Boolean> {
override val values: Sequence<Boolean> = sequenceOf(false, true)
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
Expand Down Expand Up @@ -100,12 +102,37 @@ fun ApiAccessMethodDetails(
navigator.navigate(EditApiAccessMethodDestination(it.apiAccessMethodId)) {
launchSingleTop = true
}
is ApiAccessMethodDetailsSideEffect.TestApiAccessMethodResult -> {
launch {
snackbarHostState.showSnackbarImmediately(
context.getString(
if (it.successful) {
R.string.api_reachable
} else {
R.string.api_unreachable
}
)
)
}
}
}
}

confirmDeleteListResultRecipient.OnNavResultValue { navigator.navigateUp() }

val state by viewModel.uiState.collectAsStateWithLifecycle()

LaunchedEffect(state.testingAccessMethod()) {
if (state.testingAccessMethod()) {
launch {
snackbarHostState.showSnackbarImmediately(
message = context.getString(R.string.testing),
duration = SnackbarDuration.Indefinite
)
}
}
}

ApiAccessMethodDetailsScreen(
state = state,
snackbarHostState = snackbarHostState,
Expand Down Expand Up @@ -199,12 +226,12 @@ private fun Content(
TestMethodButton(
modifier =
Modifier.padding(horizontal = Dimens.sideMargin).testTag(API_ACCESS_TEST_METHOD_BUTTON),
testMethodState = state.testApiAccessMethodState,
isTesting = state.isTestingAccessMethod,
onTestMethod = onTestMethodClicked
)
Spacer(modifier = Modifier.height(Dimens.verticalSpace))
PrimaryButton(
isEnabled = !state.isCurrentMethod,
isEnabled = !state.isCurrentMethod && !state.isTestingAccessMethod,
modifier =
Modifier.padding(horizontal = Dimens.sideMargin).testTag(API_ACCESS_USE_METHOD_BUTTON),
onClick = onUseMethodClicked,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
Expand Down Expand Up @@ -106,6 +108,20 @@ fun EditApiAccessMethod(
) {
launchSingleTop = true
}
is EditApiAccessSideEffect.TestApiAccessMethodResult -> {
launch {
snackbarHostState.showSnackbarImmediately(
message =
context.getString(
if (it.successful) {
R.string.api_reachable
} else {
R.string.api_unreachable
}
)
)
}
}
}
}

Expand All @@ -129,8 +145,21 @@ fun EditApiAccessMethod(
}

val state by viewModel.uiState.collectAsStateWithLifecycle()

LaunchedEffect(state.testingApiAccessMethod()) {
if (state.testingApiAccessMethod()) {
launch {
snackbarHostState.showSnackbarImmediately(
message = context.getString(R.string.testing),
duration = SnackbarDuration.Indefinite
)
}
}
}

EditApiAccessMethodScreen(
state = state,
snackbarHostState = snackbarHostState,
onNameChanged = viewModel::onNameChanged,
onTypeSelected = viewModel::setAccessMethodType,
onIpChanged = viewModel::onServerIpChanged,
Expand Down Expand Up @@ -227,7 +256,7 @@ fun EditApiAccessMethodScreen(
bottom = Dimens.verticalSpace,
top = Dimens.largePadding
),
testMethodState = state.testMethodState,
isTesting = state.isTestingApiAccessMethod,
onTestMethod = onTestMethod
)
AddMethodButton(isNew = !state.editMode, onAddMethod = onAddMethod)
Expand Down Expand Up @@ -431,6 +460,7 @@ private fun PasswordInput(
isValidValue = passwordError == null,
isDigitsOnlyAllowed = false,
imeAction =
// So that we avoid going back to the name input when pressing done/next
if (optional) {
ImeAction.Next
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package net.mullvad.mullvadvpn.compose.state

import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodId
import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodName
import net.mullvad.mullvadvpn.lib.model.TestApiAccessMethodState

sealed interface ApiAccessMethodDetailsUiState {
val apiAccessMethodId: ApiAccessMethodId
Expand All @@ -17,10 +16,12 @@ sealed interface ApiAccessMethodDetailsUiState {
val isEditable: Boolean,
val isDisableable: Boolean,
val isCurrentMethod: Boolean,
val testApiAccessMethodState: TestApiAccessMethodState?
val isTestingAccessMethod: Boolean,
) : ApiAccessMethodDetailsUiState

fun name() = (this as? Content)?.name?.value ?: ""

fun canBeEdited() = (this as? Content)?.isEditable ?: false
fun canBeEdited() = this is Content && isEditable

fun testingAccessMethod() = this is Content && isTestingAccessMethod
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodName
import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodType
import net.mullvad.mullvadvpn.lib.model.Cipher
import net.mullvad.mullvadvpn.lib.model.InvalidDataError
import net.mullvad.mullvadvpn.lib.model.TestApiAccessMethodState

sealed interface EditApiAccessMethodUiState {
val editMode: Boolean
Expand All @@ -17,10 +16,12 @@ sealed interface EditApiAccessMethodUiState {
override val editMode: Boolean,
val formData: EditApiAccessFormData,
val hasChanges: Boolean,
val testMethodState: TestApiAccessMethodState?
val isTestingApiAccessMethod: Boolean,
) : EditApiAccessMethodUiState

fun hasChanges() = this is Content && hasChanges

fun testingApiAccessMethod(): Boolean = this is Content && isTestingApiAccessMethod
}

data class EditApiAccessFormData(
Expand Down
Loading

0 comments on commit 37a919f

Please sign in to comment.