Skip to content

Commit

Permalink
Fix pref center dialog allowing invalid emails when submitting via ke…
Browse files Browse the repository at this point in the history
…yboard, improve pending/resend delayed visibility changes (#1468)

* Fix issue with keyboard enter allowing invalid emails to be submitted

* Improve pending/resend delayed visibility changes to handle contact hannel updates
  • Loading branch information
jyaganeh authored Jun 28, 2024
1 parent 2603659 commit de401a4
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,8 @@ internal class PreferenceCenterViewModel @JvmOverloads constructor(
val isPending = !channel.isOptedIn
if (isPending) {
schedulePendingResendVisibilityChanges(channel)
} else {
cancelPendingResendVisibilityChanges(channel)
}
ContactChannelState(
showResendButton = false, showPendingButton = isPending
Expand All @@ -290,6 +292,8 @@ internal class PreferenceCenterViewModel @JvmOverloads constructor(
val isPending = !channel.isOptedIn
if (isPending) {
schedulePendingResendVisibilityChanges(channel, onlyHide = true)
} else {
cancelPendingResendVisibilityChanges(channel)
}
channelState
}
Expand Down Expand Up @@ -431,33 +435,40 @@ internal class PreferenceCenterViewModel @JvmOverloads constructor(
}
}

private var showResendButtonJob: Job? = null
private var hidePendingLabelJob: Job? = null
private var showResendButtonJobs: MutableMap<ContactChannel, Job> = mutableMapOf()
private var hidePendingLabelJobs: MutableMap<ContactChannel, Job> = mutableMapOf()

fun cancelPendingResendVisibilityChanges(channel: ContactChannel) {
cancelPendingVisibilityChanges(channel)
cancelResendVisibilityChanges(channel)
}

fun cancelPendingVisibilityChanges(channel: ContactChannel) {
hidePendingLabelJobs[channel]?.cancel()
hidePendingLabelJobs.remove(channel)
}

fun cancelResendVisibilityChanges(channel: ContactChannel) {
showResendButtonJobs[channel]?.cancel()
showResendButtonJobs.remove(channel)
}

fun schedulePendingResendVisibilityChanges(channel: ContactChannel, onlyHide: Boolean = false) {
if (!onlyHide) {
showResendButtonJob?.cancel()
showResendButtonJob = viewModelScope.launch(dispatcher) {
cancelResendVisibilityChanges(channel)
showResendButtonJobs[channel] = viewModelScope.launch(dispatcher) {
delay(defaultResendLabelHideDelay)
handle(
Action.UpdateContactChannel(
channel, ContactChannelState(
showResendButton = true, showPendingButton = true
)
)
)
handle(Action.UpdateContactChannel(
channel, ContactChannelState(showResendButton = true, showPendingButton = true)
))
}
}

hidePendingLabelJob?.cancel()
hidePendingLabelJob = viewModelScope.launch(dispatcher) {
cancelPendingVisibilityChanges(channel)
hidePendingLabelJobs[channel] = viewModelScope.launch(dispatcher) {
delay(defaultPendingLabelHideDelay)
handle(Action.UpdateContactChannel(
channel,
ContactChannelState(
showPendingButton = false,
showResendButton = false
)
channel, ContactChannelState(showPendingButton = false, showResendButton = false)
))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,32 @@ internal class ContactChannelDialogInputView@JvmOverloads constructor(
private val countryPickerInputView: TextInputLayout
private val countryPickerTextView: AutoCompleteTextView

var onValidationChanged: ((Boolean) -> Unit)? = null
var onSubmit: (() -> Unit)? = null

private val adapter: ArrayAdapter<String> by lazy {
ArrayAdapter(context, android.R.layout.simple_dropdown_item_1line)
}

private var platform: Item.ContactManagement.Platform? = null
private var selectedSender: SmsSenderInfo? = null

private var isValid = false

private val validator: (input: String?) -> Boolean = { input ->
when (platform) {
is Item.ContactManagement.Platform.Email -> {
val formatted = formatEmail(input)
!input.isNullOrBlank() && emailRegex.matches(formatted)
}
is Item.ContactManagement.Platform.Sms -> {
val formatted = formatPhone(selectedSender?.dialingCode, input)
!input.isNullOrBlank() && phoneRegex.matches(formatted)
}
else -> false
}
}

init {
inflate(context, R.layout.ua_contact_channel_dialog_input, this)
textInputView = findViewById(R.id.text_input)
Expand All @@ -46,7 +72,8 @@ internal class ContactChannelDialogInputView@JvmOverloads constructor(
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) = Unit

override fun afterTextChanged(s: Editable?) {
onValidationChanged?.invoke(validator(s?.toString()))
isValid = validator(s?.toString())
onValidationChanged?.invoke(isValid)
}
})

Expand All @@ -56,7 +83,9 @@ internal class ContactChannelDialogInputView@JvmOverloads constructor(

setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
onSubmit?.invoke()
if (isValid) {
onSubmit?.invoke()
}
true
} else {
false
Expand All @@ -65,7 +94,9 @@ internal class ContactChannelDialogInputView@JvmOverloads constructor(

setOnKeyListener { _, keyCode, event ->
if (keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_DOWN) {
onSubmit?.invoke()
if (isValid) {
onSubmit?.invoke()
}
true
} else {
false
Expand All @@ -74,30 +105,6 @@ internal class ContactChannelDialogInputView@JvmOverloads constructor(
}
}

var onValidationChanged: ((Boolean) -> Unit)? = null
var onSubmit: (() -> Unit)? = null

private val adapter: ArrayAdapter<String> by lazy {
ArrayAdapter(context, android.R.layout.simple_dropdown_item_1line)
}

private var platform: Item.ContactManagement.Platform? = null
private var selectedSender: SmsSenderInfo? = null

private val validator: (input: String?) -> Boolean = { input ->
when (platform) {
is Item.ContactManagement.Platform.Email -> {
val formatted = formatEmail(input)
!input.isNullOrBlank() && emailRegex.matches(formatted)
}
is Item.ContactManagement.Platform.Sms -> {
val formatted = formatPhone(selectedSender?.dialingCode, input)
!input.isNullOrBlank() && phoneRegex.matches(formatted)
}
else -> false
}
}

fun setPlatform(platform: Item.ContactManagement.Platform, display: PromptDisplay) {
this.platform = platform

Expand Down

0 comments on commit de401a4

Please sign in to comment.