Fix Qr Code errors

This commit is contained in:
Andrew 2024-06-25 23:21:22 +09:30
parent db15fe0840
commit 27fda9fd46
5 changed files with 32 additions and 15 deletions

View File

@ -44,7 +44,7 @@ private val TITLES = listOf(R.string.enter_account_id, R.string.qrScan)
@Composable @Composable
internal fun NewMessage( internal fun NewMessage(
state: State, state: State,
errors: Flow<String> = emptyFlow(), qrErrors: Flow<String> = emptyFlow(),
callbacks: Callbacks = object: Callbacks {}, callbacks: Callbacks = object: Callbacks {},
onClose: () -> Unit = {}, onClose: () -> Unit = {},
onBack: () -> Unit = {}, onBack: () -> Unit = {},
@ -58,7 +58,7 @@ internal fun NewMessage(
HorizontalPager(pagerState) { HorizontalPager(pagerState) {
when (TITLES[it]) { when (TITLES[it]) {
R.string.enter_account_id -> EnterAccountId(state, callbacks, onHelp) R.string.enter_account_id -> EnterAccountId(state, callbacks, onHelp)
R.string.qrScan -> MaybeScanQrCode(errors, onScan = callbacks::onScanQrCode) R.string.qrScan -> MaybeScanQrCode(qrErrors, onScan = callbacks::onScanQrCode)
} }
} }
} }

View File

@ -7,6 +7,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asSharedFlow
@ -34,7 +35,7 @@ internal class NewMessageViewModel @Inject constructor(
private val _success = MutableSharedFlow<Success>() private val _success = MutableSharedFlow<Success>()
val success get() = _success.asSharedFlow() val success get() = _success.asSharedFlow()
private val _qrErrors = MutableSharedFlow<String>() private val _qrErrors = MutableSharedFlow<String>(extraBufferCapacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
val qrErrors = _qrErrors.asSharedFlow() val qrErrors = _qrErrors.asSharedFlow()
private var loadOnsJob: Job? = null private var loadOnsJob: Job? = null

View File

@ -4,10 +4,13 @@ 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.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -36,7 +39,7 @@ internal class LinkDeviceViewModel @Inject constructor(
private val _events = MutableSharedFlow<LoadAccountEvent>() private val _events = MutableSharedFlow<LoadAccountEvent>()
val events = _events.asSharedFlow() val events = _events.asSharedFlow()
private val _qrErrors = MutableSharedFlow<Throwable>() private val _qrErrors = MutableSharedFlow<Throwable>(extraBufferCapacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
val qrErrors = _qrErrors.asSharedFlow() val qrErrors = _qrErrors.asSharedFlow()
.mapNotNull { application.getString(R.string.qrNotRecoveryPassword) } .mapNotNull { application.getString(R.string.qrNotRecoveryPassword) }
@ -57,7 +60,7 @@ internal class LinkDeviceViewModel @Inject constructor(
try { try {
decode(string).let(::onSuccess) decode(string).let(::onSuccess)
} catch (e: Exception) { } catch (e: Exception) {
onFailure(e) onQrCodeScanFailure(e)
} }
} }
} }

View File

@ -13,6 +13,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asSharedFlow
@ -38,7 +39,7 @@ private val TITLES = listOf(R.string.view, R.string.scan)
class QRCodeActivity : PassphraseRequiredActionBarActivity() { class QRCodeActivity : PassphraseRequiredActionBarActivity() {
private val errors = MutableSharedFlow<String>() private val errors = MutableSharedFlow<String>(extraBufferCapacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) { override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {
super.onCreate(savedInstanceState, isReady) super.onCreate(savedInstanceState, isReady)

View File

@ -31,6 +31,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
@ -51,15 +52,13 @@ import com.google.mlkit.vision.barcode.BarcodeScannerOptions
import com.google.mlkit.vision.barcode.BarcodeScanning 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 kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.buffer import kotlinx.coroutines.launch
import kotlinx.coroutines.flow.filter
import network.loki.messenger.R import network.loki.messenger.R
import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.Log
import org.thoughtcrime.securesms.ui.LocalDimensions import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.base import org.thoughtcrime.securesms.ui.base
import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.xl import org.thoughtcrime.securesms.ui.xl
import java.util.concurrent.Executors import java.util.concurrent.Executors
@ -161,11 +160,24 @@ fun ScanQrCode(errors: Flow<String>, onScan: (String) -> Unit) {
val scaffoldState = rememberScaffoldState() val scaffoldState = rememberScaffoldState()
val scope = rememberCoroutineScope()
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
errors.filter { scaffoldState.snackbarHostState.currentSnackbarData == null } errors.collect { error ->
.buffer(0, BufferOverflow.DROP_OLDEST) scaffoldState.snackbarHostState
.collect { error -> .takeIf { it.currentSnackbarData == null }
scaffoldState.snackbarHostState.showSnackbar(message = error) ?.run {
scope.launch {
// showSnackbar() suspends until the Snackbar is dismissed.
// Launch in new scope so we drop new QR scan events, to prevent spamming
// snackbars to the user, or worse, queuing a chain of snackbars one after
// another to show and hide for the next minute or 2.
// Don't use debounce() because many QR scans can come through each second,
// and each scan could restart the timer which could mean no scan gets
// through until the user stops scanning; quite perplexing.
showSnackbar(message = error)
}
}
} }
} }