M201 r2: 修视觉 r1 的两条 P2 + 代码复审的坏值提示 p2
视觉 r1(fix-then-merge):
- P2-1 分隔线贴字:downloaded 组的行间距从 0 改成 `Space::X3`(12dp)。实测
说明末行→分隔线 1–3px → **12–13px**、分隔线→下一标题 4–5px → **12–17px**
(同族页 9–18px;同一把尺子量演示回退卡 16–19px)。不动 `frame::divider` /
`demo_card`;`spacing` 只作用于子节点之间,卡片首行顶距与末行底距仍是 20。
- P2-2 孤字「效」:`with_note` 把「原值 X 已按出厂 N 生效」从说明段落里挪到
**独立一行**(`\n` 分隔,渲染器按行断)。浅/深/窄三张复验:无 <20px 窄行。
两种措辞(出厂 8 / 已按 1)一字未改,presenter 侧新增 `ends_with("\n原值 …")`
断言把「独占一行」钉住。
代码复审 p2(非整数坏值被静默丢掉):
- `raw_int`(`Value::as_i64`)→ `raw_text`:文件里显式写过的原值转**上屏文本**
(字符串取原文不带 serde 引号、数字/布尔 `to_string`、`null` 当没写)。
于是 `"auto"` / `8.5` / `true` / `-4` 都能进那句提示,不再「画着 8 却说不出
用户写的 auto 被忽略」。
- 新用例 `every_bad_value_shape_says_what_the_raw_value_was`:负整数 / 字符串 /
浮点 / 布尔 / null 五种形态。
验证:fmt --all --check / check -p unlucky-app-iced --all-targets /
test -p unlucky-app-iced(845+6) / test -p unlucky-presenter(316) /
test -p unlucky-i18n(36),全部 EXIT=0。
This commit is contained in:
1 parent
ab573838f3
commit
5dda9ac31d
3 files changed
+151
-9
No files matched your search
@@ -51,12 +51,12 @@ pub(super) fn group(env: &HostEnv) -> SettingGroupView {
|
||||
let concurrency = (tuning.max_concurrency as i64).to_string();
|
||||
let retry = i64::from(tuning.max_attempts_per_source).to_string();
|
||||
let concurrency_note = applied_note(
|
||||
raw_int(env, unlucky_core::download::config::KEY_CONCURRENCY),
|
||||
raw_text(env, unlucky_core::download::config::KEY_CONCURRENCY),
|
||||
tuning.max_concurrency as i64,
|
||||
DEFAULT_MAX_CONCURRENCY as i64,
|
||||
);
|
||||
let retry_note = applied_note(
|
||||
raw_int(env, unlucky_core::download::config::KEY_RETRY_LIMIT),
|
||||
raw_text(env, unlucky_core::download::config::KEY_RETRY_LIMIT),
|
||||
i64::from(tuning.max_attempts_per_source),
|
||||
i64::from(DEFAULT_MAX_ATTEMPTS_PER_SOURCE),
|
||||
);
|
||||
@@ -174,19 +174,40 @@ fn ladder(ladder: &[&str], current: &str) -> Vec<String> {
|
||||
options
|
||||
}
|
||||
|
||||
/// 文件里**显式写过**的原值(`None` = 文件没写这个键)。
|
||||
/// 文件里**显式写过**的原值,转成**上屏文本**(`None` = 文件没写这个键)。
|
||||
///
|
||||
/// 与 `super::int` 的区别:那个走 `effective()`(文件值 → schema 默认值),本函数只问文件本身。
|
||||
/// 「原值 X 已按出厂 N 生效」这句话的两个数必须现读(一个来自文件、一个来自 core 的翻译层),
|
||||
/// **不许**拿常量或请求参数冒充——那是 U1 明令禁止的假证据。
|
||||
fn raw_int(env: &HostEnv, key: &str) -> Option<i64> {
|
||||
env.store().doc().get(key).and_then(|value| value.as_i64())
|
||||
///
|
||||
/// ## 为什么返回字符串而不是 `i64`(r1 代码复审 p2)
|
||||
///
|
||||
/// 手改文件可以把一个整数键写成 `"auto"` / `8.5` / `true`:`document::load` 对坏值只记
|
||||
/// `LoadProblem`、原样留在 `values` 里,所以 `doc().get(key)` 真的能拿到 `Some(String("auto"))`。
|
||||
/// 早先这里用 `Value::as_i64`,非整数一律 `None` ⇒ 行上画着生效值 8,却**不告诉用户他写的
|
||||
/// `auto` 被忽略了**——「设置项说假话」的最后一个洞。改成上屏文本后,越界整数(`9999` / `-4`)、
|
||||
/// 非整数 JSON(`8.5`)、别的类型(`true`)、字符串(`auto`)**都能进那句提示**;
|
||||
/// 数字 `to_string()` 出来仍是 `9999`,所以旧断言与旧措辞一字未变。
|
||||
fn raw_text(env: &HostEnv, key: &str) -> Option<String> {
|
||||
use serde_json::Value;
|
||||
let store = env.store();
|
||||
match store.doc().get(key)? {
|
||||
// `null` 等于「没写」:`effective()` 也是这么当的(`filter(|value| !value.is_null())`)。
|
||||
Value::Null => None,
|
||||
// 字符串照原文上屏(不要 serde 的引号):用户写的是 `auto`,提示里就该是 `auto`。
|
||||
Value::String(text) => Some(text.clone()),
|
||||
other => Some(other.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
/// 文件原值 ≠ 生效值时的说明;`None` = 没什么可说的(没写过,或写的就是生效值)。
|
||||
fn applied_note(raw: Option<i64>, effective: i64, factory: i64) -> Option<String> {
|
||||
///
|
||||
/// `raw` 是**上屏文本**(见 [`raw_text`]),`effective` / `factory` 是 core 翻译层的结论。
|
||||
fn applied_note(raw: Option<String>, effective: i64, factory: i64) -> Option<String> {
|
||||
let raw = raw?;
|
||||
if raw == effective {
|
||||
// 比的是「上屏文本」:文件写 `8`、生效也是 8 ⇒ 没什么可说的(`8.0` 会照实提示,因为那是一次
|
||||
// 类型不一致的坏值)。
|
||||
if raw == effective.to_string() {
|
||||
return None;
|
||||
}
|
||||
Some(if effective == factory {
|
||||
@@ -197,9 +218,15 @@ fn applied_note(raw: Option<i64>, effective: i64, factory: i64) -> Option<String
|
||||
}
|
||||
|
||||
/// 说明 +(有差异时)那一句「原值 … 生效」。
|
||||
///
|
||||
/// **那句结论独占一行(M201 r1 视觉复审 P2-2)**:原先用「;」接在说明末尾,于是在设置页 424 列的
|
||||
/// 表单宽里,越界那句的最后一个「效」被挤到第三行、单字成行(浅色 1180 / 深色 1180 / 窄窗 880
|
||||
/// 三张都是同一处孤字,x 396–407)。那句话恰好只在本 mission 的主场景(手改坏值/越界)出现,
|
||||
/// 让「用户最需要看懂的那一句」排得最难看。改法**不动排版**(换行由渲染器按 `\n` 分行),
|
||||
/// 只把结论从段落里挪出来——两个数(文件原值 / 生效值)与出厂/非出厂的两种措辞一个字都没丢。
|
||||
fn with_note(base: String, note: Option<&str>) -> String {
|
||||
match note {
|
||||
Some(note) => format!("{base};{note}"),
|
||||
Some(note) => format!("{base}\n{note}"),
|
||||
None => base,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user