P2-1(一屏两句重复):
- 留面板那一句(就在被禁用的滑块旁边,正好回答「为什么拖不动」),措辞同时点名面板与玻璃
- 删 `SettingsAppearanceSoftwareRendererNote`(catalog 一条 + 金表一行,两边同时删)
- 删 `bg_image.rs` 的 `backend_note` 渲染块与 `State::backend_note()`;state.rs 391 → 382 行
P2-2(配色:preset 的机器码):
- `palette::level_key(code)` 把 `preset`/`wallpaper`/其余 映射到已有的三条档位 key,不新增平行词表
- `bg_image.rs` 用 `tr(PaletteLevel, {level})` 传译文,中文界面显示「配色:内置色卡」
- 补 `every_level_code_maps_to_its_own_sentence`:三个码值一一对应 + 三条译文互不相同
顺手(复审 L-1/L-2/L-4,全在本 scope 内):
- `appearance_texts` 加「渲染后不许残留 `{`」断言(参数名写错当场红)
- `section/mod.rs` 文档:取词口 t/tr、填充措辞、清掉孤立 `//!`、把「没有一句英文」改成
写明两处例外(`{reason}` 原文串、专名)
145 lines
4.9 KiB
Rust
145 lines
4.9 KiB
Rust
//! 外观分组第 ④ ⑤ ⑥ ⑦ ⑧ 段:**背景图**——开关、路径、诊断、填充档、暗化强度。
|
||
//!
|
||
//! 这五段挤在一起是因为它们读同一份 `bg_*` 状态,而且**诊断必须紧贴控件**(复审 r1 P2-3:
|
||
//! 读盘失败 / CPU 降级 / 配色回落这些提示落在折叠线以下等于没提示)。
|
||
|
||
use iced::widget::column;
|
||
use iced::{Element, Length};
|
||
|
||
use unlucky_design::color::Role;
|
||
use unlucky_design::spacing::Space;
|
||
use unlucky_i18n::catalog::Key;
|
||
use unlucky_i18n::Lang;
|
||
use unlucky_presenter::prefs::BgFill;
|
||
|
||
use crate::app::components::inputs::{slider, text_field, Field, Slider};
|
||
use crate::pages::Message;
|
||
use crate::theme::Ui;
|
||
|
||
use super::super::background::{self, BG_DIM_MAX};
|
||
use super::super::palette;
|
||
use super::super::state::State;
|
||
use super::super::Change;
|
||
use super::{choice, choice_row, fixed2, label, note_line, slider_row, t, tr, tr_note};
|
||
|
||
/// 把 ④ 开关、⑤ 路径、⑥ 诊断、⑦ 填充、⑧ 暗化按视觉顺序推进 `rows`。
|
||
pub(super) fn push<'a>(
|
||
ui: &'a Ui,
|
||
state: &'a State,
|
||
lang: Lang,
|
||
rows: &mut Vec<Element<'a, Message>>,
|
||
) {
|
||
// ④ 背景图开关
|
||
rows.push(choice_row(
|
||
ui,
|
||
t(Key::SettingsAppearanceBackgroundImage, lang),
|
||
vec![
|
||
choice(
|
||
ui,
|
||
t(Key::SettingsAppearanceOff, lang),
|
||
!state.bg_enabled,
|
||
Change::BgEnabled(false),
|
||
),
|
||
choice(
|
||
ui,
|
||
t(Key::SettingsAppearanceOn, lang),
|
||
state.bg_enabled,
|
||
Change::BgEnabled(true),
|
||
),
|
||
],
|
||
));
|
||
|
||
// ⑤ 路径(文本框:受控,输入即生效)
|
||
let path_field: Element<'a, Message> = text_field(
|
||
ui,
|
||
Field::new(&state.bg_path)
|
||
.label(t(Key::SettingsAppearanceImagePath, lang))
|
||
.placeholder("D:/Pictures/background.png"),
|
||
|value| Message::Appearance(Change::BgImage(value)),
|
||
);
|
||
rows.push(
|
||
column![
|
||
label(ui, t(Key::SettingsAppearanceImagePath, lang)),
|
||
path_field
|
||
]
|
||
.spacing(ui.space(Space::X1))
|
||
.width(Length::Fill)
|
||
.into(),
|
||
);
|
||
|
||
// ⑥ 诊断(读盘失败 / 配色回落)——**不许静默**,且必须在**首屏可见处**
|
||
// (复审 r1 P2-3:文案落在折叠线以下等于没提示)。位置就在背景图那两行的紧下方。
|
||
//
|
||
// CPU 档的「面板/玻璃被强制」那句**不在这里**:它是张卡级状态,挂在被禁用的面板滑块旁边
|
||
// (`panel.rs` 的 `PanelOpacityForcedHint`),一屏只出现一次(M180 复审 P2-1)。
|
||
for note in state.diagnostics() {
|
||
let text = tr_note(lang, note);
|
||
rows.push(note_line(ui, &text, ui.color(Role::Error)));
|
||
}
|
||
if let Some(note) = state
|
||
.image()
|
||
.and_then(|image| background::small_tile_note(image, state.bg_fill))
|
||
{
|
||
let text = tr_note(lang, ¬e);
|
||
rows.push(note_line(ui, &text, ui.color(Role::OnSurfaceVariant)));
|
||
}
|
||
if let Some(key) = state.palette_note() {
|
||
rows.push(note_line(
|
||
ui,
|
||
t(key, lang),
|
||
ui.color(Role::OnSurfaceVariant),
|
||
));
|
||
}
|
||
// 生效的配色层级:显示的是**回落之后真正生效**的那一级(与底部「配色来源」里用户选的那一档
|
||
// 不一定相同)。码值 → 已有的三条档位 key(不新增平行词表),所以中文界面也读得懂。
|
||
let level = tr(
|
||
lang,
|
||
Key::SettingsAppearancePaletteLevel,
|
||
&[("level", t(palette::level_key(state.palette_level()), lang))],
|
||
);
|
||
rows.push(note_line(ui, &level, ui.color(Role::OnSurfaceVariant)));
|
||
|
||
// ⑦ 填充
|
||
rows.push(choice_row(
|
||
ui,
|
||
t(Key::SettingsAppearanceBgFill, lang),
|
||
vec![
|
||
choice(
|
||
ui,
|
||
t(Key::SettingsAppearanceBgFillCover, lang),
|
||
state.bg_fill == BgFill::Cover,
|
||
Change::BgFill(BgFill::Cover),
|
||
),
|
||
choice(
|
||
ui,
|
||
t(Key::SettingsAppearanceBgFillContain, lang),
|
||
state.bg_fill == BgFill::Contain,
|
||
Change::BgFill(BgFill::Contain),
|
||
),
|
||
choice(
|
||
ui,
|
||
t(Key::SettingsAppearanceBgFillTile, lang),
|
||
state.bg_fill == BgFill::Tile,
|
||
Change::BgFill(BgFill::Tile),
|
||
),
|
||
],
|
||
));
|
||
|
||
// ⑧ 暗化
|
||
rows.push(slider_row(
|
||
ui,
|
||
t(Key::SettingsAppearanceBgDim, lang),
|
||
format!("{:.0}%", state.bg_dim * 100.0),
|
||
tr(
|
||
lang,
|
||
Key::SettingsAppearanceBgDimHint,
|
||
&[("max", &fixed2(BG_DIM_MAX))],
|
||
),
|
||
state.bg_dim > 0.0,
|
||
slider(
|
||
Slider::new(ui, state.bg_dim / BG_DIM_MAX)
|
||
.on_change(|fraction| Message::Appearance(Change::BgDim(fraction * BG_DIM_MAX))),
|
||
),
|
||
));
|
||
}
|