diff --git a/internal/ui/comments_drawer.go b/internal/ui/comments_drawer.go index d21643f0..0ac155fc 100644 --- a/internal/ui/comments_drawer.go +++ b/internal/ui/comments_drawer.go @@ -28,6 +28,15 @@ // (理由见 `queue_drawer.go` 那一段):后者问的是「指针按在了不是这个元素的 // 地方」,而播放条上按一下也算「按在外面」——于是按播放会顺手把抽屉关了。 // +// # 面板盖住底下的播放条 +// +// 蒙版照旧在窗口上面留出 `playbarHeight`(76)那一截——它**不吃点击**的那截 +// 必须留出来,不然抽屉开着时按播放、上一首、下一首都会变成「点外面关抽屉」 +// (`queue_drawer.go` 那一段警告过)。但**面板**不再跟着蒙版留——它的 +// `Bottom` 是**负的**(−76),伸出蒙版的底边、贴着窗口下沿。底下的播放条 +// 被面板**藏在自己底下**(看不见、也点不到),而蒙版依然只在上面那段接「点 +// 外面」。 +// // # 满屏播放器那一枚不带数字 // // 播放条那一枚**继续显示评论数**(票 #682 的两级逻辑照旧);满屏那一枚**不带** @@ -90,6 +99,23 @@ func (s *Shell) viewCommentsDrawer(c *ui.Context) { } back := ui.Row(c).Key("comments-backdrop"). Absolute().Left(0).Top(0).Right(0).Bottom(bottomInset) + // ⚠️ **面板要盖住底下那条**(票:抽屉展开时播放条不该露出来): + // 它的底不是蒙版的底(上面那 76 像素),而是**窗口的底**。负的 + // `Bottom` 让面板**伸出蒙版下边**,贴着窗口下沿。 + // + // ⚠️ **盖下去的是面板,不是蒙版**:蒙版也盖到底的话,点播放条那条带 + // 会变成「点外面关抽屉」(`queue_drawer.go` 那一段警告过);而面板 + // 盖下去是把那一截**藏在自己底下**——底下的播放键拿不到点击,也 + // 不会误触发关抽屉。 + // + // ⚠️ **「盖下去」不挡命中**:hit-test 按的是元素自己的框(`runtime.go` + // 的 `commitElement` 记的是 `Rect{e.x, e.y, e.w, e.h}`),不查蒙版 + // 的裁切——所以面板虽然画在蒙版的底边下面,它那截伸出来的部分照样 + // 能吃点击、底下的播放条控件也够不到指针。 + // ⚠️ **负的 `Bottom` 就是「伸出蒙版底边、贴到窗口底」**:`bottomInset` + // 已经是「底下那条的高度」(播放条 76 / 满屏控制栏 108),取负后 + // 面板正好探出蒙版、盖住那一条。 + panelBottom := -bottomInset if s.commentsPhase == drawerOut { // ⚠️ **退场那 200ms 里,这片蒙版不吃点击**(理由同 `queue_drawer.go`): // 它是**透明**的,用户看不见它,而它盖住整页——看不见的东西吃点击, @@ -109,7 +135,7 @@ func (s *Shell) viewCommentsDrawer(c *ui.Context) { // 摆不出「从右边滑进来」——绝对定位按 **inset** 摆,那才是「从窗口 // 右边挪进来」能用的那一套(理由同 `queue_drawer.go`)。 panel := shadow.HeroMedium(ui.Column(c).Key("comments-drawer"). - Absolute().Top(0).Bottom(0).Width(commentsDrawerWidth). + Absolute().Top(0).Bottom(panelBottom).Width(commentsDrawerWidth). Background(s.cardBackground(t)).BorderStartWidth(1).BorderColor(t.Border), t) // ⚠️ **面板在退场时照旧接点击**:它还在屏幕上(滑出去那一段看得见), // 而「看不见的东西吃点击」才是坏的(那是底下那片蒙版)。 diff --git a/internal/ui/comments_drawer_test.go b/internal/ui/comments_drawer_test.go index a0a286e5..247f80a7 100644 --- a/internal/ui/comments_drawer_test.go +++ b/internal/ui/comments_drawer_test.go @@ -203,6 +203,39 @@ func TestTheCommentsDrawerDoesNotEatThePlayBarClick(t *testing.T) { } } +// TestTheCommentsDrawerPanelCoversThePlayBarStrip 断「抽屉面板**盖住**底下的 +// 播放条」。 +// +// 🔴 **用户明确要求了**:抽屉展开时底下那块播放条不该露出来——不是「点不动」 +// (那是蒙版的事),是「**看不见**」。 +// +// ⚠️ **盖的是面板,不是蒙版**:蒙版也盖到底的话,点播放条那条带会变成「点外面 +// 关抽屉」——而用户按的是「播放」。面板盖下去是把那一截**藏在自己底下**,底下 +// 的控件拿不到点击,也不会误触发关抽屉。 +// +// ⚠️ **判据是「面板下缘贴到窗口底」**:面板的 Bottom 是**相对于蒙版的底**的 +// (蒙版在窗口上面留出 playbarHeight),所以面板 Bottom(0) 时它的下缘 = 蒙版底 − +// playbarHeight = 窗口底 − playbarHeight——**还不够**。要盖到底,面板的 Bottom 得是 +// **负的**(−playbarHeight),让它**伸出蒙版的底边**,贴着窗口下沿。 +func TestTheCommentsDrawerPanelCoversThePlayBarStrip(t *testing.T) { + b := newCommentBili(t, "reply-main.json") + _, tt := newCommentsShell(t, b, mvItem(), 1400, 900) + + // 面板是「评论」那个 RoleDialog——Find 到的是它的盒子。 + panel, ok := tt.Find("评论") + if !ok { + t.Fatalf("画面上找不到评论抽屉面板,文字有 %q", tt.Texts()) + } + // 面板下缘要贴到窗口底(900),而不是悬在播放条上面(900−76=824)。 + // + // ⚠️ **容差 1 个像素**:阴影那一圈可能把盒子撑出去一点点,而「盖住」看的是 + // 面板自己的下缘,不是影的外沿。 + if panel.Y+panel.H < 900-1 { + t.Errorf("面板下缘在 %.1f,播放条那条带(%.1f~%d)还露在外面——"+ + "面板要盖到窗口底", panel.Y+panel.H, float32(900-playbarHeight), 900) + } +} + // ───────────────────────────────────────────────────────────────────────────── // 宽度 // ───────────────────────────────────────────────────────────────────────────── diff --git a/internal/ui/comments_shot_test.go b/internal/ui/comments_shot_test.go index 8418c745..6ba8a16f 100644 --- a/internal/ui/comments_shot_test.go +++ b/internal/ui/comments_shot_test.go @@ -227,6 +227,36 @@ func TestRenderCommentsMentionFilterShots(t *testing.T) { } } +// TestRenderCommentsDrawerCoversPlayBarShot 出「抽屉面板盖住底下的播放条」那一张: +// 面板下缘贴着窗口底,底下那条播放条在面板自己那一段(最右 400)里**看不见**。 +// +// 🔴 **这是「盖住播放器」那一票的画面材料**:要审的是**最右那一条 400 宽里**—— +// 面板把播放条遮到窗口底了,还是那 76 高的播放条还露在外面。裁的是**右下角** +// 那一块(面板下缘 + 播放条那一截的交界处)。 +func TestRenderCommentsDrawerCoversPlayBarShot(t *testing.T) { + dir := os.Getenv("BIU_SHOT_DIR") + if dir == "" { + t.Skip("设 BIU_SHOT_DIR 才会存图") + } + for _, dark := range []bool{false, true} { + name := "浅色" + if dark { + name = "深色" + } + t.Run(name, func(t *testing.T) { + b := newCommentBili(t, "reply-main.json") + _, tt := newCommentsShell(t, b, mvItem(), 1400, 900, systemIsDark(dark)) + + // 裁右下角:窗口右沿 1400、下沿 900,裁 460×200 那块 + // (面板宽 400,含左缘 60 余量;高 200 含面板下缘和播放条交界)。 + saveRect(t, dir, fmt.Sprintf("26-评论抽屉-盖住播放条-%s.png", name), tt, + 940, 700, 460, 200) + // 整页一张作对照(那一截在最右下,整页里看得见它和播放条的关系)。 + save(t, dir, fmt.Sprintf("27-评论抽屉-整页-%s.png", name), tt) + }) + } +} + // TestRenderCommentsHighlightShots 出「筛选开着、正文里命中的歌名高亮」那一张, // 深浅各一套(票 #684)。 //