diff --git a/crates/app-iced/src/pages/download/options/view.rs b/crates/app-iced/src/pages/download/options/view.rs index 4b3fd6f..9d08cdb 100644 --- a/crates/app-iced/src/pages/download/options/view.rs +++ b/crates/app-iced/src/pages/download/options/view.rs @@ -66,12 +66,17 @@ pub(super) fn version_menu_height(items: usize) -> f32 { rows * ITEM + Space::X2.dp() * 2.0 } -/// 选项区(面板的下半块):**可滚的上半块 + 钉死的页脚**。 +/// 选项区(面板的下半块):**可滚的上半块 + 钉死的下半块**。 /// -/// `scroll` = 面板此刻是不是「自己可滚」的那一档(`rows::TailShare::Shared`)。是的话上半块 -/// 收进 `scrollable` 吃 `Fill`,**实例名那一格留在页脚、永远在屏**——这条是 D30 r2 S7 的修法: -/// 面板变高(多了加载器版本列表)之后,原先实例名会被挤到首屏外(1180×760 实测要滚 1 屏), -/// 钉成页脚之后可达性由**结构**保证,不依赖滚轮(`install.rs` 模块文档里登记的方案)。 +/// `scroll` = 面板此刻是不是「自己可滚」的那一档(`rows::TailShare::Shared`)。是的话: +/// +/// - **滚动区**:head(版本 id + 安装按钮)+ 加载器 chips + 中性说明 + 错误行; +/// - **钉死区**:加载器版本菜单 + 实例名输入框。 +/// +/// 为什么菜单也要钉(D30 四审):裁切位置由**钉死区高度**决定,与窗宽无关(1180 与 720 都切在 +/// 同一个 y)。之前只钉实例名,菜单就正好落在切线上——760 下菜单容器 642–706 只有 18px 可见、 +/// 条目文字一格都没画出来。把菜单一起钉住之后,它不再依赖首屏剩余高度分配,可达性由结构保证; +/// 滚动区溢出时滚的是说明/错误行,那是可以接受被滚走的内容。 pub(crate) fn section<'a>( ui: &'a Ui, catalog: Catalog, @@ -110,20 +115,8 @@ pub(crate) fn section<'a>( // 换行由 iced 的文本布局负责,长句不会横向溢出;但**视觉验收仍需截图确认**(D30)。 // 「加载器版本」这一段只在**真该有列表**时出现:原版没有、静态不兼容没有(原因在下面那行)、 // 取不到也没有(同样在原因行)。留一个空标题只会让人以为界面缺了一块。 - if show_versions(options) { - body = body.push(frame::text_role( - ui, - TypeRole::LabelMedium, - false, - catalog.text(Key::DownloadOptionsLoaderVersion), - ui.color(Role::OnSurfaceVariant), - )); - body = body.push(version_list(ui, catalog, options)); - } - - // 中性说明排在**版本菜单之后**(D30 三审 S7-clip):说明两行高,排在菜单前面会把 - // 「加载器版本」这个本页唯一的加载器专属控件顶出首屏,而面板上半块是滚动区,切点会落在 - // 字形上。挪到菜单后面之后 1180×760 首屏能装下 head + chips + 标签 + 菜单,切点不再切字。 + // 中性说明留在**滚动区**(D30 四审裁决):它两行高、且不是控件,溢出时被滚走可以接受; + // 加载器版本菜单是控件,已经搬到钉死区(见下面的 `pinned`),不再和它抢首屏高度。 if let Some(note) = &options.note { body = body.push(frame::text_role( ui, @@ -144,26 +137,37 @@ pub(crate) fn section<'a>( )); } - // 页脚:实例名(钉死,不参与滚动)。见 `section` 的文档。 - let footer = text_field( + // 钉死区:加载器版本菜单 + 实例名(都不参与滚动)。见 `section` 的文档。 + let mut pinned = column![].spacing(ui.space(Space::X2)).width(Length::Fill); + if show_versions(options) { + pinned = pinned.push(frame::text_role( + ui, + TypeRole::LabelMedium, + false, + catalog.text(Key::DownloadOptionsLoaderVersion), + ui.color(Role::OnSurfaceVariant), + )); + pinned = pinned.push(version_list(ui, catalog, options)); + } + pinned = pinned.push(text_field( ui, Field::new(options.instance_name.as_str()) .variant(FieldVariant::Outlined) .label(catalog.text(Key::DownloadOptionsInstanceName)) .placeholder(catalog.text(Key::DownloadOptionsInstanceNameHint)), Message::SetInstanceName, - ); + )); if !scroll { // 钉死档(三栏 + 无版本列表 / chips 以外的矮面板):行为与以前一致,一列内容到底。 - body = body.push(Element::from(footer)); + body = body.push(Element::from(pinned)); return body.into(); } column![ scrollable(body) .height(Length::Fill) .style(frame::scroll_style(ui)), - footer, + pinned, ] .spacing(ui.space(Space::X2)) .height(Length::Fill)