Skip to content

Commit

Permalink
Fix Voucher dialog copy/paste issue
Browse files Browse the repository at this point in the history
  • Loading branch information
sabercodic committed Nov 22, 2023
1 parent e0e5ab1 commit da2c1b9
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import net.mullvad.mullvadvpn.compose.button.VariantButton
import net.mullvad.mullvadvpn.compose.component.MullvadCircularProgressIndicatorSmall
import net.mullvad.mullvadvpn.compose.state.VoucherDialogState
import net.mullvad.mullvadvpn.compose.state.VoucherDialogUiState
import net.mullvad.mullvadvpn.compose.textfield.GroupedTextField
import net.mullvad.mullvadvpn.compose.textfield.CustomTextField
import net.mullvad.mullvadvpn.compose.util.MAX_VOUCHER_LENGTH
import net.mullvad.mullvadvpn.compose.util.vouchersVisualTransformation
import net.mullvad.mullvadvpn.constant.VOUCHER_LENGTH
Expand Down Expand Up @@ -217,23 +217,20 @@ private fun EnterVoucherBody(
onVoucherInputChange: (String) -> Unit = {},
onRedeem: (voucherCode: String) -> Unit
) {
GroupedTextField(
CustomTextField(
value = uiState.voucherInput,
onSubmit = { input ->
if (uiState.voucherInput.length == VOUCHER_LENGTH) {
onRedeem(input)
}
},
onValueChanged = { input -> onVoucherInputChange(input.uppercase()) },
onValueChanged = { input -> onVoucherInputChange(input) },
isValidValue =
uiState.voucherInput.isEmpty() || uiState.voucherInput.length == MAX_VOUCHER_LENGTH,
keyboardType = KeyboardType.Password,
placeholderText = stringResource(id = R.string.voucher_hint),
visualTransformation = vouchersVisualTransformation(),
maxCharLength = VOUCHER_LENGTH,
isDigitsOnlyAllowed = false,
isEnabled = true,
validateRegex = "^[A-Za-z0-9]*$".toRegex()
isDigitsOnlyAllowed = false
)
Spacer(modifier = Modifier.height(Dimens.smallPadding))
Row(
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ const val VOUCHER_CHUNK_SIZE = 4
const val MAX_VOUCHER_LENGTH = 16

fun vouchersVisualTransformation() = VisualTransformation { text ->
var out = text.chunked(VOUCHER_CHUNK_SIZE).joinToString(VOUCHER_SEPARATOR)
var out =
text
.substring(0, min(MAX_VOUCHER_LENGTH, text.length))
.chunked(VOUCHER_CHUNK_SIZE)
.joinToString(VOUCHER_SEPARATOR)
if (
text.length % VOUCHER_CHUNK_SIZE == 0 &&
text.isNotEmpty() &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@ fun ServiceConnectionManager.settingsListener() =

fun ServiceConnectionManager.splitTunneling() =
this.connectionState.value.readyContainer()?.splitTunneling

fun ServiceConnectionManager.voucherRedeemer() =
this.connectionState.value.readyContainer()?.voucherRedeemer
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package net.mullvad.mullvadvpn.util

private const val VALID_VOUCHER_CHARACTER_REGEX_PATTERN = "^[A-Za-z0-9- \r\n]*$"
private const val IGNORED_VOUCHER_CHARACTER_REGEX_PATTERN = """[- \n\r]"""

object VoucherRegexHelper {
fun validate(input: String): Boolean {
return VALID_VOUCHER_CHARACTER_REGEX_PATTERN.toRegex().matches(input)
}

fun trim(input: String): String =
input.replace(Regex(IGNORED_VOUCHER_CHARACTER_REGEX_PATTERN), "")
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,23 @@ import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.compose.state.LoginUiState
import net.mullvad.mullvadvpn.compose.state.VoucherDialogState
import net.mullvad.mullvadvpn.compose.state.VoucherDialogUiState
import net.mullvad.mullvadvpn.constant.VOUCHER_LENGTH
import net.mullvad.mullvadvpn.model.VoucherSubmissionError
import net.mullvad.mullvadvpn.model.VoucherSubmissionResult
import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionContainer
import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionManager
import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionState
import net.mullvad.mullvadvpn.ui.serviceconnection.VoucherRedeemer
import net.mullvad.mullvadvpn.ui.serviceconnection.voucherRedeemer
import net.mullvad.mullvadvpn.util.VoucherRegexHelper

class VoucherDialogViewModel(
serviceConnectionManager: ServiceConnectionManager,
private val serviceConnectionManager: ServiceConnectionManager,
private val resources: Resources
) : ViewModel() {

private val vmState = MutableStateFlow<VoucherDialogState>(VoucherDialogState.Default)
private val voucherInput = MutableStateFlow(LoginUiState.INITIAL.accountNumberInput)

private lateinit var voucherRedeemer: VoucherRedeemer
private val _shared: SharedFlow<ServiceConnectionContainer> =
serviceConnectionManager.connectionState
.flatMapLatest { state ->
Expand All @@ -47,8 +48,7 @@ class VoucherDialogViewModel(

var uiState =
_shared
.flatMapLatest { serviceConnection ->
voucherRedeemer = serviceConnection.voucherRedeemer
.flatMapLatest {
combine(vmState, voucherInput) { state, input ->
VoucherDialogUiState(voucherInput = input, voucherViewModelState = state)
}
Expand All @@ -58,7 +58,7 @@ class VoucherDialogViewModel(
fun onRedeem(voucherCode: String) {
vmState.update { VoucherDialogState.Verifying }
viewModelScope.launch {
when (val result = voucherRedeemer.submit(voucherCode)) {
when (val result = serviceConnectionManager.voucherRedeemer()?.submit(voucherCode)) {
is VoucherSubmissionResult.Ok -> handleAddedTime(result.submission.timeAdded)
is VoucherSubmissionResult.Error -> setError(result.error)
else -> {
Expand All @@ -69,7 +69,16 @@ class VoucherDialogViewModel(
}

fun onVoucherInputChange(voucherString: String) {
voucherInput.value = voucherString

if (VoucherRegexHelper.validate(voucherString)) {
voucherInput.value =
VoucherRegexHelper.trim(voucherString)
.substring(
0,
Integer.min(VOUCHER_LENGTH, VoucherRegexHelper.trim(voucherString).length)
)
.uppercase()
}
}

private fun handleAddedTime(timeAdded: Long) {
Expand Down

0 comments on commit da2c1b9

Please sign in to comment.