fix(app-iced): M104 r2 —— Route::Agent ⟺ Detached 的不变式 + 复审 P3 六条
p2-1(唯一 p2):`Route::Agent` 与 `RailState::Detached` 之前没有绑定——从左侧导航第五项 (本 mission 点名的入口)进独立页时档位还是 Collapsed/Expanded,于是页头出现「Open assistant」 「Collapse/Pop out」、挂着不化的未读胶囊、Esc 也收不走页面(复审用产品 bin 复现)。 - **单一入口**:`App::sync_agent_route()`(update/agent.rs)在 `refresh_view` 开头调用, 两条对向规则:在独立页 ⇒ Detached(顺带清未读);离开独立页而档位还是 Detached ⇒ 收回右栗。 每一次路由变化都经过 refresh_view,所以导航 / ULL_START_ROUTE / detach / back 共用这一处。 - **结构性兜底**:`conversation::actions` 先按宿主分流,`Host::Page` 的动作恒为「Dock back」。 - **启动顺序**:`boot_agent()`(窗口尺寸 adopt + 拆出档直达独立页)必须在 `dispatch(RefreshAll)` 之前——那次 dispatch 会 pump→auto_select 把路由拉到实例详情,同步器随即把档位收回(实测踩到)。 - 测试:`entering_the_agent_route_detaches_the_rail`(走 `Message::Select(NavItem::Ai)` 真路径, 含未读清零 / Esc 离开 / 从页上点别的导航收回)、`the_page_navigation_entry_also_detaches`。 变异自证:把 `sync_agent_route` 改成 no-op ⇒ 3 红(含这两条)。 - 图 13/14:导航入口(折叠档带 2 条未读 / 展开档)进页后都是 Dock back、无未读胶囊、副标题单行。 P3-2 Enter/Shift+Enter 有测试了:分流抽成纯函数 `composer::binding_for`, `enter_sends_and_shift_enter_breaks_the_line` 覆盖「发送 / 换行 / 未聚焦不抢 / 其它键交回默认」; `AgentUi::edit` 里与 fallthrough 等价的冗余 Enter 分支删掉;三档测试改走 `agent.edit(...)`。 P3-4 自证式断言换字面量(320+8+852=1180 等);变异 RESIZE_GUTTER 8→0 ⇒ 6 红(含这条)。 P3-5 两条死文案真用上:8px 拖拽缝有了 tooltip(AgentResize + AgentWidthLabel「当前多宽」)。 P3-6 `on_boot` 的两块逻辑搬进 `update/agent.rs::boot_agent`:update.rs 372→383(+11,见报告逐行)。 P3-7 拖拽层补 on_press/on_exit:窗外松手不再僵住(窗内按下→清态;离窗→收在当前值)。 P3-9 顺手:只有几何/路由会变的消息才重建视图模型(每个字符、每次指针移动不再重建)。 门禁:fmt 0 / clippy(workspace,-D warnings) 0 / pages_demo 0 / 全文件 ≤400(最大 view.rs 373 之外 conversation.rs 383、update.rs 383)
This commit is contained in:
1 parent
8db1c5ab16
commit
9253684387
11 files changed
+495
-208
No files matched your search
@@ -44,67 +44,49 @@ impl App {
|
||||
}
|
||||
|
||||
// 产品页走**内容槽位**:外壳(标题栏 / 拖动与缩放热区 / 三个 caption 键 / rail)由
|
||||
// `shell` 画,中间那块才是页面。M90 r2 之前这里用的是 `pages::app`(自带一条**没有任何
|
||||
// 控件**的标题栏留白带),而 `DragWindow` / `ResizeStart` / `Minimize` / `ToggleMaximize` /
|
||||
// `Close` 五个消息只在外壳里构造 ⇒ 产品页「拖不动、缩不了、点不到关闭」。
|
||||
// `shell` 画,中间那块才是页面(`DragWindow`/`ResizeStart`/`Minimize`/`ToggleMaximize`/`Close`
|
||||
// 五种消息的构造点只在外壳里,页面树自己画的标题栏拖不动窗口)。
|
||||
//
|
||||
// M93:三样东西从外观状态进来——①背景层(垫在最底下)②面板 α(外壳层的底色)③设置页要读
|
||||
// 的那份状态本身。M101 r2 起 ③ 走 `page_with_settings`:外观状态 + 各组自己的状态
|
||||
// (`App.settings`)一起递进去,四条填页线加字段不用动这一行。
|
||||
// 的那份状态。M101 r2 起 ③ 走 `page_with_settings`:外观状态 + 各组自己的状态一起递进去。
|
||||
let background =
|
||||
pages::appearance::layer(&self.ui, &self.appearance, (self.width, self.height))
|
||||
.map(|element| element.map(Message::Page));
|
||||
// 右栗(M104):拆出档返回 `None`(会话已在独立页里);拖拽期间另有铺满窗口的取指针层。
|
||||
let overlay = agent::drag_overlay(&self.agent).map(|element| element.map(Message::Agent));
|
||||
|
||||
match pages::Screen::of(self.state.route()) {
|
||||
Some(_) => {
|
||||
let background =
|
||||
pages::appearance::layer(&self.ui, &self.appearance, (self.width, self.height))
|
||||
.map(|element| element.map(Message::Page));
|
||||
|
||||
// 右栗(M104):`Detached` 档返回 `None`(会话已经在独立页里);拖拽期间另有一层
|
||||
// 铺满窗口的取指针层,所以两件东西分开传。
|
||||
let right = agent::docked(&self.ui, &self.agent, self.width)
|
||||
.map(|element| element.map(Message::Agent));
|
||||
let overlay =
|
||||
agent::drag_overlay(&self.agent).map(|element| element.map(Message::Agent));
|
||||
|
||||
shell::view_with_background(
|
||||
Some(_) => shell::view_with_background(
|
||||
&self.ui,
|
||||
nav_item_of(self.state.route()),
|
||||
APP_TITLE,
|
||||
background,
|
||||
// M101 r2:设置页的只读状态(外观运行期状态 + 各组自己的状态)一次递进去。
|
||||
pages::page_with_settings(
|
||||
&self.ui,
|
||||
nav_item_of(self.state.route()),
|
||||
APP_TITLE,
|
||||
background,
|
||||
// M101 r2:设置页的只读状态(外观运行期状态 + 各组自己的状态)一次递进去。
|
||||
// `settings` 的所有者是 `App`;这里只借一帧,加/改某一组的字段不用动这行。
|
||||
pages::page_with_settings(
|
||||
&self.ui,
|
||||
&self.view,
|
||||
pages::settings::States {
|
||||
appearance: Some(&self.appearance),
|
||||
groups: &self.settings,
|
||||
},
|
||||
)
|
||||
.map(Message::Page),
|
||||
right,
|
||||
overlay,
|
||||
self.options.force_state,
|
||||
&self.view,
|
||||
pages::settings::States {
|
||||
appearance: Some(&self.appearance),
|
||||
groups: &self.settings,
|
||||
},
|
||||
)
|
||||
}
|
||||
// `Route::Agent`:AI 独立页(M104)。它与右栗**共用**同一个会话视图
|
||||
// (`agent::page` 内部调的是 `conversation::view`),这里只是把会话摆进页面槽位。
|
||||
None => {
|
||||
let background =
|
||||
pages::appearance::layer(&self.ui, &self.appearance, (self.width, self.height))
|
||||
.map(|element| element.map(Message::Page));
|
||||
let overlay =
|
||||
agent::drag_overlay(&self.agent).map(|element| element.map(Message::Agent));
|
||||
|
||||
shell::view_with_background(
|
||||
&self.ui,
|
||||
NavItem::Ai,
|
||||
APP_TITLE,
|
||||
background,
|
||||
agent::page(&self.ui, &self.agent, self.width).map(Message::Agent),
|
||||
None,
|
||||
overlay,
|
||||
self.options.force_state,
|
||||
)
|
||||
}
|
||||
.map(Message::Page),
|
||||
agent::docked(&self.ui, &self.agent, self.width)
|
||||
.map(|element| element.map(Message::Agent)),
|
||||
overlay,
|
||||
self.options.force_state,
|
||||
),
|
||||
// `Route::Agent`:独立页与右栗共用同一个 `conversation::view`(`agent::page` 内部调的它)。
|
||||
None => shell::view_with_background(
|
||||
&self.ui,
|
||||
NavItem::Ai,
|
||||
APP_TITLE,
|
||||
background,
|
||||
agent::page(&self.ui, &self.agent, self.width).map(Message::Agent),
|
||||
None,
|
||||
overlay,
|
||||
self.options.force_state,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user