[Link new device] Improve UI transition between QRCodes.
This commit is contained in:
parent
1500c0fadd
commit
9d704fb751
4 changed files with 99 additions and 28 deletions
|
|
@ -22,6 +22,9 @@ import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.core.log.logger.LoggerTag
|
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||||
import io.element.android.libraries.matrix.api.linknewdevice.LinkMobileStep
|
import io.element.android.libraries.matrix.api.linknewdevice.LinkMobileStep
|
||||||
import io.element.android.libraries.matrix.api.logs.LoggerTags
|
import io.element.android.libraries.matrix.api.logs.LoggerTags
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
private val tag = LoggerTag("ShowQrCodePresenter", LoggerTags.linkNewDevice)
|
private val tag = LoggerTag("ShowQrCodePresenter", LoggerTags.linkNewDevice)
|
||||||
|
|
@ -36,20 +39,54 @@ class ShowQrCodePresenter(
|
||||||
fun create(initialData: String): ShowQrCodePresenter
|
fun create(initialData: String): ShowQrCodePresenter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var loadingJob: Job? = null
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun present(): ShowQrCodeState {
|
override fun present(): ShowQrCodeState {
|
||||||
var qrCodeRotationCounter by remember { mutableIntStateOf(MAX_QR_CODE_ROTATION) }
|
var qrCodeRotationCounter by remember { mutableIntStateOf(MAX_QR_CODE_ROTATION) }
|
||||||
val data by produceState<AsyncData<String>>(AsyncData.Success(initialData)) {
|
val state by produceState(
|
||||||
|
initialValue = ShowQrCodeState(
|
||||||
|
data1 = AsyncData.Success(initialData),
|
||||||
|
data2 = AsyncData.Uninitialized,
|
||||||
|
dataToRender = 1,
|
||||||
|
)
|
||||||
|
) {
|
||||||
linkNewMobileHandler.stepFlow.collect { step ->
|
linkNewMobileHandler.stepFlow.collect { step ->
|
||||||
|
val currentValue = value
|
||||||
when (step) {
|
when (step) {
|
||||||
is LinkMobileStep.QrReady -> {
|
is LinkMobileStep.QrReady -> {
|
||||||
value = AsyncData.Success(step.data)
|
loadingJob?.cancel()
|
||||||
|
if (currentValue.dataToRender == 1) {
|
||||||
|
value = currentValue.copy(
|
||||||
|
data2 = AsyncData.Success(step.data),
|
||||||
|
dataToRender = 2,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
value = currentValue.copy(
|
||||||
|
data1 = AsyncData.Success(step.data),
|
||||||
|
dataToRender = 1,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
is LinkMobileStep.QrRotating -> {
|
is LinkMobileStep.QrRotating -> {
|
||||||
if (qrCodeRotationCounter-- > 0) {
|
if (qrCodeRotationCounter-- > 0) {
|
||||||
Timber.tag(tag.value).d("Rotating QrCode")
|
Timber.tag(tag.value).d("Rotating QrCode")
|
||||||
linkNewMobileHandler.rotateQrCode()
|
linkNewMobileHandler.rotateQrCode()
|
||||||
value = AsyncData.Loading()
|
// Ensure that outdated data is not rendered too long while rotating QR code
|
||||||
|
loadingJob = launch {
|
||||||
|
delay(1000)
|
||||||
|
if (currentValue.dataToRender == 1) {
|
||||||
|
value = currentValue.copy(
|
||||||
|
data2 = AsyncData.Loading(),
|
||||||
|
dataToRender = 2,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
value = currentValue.copy(
|
||||||
|
data1 = AsyncData.Loading(),
|
||||||
|
dataToRender = 1,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Timber.tag(tag.value).w("Max QR code rotation reached, not rotating anymore")
|
Timber.tag(tag.value).w("Max QR code rotation reached, not rotating anymore")
|
||||||
linkNewMobileHandler.onTooManyRotation()
|
linkNewMobileHandler.onTooManyRotation()
|
||||||
|
|
@ -60,9 +97,7 @@ class ShowQrCodePresenter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ShowQrCodeState(
|
return state
|
||||||
data = data,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
||||||
|
|
@ -10,5 +10,7 @@ package io.element.android.features.linknewdevice.impl.screens.qrcode
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
|
|
||||||
data class ShowQrCodeState(
|
data class ShowQrCodeState(
|
||||||
val data: AsyncData<String>,
|
val data1: AsyncData<String>,
|
||||||
|
val data2: AsyncData<String>,
|
||||||
|
val dataToRender: Int,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -14,14 +14,23 @@ class ShowQrCodeStateProvider : PreviewParameterProvider<ShowQrCodeState> {
|
||||||
override val values: Sequence<ShowQrCodeState>
|
override val values: Sequence<ShowQrCodeState>
|
||||||
get() = sequenceOf(
|
get() = sequenceOf(
|
||||||
aShowQrCodeState(),
|
aShowQrCodeState(),
|
||||||
ShowQrCodeState(
|
aShowQrCodeState(
|
||||||
data = AsyncData.Loading(),
|
data1 = AsyncData.Loading(),
|
||||||
|
),
|
||||||
|
aShowQrCodeState(
|
||||||
|
data1 = AsyncData.Success("DATA"),
|
||||||
|
data2 = AsyncData.Success("DATA2"),
|
||||||
|
dataToRender = 2,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun aShowQrCodeState(
|
private fun aShowQrCodeState(
|
||||||
data: AsyncData.Success<String> = AsyncData.Success("DATA"),
|
data1: AsyncData<String> = AsyncData.Success("DATA"),
|
||||||
|
data2: AsyncData<String> = AsyncData.Uninitialized,
|
||||||
|
dataToRender: Int = 1,
|
||||||
) = ShowQrCodeState(
|
) = ShowQrCodeState(
|
||||||
data = data,
|
data1 = data1,
|
||||||
|
data2 = data2,
|
||||||
|
dataToRender = dataToRender,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@
|
||||||
|
|
||||||
package io.element.android.features.linknewdevice.impl.screens.qrcode
|
package io.element.android.features.linknewdevice.impl.screens.qrcode
|
||||||
|
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.animation.fadeIn
|
||||||
|
import androidx.compose.animation.fadeOut
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
|
@ -58,23 +61,15 @@ fun ShowQrCodeView(
|
||||||
Modifier.fillMaxWidth(),
|
Modifier.fillMaxWidth(),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
when (val str = state.data.dataOrNull()) {
|
Box {
|
||||||
null -> {
|
QrCodeOrLoading(
|
||||||
Box(
|
isVisible = state.dataToRender == 1,
|
||||||
modifier = Modifier
|
data = state.data1.dataOrNull(),
|
||||||
.size(220.dp),
|
)
|
||||||
contentAlignment = Alignment.Center,
|
QrCodeOrLoading(
|
||||||
) {
|
isVisible = state.dataToRender == 2,
|
||||||
CircularProgressIndicator()
|
data = state.data2.dataOrNull(),
|
||||||
}
|
)
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
QrCodeImage(
|
|
||||||
data = str,
|
|
||||||
modifier = Modifier
|
|
||||||
.size(220.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.height(32.dp))
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
NumberedListOrganism(
|
NumberedListOrganism(
|
||||||
|
|
@ -95,6 +90,36 @@ fun ShowQrCodeView(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun QrCodeOrLoading(
|
||||||
|
isVisible: Boolean,
|
||||||
|
data: String?,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
AnimatedVisibility(
|
||||||
|
modifier = modifier,
|
||||||
|
visible = isVisible,
|
||||||
|
enter = fadeIn(),
|
||||||
|
exit = fadeOut(),
|
||||||
|
) {
|
||||||
|
if (data == null) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(220.dp),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
) {
|
||||||
|
CircularProgressIndicator()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QrCodeImage(
|
||||||
|
data = data,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(220.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@PreviewsDayNight
|
@PreviewsDayNight
|
||||||
@Composable
|
@Composable
|
||||||
internal fun ShowQrCodeViewPreview(
|
internal fun ShowQrCodeViewPreview(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue