Skip to content

Commit 866bdeb

Browse files
authored
Merge pull request #161 from code-payments/chore/phone-confirm-resend
chore(phone/confirm): move loading state for resend code to text container
2 parents 58edb20 + bf7362f commit 866bdeb

2 files changed

Lines changed: 40 additions & 19 deletions

File tree

app/src/main/java/com/getcode/view/login/PhoneConfirm.kt

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
99
import androidx.compose.foundation.layout.imePadding
1010
import androidx.compose.foundation.layout.navigationBars
1111
import androidx.compose.foundation.layout.padding
12+
import androidx.compose.foundation.layout.size
1213
import androidx.compose.foundation.layout.width
1314
import androidx.compose.foundation.layout.windowInsetsPadding
1415
import androidx.compose.foundation.layout.wrapContentHeight
@@ -38,6 +39,7 @@ import androidx.compose.ui.text.style.TextAlign
3839
import androidx.compose.ui.text.style.TextDecoration
3940
import androidx.compose.ui.text.withStyle
4041
import androidx.compose.ui.tooling.preview.Preview
42+
import androidx.compose.ui.unit.dp
4143
import androidx.hilt.navigation.compose.hiltViewModel
4244
import com.getcode.LocalPhoneFormatter
4345
import com.getcode.R
@@ -46,13 +48,14 @@ import com.getcode.navigation.screens.LoginArgs
4648
import com.getcode.network.repository.replaceParam
4749
import com.getcode.theme.BrandLight
4850
import com.getcode.theme.CodeTheme
51+
import com.getcode.theme.White
4952
import com.getcode.ui.components.ButtonState
5053
import com.getcode.ui.components.CodeButton
54+
import com.getcode.ui.components.CodeCircularProgressIndicator
5155
import com.getcode.ui.components.OtpRow
5256

53-
const val OTP_LENGTH = 6
57+
internal const val OTP_LENGTH = 6
5458

55-
@OptIn(ExperimentalComposeUiApi::class)
5659
@Preview
5760
@Composable
5861
fun PhoneConfirm(
@@ -142,6 +145,14 @@ fun PhoneConfirm(
142145
"0:${if (dataState.resetTimerTime < 10) "0" else ""}${dataState.resetTimerTime}"
143146
)
144147
)
148+
} else if (dataState.isResendingCode) {
149+
CodeCircularProgressIndicator(
150+
strokeWidth = CodeTheme.dimens.thickBorder,
151+
color = BrandLight,
152+
modifier = Modifier
153+
.size(CodeTheme.dimens.grid.x4)
154+
.align(Alignment.CenterHorizontally),
155+
)
145156
} else {
146157
val text = buildAnnotatedString {
147158
append(stringResource(id = R.string.subtitle_didntGetCodeResend))
@@ -181,7 +192,7 @@ fun PhoneConfirm(
181192
onClick = {
182193
viewModel.onSubmit()
183194
},
184-
isLoading = dataState.isLoading,
195+
isLoading = dataState.isLoading && !dataState.isResendingCode,
185196
isSuccess = dataState.isSuccess,
186197
enabled = false,
187198
text = stringResource(R.string.action_confirm),

app/src/main/java/com/getcode/view/login/PhoneConfirmViewModel.kt

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,20 @@ import com.getcode.App
99
import com.getcode.R
1010
import com.getcode.crypt.MnemonicPhrase
1111
import com.getcode.ed25519.Ed25519
12-
import com.getcode.manager.*
13-
import com.getcode.navigation.screens.AccessKeyScreen
12+
import com.getcode.manager.SessionManager
13+
import com.getcode.manager.TopBarManager
1414
import com.getcode.navigation.core.CodeNavigator
15+
import com.getcode.navigation.screens.AccessKeyScreen
1516
import com.getcode.navigation.screens.HomeScreen
1617
import com.getcode.navigation.screens.PhoneNumberScreen
17-
import com.getcode.network.repository.*
18+
import com.getcode.network.repository.IdentityRepository
19+
import com.getcode.network.repository.PhoneRepository
20+
import com.getcode.network.repository.encodeBase64
1821
import com.getcode.util.OtpSmsBroadcastReceiver
1922
import com.getcode.util.PhoneUtils
2023
import com.getcode.util.resources.ResourceHelper
2124
import com.getcode.utils.ErrorUtils
22-
import com.getcode.view.*
25+
import com.getcode.view.BaseViewModel
2326
import dagger.hilt.android.lifecycle.HiltViewModel
2427
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
2528
import io.reactivex.rxjava3.annotations.NonNull
@@ -31,7 +34,7 @@ import kotlinx.coroutines.Dispatchers
3134
import kotlinx.coroutines.flow.MutableStateFlow
3235
import kotlinx.coroutines.flow.update
3336
import kotlinx.coroutines.launch
34-
import java.util.*
37+
import java.util.Timer
3538
import java.util.concurrent.TimeUnit
3639
import javax.inject.Inject
3740
import kotlin.concurrent.fixedRateTimer
@@ -44,15 +47,15 @@ data class PhoneConfirmUiModel(
4447
val phoneNumber: String? = null,
4548
val phoneNumberFormatted: String? = null,
4649
val isLoading: Boolean = false,
50+
val isResendingCode: Boolean = false,
4751
val isSuccess: Boolean = false,
4852
val isAutoSubmitted: Boolean = false,
4953
val entropyB64: String? = null,
5054
val isPhoneLinking: Boolean = false,
5155
val isNewAccount: Boolean = false,
5256
val isResendTimerRunning: Boolean = true,
53-
val resetTimerTime: Int = 60,
57+
val resetTimerTime: Int = PhoneConfirmViewModel.RESEND_TIMER_MAX,
5458
val attempts: Int = 0,
55-
val isCodeResent: Boolean = false
5659
)
5760

5861
@HiltViewModel
@@ -62,6 +65,11 @@ class PhoneConfirmViewModel @Inject constructor(
6265
private val phoneUtils: PhoneUtils,
6366
private val resources: ResourceHelper,
6467
) : BaseViewModel(resources) {
68+
69+
companion object {
70+
internal const val RESEND_TIMER_MAX = 60
71+
}
72+
6573
val uiFlow = MutableStateFlow(PhoneConfirmUiModel())
6674
private var navigator: CodeNavigator? = null
6775
private var timer: Timer? = null
@@ -156,9 +164,8 @@ class PhoneConfirmViewModel @Inject constructor(
156164
private fun startTimer() {
157165
uiFlow.update {
158166
it.copy(
159-
isCodeResent = false,
160167
isResendTimerRunning = true,
161-
resetTimerTime = 60
168+
resetTimerTime = RESEND_TIMER_MAX
162169
)
163170
}
164171
timer?.cancel()
@@ -175,25 +182,23 @@ class PhoneConfirmViewModel @Inject constructor(
175182
}
176183

177184
fun resendCode() {
178-
startTimer()
179-
180185
val phoneNumber = uiFlow.value.phoneNumber ?: return
181186

182187
CoroutineScope(Dispatchers.IO).launch {
183188
phoneRepository.sendVerificationCode(phoneNumber)
184189
.firstElement()
190+
.doOnSubscribe { setIsResending(true) }
191+
.doOnTerminate { setIsResending(false) }
192+
.doOnComplete { setIsResending(false) }
185193
.observeOn(AndroidSchedulers.mainThread())
186-
.doOnSubscribe { setIsLoading(true) }
187-
.doOnTerminate { setIsLoading(false) }
188-
.doOnComplete { setIsLoading(false) }
189194
.map { res ->
190195
when (res) {
191196
PhoneVerificationService.SendVerificationCodeResponse.Result.OK -> null
192197
else -> getGenericError()
193198
}?.let { message -> TopBarManager.showMessage(message) }
194199
res == PhoneVerificationService.SendVerificationCodeResponse.Result.OK
195200
}
196-
.subscribe({}, ErrorUtils::handleError)
201+
.subscribe({ startTimer() }, ErrorUtils::handleError)
197202
}
198203
}
199204

@@ -259,7 +264,6 @@ class PhoneConfirmViewModel @Inject constructor(
259264
val isPhoneLinking = uiFlow.value.isPhoneLinking
260265
val isNewAccount = uiFlow.value.isNewAccount
261266
val attempts = uiFlow.value.attempts
262-
val isSeedInput = entropyB64 != null
263267

264268
if (entropyB64 == null && !isNewAccount) return
265269

@@ -358,6 +362,12 @@ class PhoneConfirmViewModel @Inject constructor(
358362
}
359363
}
360364

365+
private fun setIsResending(resending: Boolean) {
366+
uiFlow.update {
367+
it.copy(isResendingCode = resending)
368+
}
369+
}
370+
361371
private fun getInvalidCodeError() = TopBarManager.TopBarMessage(
362372
resources.getString(R.string.error_title_invalidVerificationCode),
363373
resources.getString(R.string.error_description_invalidVerificationCode)

0 commit comments

Comments
 (0)