refactor(presenter): 两处纯搬移腾出 400 行余量(events 用例 / AI 栏事件投递)

events.rs 399 行、state.rs 400 行(AGENTS §3.1 与 §3.9 的零余量贴线文件)。M223 要往
AppCommand/CoreEvent 各加一条「导入已有版本」的变体、往 AppState 加一份事件态,都得先腾地方。

纯搬移、一行未改:
- events.rs 尾部 #[cfg(test)] mod tests(80 行)→ dto/events/tests.rs(399 → 321);
- state.rs 的 apply_agent + agent_rail_visible(28 行)→ state/agent.rs(400 → 376)。

方法路径不变(impl 写在子模块、pub use 无需新增),断言一条未动,搬移 diff 可逐行对。
This commit is contained in:
AskaEth committed 2026-11-10 19:37:23 +08:00
1 parent 13a317d35c
commit 9ab909d01c
4 files changed
+129 -105

No files matched your search

+39
View File
@@ -0,0 +1,39 @@
//! AI 栏的事件投递与可见性判定(M223 从 `state.rs` **纯搬移**,一行未改)。
//!
//! 为什么搬:M223 要往 `AppState` 加「导入已有版本」的状态字段与一条 `CoreEvent::Adopt` 分支,
//! 而 `state.rs` 当时正好 400 行(零余量,AGENTS §3.9)。拆分口径与 [`super::tiles`] 一致:
//! **纯搬移、一行不改**;`impl AppState` 写在子模块里,方法路径
//! `AppState::apply_agent` / `AppState::agent_rail_visible` 对调用方完全不变
//! (子模块看得见父模块的私有字段,所以这里直接用 `self.ai` / `self.prefs`)。
use crate::dto::AgentEvent;
use crate::router::AiPanelMode;
use super::AppState;
impl AppState {
/// agent 事件 → AI 栏视图模型(投影规则见 [`crate::agent::rail`])。
///
/// 未读规则:栏不可见时,助手侧新内容(助手/工具消息、错误、待确认请求)逐条累加 `unread`;
/// 用户自己说的话与纯增量不算。栏可见时到达的内容直接算已读(红点不该在眼前亮着)。
pub fn apply_agent(&mut self, event: AgentEvent) {
let visible = self.agent_rail_visible();
let fresh = self.ai.ingest(&event);
if fresh {
if visible {
self.ai.mark_read();
} else {
self.ai.unread = self.ai.unread.saturating_add(1);
}
}
}
/// AI 栏此刻是否「在用户眼前」。
///
/// 独立页形态(栈顶是 `Route::Agent`)必然可见;停靠形态下只有收成 icon 轨才算离开——
/// 右侧常驻栏在任何一级页面都挂着,用户扫一眼就能看到。
#[must_use]
pub fn agent_rail_visible(&self) -> bool {
self.ai_mode() == AiPanelMode::Page || !self.prefs.ai_collapsed
}
}