mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-27 12:05:22 +00:00
Fix multiple loading activities launched
This commit is contained in:
parent
0e7f95dede
commit
0dde7297b8
@ -66,6 +66,7 @@ import com.google.mlkit.vision.barcode.BarcodeScanning
|
|||||||
import com.google.mlkit.vision.barcode.common.Barcode
|
import com.google.mlkit.vision.barcode.common.Barcode
|
||||||
import com.google.mlkit.vision.common.InputImage
|
import com.google.mlkit.vision.common.InputImage
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
import org.session.libsession.utilities.TextSecurePreferences
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
@ -78,6 +79,7 @@ import org.thoughtcrime.securesms.ui.colorDestructive
|
|||||||
import org.thoughtcrime.securesms.ui.components.SessionTabRow
|
import org.thoughtcrime.securesms.ui.components.SessionTabRow
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
private const val TAG = "LinkDeviceActivity"
|
private const val TAG = "LinkDeviceActivity"
|
||||||
|
|
||||||
@ -108,6 +110,7 @@ class LinkDeviceActivity : BaseActionBarActivity() {
|
|||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
viewModel.eventFlow.collect {
|
viewModel.eventFlow.collect {
|
||||||
startLoadingActivity(it.mnemonic)
|
startLoadingActivity(it.mnemonic)
|
||||||
|
finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,7 +118,7 @@ class LinkDeviceActivity : BaseActionBarActivity() {
|
|||||||
setContent {
|
setContent {
|
||||||
val state by viewModel.stateFlow.collectAsState()
|
val state by viewModel.stateFlow.collectAsState()
|
||||||
AppTheme {
|
AppTheme {
|
||||||
LoadAccountScreen(state, viewModel::onChange, viewModel::tryPhrase)
|
LoadAccountScreen(state, viewModel::onChange, viewModel::onContinue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.let(::setContentView)
|
}.let(::setContentView)
|
||||||
|
@ -1,28 +1,26 @@
|
|||||||
package org.thoughtcrime.securesms.onboarding
|
package org.thoughtcrime.securesms.onboarding
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import androidx.compose.runtime.snapshots.SnapshotApplyResult
|
|
||||||
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.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlinx.coroutines.flow.consumeAsFlow
|
import kotlinx.coroutines.flow.consumeAsFlow
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.debounce
|
||||||
import kotlinx.coroutines.flow.first
|
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.receiveAsFlow
|
import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
|
import kotlinx.coroutines.flow.take
|
||||||
import kotlinx.coroutines.flow.takeWhile
|
import kotlinx.coroutines.flow.takeWhile
|
||||||
import kotlinx.coroutines.flow.transformWhile
|
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.session.libsignal.crypto.MnemonicCodec
|
import org.session.libsignal.crypto.MnemonicCodec
|
||||||
import org.session.libsignal.utilities.Hex
|
import org.session.libsignal.utilities.Hex
|
||||||
import org.thoughtcrime.securesms.crypto.MnemonicUtilities
|
import org.thoughtcrime.securesms.crypto.MnemonicUtilities
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
|
||||||
class LinkDeviceEvent(val mnemonic: ByteArray)
|
class LinkDeviceEvent(val mnemonic: ByteArray)
|
||||||
|
|
||||||
@ -30,38 +28,51 @@ class LinkDeviceEvent(val mnemonic: ByteArray)
|
|||||||
class LinkDeviceViewModel @Inject constructor(
|
class LinkDeviceViewModel @Inject constructor(
|
||||||
application: Application
|
application: Application
|
||||||
): AndroidViewModel(application) {
|
): AndroidViewModel(application) {
|
||||||
|
private val QR_ERROR_TIME = 3.seconds
|
||||||
private val state = MutableStateFlow(LinkDeviceState())
|
private val state = MutableStateFlow(LinkDeviceState())
|
||||||
val stateFlow = state.asStateFlow()
|
val stateFlow = state.asStateFlow()
|
||||||
|
|
||||||
private val qrErrors = Channel<Throwable>()
|
|
||||||
private val event = Channel<LinkDeviceEvent>()
|
private val event = Channel<LinkDeviceEvent>()
|
||||||
val eventFlow = event.receiveAsFlow()
|
val eventFlow = event.receiveAsFlow().take(1)
|
||||||
|
private val qrErrors = Channel<Throwable>()
|
||||||
|
private val qrErrorsFlow = qrErrors.receiveAsFlow().debounce(QR_ERROR_TIME).takeWhile { event.isEmpty }
|
||||||
|
|
||||||
private val phrases = Channel<String>()
|
private val codec by lazy { MnemonicCodec { MnemonicUtilities.loadFileContents(getApplication(), it) } }
|
||||||
|
|
||||||
init {
|
fun onContinue() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
phrases.receiveAsFlow().map {
|
runDecodeCatching(state.value.recoveryPhrase)
|
||||||
runCatching {
|
.onSuccess(::onSuccess)
|
||||||
MnemonicCodec { MnemonicUtilities.loadFileContents(getApplication(), it) }
|
.onFailure(::onFailure)
|
||||||
.decode(it)
|
|
||||||
.let(Hex::fromStringCondensed)
|
|
||||||
}
|
|
||||||
}.takeWhile {
|
|
||||||
it.getOrNull()?.let(::LinkDeviceEvent)?.let { event.send(it) }
|
|
||||||
it.exceptionOrNull()?.let { qrErrors.send(it) }
|
|
||||||
it.isFailure
|
|
||||||
}.collect()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun tryPhrase(string: String = state.value.recoveryPhrase) {
|
fun scan(string: String) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
phrases.send(string)
|
runDecodeCatching(string)
|
||||||
|
.onSuccess(::onSuccess)
|
||||||
|
.onFailure(::onScanFailure)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun onChange(recoveryPhrase: String) {
|
fun onChange(recoveryPhrase: String) {
|
||||||
state.value = LinkDeviceState(recoveryPhrase)
|
state.value = LinkDeviceState(recoveryPhrase)
|
||||||
}
|
}
|
||||||
|
private fun onSuccess(seed: ByteArray) {
|
||||||
|
viewModelScope.launch { event.send(LinkDeviceEvent(seed)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onFailure(error: Throwable) {
|
||||||
|
state.update { it.copy(error = error.message) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onScanFailure(error: Throwable) {
|
||||||
|
state.update { it.copy(error = error.message) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun runDecodeCatching(mnemonic: String) = runCatching {
|
||||||
|
decode(mnemonic)
|
||||||
|
}
|
||||||
|
private fun decode(mnemonic: String) = codec.decode(mnemonic).let(Hex::fromStringCondensed)!!
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user