Skip to content
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
Expand Up @@ -17,12 +17,13 @@ import com.flipcash.services.user.UserManager
import com.flipcash.services.models.PhoneVerificationError
import com.getcode.manager.BottomBarManager
import com.getcode.util.resources.ResourceHelper
import com.getcode.utils.TraceType
import com.getcode.utils.trace
import com.getcode.view.BaseViewModel
import com.getcode.view.LoadingSuccessState
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.launchIn
Expand Down Expand Up @@ -95,6 +96,7 @@ internal class PhoneVerificationViewModel @Inject constructor(
data object OnVerifyCodeClicked : Event
data object OnCodeVerified : Event
data object LinkForPayment : Event
data object OnPhoneVerificationComplete : Event

data object OnMaxAttemptsReached : Event
}
Expand Down Expand Up @@ -166,11 +168,15 @@ internal class PhoneVerificationViewModel @Inject constructor(
val cleanedNumber = phoneUtils.cleanNumber(number, locale)
ContactMethod.Phone(cleanedNumber)
}
.onEach { dispatchEvent(Event.OnVerifyingCodeChanged(loading = true)) }
.onEach {
trace(message = "Verifying code", type = TraceType.Process)
dispatchEvent(Event.OnVerifyingCodeChanged(loading = true))
}
.map { method ->
verificationController.checkVerificationCode(method, stateFlow.value.codeTextFieldState.text.toString())
}.onResult(
onSuccess = {
trace(message = "Code verified successfully", type = TraceType.Process)
stopTimer()
dispatchEvent(Event.OnVerifyingCodeChanged(success = true))
viewModelScope.launch {
Expand All @@ -184,6 +190,7 @@ internal class PhoneVerificationViewModel @Inject constructor(
}
},
onError = {
trace(message = "Code verification failed: $it", type = TraceType.Error)
dispatchEvent(Event.OnVerifyingCodeChanged())
val (title, message) = when (it) {
is PhoneVerificationError -> when (it) {
Expand All @@ -206,18 +213,24 @@ internal class PhoneVerificationViewModel @Inject constructor(

eventFlow
.filterIsInstance<Event.LinkForPayment>()
.filter {
featureFlags.observe(FeatureFlag.PhoneNumberSend).value ||
userManager.state.value.flags?.enablePhoneNumberSend == true
}
.map {
val number = stateFlow.value.numberTextFieldState.text.toString()
val locale = stateFlow.value.selectedLocale
val cleanedNumber = phoneUtils.cleanNumber(number, locale)
trace(message = "Calling linkForPayment", type = TraceType.Process)
ContactMethod.Phone(cleanedNumber)
}
.map { verificationController.linkForPayment(it) }
.launchIn(viewModelScope)
.map { method -> verificationController.linkForPayment(method) }
.onResult(
onSuccess = {
trace(message = "linkForPayment succeeded", type = TraceType.Process)
dispatchEvent(Event.OnPhoneVerificationComplete)
},
onError = {
trace(message = "linkForPayment failed: $it", type = TraceType.Error)
dispatchEvent(Event.OnPhoneVerificationComplete)
}
).launchIn(viewModelScope)
}

private suspend fun handleSendVerificationCode(method: ContactMethod) {
Expand Down Expand Up @@ -268,6 +281,17 @@ internal class PhoneVerificationViewModel @Inject constructor(
}
}

suspend fun awaitLinkForPayment() {
val isEnabled = featureFlags.observe(FeatureFlag.PhoneNumberSend).value ||
userManager.state.value.flags?.enablePhoneNumberSend == true
if (!isEnabled) return

val number = stateFlow.value.numberTextFieldState.text.toString()
val locale = stateFlow.value.selectedLocale
val cleanedNumber = phoneUtils.cleanNumber(number, locale)
verificationController.linkForPayment(ContactMethod.Phone(cleanedNumber))
}

private fun startTimer() {
dispatchEvent(
Event.OnTimerTick(
Expand Down Expand Up @@ -319,6 +343,7 @@ internal class PhoneVerificationViewModel @Inject constructor(
Event.OnVerifyCodeClicked -> { state -> state }
Event.OnCodeVerified -> { state -> state }
Event.LinkForPayment -> { state -> state }
Event.OnPhoneVerificationComplete -> { state -> state }
is Event.OnPhoneNumberFormatted -> { state -> state.copy(formattedPhone = event.formatted) }
Event.OnSendCodeClicked -> { state -> state.copy(attempts = state.attempts + 1) }
Event.OnMaxAttemptsReached -> { state -> state }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,23 @@ fun PhoneCodeContent(
.launchIn(this)
}

LaunchedEffect(viewModel, includeEmail, linkForPayment) {
LaunchedEffect(viewModel, linkForPayment) {
viewModel.eventFlow
.filterIsInstance<PhoneVerificationViewModel.Event.OnCodeVerified>()
.onEach {
if (linkForPayment) {
viewModel.dispatchEvent(PhoneVerificationViewModel.Event.LinkForPayment)
} else {
viewModel.dispatchEvent(PhoneVerificationViewModel.Event.OnPhoneVerificationComplete)
}
}
.launchIn(this)
}

LaunchedEffect(viewModel, includeEmail) {
viewModel.eventFlow
.filterIsInstance<PhoneVerificationViewModel.Event.OnPhoneVerificationComplete>()
.onEach {
if (includeEmail) {
flowNavigator.navigateTo(VerificationStep.EmailEntry)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,13 @@ fun MyAccountScreen() {

LaunchedEffect(viewModel) {
viewModel.eventFlow
.filterIsInstance<MyAccountScreenViewModel.Event.OnVerifyPhoneClicked>()
.filterIsInstance<MyAccountScreenViewModel.Event.ConnectPhoneClicked>()
.onEach {
val flow = AppRoute.Verification(
origin = AppRoute.Menu.MyAccount,
includePhone = true,
includeEmail = false,
linkForPayment = it.linkForPayment
)

navigator.push(flow) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.content.ClipboardManager
import androidx.lifecycle.viewModelScope
import com.flipcash.app.auth.AuthManager
import com.flipcash.app.core.extensions.setText
import com.flipcash.app.featureflags.FeatureFlag
import com.flipcash.app.featureflags.FeatureFlagController
import com.flipcash.app.menu.MenuItem
import com.flipcash.features.myaccount.R
Expand Down Expand Up @@ -54,14 +55,16 @@ internal class MyAccountScreenViewModel @Inject constructor(
val accountId: String? = null,
val publicKey: String? = null,
val pushToken: String? = null,
val linkForPayment: Boolean = false,
val items: List<MenuItem<Event>> = FullMenuList
)

internal sealed interface Event {
data class OnUserAssociated(
val userId: String?,
val publicKey: String?,
val pushToken: String? = null
val pushToken: String? = null,
val linkForPayment: Boolean = false,
) : Event

data class OnBetaFeaturesUnlocked(val unlocked: Boolean) : Event
Expand All @@ -71,6 +74,7 @@ internal class MyAccountScreenViewModel @Inject constructor(
data object OnViewAccessKey : Event
data object OnVerifyEmailClicked : Event
data object OnVerifyPhoneClicked : Event
data class ConnectPhoneClicked(val linkForPayment: Boolean) : Event
data object OnDeleteAccountClicked : Event
data object OnAccountDeleted : Event
data object CopyPublicKey : Event
Expand All @@ -81,19 +85,26 @@ internal class MyAccountScreenViewModel @Inject constructor(
}

init {
userManager.state
.onEach {
val userId = it.accountId?.base64
val publicKey = it.cluster?.authorityPublicKey?.base58()
combine(
userManager.state,
featureFlagController.observe(FeatureFlag.PhoneNumberSend),
) { state, sendEnabled ->
val userId = state.accountId?.base64
val publicKey = state.cluster?.authorityPublicKey?.base58()

dispatchEvent(
Event.OnUserAssociated(
userId = userId,
publicKey = publicKey,
pushToken = it.pushToken
)
val linkForPayment = sendEnabled ||
state.flags?.enablePhoneNumberSend == true

dispatchEvent(
Event.OnUserAssociated(
userId = userId,
publicKey = publicKey,
pushToken = state.pushToken,
linkForPayment = linkForPayment,
)
}.launchIn(viewModelScope)
)

}.launchIn(viewModelScope)

combine(
featureFlagController.observeOverride(),
Expand Down Expand Up @@ -183,6 +194,12 @@ internal class MyAccountScreenViewModel @Inject constructor(
)
}.launchIn(viewModelScope)

eventFlow
.filterIsInstance<Event.OnVerifyPhoneClicked>()
.onEach {
dispatchEvent(Event.ConnectPhoneClicked(stateFlow.value.linkForPayment))
}.launchIn(viewModelScope)

eventFlow
.filterIsInstance<Event.OnLogOutClicked>()
.onEach {
Expand Down Expand Up @@ -228,13 +245,15 @@ internal class MyAccountScreenViewModel @Inject constructor(
state.copy(
accountId = event.userId,
publicKey = event.publicKey,
pushToken = event.pushToken
pushToken = event.pushToken,
linkForPayment = event.linkForPayment,
)
}

Event.OnLogOutClicked,
Event.OnLoggedOutCompletely,
Event.OnVerifyPhoneClicked,
is Event.ConnectPhoneClicked,
Event.OnVerifyEmailClicked,
Event.OnViewAccessKey,
Event.CopyPublicKey,
Expand Down
Loading