refactor(download): rebase 到 M93 之后 app/update.rs 破 400 → 下载页四支拆到 update/download.rs

M93(外观三件套接线)合入后 `app/update.rs` 从 348 涨到 410 行,再加上下载页的四个 arm
会顶破 ≤400 硬线。把下载页那几支(SelectVersion / InstallVersion / CancelInstall /
SetCategory / Action::RefreshSources)挪到 `app/update/download.rs`(`app/update/**` 在本
mission scope 内),`on_page` 入口只留一句 `if self.on_download(&message) { return; }`,
match 末尾补一条 `_ => {}` 做穷尽性。

行为零变化:指令、视图模型写法、`refresh_view` 顺序都照搬;M93 的 `Appearance` arm /
`env_start_route` / `on_appearance` 一行没动。

行数:update.rs 410 → 397,download.rs 57。
This commit is contained in:
tower committed 2026-11-02 21:45:40 +08:00
1 parent 6453c76750
commit 5340908882
2 files changed
+69 -25

No files matched your search

+12 -25
View File
@@ -41,6 +41,8 @@ use super::message::{route_of, Message};
use super::state::{App, IDLE_TICK, TICK, TICK_MS, WATCH_WINDOW};
use super::CAPTURE_AT_FRAME;
mod download;
impl App {
/// 一条消息进来,改状态并返回后续任务。
pub(super) fn update(&mut self, message: Message) -> Task<Message> {
@@ -275,6 +277,11 @@ impl App {
/// 页面消息:导航走路由栈,动作翻成 `AppCommand`。
fn on_page(&mut self, message: pages::Message) {
// 下载页的四支(含「刷新下载源」)在 `update/download.rs`:本文件 M93 合入后已贴 400 行
if self.on_download(&message) {
return;
}
match message {
pages::Message::Navigate(route) => {
self.state.navigate(route);
@@ -284,32 +291,12 @@ impl App {
pages::Message::Launch(id) => self.dispatch(AppCommand::LaunchInstance(id)),
pages::Message::Stop(id) => self.dispatch(AppCommand::StopInstance(id)),
pages::Message::Appearance(change) => self.on_appearance(change),
// ── 下载页(M94):选中是**页面内**状态(不 dispatch),其余三条都派真指令。
pages::Message::SelectVersion(id) => self.view.download.selected = Some(id),
pages::Message::InstallVersion(id) => self.dispatch(AppCommand::InstallVersion(id)),
pages::Message::CancelInstall => self.dispatch(AppCommand::CancelInstall),
pages::Message::SetCategory(category) => {
// 分类是**本页的过滤条件**,不是后端事实的乐观回显:真 host 会把
// `ListVersions` 的分类参数丢掉、回全量清单(复审 P2-1),所以过滤在本页做。
// 写进视图模型 → 立刻按它重建(`refresh_view` 会把 category 带回去并据此过滤行),
// 于是 chip 与列表用同一个谓词,不存在「chip 说正式版、列表是全量」的两份真相。
self.view.download.category = category;
self.view_dirty = true;
self.refresh_view();
// 列表内容仍然由后端给:真指令照派(presenter 修好 `spawn_list` 之后它就是那一路)
if let Some(kind) = category.command() {
self.dispatch(AppCommand::ListVersions(kind));
}
}
// 还没接后端的占位动作:只打日志(哪几个、为什么,见 pages 模块文档的偏离登记)
pages::Message::Action(action) => match action {
// 「刷新下载源」不是占位动作:具体分类 → 重拉该分类;「全部」→ 让 host 重扫一遍
pages::Action::RefreshSources => match self.view.download.category.command() {
Some(kind) => self.dispatch(AppCommand::ListVersions(kind)),
None => self.dispatch(AppCommand::RefreshAll),
},
_ => eprintln!("[page] 占位动作 {action:?} pressed(没有对应 AppCommand)"),
},
pages::Message::Action(action) => {
eprintln!("[page] 占位动作 {action:?} pressed(没有对应 AppCommand)");
}
// 下载页四支 +「刷新下载源」已由上面的 `on_download` 消化,这里只是穷尽性兜底
_ => {}
}
}
@@ -0,0 +1,57 @@
//! 下载页在 app 层的那几支(M94)。
//!
//! 为什么单独一个文件:M93(外观三件套接线)合入后 `update.rs` 已经贴到 400 行,下载页再往里塞
//! 四个 arm 就顶破硬线;拆出来是既不动 M93 的代码、又能守住 ≤400 的办法(`app/update/**` 属本
//! mission scope)。
//!
//! ## 四支各自的纪律
//!
//! | 消息 | 落点 | 为什么 |
//! |---|---|---|
//! | [`pages::Message::SelectVersion`] | **只改视图模型** | 选中是页面内状态,不是业务命令 |
//! | [`pages::Message::InstallVersion`] | `AppCommand::InstallVersion` | 真指令,回事件后才画进度 |
//! | [`pages::Message::CancelInstall`] | `AppCommand::CancelInstall` | 同上(host 侧对没在跑的任务是 no-op) |
//! | [`pages::Message::SetCategory`] | 写分类 → 重建 → `AppCommand::ListVersions` | 见下 |
//!
//! [「刷新下载源」](pages::Action::RefreshSources) 也在这里:它不是占位动作,具体分类 → 重拉该分类、
//! 「全部」→ 让 host 重扫一遍(`RefreshAll`)。
//!
//! ## 分类为什么既写视图模型、又派指令
//!
//! 真 host 的 `AppCommand::ListVersions(_)` 会丢掉分类参数、回全量清单(复审 P2-1),所以**过滤在
//! 本页做**:写进视图模型 → 立刻 `refresh_view()`(它会把 category 带回去、按同一谓词过滤行)→
//! 再派指令。这不是「乐观回显」:写的是**过滤条件本身**,chip 与列表用同一个
//! [`Category::matches`](crate::pages::Category),于是不可能出现「chip 说正式版、列表是全量」的两份真相。
use super::*;
impl App {
/// 下载页的消息。**处理了返回 `true`**(`on_page` 里就不用再写一遍这些 arm)。
pub(super) fn on_download(&mut self, message: &pages::Message) -> bool {
match message {
pages::Message::SelectVersion(id) => {
self.view.download.selected = Some(id.clone());
}
pages::Message::InstallVersion(id) => {
self.dispatch(AppCommand::InstallVersion(id.clone()));
}
pages::Message::CancelInstall => self.dispatch(AppCommand::CancelInstall),
pages::Message::SetCategory(category) => {
self.view.download.category = *category;
self.view_dirty = true;
self.refresh_view();
if let Some(kind) = category.command() {
self.dispatch(AppCommand::ListVersions(kind));
}
}
pages::Message::Action(pages::Action::RefreshSources) => {
match self.view.download.category.command() {
Some(kind) => self.dispatch(AppCommand::ListVersions(kind)),
None => self.dispatch(AppCommand::RefreshAll),
}
}
_ => return false,
}
true
}
}