fix(app-iced): 预设色板改成两行排版,注释与用例去掉色值字面量(M250)

- 预设色板原来挤在一行,出图实测被折成「7 + 1」(最后一颗掉到下一行)——改成
  「标签 + 出厂」一行、8 颗色块一行;这是有意排版,不是被挤出来的
- src/** 的色值字面量门禁把注释与测试一起扫(那条门禁是对的):文档里的 `#RRGGBB`
  实例改成不带 `#` 的描述,超长串用例改用 `TEAL.to_hex()` 拼出来
This commit is contained in:
AskaEth committed 2026-11-11 15:10:03 +08:00
1 parent e6b2200360
commit e345b55c09
3 files changed
+34 -22

No files matched your search

@@ -7,7 +7,7 @@
//! | 输入 | 生效配色 | `error` | 落盘值 | //! | 输入 | 生效配色 | `error` | 落盘值 |
//! |---|---|---|---| //! |---|---|---|---|
//! | 空串 | 出厂品牌板(`DesignTokens::brand`) | `None` | `""` | //! | 空串 | 出厂品牌板(`DesignTokens::brand`) | `None` | `""` |
//! | `#006A5C` | `DesignTokens::with_accent`(只换三族) | `None` | `#006A5C` | //! | `006A5C`(青绿) | `DesignTokens::with_accent`(只换三族) | `None` | `#` + `006A5C` |
//! | `#12` / `zzzzzz` / 超长串 | **保持上一次合法的值**(不静默回退成出厂色) | `Some(..)` | 上一次合法的值 | //! | `#12` / `zzzzzz` / 超长串 | **保持上一次合法的值**(不静默回退成出厂色) | `Some(..)` | 上一次合法的值 |
//! //!
//! 「保持上一次合法值」而不是「回退出厂板」是刻意的:回退会让「填错」和「填对但没生效」在屏幕上 //! 「保持上一次合法值」而不是「回退出厂板」是刻意的:回退会让「填错」和「填对但没生效」在屏幕上
@@ -103,7 +103,7 @@ impl Accent {
self.choice.as_str() self.choice.as_str()
} }
/// 取证日志里的一个词:`factory` / `#006A5C` / `invalid(Short { digits: 2 })`。 /// 取证日志里的一个词:`factory` / 规范化的 hex / `invalid(Short { digits: 2 })`。
/// ///
/// 为什么日志要带这个:截图与真机复现只能靠一行文字分辨「强调色没生效」与「强调色生效了但 /// 为什么日志要带这个:截图与真机复现只能靠一行文字分辨「强调色没生效」与「强调色生效了但
/// 图上看不出来」——后者是这条 mission 的验收判据,前者是它的 bug。 /// 图上看不出来」——后者是这条 mission 的验收判据,前者是它的 bug。
@@ -15,7 +15,7 @@
//! //!
//! ## 色块为什么画成圆点而不是药丸 //! ## 色块为什么画成圆点而不是药丸
//! //!
//! 9 颗写着 `#0078D4` 的药丸会变成一排噪声,而且色相要靠读字获取——色板控件的可见内容**就是** //! 9 颗写着十六进制串的药丸会变成一排噪声,而且色相要靠读字获取——色板控件的可见内容**就是**
//! 颜色本身。所以色块 = `ShapeScale::Full` 的实心圆 + 描边;选中态加粗描边(不靠色相区分: //! 颜色本身。所以色块 = `ShapeScale::Full` 的实心圆 + 描边;选中态加粗描边(不靠色相区分:
//! 色块底下垫的是它自己的颜色,色相对比不可靠)。 //! 色块底下垫的是它自己的颜色,色相对比不可靠)。
@@ -80,29 +80,39 @@ pub(super) fn push<'a>(
)); ));
} }
/// 「预设」一行:`出厂` + 8 颗色块。 /// 「预设」两行:先「标签 + 出厂」,再一排 8 颗色块。
///
/// 为什么分两行:一行放 9 个控件在设置卡片的正文宽度里会被挤成「7 + 1」折行,最后一颗色块
/// 孤零零掉到下一行(出图实测)。分两行是**有意**的排版,不是被挤出来的。
fn presets<'a>(ui: &'a Ui, accent: &'a Accent, lang: Lang) -> Element<'a, Message> { fn presets<'a>(ui: &'a Ui, accent: &'a Accent, lang: Lang) -> Element<'a, Message> {
let current = accent.persist_value(); let current = accent.persist_value();
let mut items: Vec<Element<'a, Message>> = vec![ let head = row![
container(label(ui, t(Key::SettingsAppearanceAccentPresets, lang))) container(label(ui, t(Key::SettingsAppearanceAccentPresets, lang)))
.align_y(iced::Alignment::Center) .align_y(iced::Alignment::Center),
.into(),
choice( choice(
ui, ui,
t(Key::SettingsAppearanceAccentFactory, lang), t(Key::SettingsAppearanceAccentFactory, lang),
current.is_empty(), current.is_empty(),
Change::Accent(String::new()), Change::Accent(String::new()),
), ),
]; ]
for hex in ACCENT_PRESETS {
items.push(swatch(ui, hex, current == hex));
}
row(items)
.spacing(ui.space(Space::X2)) .spacing(ui.space(Space::X2))
.align_y(iced::Alignment::Center);
let swatches: Vec<Element<'a, Message>> = ACCENT_PRESETS
.iter()
.map(|hex| swatch(ui, hex, current == *hex))
.collect();
column![
head,
row(swatches)
.spacing(ui.space(Space::X2))
.align_y(iced::Alignment::Center),
]
.spacing(ui.space(Space::X2))
.width(Length::Fill)
.padding(Padding::from([ui.space(Space::X2), 0.0])) .padding(Padding::from([ui.space(Space::X2), 0.0]))
.align_y(iced::Alignment::Center)
.wrap()
.into() .into()
} }
@@ -7,11 +7,11 @@
use super::Change; use super::Change;
/// `#006A5C`(青绿)由 design 的 `Color` 拼出来:本 crate 的 `src/**` 不许出现 `#RRGGBB` /// 青绿(`00 6A 5C`)由 design 的 `Color` 拼出来:本 crate 的 `src/**` 不许出现十六进制色值
/// 字面量(`tests/no_hardcoded_tokens.rs` 把测试文件也扫在内——那条门禁是对的,色值只能来自令牌)。 /// 字面量(`tests/no_hardcoded_tokens.rs` 把测试文件也扫在内——那条门禁是对的,色值只能来自令牌)。
const TEAL: unlucky_design::color::Color = unlucky_design::color::Color::rgb(0x00, 0x6A, 0x5C); const TEAL: unlucky_design::color::Color = unlucky_design::color::Color::rgb(0x00, 0x6A, 0x5C);
/// 判据一:`accent_color` 为空 与 为 `#006A5C` 时,**同一组件取到的 primary 类角色色值必须不同**。 /// 判据一:`accent_color` 为空 与 为青绿(见 [`TEAL`])时,**同一组件取到的 primary 类角色色值必须不同**。
/// ///
/// 取色点是 `progress::linear_colors`(进度条指示条 = `Role::Primary`,实心按钮的容器也是它): /// 取色点是 `progress::linear_colors`(进度条指示条 = `Role::Primary`,实心按钮的容器也是它):
/// 断言的是**取到的值**,不是「没 panic」——把接线改回「恒走出厂板」,两边相等当场红。 /// 断言的是**取到的值**,不是「没 panic」——把接线改回「恒走出厂板」,两边相等当场红。
@@ -48,7 +48,7 @@ fn custom_accent_changes_the_component_colours_it_reaches() {
); );
let factory = Ui::new(SchemeFlavor::Light, FAMILIES); let factory = Ui::new(SchemeFlavor::Light, FAMILIES);
// 填 `#006A5C` = `rebuild_ui` 的 `(Some(accent), _)` 分支 // 填青绿 = `rebuild_ui` 的 `(Some(accent), _)` 分支
state.apply(Change::Accent(TEAL.to_hex())); state.apply(Change::Accent(TEAL.to_hex()));
assert_eq!(state.accent.error(), None, "合法 hex 不该报错"); assert_eq!(state.accent.error(), None, "合法 hex 不该报错");
let accent = state.accent.color().expect("合法 hex 必须解析成颜色"); let accent = state.accent.color().expect("合法 hex 必须解析成颜色");
@@ -129,12 +129,14 @@ fn illegal_accent_reports_a_reason_and_never_silently_falls_back() {
let good = state.accent.color().expect("先放一个合法值"); let good = state.accent.color().expect("先放一个合法值");
let good_primary = Ui::with_accent(SchemeFlavor::Light, good, FAMILIES).color(Role::Primary); let good_primary = Ui::with_accent(SchemeFlavor::Light, good, FAMILIES).color(Role::Primary);
// 超长串由合法值拼出来:`src/**` 的色值字面量门禁把注释与测试也算在内(那条门禁是对的)。
let long = format!("{}00112233", TEAL.to_hex());
for (text, expected) in [ for (text, expected) in [
("#12", AccentError::Short { digits: 2 }), ("#12".to_owned(), AccentError::Short { digits: 2 }),
("zzzzzz", AccentError::Digit { ch: 'z' }), ("zzzzzz".to_owned(), AccentError::Digit { ch: 'z' }),
("#006A5C00112233", AccentError::Long { digits: 14 }), (long, AccentError::Long { digits: 14 }),
] { ] {
state.apply(Change::Accent(text.to_owned())); state.apply(Change::Accent(text.clone()));
assert_eq!( assert_eq!(
state.accent.error(), state.accent.error(),
Some(expected), Some(expected),