Berkeli Alashov
06/29/2022, 11:04 PMFullScreenLoading
. Requirements include to announce loading starting and finishing via TalkBack. I have two possible implementations using DisposableEffect
in loading icon's composable scope and both are not ideal. Including code in comments. Any ideas to improve option 1 (from code) or maybe I should go with option 2 in cases like this?Berkeli Alashov
06/29/2022, 11:05 PM@Composable
fun FullScreenLoading(
isLoading: Boolean,
modifier: Modifier = Modifier,
iconSize: Dp = 32.dp,
content: @Composable BoxScope.() -> Unit
) {
val loadingContentCd = "Loading"
val finishedLoadingCd = "Finished Loading"
var finishedLoading by remember { mutableStateOf(false) }
// option 1: works for normal usages, but not when compose screen is closed quickly after loading is finished (isLoading=false state is not reached before navigating away)
// possible fix for that is to delay navigating away shortly after loading is finished (~350ms delay seems to be enough on my test devices, but not 325ms.. not ideal since it could require different delays for different devices)
if (finishedLoading) {
Text(text = " ", modifier = Modifier
.focusable(false)
.semantics {
liveRegion = LiveRegionMode.Assertive
contentDescription = finishedLoadingCd
}
)
}
Box(modifier.fillMaxSize()) {
content()
if (isLoading) {
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.White.copy(alpha = 0.8f))
//.simpleClickable { Timber.i("FullScreenLoading clicked") }
.semantics {
liveRegion = LiveRegionMode.Assertive
contentDescription = loadingContentCd
}
) {
// Loading icon goes here
Box(
modifier = Modifier
.size(iconSize)
.align(Alignment.Center)
.background(Color.Red)
)
val context = LocalContext.current
DisposableEffect(context) {
onDispose {
// option 1:
finishedLoading = true
// option 2: use announceForAccessibility through host activity
// announceForAccessibility is not recommended even for View system anymore and Compose won't have support for it: <https://issuetracker.google.com/issues/172590945>
// context.findActivity().getRootView().announceForAccessibility(finishedLoadingCd)
}
}
}
}
}
}
@Preview
@Composable
private fun FullScreenLoadingPreview() {
var isLoading by remember { mutableStateOf(true) }
LaunchedEffect(Unit) {
while (true) {
delay(3000)
isLoading = !isLoading
}
}
FullScreenLoading(isLoading = isLoading) {
Text(text = "Content")
}
}