Fix loading state in New Message Fragment

pr/1451-theming
Andrew 11 months ago
parent 60d41ad10d
commit f8e3bc7d9a

@ -183,6 +183,7 @@ fun EnterAccountId(
.padding(horizontal = LocalDimensions.current.marginLarge) .padding(horizontal = LocalDimensions.current.marginLarge)
.fillMaxWidth() .fillMaxWidth()
.contentDescription(R.string.next), .contentDescription(R.string.next),
enabled = state.isNextButtonEnabled,
onClick = { callbacks.onContinue() } onClick = { callbacks.onContinue() }
) { ) {
LoadingArcOr(state.loading) { LoadingArcOr(state.loading) {

@ -4,27 +4,29 @@ import android.app.Application
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withTimeout
import network.loki.messenger.R import network.loki.messenger.R
import nl.komponents.kovenant.ui.failUi
import nl.komponents.kovenant.ui.successUi
import org.session.libsession.snode.SnodeAPI import org.session.libsession.snode.SnodeAPI
import org.session.libsignal.utilities.PublicKeyValidation import org.session.libsignal.utilities.PublicKeyValidation
import org.thoughtcrime.securesms.ui.GetString import org.thoughtcrime.securesms.ui.GetString
import javax.inject.Inject import javax.inject.Inject
import kotlin.time.Duration.Companion.seconds
@HiltViewModel @HiltViewModel
class NewMessageViewModel @Inject constructor( class NewMessageViewModel @Inject constructor(
private val application: Application private val application: Application
): AndroidViewModel(application), Callbacks { ): AndroidViewModel(application), Callbacks {
private val _state = MutableStateFlow(State()) private val _state = MutableStateFlow(State())
val state = _state.asStateFlow() val state = _state.asStateFlow()
@ -34,11 +36,13 @@ class NewMessageViewModel @Inject constructor(
private val _qrErrors = Channel<String>() private val _qrErrors = Channel<String>()
val qrErrors: Flow<String> = _qrErrors.receiveAsFlow() val qrErrors: Flow<String> = _qrErrors.receiveAsFlow()
private var job: Job? = null
override fun onChange(value: String) { override fun onChange(value: String) {
_state.update { it.copy( job?.cancel()
newMessageIdOrOns = value, job = null
error = null
) } _state.update { State(newMessageIdOrOns = value) }
} }
override fun onContinue() { override fun onContinue() {
@ -54,6 +58,8 @@ class NewMessageViewModel @Inject constructor(
} }
private fun createPrivateChatIfPossible(onsNameOrPublicKey: String) { private fun createPrivateChatIfPossible(onsNameOrPublicKey: String) {
if (job?.isActive == true) return
if (PublicKeyValidation.isValid(onsNameOrPublicKey, isPrefixRequired = false)) { if (PublicKeyValidation.isValid(onsNameOrPublicKey, isPrefixRequired = false)) {
if (PublicKeyValidation.hasValidPrefix(onsNameOrPublicKey)) { if (PublicKeyValidation.hasValidPrefix(onsNameOrPublicKey)) {
onPublicKey(onsNameOrPublicKey) onPublicKey(onsNameOrPublicKey)
@ -64,11 +70,18 @@ class NewMessageViewModel @Inject constructor(
// This could be an ONS name // This could be an ONS name
_state.update { it.copy(error = null, loading = true) } _state.update { it.copy(error = null, loading = true) }
SnodeAPI.getSessionID(onsNameOrPublicKey).successUi { hexEncodedPublicKey -> job = viewModelScope.launch(Dispatchers.IO) {
_state.update { it.copy(loading = false) } try {
onPublicKey(onsNameOrPublicKey) withTimeout(5.seconds) {
}.failUi { exception -> SnodeAPI.getSessionID(onsNameOrPublicKey).get()
_state.update { it.copy(loading = false, error = GetString(exception) { it.toMessage() }) } }
if (isActive) {
_state.update { it.copy(loading = false) }
onPublicKey(onsNameOrPublicKey)
}
} catch (e: Exception) {
if (isActive) _state.update { it.copy(loading = false, error = GetString(e) { it.toMessage() }) }
}
} }
} }
} }
@ -87,7 +100,9 @@ data class State(
val newMessageIdOrOns: String = "", val newMessageIdOrOns: String = "",
val error: GetString? = null, val error: GetString? = null,
val loading: Boolean = false val loading: Boolean = false
) ) {
val isNextButtonEnabled: Boolean get() = newMessageIdOrOns.isNotBlank()
}
sealed interface Event { sealed interface Event {
data class Success(val key: String): Event data class Success(val key: String): Event

@ -93,12 +93,14 @@ fun OutlineButton(
@Composable @Composable
fun OutlineButton( fun OutlineButton(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
onClick: () -> Unit, onClick: () -> Unit,
content: @Composable () -> Unit = {} content: @Composable () -> Unit = {}
) { ) {
OutlinedButton( OutlinedButton(
modifier = modifier.applyButtonSize(), modifier = modifier.applyButtonSize(),
enabled = enabled,
interactionSource = interactionSource, interactionSource = interactionSource,
onClick = onClick, onClick = onClick,
border = BorderStroke(1.dp, LocalButtonColor.current), border = BorderStroke(1.dp, LocalButtonColor.current),

Loading…
Cancel
Save