merge(dev): 解 M196 与 dev(M179/M193)在 settings/mod.rs 的冲突
`origin/main` 是 D41 的孤儿快照(单提交、与开发史无共同祖先),M179/M193 这些提交在 `origin/dev` 上;按「跟上主线」的意图合的是 `origin/dev`。用 merge 不用 rebase:复审 clean 的 tip `e5a4b9b` 原样保留,本提交只负责解冲突。 唯一冲突:`settings/mod.rs` 里 `form` 的文档注释(M179 与 M195 重写过同一段)。两边都留: - **M179/M193**:`type Body` 带 `Lang`、四条按下标分发(General / Update / Assistant / Java)、 M193 的 download / logs 接线及其文档更新——只有一处措辞随之调整:「四组在下面各有 `else if`」 → 「在 [`section_columns`] 里各有 `else if`」,因为 M195 把那层循环抽成了独立函数; - **M195**:循环之后不再 push 那张「没有逐实例覆盖」的空态卡、`overrides_empty` 不存在、 `section_columns` 与其行为断言(`frame.rs` 两条用例)。 合并后的注释同时说明两件事:`GROUP.body` 从形参拿生效语言(M179)+ 尾部不许再挂东西、 逐实例覆盖的真控件在实例详情页(M195)。 为守住 400 行硬线(冲突态 424 → 399),只压自己的重复叙述:M196 段压到 4 行、 `section_columns` 的文档改为指向 `form`(它原来重复了一遍分发点,且在 M179 之后已不准确)、 模块文档里一段被 M179 实现取代的历史「r3 订正」压成一句可执行的结论。 代码零语义改动(证据见汇报):`section_columns` 的循环体与 `origin/dev` 归一化后逐字节相同(46 行), `GROUPS` / `GROUP_LABELS` 三方一致;相对 `origin/dev` 的差异只剩本 mission 的 4 个文件。
This commit is contained in:
commit
fb0b1a5311
274 files changed
+24717
-1998
No files matched your search
@@ -25,7 +25,7 @@
|
||||
//! | 分组 | 文件(正文 / 状态 / 消息) | 谁会动它 |
|
||||
//! |---|---|---|
|
||||
//! | General | [`general`] | language+appearance 线(语言下拉 + 主题 / 启动页) |
|
||||
//! | Appearance | [`appearance`] | language+appearance 线(真控件已在 `pages/appearance/section.rs`) |
|
||||
//! | Appearance | [`appearance`] | language+appearance 线(真控件已在 `pages/appearance/section/`) |
|
||||
//! | Java | [`java`] | java 线 |
|
||||
//! | Downloads | [`download`] | download 线 |
|
||||
//! | Updates | [`update`] | update 线(M159,按下标分发) |
|
||||
@@ -106,18 +106,11 @@
|
||||
//! `app/view.rs:70`),四处都要补字段 ⇒ **3 个共享文件**:`settings/state.rs`、`pages/mod.rs`、
|
||||
//! **`app/view.rs`**(最后这个正是 M104 的落点,本 mission 反复设锚点要避开的就是它);
|
||||
//! - 给 `settings::view` **加一个 `model: &Model` 形参**(`pages/mod.rs` 的 `render` 本来就拿着
|
||||
//! `model`,直接往下传)⇒ **2 个共享文件**(`settings/mod.rs` + `pages/mod.rs`),
|
||||
//! `app/view.rs` 不用动 —— **推荐这个形状**。
|
||||
//!
|
||||
//! 顺带订正 r3 之前那句「在 `app/state.rs` 用真值初始化 `Groups.language_appearance`(1 个文件)」:
|
||||
//! **M106 起语言已经有真值源**——`App::lang: LangState`(`crates/app-iced/src/ui/lang.rs`,用户档位
|
||||
//! `LangChoice` + 探测结论 `Detection`),由 `App::refresh_view` 经 `view::model(…, lang)` 灌进
|
||||
//! `pages::Model.lang`,设置页再从 `settings::view` 的 `language` 形参拿到它。所以下一条线要给某一组
|
||||
//! 读「当前语言」时,**不需要**再造一层状态:要么走 `Model.lang`(给 `settings::view` 加形参,
|
||||
//! 与 M106 同形状),要么读 `Groups` 里本线的字段。两种形状都是「谁先撞谁付一次钱」的一次性代价,
|
||||
//! 不是永久性四路撞车。
|
||||
//! `model`,直接往下传)⇒ **2 个共享文件**(`settings/mod.rs` + `pages/mod.rs`),`app/view.rs`
|
||||
//! 不用动 —— **推荐这个形状**。语言也已有真值源(`ui/lang.rs` 的 `App::lang` → `view::model(…)`
|
||||
//! → `Model.lang`):某组读「当前语言」走它或 `Groups` 里本线字段,别再另造一层状态。
|
||||
//! 5. **首帧取数 / 异步发起**(同上,r2 复审 P1 补)—— [`Body`] 是
|
||||
//! `fn(&Ui, States) -> Option<Element>`,返回不了 `Task`;而且 `settings::view` → `pages::render`
|
||||
//! `fn(&Ui, States, Lang) -> Option<Element>`,返回不了 `Task`;而且 `settings::view` → `pages::render`
|
||||
//! → `App::view` **一路都返回 `Element`**(iced 0.14 的 `view` 也只返回 `Element`,`view(&self)`
|
||||
//! 又改不了状态),**view 期间产出的 `Task` 没有出口**。所以只有一条路:在 `app/update.rs` 的
|
||||
//! `Message::Boot` 分支补一次首帧派发(**1 个共享文件**——`on_boot` 本来就在派
|
||||
@@ -143,6 +136,7 @@ mod frame;
|
||||
mod general;
|
||||
pub(crate) mod java;
|
||||
pub(crate) mod language_appearance;
|
||||
mod logs_row;
|
||||
mod message;
|
||||
mod state;
|
||||
pub(crate) mod update;
|
||||
@@ -193,13 +187,16 @@ impl Default for Language {
|
||||
}
|
||||
}
|
||||
|
||||
/// 一个分组正文的**真控件渲染器**:入参是「画一帧时那份只读状态」(组状态 + 外观状态),
|
||||
/// 返回 `None` = 这一组现在没东西可画(例如外观分组在 harness 路径下没有外观状态),
|
||||
/// 由 [`form`] 退回演示行。
|
||||
/// 一个分组正文的**真控件渲染器**:入参是「画一帧时那份只读状态」(组状态 + 外观状态)
|
||||
/// 与**这一次生效的语言**,返回 `None` = 这一组现在没东西可画(例如外观分组在 harness 路径下
|
||||
/// 没有外观状态),由 [`form`] 退回演示行。
|
||||
///
|
||||
/// 各组自己的渲染器**定义在自己文件里**,签名是这一条:于是「这一组要读哪些状态」由它自己决定,
|
||||
/// 本文件不需要认识任何一组的字段(r1 复审 P1 要的正是这一点)。
|
||||
type Body = for<'a> fn(&'a Ui, States<'a>) -> Option<Element<'a, Message>>;
|
||||
///
|
||||
/// `lang` 是 M179 加的:槽位此前拿不到语言,唯一挂了真控件的外观组只能写死英文;接进**唯一的那个
|
||||
/// 槽位**比再给 [`form`] 加一条按下标分发的 `else if` 更省行数(本文件贴着 400 行硬顶)。
|
||||
type Body = for<'a> fn(&'a Ui, States<'a>, Lang) -> Option<Element<'a, Message>>;
|
||||
|
||||
/// 一个设置分组:名字、图标、演示行、(可选)把这一组正文画成真控件的渲染器。
|
||||
///
|
||||
@@ -236,9 +233,9 @@ const SELECTED: usize = 0;
|
||||
|
||||
/// General 分组在 [`GROUPS`] 里的下标(0)。它与 [`SELECTED`] 同值**是巧合,不是依赖**。
|
||||
///
|
||||
/// 为什么需要它:语言行要的是「当前档位 + 生效语言」([`Language`]),而 `Group.body` 的签名只带
|
||||
/// [`States`](外观 + 组状态)——给 `States` 加字段要动 `settings/state.rs` 与 4 处 struct literal
|
||||
/// (见本文件文档「仍然共享」第 4 条),给 `Body` 加形参会令另外三组各自的 `body` 函数编译不过。
|
||||
/// 为什么需要它:语言行要的是「当前档位 + 生效语言」([`Language`]),而 `Group.body` 只带
|
||||
/// [`States`] 与**生效语言**(`Lang`,M179)——档位 `LangChoice` 装不进去(`States` 也装不下:
|
||||
/// 加字段要动 `settings/state.rs` 与 4 处 struct literal,见本文件文档「仍然共享」第 4 条)。
|
||||
/// 所以这里做一次**按下标的分发**:代价是一行 `if`,换来 `general::GROUP.body` 仍是 `None`
|
||||
/// (`tests/mod.rs` 的「只有外观组带真控件 body」照样成立)。
|
||||
const GENERAL_GROUP: usize = 0;
|
||||
@@ -266,11 +263,17 @@ const UPDATE_GROUP: usize = update::UPDATE_GROUP;
|
||||
|
||||
/// 「助手(AI)」分组在 [`GROUPS`] 里的下标(真源在 `settings/ai_about.rs`,这里只转发)。
|
||||
///
|
||||
/// 与 [`GENERAL_GROUP`] / [`UPDATE_GROUP`] 同一条做法:本组要画中英两套文案(`Lang`)与
|
||||
/// 「测试连接」的结论,`Group.body` 的签名里没有 `Lang`,所以由 `view` 的 `language` 形参一路
|
||||
/// 递到 [`form`] 的分发点,`GROUP.body` 保持 `None`。
|
||||
/// 与 [`GENERAL_GROUP`] / [`UPDATE_GROUP`] 同一条做法:由 `view` 的 `language` 形参递到 [`form`]
|
||||
/// 按本下标分发,`GROUP.body` 保持 `None`(本组**尚未**迁到 [`Body`] 槽位:槽位现在带 `Lang` 了,
|
||||
/// 迁它要把 `ai::view::body` 的返回值改成 `Option<Element>`,是一次独立重构——M179 不做)。
|
||||
const AI_GROUP: usize = ai_about::AI_GROUP;
|
||||
|
||||
/// 「Java」分组在 [`GROUPS`] 里的下标(真源在 `settings/java.rs`,这里只转发)。
|
||||
///
|
||||
/// M175 起这一组也按下标分发:它要 `Lang`(中英文案)并且要读后台扫描的快照
|
||||
/// (扫描线程不碰 `App`,结论由心跳灌进 `Groups.java`,页面只从 [`States`] 里取)。
|
||||
const JAVA_GROUP: usize = java::JAVA_GROUP;
|
||||
|
||||
/// 整页。
|
||||
///
|
||||
/// `states` 是「画一帧时那份只读状态」:[`States::appearance`] 是 M93 接进来的外观运行期状态
|
||||
@@ -306,17 +309,15 @@ pub fn view<'a>(
|
||||
|
||||
/// 表单列(正文列宽 ≤424)。`only = Some(i)` 只渲染一组(supporting-pane),`None` 渲染全部(窄窗按组堆叠)。
|
||||
///
|
||||
/// ## M196:正文到最后一组就结束,尾部**什么**都不许挂
|
||||
/// **分发点(两条路,M106 起就并存)**:①`GROUP.body`——`Some(f)` 自己去 [`States`] 取数,并从形参拿
|
||||
/// **生效语言**(`None` 退回演示行);②**按下标分发**——General(语言档位)/ Update(presenter 快照)/
|
||||
/// Assistant(`Lang` + 测试结论)/ Java(`Lang` + 扫描槽)在 [`section_columns`] 里各有 `else if`,它们
|
||||
/// 的 `GROUP.body` 仍是 `None`(理由见各自的 `<组>_GROUP` 常量);分组名只作 `GROUPS` 元素的 id。
|
||||
///
|
||||
/// 这里原先在循环之后无条件叠了一张「没有逐实例覆盖」的空态卡(M84 骨架期的占位,M99 纯搬移时原样
|
||||
/// 留着),于是**每一组**下面都长出同一张卡(用户在 M174 的助手页与 M175 的 Java 页都看到了它:两张图
|
||||
/// 1180×1100、位置一致、说明被窗口下沿截断)。**删掉,不挪给任何一组。**
|
||||
///
|
||||
/// 它不是「还没接的活」,是**放错了地方**:逐实例覆盖(内存 / Java 运行时 / JVM 参数)的真控件在
|
||||
/// **实例详情页**的「启动参数」区(M157 `pages/instances/launch_args.rs` → `AppCommand::set_launch_args`
|
||||
/// → presenter `host/launch_args.rs` 的 `resolved`/`apply`,写回 `config/instances/<id>.json`;回落与
|
||||
/// 落位在 core 的 `game/launch_overrides.rs` / `launch/overrides.rs`)。设置页拿不到那份快照,也不该
|
||||
/// 重复一份([`view`] 的形参里没有 `Model`);真正无人产出的是 UI 变体 `Action::AddOverride`(死消息)。
|
||||
/// **尾部不许再挂东西(M196)**:循环之后原先无条件叠了一张「没有逐实例覆盖」的空态卡(来历见
|
||||
/// `frame.rs`),于是**每一组**下面都长出同一张卡。它**放错了地方**:真控件在**实例详情页**的「启动
|
||||
/// 参数」区(M157 `pages/instances/launch_args.rs` → `AppCommand::set_launch_args`),设置页拿不到那份
|
||||
/// 快照([`view`] 没有 `Model`);无人产出的只有 `Action::AddOverride`。删掉,守门见 `frame.rs` 末尾。
|
||||
fn form<'a>(
|
||||
ui: &'a Ui,
|
||||
only: Option<usize>,
|
||||
@@ -333,12 +334,8 @@ fn form<'a>(
|
||||
frame::scroll(ui, stack)
|
||||
}
|
||||
|
||||
/// 正文里**每组一件**的列(该组标题 + 正文),顺序 = [`GROUPS`] 顺序,只含被选中的那些。
|
||||
///
|
||||
/// **分发点**:正文由 `GROUP.body` 决定——`Some(f)` 自己去 [`States`] 取数(`None` 退回演示行);
|
||||
/// 这里不出现任何分组名、不比较下标、也不认识任何一组的字段。抽成独立函数是为了能被**行为断言**
|
||||
/// 量到(`frame.rs` 的 `the_form_holds_exactly_one_column_per_group` 数它的列数,换名字也红);
|
||||
/// 收尾留在 [`form`],由 push 计数守住——两半合起来 =「正文恰好这些列,没有尾巴」。
|
||||
/// 正文里**每组一件**的列(顺序 = [`GROUPS`],只含被选中的那些;分发点见 [`form`] 的文档)。抽出来是
|
||||
/// 为了能被**行为断言**量到:`frame.rs` 的 `the_form_holds_exactly_one_column_per_group` 数它的列数。
|
||||
fn section_columns<'a>(
|
||||
ui: &'a Ui,
|
||||
only: Option<usize>,
|
||||
@@ -368,10 +365,13 @@ fn section_columns<'a>(
|
||||
} else if index == AI_GROUP {
|
||||
// M174:助手组要 i18n 文案与「测试连接」结论,与 General / Update 同一条按下标分发。
|
||||
ai::view::body(ui, states, language.effective)
|
||||
} else if index == JAVA_GROUP {
|
||||
// M175:Java 组要 i18n 文案 + 扫描快照,同样按下标分发(`GROUP.body` 保持 `None`)。
|
||||
java::view::body(ui, states, language.effective)
|
||||
} else {
|
||||
group
|
||||
.body
|
||||
.and_then(|body| body(ui, states))
|
||||
.and_then(|body| body(ui, states, language.effective))
|
||||
.unwrap_or_else(|| frame::demo_card(ui, group.rows))
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user