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