Use AnimatedContent instead of reinventing the wheel.
This commit is contained in:
parent
000dc3d6c2
commit
1902920983
7 changed files with 37 additions and 84 deletions
|
|
@ -46,27 +46,16 @@ class ShowQrCodePresenter(
|
||||||
var qrCodeRotationCounter by remember { mutableIntStateOf(MAX_QR_CODE_ROTATION) }
|
var qrCodeRotationCounter by remember { mutableIntStateOf(MAX_QR_CODE_ROTATION) }
|
||||||
val state by produceState(
|
val state by produceState(
|
||||||
initialValue = ShowQrCodeState(
|
initialValue = ShowQrCodeState(
|
||||||
data1 = AsyncData.Success(initialData),
|
data = 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 -> {
|
||||||
loadingJob?.cancel()
|
loadingJob?.cancel()
|
||||||
if (currentValue.dataToRender == 1) {
|
value = ShowQrCodeState(
|
||||||
value = currentValue.copy(
|
data = AsyncData.Success(step.data),
|
||||||
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) {
|
||||||
|
|
@ -75,17 +64,9 @@ class ShowQrCodePresenter(
|
||||||
// Ensure that outdated data is not rendered too long while rotating QR code
|
// Ensure that outdated data is not rendered too long while rotating QR code
|
||||||
loadingJob = launch {
|
loadingJob = launch {
|
||||||
delay(1000)
|
delay(1000)
|
||||||
if (currentValue.dataToRender == 1) {
|
value = ShowQrCodeState(
|
||||||
value = currentValue.copy(
|
data = AsyncData.Loading(),
|
||||||
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")
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,5 @@ 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 data1: AsyncData<String>,
|
val data: AsyncData<String>,
|
||||||
val data2: AsyncData<String>,
|
|
||||||
val dataToRender: Int,
|
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -15,22 +15,13 @@ class ShowQrCodeStateProvider : PreviewParameterProvider<ShowQrCodeState> {
|
||||||
get() = sequenceOf(
|
get() = sequenceOf(
|
||||||
aShowQrCodeState(),
|
aShowQrCodeState(),
|
||||||
aShowQrCodeState(
|
aShowQrCodeState(
|
||||||
data1 = AsyncData.Loading(),
|
data = AsyncData.Loading(),
|
||||||
),
|
|
||||||
aShowQrCodeState(
|
|
||||||
data1 = AsyncData.Success("DATA"),
|
|
||||||
data2 = AsyncData.Success("DATA2"),
|
|
||||||
dataToRender = 2,
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun aShowQrCodeState(
|
internal fun aShowQrCodeState(
|
||||||
data1: AsyncData<String> = AsyncData.Success("DATA"),
|
data: AsyncData<String> = AsyncData.Success("DATA"),
|
||||||
data2: AsyncData<String> = AsyncData.Uninitialized,
|
|
||||||
dataToRender: Int = 1,
|
|
||||||
) = ShowQrCodeState(
|
) = ShowQrCodeState(
|
||||||
data1 = data1,
|
data = data,
|
||||||
data2 = data2,
|
|
||||||
dataToRender = dataToRender,
|
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,11 @@
|
||||||
|
|
||||||
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.AnimatedContent
|
||||||
|
import androidx.compose.animation.ExperimentalAnimationApi
|
||||||
import androidx.compose.animation.fadeIn
|
import androidx.compose.animation.fadeIn
|
||||||
import androidx.compose.animation.fadeOut
|
import androidx.compose.animation.fadeOut
|
||||||
|
import androidx.compose.animation.togetherWith
|
||||||
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
|
||||||
|
|
@ -44,6 +46,7 @@ import kotlinx.collections.immutable.persistentListOf
|
||||||
* QrCode display screen:
|
* QrCode display screen:
|
||||||
* https://www.figma.com/design/pDlJZGBsri47FNTXMnEdXB/Compound-Android-Templates?node-id=2027-23617
|
* https://www.figma.com/design/pDlJZGBsri47FNTXMnEdXB/Compound-Android-Templates?node-id=2027-23617
|
||||||
*/
|
*/
|
||||||
|
@OptIn(ExperimentalAnimationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun ShowQrCodeView(
|
fun ShowQrCodeView(
|
||||||
state: ShowQrCodeState,
|
state: ShowQrCodeState,
|
||||||
|
|
@ -61,14 +64,15 @@ fun ShowQrCodeView(
|
||||||
Modifier.fillMaxWidth(),
|
Modifier.fillMaxWidth(),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
Box {
|
AnimatedContent(
|
||||||
|
targetState = state.data.dataOrNull(),
|
||||||
|
transitionSpec = {
|
||||||
|
fadeIn().togetherWith(fadeOut())
|
||||||
|
}
|
||||||
|
) { data ->
|
||||||
QrCodeOrLoading(
|
QrCodeOrLoading(
|
||||||
isVisible = state.dataToRender == 1,
|
modifier = modifier.size(220.dp),
|
||||||
data = state.data1.dataOrNull(),
|
data = data,
|
||||||
)
|
|
||||||
QrCodeOrLoading(
|
|
||||||
isVisible = state.dataToRender == 2,
|
|
||||||
data = state.data2.dataOrNull(),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.height(32.dp))
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
|
|
@ -92,31 +96,21 @@ fun ShowQrCodeView(
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun QrCodeOrLoading(
|
private fun QrCodeOrLoading(
|
||||||
isVisible: Boolean,
|
|
||||||
data: String?,
|
data: String?,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
AnimatedVisibility(
|
if (data == null) {
|
||||||
modifier = modifier,
|
Box(
|
||||||
visible = isVisible,
|
modifier = modifier,
|
||||||
enter = fadeIn(),
|
contentAlignment = Alignment.Center,
|
||||||
exit = fadeOut(),
|
) {
|
||||||
) {
|
CircularProgressIndicator()
|
||||||
if (data == null) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.size(220.dp),
|
|
||||||
contentAlignment = Alignment.Center,
|
|
||||||
) {
|
|
||||||
CircularProgressIndicator()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
QrCodeImage(
|
|
||||||
data = data,
|
|
||||||
modifier = Modifier
|
|
||||||
.size(220.dp)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
QrCodeImage(
|
||||||
|
modifier = modifier,
|
||||||
|
data = data,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,9 +32,7 @@ class ShowQrCodePresenterTest {
|
||||||
fun `present - initial state`() = runTest {
|
fun `present - initial state`() = runTest {
|
||||||
createPresenter().test {
|
createPresenter().test {
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
assertThat(initialState.data1.dataOrNull()).isEqualTo("DATA")
|
assertThat(initialState.data.dataOrNull()).isEqualTo("DATA")
|
||||||
assertThat(initialState.data2.isUninitialized()).isTrue()
|
|
||||||
assertThat(initialState.dataToRender).isEqualTo(1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,8 +59,7 @@ class ShowQrCodePresenterTest {
|
||||||
)
|
)
|
||||||
runCurrent()
|
runCurrent()
|
||||||
val finalState = awaitItem()
|
val finalState = awaitItem()
|
||||||
assertThat(finalState.data2.isLoading()).isTrue()
|
assertThat(finalState.data.isLoading()).isTrue()
|
||||||
assertThat(finalState.dataToRender).isEqualTo(2)
|
|
||||||
createLinkMobileHandlerResult.assertions().isCalledExactly(2)
|
createLinkMobileHandlerResult.assertions().isCalledExactly(2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -90,9 +87,7 @@ class ShowQrCodePresenterTest {
|
||||||
LinkMobileStep.QrReady("DATA2")
|
LinkMobileStep.QrReady("DATA2")
|
||||||
)
|
)
|
||||||
val finalState = awaitItem()
|
val finalState = awaitItem()
|
||||||
assertThat(finalState.data1.dataOrNull()).isEqualTo("DATA")
|
assertThat(finalState.data.dataOrNull()).isEqualTo("DATA2")
|
||||||
assertThat(finalState.data2.dataOrNull()).isEqualTo("DATA2")
|
|
||||||
assertThat(finalState.dataToRender).isEqualTo(2)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:151eaa4b5619afd76b94de518dc2868d735b6b7a167056941e1f429520c3bf0d
|
|
||||||
size 31836
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:aa2303b621070608ba79673322f61bfa686b9729eb445913dd8d059d62c9764a
|
|
||||||
size 32374
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue