Skip to content

Commit 1e328ca

Browse files
eriedclaude
andcommitted
fix(settings): stop the stepper bubble flashing black over the keyboard
The NumberUpDown stepper bubble is a Popup (its own window). Drawing it while the window is still resizing for the keyboard / scrolling the field into view flashed it as a black rectangle just above the keyboard. The old mitigation was a fixed 250 ms delay, which a slower phone (or a field low in a long list like the new InMotion PIN, which scrolls a lot) outruns - so the bubble appeared mid-animation and flashed. Gate the reveal on the IME animation actually finishing (ime inset stable and non-zero) instead of a fixed delay, with a 600 ms fallback so a hardware keyboard or a window without ime insets still shows the stepper. No behaviour change once settled; the fade-in is unchanged. Affects every NumberUpDown field. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GADLyChheAoMX9dQbRgRnH
1 parent b452364 commit 1e328ca

1 file changed

Lines changed: 21 additions & 4 deletions

File tree

app/src/main/java/com/eried/eucplanet/ui/settings/AlarmSettingsContent.kt

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import androidx.compose.foundation.layout.fillMaxHeight
1212
import androidx.compose.foundation.layout.fillMaxWidth
1313
import androidx.compose.foundation.layout.height
1414
import androidx.compose.foundation.layout.heightIn
15+
import androidx.compose.foundation.layout.WindowInsets
16+
import androidx.compose.foundation.layout.ime
17+
import androidx.compose.foundation.layout.imeAnimationTarget
1518
import androidx.compose.foundation.layout.imePadding
1619
import androidx.compose.foundation.layout.padding
1720
import androidx.compose.foundation.layout.size
@@ -1570,6 +1573,7 @@ private fun SectionTitleWithPreview(
15701573
* the live value when unfocused and lets the user type freely while focused
15711574
* (reconciling to the clamped value on blur).
15721575
*/
1576+
@OptIn(androidx.compose.foundation.layout.ExperimentalLayoutApi::class)
15731577
@Composable
15741578
internal fun NumberUpDown(
15751579
value: Int,
@@ -1687,17 +1691,30 @@ internal fun NumberUpDown(
16871691
// is no room -- so it never competes for row width. Non-focusable so
16881692
// tapping a stepper keeps the keyboard up.
16891693
if (focused && enabled) {
1690-
// Hold the stepper bubble back until the keyboard's open animation has
1691-
// settled, then fade it in. Drawing the Popup while the window is still
1692-
// resizing/scrolling made it flash in and jump as a black rectangle.
1694+
// Hold the stepper bubble back until the keyboard has FINISHED
1695+
// animating in, then fade it in. Drawing the Popup while the window
1696+
// is still resizing/scrolling flashed it as a black rectangle -
1697+
// worst on a field low in a long list (like the InMotion PIN), which
1698+
// scrolls a lot, on a slower phone where the animation runs past the
1699+
// old fixed 250 ms delay. Gate on the IME inset being stable and
1700+
// non-zero (animation done) instead. Fallback delay so a hardware
1701+
// keyboard / a window without ime insets still reveals the stepper.
16931702
var bubbleShown by remember { mutableStateOf(false) }
16941703
val bubbleAlpha by animateFloatAsState(
16951704
targetValue = if (bubbleShown) 1f else 0f,
16961705
animationSpec = tween(140),
16971706
label = "stepperBubbleFade",
16981707
)
1708+
val imeBottom = WindowInsets.ime.getBottom(density)
1709+
val imeTarget = WindowInsets.imeAnimationTarget.getBottom(density)
1710+
LaunchedEffect(imeBottom, imeTarget) {
1711+
if (imeBottom > 0 && imeBottom == imeTarget) {
1712+
kotlinx.coroutines.delay(60)
1713+
bubbleShown = true
1714+
}
1715+
}
16991716
LaunchedEffect(Unit) {
1700-
kotlinx.coroutines.delay(250)
1717+
kotlinx.coroutines.delay(600)
17011718
bubbleShown = true
17021719
}
17031720
if (bubbleAlpha > 0.01f) {

0 commit comments

Comments
 (0)