fix(m179): 复审 r2 —— 订正「Body 带 Lang 之后」残留的六处文档漂移

P2-1:`settings/mod.rs:273`(`AI_GROUP`)还写着「`Group.body` 的签名里没有 `Lang`」,
而同一次提交在同一个文件把槽位改成了 `fn(&Ui, States, Lang)` 并在上方 `GENERAL_GROUP`
按新事实重写 —— 一个文件里两段互相矛盾的说明。本条按新事实重写(行数不变,仍是 389 行)。

一并订正 finding 里剩下的外域漂移(tower 已扩 scope):
- `settings/ai_about.rs:8`(同一句假话的表格行,finding 没列到)与 `:14-16`
- `settings/general.rs:7-11`(槽位现在带 `Lang`,装不下的只剩**档位** `LangChoice`)
- `settings/general.rs:287`、`settings/update.rs:5`、`pages/mod.rs:271`、
  `settings/language_appearance.rs:20` 的 `pages/appearance/section.rs` 路径

措辞与复审建议的一处偏离(已在提交与报告里说明):复审建议写「槽位给不了『测试连接』的
结论」,与实现不符——该结论在 `States.groups.ai_about` 里,槽位拿得到;AI 组仍按下标分发
的真实原因是**尚未迁移**(槽位要 `Option<Element>`,`ai::view::body` 返回 `Element`)。

零代码改动:本提交所有变更行都是以 `//!` / `///` 开头的文档行
(`git diff -U0 | grep '^[+-]' | grep -vE '^[+-]+\s*//[/!]'` 为空)。
按 tower 要求**不动** `crates/i18n/src/catalog/settings/appearance.rs:8`(M180 正在改)。

验证:cargo fmt --all --check → 0;cargo check -p unlucky-app-iced --all-targets → 0;
cargo clippy -p unlucky-app-iced --all-targets -D warnings → 0;
cargo test -p unlucky-app-iced --lib appearance → 0(37 passed)。
This commit is contained in:
AskaEth committed 2026-11-08 21:01:25 +08:00
1 parent b457f0acc8
commit ca92014b81
6 files changed
+20 -18

No files matched your search

+1 -1
View File
@@ -268,7 +268,7 @@ pub fn app<'a>(
/// 同 [`app`],但可以带上**外观运行期状态**。 /// 同 [`app`],但可以带上**外观运行期状态**。
/// ///
/// `Some(state)` ⇒ 设置页「外观」分组画**真控件**(`pages/appearance/section.rs`); /// `Some(state)` ⇒ 设置页「外观」分组画**真控件**(`pages/appearance/section/`);
/// `None` ⇒ 画演示行,与 [`app`] 逐像素等价。harness 的 `--appearance=real` 走的就是这一支: /// `None` ⇒ 画演示行,与 [`app`] 逐像素等价。harness 的 `--appearance=real` 走的就是这一支:
/// M100 之前 harness 恒传 `None`,于是 D30 要的「带真实外观控件」那一屏**根本不存在**—— /// M100 之前 harness 恒传 `None`,于是 D30 要的「带真实外观控件」那一屏**根本不存在**——
/// 报告上写着「设置页已接真控件」,图里却只有演示行(U1 的形状)。 /// 报告上写着「设置页已接真控件」,图里却只有演示行(U1 的形状)。
@@ -5,15 +5,16 @@
//! | 这里 | 内容 | //! | 这里 | 内容 |
//! |---|---| //! |---|---|
//! | [`GROUP`] | 左列名 / 图标 / 演示行(产品路径走 [`super::ai::view::body`]) | //! | [`GROUP`] | 左列名 / 图标 / 演示行(产品路径走 [`super::ai::view::body`]) |
//! | [`AI_GROUP`] | 本组在 `GROUPS` 里的下标(与 General / Update 同一条**按下标分发**:本组要 i18n 文案与 `Lang` 形参,`Group.body` 的签名里没有它) | //! | [`AI_GROUP`] | 本组在 `GROUPS` 里的下标(与 General / Update 同一条**按下标分发**:本组尚未迁到 `Group.body` 槽位,见下节) |
//! | [`Message`] | 本线的消息口(落点 `app/update/settings/ai_about.rs`) | //! | [`Message`] | 本线的消息口(落点 `app/update/settings/ai_about.rs`) |
//! | [`State`] | 转发 `ai::State`(`Groups.ai_about` 的载荷类型不变,`settings/state.rs` 一行不用改) | //! | [`State`] | 转发 `ai::State`(`Groups.ai_about` 的载荷类型不变,`settings/state.rs` 一行不用改) |
//! //!
//! ## 为什么 `body` 是 `None` 而不是 `Some(..)` //! ## 为什么 `body` 是 `None` 而不是 `Some(..)`
//! //!
//! `Group.body` 的签名是 `fn(&Ui, States) -> Option<Element>`:拿不到 `Lang`,也就画不出中英两套 //! `Group.body` 的槽位(M179 起)拿的是 [`States`](super::States) 与**生效语言** `Lang`——本组要的
//! 文案(本组的硬要求是「不得硬编码中文」)。M106 的语言行与 M159 的更新组是同一个理由走了 //! 两件它其实都装得下。本组仍走按下标分发,是因为**还没迁过去**:槽位要求返回 `Option<Element>`,
//! 按下标分发;本组沿用同一条路,代价是 `settings/mod.rs` 里多一行 `else if`。 //! 而 `ai::view::body` 返回 `Element`,把本组(以及 Java 组)统一迁到槽位上是一次独立重构。
//! M106 的语言行与 M159 的更新组当初也是同一个理由走上这条路,代价是 `settings/mod.rs` 多一行 `else if`。
//! //!
//! ## 密钥纪律 //! ## 密钥纪律
//! //!
@@ -4,10 +4,11 @@
//! //!
//! ## 这一组为什么特殊 //! ## 这一组为什么特殊
//! //!
//! 它**不走** `Group::body`:那个渲染器的签名是 `fn(&Ui, States) -> Option<Element>`,`States` 只有 //! 它**不走** `Group::body`:那个渲染器拿的是 [`States`](super::States) 与**生效语言** `Lang`
//! `appearance` + `groups` 两格,装不下「当前语言档位 + 生效语言」。语言行要的两件在 //! (M179 起;此前连 `Lang` 都没有),而语言行要的是「当前语言**档位** `LangChoice` + 生效语言」
//! `pages::Language` 里,由 `pages::settings::view` 的 `language` 形参一路递进来、`form` 按下标 //! 这一对——档位不在 `States` 里。所以它由 `pages::settings::view` 的 `language` 形参一路递进来、
//! 转交 [`body`];所以 `GROUP.body` 仍是 `None`,`tests/mod.rs` 那条「只有外观组带真控件」照样成立。 //! `form` 按下标转交 [`body`];`GROUP.body` 仍是 `None`,`tests/mod.rs` 那条「只有外观组带真控件」
//! 照样成立。
//! //!
//! ## 语言切换**没有**走 M101 的 `GroupMessage` 投递口(偏离,已登记) //! ## 语言切换**没有**走 M101 的 `GroupMessage` 投递口(偏离,已登记)
//! //!
@@ -284,7 +285,7 @@ fn setting_row<'a>(ui: &'a Ui, label: &'a str, value: &'a str) -> Element<'a, Me
/// 一个互斥按钮(选中态 `SecondaryContainer`,未选中透明 + `OnSurfaceVariant`)。 /// 一个互斥按钮(选中态 `SecondaryContainer`,未选中透明 + `OnSurfaceVariant`)。
/// ///
/// 与 `pages/appearance/section.rs` 的 `choice` 同款,但文案来自 catalog(那份是英文基线)。 /// 与 `pages/appearance/section/mod.rs` 的 `choice` 同款,但文案来自 catalog(那份是英文基线)。
fn chip<'a>(ui: &'a Ui, text: &'a str, selected: bool, choice: LangChoice) -> Element<'a, Message> { fn chip<'a>(ui: &'a Ui, text: &'a str, selected: bool, choice: LangChoice) -> Element<'a, Message> {
let height = ui.metrics().control_height; let height = ui.metrics().control_height;
let content_color = if selected { let content_color = if selected {
@@ -17,7 +17,7 @@
//! | `crates/i18n/src/catalog/settings/general.rs` / `appearance.rs` | 两组的文案 key | //! | `crates/i18n/src/catalog/settings/general.rs` / `appearance.rs` | 两组的文案 key |
//! | `crates/app-iced/src/app/update/settings/language_appearance.rs` | 消息的落点 | //! | `crates/app-iced/src/app/update/settings/language_appearance.rs` | 消息的落点 |
//! //!
//! 真控件那半边在 `pages/appearance/section.rs`(`appearance.rs` 只负责把 `body` 挂上去)。 //! 真控件那半边在 `pages/appearance/section/`(`appearance.rs` 只负责把 `body` 挂上去)。
/// 语言 + 外观线的状态(**只归本线**)。 /// 语言 + 外观线的状态(**只归本线**)。
/// ///
+3 -3
View File
@@ -269,9 +269,9 @@ const UPDATE_GROUP: usize = update::UPDATE_GROUP;
/// 「助手(AI)」分组在 [`GROUPS`] 里的下标(真源在 `settings/ai_about.rs`,这里只转发)。 /// 「助手(AI)」分组在 [`GROUPS`] 里的下标(真源在 `settings/ai_about.rs`,这里只转发)。
/// ///
/// 与 [`GENERAL_GROUP`] / [`UPDATE_GROUP`] 同一条做法:本组要画中英两套文案(`Lang`)与 /// 与 [`GENERAL_GROUP`] / [`UPDATE_GROUP`] 同一条做法:由 `view` 的 `language` 形参递到 [`form`]
/// 「测试连接」的结论,`Group.body` 的签名里没有 `Lang`,所以由 `view` 的 `language` 形参一路 /// 按本下标分发,`GROUP.body` 保持 `None`(本组**尚未**迁到 [`Body`] 槽位:槽位现在带 `Lang` 了,
/// 递到 [`form`] 的分发点,`GROUP.body` 保持 `None`。 /// 迁它要把 `ai::view::body` 的返回值改成 `Option<Element>`,是一次独立重构——M179 不做)。
const AI_GROUP: usize = ai_about::AI_GROUP; const AI_GROUP: usize = ai_about::AI_GROUP;
/// 「Java」分组在 [`GROUPS`] 里的下标(真源在 `settings/java.rs`,这里只转发)。 /// 「Java」分组在 [`GROUPS`] 里的下标(真源在 `settings/java.rs`,这里只转发)。
+4 -4
View File
@@ -2,10 +2,10 @@
//! //!
//! ## 为什么这一组不走 `Group.body` //! ## 为什么这一组不走 `Group.body`
//! //!
//! `Group.body` 的签名是 `fn(&Ui, States) -> Option<Element>`,而 `States` 只有「外观状态 + 各组 //! `Group.body` 的槽位拿的是 [`States`](super::States) 与**生效语言** `Lang`(M179 起),而更新状态
//! 自己的状态」两格。更新状态是 **presenter 快照**(不是某一组的字段),与 M106 的语言行同一种 //! 是 **presenter 快照**(`pages::Update`,不是某一组的字段、也不在 `States` 里),槽位装不下它。
//! 情形:`settings/mod.rs` 按下标([`UPDATE_GROUP`])把 `settings::view` 的 `update` 形参交给 //! 与 M106 的语言行同一种情形:`settings/mod.rs` 按下标([`UPDATE_GROUP`])把 `settings::view` 的
//! [`body`],`GROUP.body` 仍是 `None`。 //! `update` 形参交给 [`body`],`GROUP.body` 仍是 `None`。
//! //!
//! 消息也**不**走 `GroupMessage`:更新动作是「跨页的一次性意图」(检查 / 下载安装 / 忽略 / //! 消息也**不**走 `GroupMessage`:更新动作是「跨页的一次性意图」(检查 / 下载安装 / 忽略 /
//! 重启),落点是 `app/update/update_action.rs`,`pages::Message::Update(UpdateAction)` 一支就够。 //! 重启),落点是 `app/update/update_action.rs`,`pages::Message::Update(UpdateAction)` 一支就够。