fix(chat): 分享确认面板一打开就崩 —— 正文那一层绝不能再拿到 Dp.Infinity

真机崩溃栈:heightIn(max = Dp.Infinity) 等于不施加约束,verticalScroll 在无界高度下被测量时
checkScrollableContainerConstraints 直接抛 IllegalStateException(ScrollNode.measure ←
SizeNode.measure ← DialogLayout.internalOnMeasure),分享进来、面板刚打开就闪退。

改法:这一层的高度上限只经纯函数 shareConfirmWindowCap() 一个出口 —— 首帧用
SHARE_PREVIEW_MAX_HEIGHT(150dp) 兜底(有限值),展开态这一层不设上限(外层 240dp 仍是有限约束),
并且不再用 Dp.Infinity 当「还没量到」的哨兵值(改用 null)。新增 4 条单测钉住
「任何输入组合都不会产出非有限上限」。
This commit is contained in:
AskaEth committed 2026-10-07 09:45:34 +08:00
1 parent af9c63d267
commit 6d4f2cdbae
2 files changed
+91 -17

No files matched your search

@@ -317,3 +317,53 @@ class ShareConfirmTest {
assertTrue(SHARE_PREVIEW_COLLAPSE_LABEL.isNotBlank())
}
}
/**
* W58:正文那一窗的高度上限**永远不许是 [androidx.compose.ui.unit.Dp.Infinity]**。
*
* 背景是真机上的一次崩溃:`heightIn(max = Dp.Infinity)` 等于**不施加约束**,而 `verticalScroll`
* 一旦在无界高度下被测量,Compose 的 `checkScrollableContainerConstraints` 会直接抛
* `IllegalStateException` 把 App 打崩(分享面板一打开就闪退,栈是 `ScrollNode.measure` ←
* `SizeNode.measure` ← `DialogLayout.internalOnMeasure`)。
*
* 这条不变量只能靠纯函数钉住:本模块的 `testImplementation` 只有 junit,没有 Compose UI 测试依赖,
* 渲染层的崩溃单测抓不到。
*/
class ShareConfirmWindowCapTest {
@Test
fun `the fallback cap is finite and never infinity`() {
val fallback = shareConfirmWindowCap(measured = null, expanded = false)
org.junit.Assert.assertNotNull("首帧必须给出一个上限,不能是 null", fallback)
assertTrue("首帧的兜底上限必须是有限值", fallback!!.value.isFinite())
assertEquals(SHARE_PREVIEW_MAX_HEIGHT, fallback)
}
@Test
fun `the expanded state leaves this layer unbounded instead of passing infinity`() {
// 展开态是「这一层不设上限」(null),**不是**「给一个无穷大的上限」——后者正是崩溃的成因。
org.junit.Assert.assertNull(shareConfirmWindowCap(measured = null, expanded = true))
org.junit.Assert.assertNull(shareConfirmWindowCap(measured = 42.dp, expanded = true))
// 而且外层仍然是一层**有限**约束在管事。
assertTrue(sharePreviewMaxHeight(expanded = true).value.isFinite())
}
@Test
fun `a measured cap is passed through`() {
assertEquals(42.dp, shareConfirmWindowCap(measured = 42.dp, expanded = false))
}
@Test
fun `no input combination can produce a non finite cap`() {
val measured = listOf(null, 0.dp, 1.dp, 150.dp, 10_000.dp)
for (m in measured) {
for (expanded in listOf(false, true)) {
val cap = shareConfirmWindowCap(m, expanded)
assertTrue(
"m=$m expanded=$expanded 给出了非有限的上限:$cap",
cap == null || cap.value.isFinite(),
)
}
}
}
}