feat(app-iced): Ink Cat / Silver Cat 换肤 —— 双色板默认 + 规格卡组件几何(M229)
产品出厂外观从 tone 派生的 `Scheme::baseline` 切到品牌色板:深色 = Ink(淡绿)、 浅色 = Silver(钢蓝),D38 取色链(背景图 / 壁纸)仍然优先,取色失败回落到色板。 主题三档接进设置页「通用 → 主题」:Ink / Silver / 跟随系统(落盘仍是 `appearance.theme_mode` 的 dark / light / auto,不新增配置键)。 组件几何按规格卡对齐(M228 的 `inkcat` 登记项逐条落地): - 卡片圆角 12 → 16;实例元信息卡改用新的 ELEVATED CARD(无描边、SurfaceContainer 底、内距 24、上标注 11/600) - Snackbar 48/4 → 52/16(双行 72) - Checkbox 20/rx2 → 18/rx4;Radio 20 → 18 Ø(内点仍 10) - 按钮加 XS~XL 五档(产品仍只用 S=40),内距改走 ControlSize::pad_x - 新增 FAB 四态(40/56/80/160×56)与图标按钮第四式 outlined - 语言与主题两行 chips 统一成规格卡 chip(32 高 / rx8) `theme.rs` 原本正好 400 行,先把单测纯搬移到 `theme/tests.rs` 再加色板字段; `app/tests.rs`、`settings/general.rs` 同样按纯搬移拆分守 400 行硬线。 验证:cargo fmt --all --check、cargo check -p unlucky-app-iced --all-targets、 cargo test --workspace(除 clippy 前的一轮 flake,见报告)、cargo clippy --workspace --all-targets -- -D warnings、全仓 400 行扫描。视觉矩阵 42 张在 DevDocs/artifacts/m229/(gitignored,不进提交)。
This commit is contained in:
1 parent
a06b7ff4ec
commit
db541c820e
44 files changed
+1439
-300
No files matched your search
@@ -29,9 +29,11 @@
|
||||
//! 3. **文案全部走 catalog**([`Key`]),三档选项名跟着界面语言走(见 `catalog/general.rs`
|
||||
//! 的头注释:为什么不写语言自称)。
|
||||
//!
|
||||
//! ## 其余三行仍只读
|
||||
//! ## 主题行已接真控件(M229),另两行仍只读
|
||||
//!
|
||||
//! 主题 / 启动页 / 关闭按钮还没有后端(`pages::Action` 里是占位动作),所以它们是**只读行**;
|
||||
//! 主题三档(Ink / Silver / 跟随系统)在 M229 接成真控件:点一下换色板 + 落盘
|
||||
//! `appearance.theme_mode`(实现在 `general/theme.rs`,消息是 `pages::Message::Theme`)。
|
||||
//! 启动页 / 关闭按钮还没有后端(`pages::Action` 里是占位动作),仍是**只读行**;
|
||||
//! 但标签与取值已经进 catalog,中文界面下不会再冒出英文。
|
||||
//!
|
||||
//! 分组元数据只有一份(这里的 [`GROUP`]):`settings/mod.rs` 的 `GROUPS` 直接引用它。
|
||||
@@ -41,7 +43,6 @@ use iced::{Alignment, Background, Border, Element, Length, Padding, Shadow, Them
|
||||
|
||||
use unlucky_design::color::{Role, StateLayer};
|
||||
use unlucky_design::icons::IconKind;
|
||||
use unlucky_design::shape::ShapeScale;
|
||||
use unlucky_design::spacing::Space;
|
||||
use unlucky_design::typography::TypeRole;
|
||||
use unlucky_i18n::catalog::Key;
|
||||
@@ -52,16 +53,18 @@ use crate::pages::{frame, Language, Message};
|
||||
use crate::theme::Ui;
|
||||
|
||||
use super::frame::{card, divider};
|
||||
use super::Group;
|
||||
use super::{Group, States};
|
||||
|
||||
mod theme;
|
||||
|
||||
/// General 分组(左列名固定英文:左列是**导航**,与导航轨同源,不进 catalog)。
|
||||
pub(super) const GROUP: Group = Group {
|
||||
name: "General",
|
||||
icon: IconKind::Settings,
|
||||
// 只给 harness(`pages_demo` 走 `appearance: None` 时)用的演示行:产品路径走 [`body`]。
|
||||
// 语言那一行**不在**这里——它的值是要跟着语言变的,写死在静态表里就是用户看到的那条假值。
|
||||
// 语言与主题那两行**不在**这里——它们的值跟着语言/档位变,写死在静态表里就是用户看到的假值
|
||||
// (语言 M106 移出、主题 M229 移出)。
|
||||
rows: &[
|
||||
("Theme", "Follow system"),
|
||||
("Startup page", "Instances"),
|
||||
("Close button", "Exit to tray"),
|
||||
],
|
||||
@@ -69,7 +72,7 @@ pub(super) const GROUP: Group = Group {
|
||||
};
|
||||
|
||||
/// 这一组的正文(**产品路径**)。
|
||||
pub(super) fn body<'a>(ui: &'a Ui, language: Language) -> Element<'a, Message> {
|
||||
pub(super) fn body<'a>(ui: &'a Ui, states: States<'a>, language: Language) -> Element<'a, Message> {
|
||||
let catalog = language.effective.catalog();
|
||||
let mut stacked = column![].spacing(0.0).width(Length::Fill);
|
||||
stacked = stacked.push(language_row(ui, language));
|
||||
@@ -78,14 +81,22 @@ pub(super) fn body<'a>(ui: &'a Ui, language: Language) -> Element<'a, Message> {
|
||||
stacked = stacked.push(divider(ui));
|
||||
stacked = stacked.push(font_row(ui, language));
|
||||
|
||||
// M188:日志文件夹(路径 + 打开 + 复制路径)。放在「主题/启动页」之前——用户投诉
|
||||
// M229:主题行接真控件(Ink / Silver / 跟随系统)。档位住在设置组的自有状态里
|
||||
// (`language_appearance::State::theme`),与语言行同一个排版:标题 + 三枚互斥 chip + 一句说明。
|
||||
stacked = stacked.push(divider(ui));
|
||||
stacked = stacked.push(theme::view(
|
||||
ui,
|
||||
&catalog,
|
||||
states.groups.language_appearance.theme,
|
||||
));
|
||||
|
||||
// M188:日志文件夹(路径 + 打开 + 复制路径)。放在「启动页/关闭按钮」之前——用户投诉
|
||||
// 「找不到崩溃日志」要的答案,不该埋在只读行后面。
|
||||
stacked = stacked.push(divider(ui));
|
||||
stacked = stacked.push(super::logs_row::folder_row(ui, &catalog));
|
||||
|
||||
// 主题 / 启动页 / 关闭按钮:还没有后端,只读;文案已经进 catalog。
|
||||
// 启动页 / 关闭按钮:还没有后端,只读;文案已经进 catalog。
|
||||
for (label, value) in [
|
||||
(Key::SettingsTheme, Key::SettingsThemeFollowSystem),
|
||||
(Key::SettingsStartupPage, Key::SettingsStartupInstances),
|
||||
(Key::SettingsCloseButton, Key::SettingsCloseToTray),
|
||||
] {
|
||||
@@ -290,14 +301,20 @@ fn setting_row<'a>(ui: &'a Ui, label: &'a str, value: &'a str) -> Element<'a, Me
|
||||
|
||||
/// 一个互斥按钮(选中态 `SecondaryContainer`,未选中透明 + `OnSurfaceVariant`)。
|
||||
///
|
||||
/// 与 `pages/appearance/section/mod.rs` 的 `choice` 同款,但文案来自 catalog(那份是英文基线)。
|
||||
/// 与 `pages/appearance/section/mod.rs` 的 `choice` 同款几何,但文案来自 catalog(那份是英文基线)。
|
||||
///
|
||||
/// **几何(M229)**:取规格卡的 chip(高 32、圆角 8、内距 16、未选中 1px `OutlineVariant`),
|
||||
/// 与同屏的主题三档 chips 完全同源——两行都是「并排的互斥筛选」,长得不一样会让读者以为是
|
||||
/// 两种控件(M229 第一版就是这样:语言 40 高药丸、主题 32 高方角,出图一眼就不齐)。
|
||||
fn chip<'a>(ui: &'a Ui, text: &'a str, selected: bool, choice: LangChoice) -> Element<'a, Message> {
|
||||
let height = ui.metrics().control_height;
|
||||
let box_ = unlucky_design::inkcat::metrics::CHIP;
|
||||
let height = box_.height;
|
||||
let content_color = if selected {
|
||||
ui.color(Role::OnSecondaryContainer)
|
||||
} else {
|
||||
ui.color(Role::OnSurfaceVariant)
|
||||
};
|
||||
let border_color = ui.color(Role::OutlineVariant);
|
||||
|
||||
button(
|
||||
container(frame::text_role(
|
||||
@@ -310,7 +327,10 @@ fn chip<'a>(ui: &'a Ui, text: &'a str, selected: bool, choice: LangChoice) -> El
|
||||
.align_y(Alignment::Center),
|
||||
)
|
||||
.height(height)
|
||||
.padding(Padding::from([0.0, ui.space(Space::X3)]))
|
||||
.padding(Padding::from([
|
||||
0.0,
|
||||
unlucky_design::inkcat::metrics::CHIP_PAD_X,
|
||||
]))
|
||||
.style(move |_theme: &IcedTheme, status| {
|
||||
let background = if selected {
|
||||
Some(Background::Color(ui.color(Role::SecondaryContainer)))
|
||||
@@ -328,8 +348,13 @@ fn chip<'a>(ui: &'a Ui, text: &'a str, selected: bool, choice: LangChoice) -> El
|
||||
background,
|
||||
text_color: content_color,
|
||||
border: Border {
|
||||
radius: ui.radius(ShapeScale::Full, height),
|
||||
..Border::default()
|
||||
color: border_color,
|
||||
width: if selected {
|
||||
0.0
|
||||
} else {
|
||||
crate::theme::STROKE_PX
|
||||
},
|
||||
radius: ui.radius(box_.shape, height),
|
||||
},
|
||||
shadow: Shadow::default(),
|
||||
snap: true,
|
||||
|
||||
Reference in new issue
Block a user