fix(download): M94 r1 —— 五条复审(P2-1/2/3/4/6)
P2-1 占位规则统一:加载态原先贴顶、空态居中 → 两态都走同一套「内容在可用区居中」
(依据:components::feedback::empty_state 的既有口径 12b §15.4;两态互切不再纵向跳)。
实测两个状态的内容中心线 y=449 / y=445(差 4px)。
P2-2 文案只说真能做到的事:
- 删「The list appears after the first successful fetch; this page never goes blank.」
(工程话术 + 承诺了 UI 做不到的「永空白」)→「如果一直停在这里,点右上角的刷新。」
(对应页头那个真的 Refresh 按钮)
- 空态「Switch the category or clear the filter」删掉「清筛选」(页面没有筛选控件)
→「换一个分类,或刷新一次列表。」
- 副标题「Version list from the official manifest」去掉 manifest 这种工程词 →「可以安装的版本」
P2-3 去掉静止的 indeterminate 进度条:页面没有帧订阅,indeterminate 只会拿到一个固定相位
(看起来像 17% 卡住)。加载态改成纯文字;安装面板只在进度已知时画 determinate。
两帧证据:215/512 → 条填 177px(42%),409/512 → 338px(80%),条随事件走而不是动画。
P2-4 失败态与安装中彻底不同构:失败不再画进度条,改成整块 ErrorContainer 面板
(ErrorContainer 底 + Error 图标 + Error 色标题 + 停在哪个文件 + 说明 + 实心「打开日志」)。
实测底色:浅色 (255,218,214) / 深色 (147,0,10),安装中面板底色仍是页面底色。
P2-6 死 key 与假守卫:
- 删掉没用的 DownloadSelected;
- 用真的守卫替换原来那条「前缀遍历 + 条数下限」:every_download_key_is_referenced_by_the_page
用 include_str! 把页面源码编进来,目录里每个 Download* key 必须在源码里出现 Key::Xxx。
实证:把 DownloadSelected 放回去 → 该测试红并点名 key;删掉 → 绿。
注释里也写清抓不住的三种情况(反向是编译错误 / 译文完整性归 i18n 自己的测试 / 宏拼 key 能骗过它)。
门禁:fmt --check 干净、clippy -D warnings 干净、app-iced 276 + i18n 23 全绿;
tests.rs 384→383 行(不再贴顶),其余文件均 ≤400。
This commit is contained in:
1 parent
57e8380b24
commit
9d6ee70301
6 files changed
+229
-145
No files matched your search
@@ -73,8 +73,6 @@ fn extra_width_goes_to_margin_not_to_the_column() {
|
||||
// --------------------------------------------------------------- 快照 → 模型
|
||||
|
||||
/// 真快照进得来:行数、分类、选中项、已装标记全部来自 `AppState`。
|
||||
///
|
||||
/// 抓得住:页面自己造数据、或把 `installed` / `kind` 丢了。
|
||||
/// 抓不住:快照字段在 `app/view.rs` 被漏接(那由 `app/update.rs` 的接线测试兜)。
|
||||
#[test]
|
||||
fn the_snapshot_becomes_the_page_model() {
|
||||
@@ -125,8 +123,6 @@ fn the_snapshot_becomes_the_page_model() {
|
||||
}
|
||||
|
||||
/// 快照里的两个过滤条件(`installed_only` / `download_query`)原样照用。
|
||||
///
|
||||
/// 抓得住:页面把 presenter 的过滤条件丢了(用户设了「仅已装」,页面照画全部)。
|
||||
/// 抓不住:过滤词大小写之外的语言学规则(那属于 presenter 的搜索口径)。
|
||||
#[test]
|
||||
fn presenter_filters_still_apply() {
|
||||
@@ -151,9 +147,7 @@ fn presenter_filters_still_apply() {
|
||||
assert!(queried.rows.iter().all(|row| row.id.starts_with("1.21")));
|
||||
}
|
||||
|
||||
/// 空快照 = 加载态;过滤掉所有行 = 空态。两者都**不许**是白屏。
|
||||
///
|
||||
/// 抓得住:把「还没拉到」画成「没有版本」(谎报空态),或反过来。
|
||||
/// 空快照 = 加载态;过滤掉所有行 = 空态(抓「把还没拉到画成没有版本」,或反过来)。
|
||||
/// 抓不住:真机上卡在加载态多久(没有超时信号,见模块文档的缺口表)。
|
||||
#[test]
|
||||
fn loading_and_empty_are_different_states() {
|
||||
@@ -213,31 +207,39 @@ fn category_commands_are_real() {
|
||||
|
||||
// --------------------------------------------------------------- 文案(i18n)
|
||||
|
||||
/// 中英两套目录都能把这一页的每个 key 求出来(缺译会露出 `⟪missing⟫`)。
|
||||
/// 每个 `Download*` key 都**真的被页面引用**(死 key 守门,M94 r1 / P2-6)。
|
||||
///
|
||||
/// 「这一页的 key」按 `Download` 前缀取,不手写清单:清单会漏、会在下一次加 key 时不同步,
|
||||
/// 而前缀遍历顺手还守住了「不许把 key 悄悄删掉」(条数下限)。
|
||||
///
|
||||
/// 抓得住:新增 key 只写了一种语言(另一套会显示 `⟪missing⟫`)。
|
||||
/// 抓不住:译文质量,以及**没有用到的** key(那是 `catalog` 自己的完整性测试)。
|
||||
/// 复审抓到的 `DownloadSelected` 就是这条要拦的东西:目录里定义了、页面没人用。所以这里把页面
|
||||
/// 源码用 `include_str!` 编进来扫一遍。**抓不住什么也说清**:反向(引用了不存在的 key)是编译错误,
|
||||
/// 不需要测试;译文对不对、两套语言都填了没由 `i18n` 自己的 `built_in_catalogs_have_every_key` 守;
|
||||
/// 它只看字面出现,用宏拼 key 名能骗过它。
|
||||
#[test]
|
||||
fn every_download_key_exists_in_both_catalogs() {
|
||||
let download_keys: Vec<Key> = Key::ALL
|
||||
.iter()
|
||||
.copied()
|
||||
.filter(|key| key.name().starts_with("Download"))
|
||||
.collect();
|
||||
assert!(download_keys.len() >= 25, "下载页的 key 不该被悄悄删掉");
|
||||
fn every_download_key_is_referenced_by_the_page() {
|
||||
const SOURCES: [&str; 6] = [
|
||||
include_str!("../download.rs"),
|
||||
include_str!("model.rs"),
|
||||
include_str!("rows.rs"),
|
||||
include_str!("install.rs"),
|
||||
include_str!("states.rs"),
|
||||
include_str!("demo.rs"),
|
||||
];
|
||||
|
||||
for lang in [Lang::En, Lang::ZhCn] {
|
||||
let catalog = lang.catalog();
|
||||
for key in &download_keys {
|
||||
let text = catalog.text(*key);
|
||||
assert_ne!(text, unlucky_i18n::catalog::MISSING, "{key:?} 缺译");
|
||||
assert!(!text.is_empty(), "{key:?} 是空串");
|
||||
}
|
||||
assert!(catalog.missing().is_empty(), "内置目录不许有缺译");
|
||||
let mut checked = 0;
|
||||
for key in Key::ALL
|
||||
.iter()
|
||||
.filter(|key| key.name().starts_with("Download"))
|
||||
{
|
||||
let needle = format!("Key::{}", key.name());
|
||||
assert!(
|
||||
SOURCES.iter().any(|source| source.contains(&needle)),
|
||||
"{needle} 在目录里定义了,但下载页没有任何地方用它(死 key,删掉或接上)"
|
||||
);
|
||||
checked += 1;
|
||||
}
|
||||
assert!(
|
||||
checked > 20,
|
||||
"下载页的 key 不该被成批删掉(只查到 {checked} 条)"
|
||||
);
|
||||
}
|
||||
|
||||
/// 页面级的文案全部按 `Catalog` 走:中文目录出中文,英文目录出英文,**且不含 core 的中文业务串**。
|
||||
@@ -360,10 +362,7 @@ fn a_failed_install_stays_visible() {
|
||||
assert_eq!(model.stage_label, "Install failed");
|
||||
}
|
||||
|
||||
/// 演示数据自己也得守规矩(它是出图的基线)。
|
||||
///
|
||||
/// 抓得住:演示数据里混进中文字面量、或行数与分类对不上。
|
||||
/// 抓不住:图上好不好看。
|
||||
/// 演示数据自己也得守规矩(它是出图的基线):抓中文字面量混入 / 行数与分类对不上。
|
||||
#[test]
|
||||
fn the_demo_data_is_sane() {
|
||||
let catalog = Lang::En.catalog();
|
||||
|
||||
Reference in new issue
Block a user