fix(app-iced): M157 r2 详情列加滚动区 + 启动参数卡对齐信息卡(D30 复审)
- 详情列(含卡片与动作行)套 scrollable:1180×1000 下被裁的内容可达、滚动条与左列同一套几何;右侧 X2 内缩,卡片描边不再被滚动条压住 - 启动参数卡改用 frame::card(card_padding 21 + OutlinedCard 描边),标题 LabelMedium 不加粗——与相邻信息卡同款 - 段间距 X3→X2,卡片不再比内容长 - 演示夹具补 Game arguments(--fullscreen) - presenter host 单测临时目录加序号(同一进程并行用例互删导致 flake)
This commit is contained in:
1 parent
e2021645d7
commit
c76a1437e6
5 files changed
+56
-23
No files matched your search
@@ -103,7 +103,7 @@ fn demo_view() -> LaunchArgsView {
|
|||||||
LaunchArgsView {
|
LaunchArgsView {
|
||||||
instance_id: DEMO[SELECTED].name.to_string(),
|
instance_id: DEMO[SELECTED].name.to_string(),
|
||||||
jvm_args: "-XX:+UseG1GC".to_string(),
|
jvm_args: "-XX:+UseG1GC".to_string(),
|
||||||
game_args: String::new(),
|
game_args: "--fullscreen".to_string(),
|
||||||
memory_mb: (!gated).then_some(4096),
|
memory_mb: (!gated).then_some(4096),
|
||||||
memory_effective_mb: if gated { 2048 } else { 4096 },
|
memory_effective_mb: if gated { 2048 } else { 4096 },
|
||||||
java_path: String::new(),
|
java_path: String::new(),
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
//! → 一条分隔线 → 正文段 / 运行状态行 → 动作行(Duplicate / Open folder / Delete)。
|
//! → 一条分隔线 → 正文段 / 运行状态行 → 动作行(Duplicate / Open folder / Delete)。
|
||||||
//! 窄窗(<840)时列表退成上一屏,本文件只画详情 + 一个「返回」按钮。
|
//! 窄窗(<840)时列表退成上一屏,本文件只画详情 + 一个「返回」按钮。
|
||||||
|
|
||||||
use iced::widget::{column, container, row};
|
use iced::widget::{column, container, row, scrollable};
|
||||||
use iced::{Alignment, Element, Length};
|
use iced::{Alignment, Element, Length, Padding};
|
||||||
|
|
||||||
use unlucky_design::color::Role;
|
use unlucky_design::color::Role;
|
||||||
use unlucky_design::spacing::Space;
|
use unlucky_design::spacing::Space;
|
||||||
@@ -48,8 +48,13 @@ pub(super) fn detail_column<'a>(
|
|||||||
// M157:启动参数区在正文段之后、动作行之前(详情列 424px 内,卡片式)。
|
// M157:启动参数区在正文段之后、动作行之前(详情列 424px 内,卡片式)。
|
||||||
body = body.push(super::launch_args::section(ui, &detail.launch, form, texts));
|
body = body.push(super::launch_args::section(ui, &detail.launch, form, texts));
|
||||||
|
|
||||||
// 页头 + 元信息网格 + **一条**分隔线以下才是正文与操作区(M84 那两条线是占位时期的排版残留)
|
// 页头 + 元信息网格 + **一条**分隔线以下才是正文与操作区(M84 那两条线是占位时期的排版残留)。
|
||||||
frame::left_aligned(metrics.column, body.push(action_row(ui, forced, texts)))
|
//
|
||||||
|
// M157 r2(D30 复审):详情列的内容(正文段 + 启动参数卡 + 动作行)在 1180×1000 下**超出一屏**,
|
||||||
|
// 而这里原来没有滚动区 ⇒ Max memory 以下的控件被静默裁掉、够不着。现在整列套一个滚动区
|
||||||
|
// (与左列列表同一套滚动条样式与宽度),被裁内容可达;滚动条是唯一入口,没有第二份状态。
|
||||||
|
let content = body.push(action_row(ui, forced, texts));
|
||||||
|
frame::left_aligned(metrics.column, scroller(ui, content))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn narrow_detail<'a>(
|
pub(super) fn narrow_detail<'a>(
|
||||||
@@ -89,7 +94,30 @@ pub(super) fn narrow_detail<'a>(
|
|||||||
ui.color(Role::OnSurfaceVariant),
|
ui.color(Role::OnSurfaceVariant),
|
||||||
));
|
));
|
||||||
|
|
||||||
frame::body(metrics, body.push(action_row(ui, forced, texts)))
|
frame::body(
|
||||||
|
metrics,
|
||||||
|
scroller(ui, body.push(action_row(ui, forced, texts))),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 详情列的滚动区(M157 r2):与左列列表同一套滚动条几何(宽 6 / 内缩 2 / 同一 `style`)。
|
||||||
|
///
|
||||||
|
/// 右侧留 `Space::X2` 内缩:滚动条是**覆盖**在内容上的,不留这条缝时卡片的 1dp 描边会被
|
||||||
|
/// 滚动条压住(D30 复审里「卡片右边框缺一截」就是它)。
|
||||||
|
fn scroller<'a>(ui: &'a Ui, content: impl Into<Element<'a, Message>>) -> Element<'a, Message> {
|
||||||
|
let content = container(content)
|
||||||
|
.width(Length::Fill)
|
||||||
|
.padding(Padding::default().right(ui.space(Space::X2)));
|
||||||
|
scrollable(content)
|
||||||
|
.direction(scrollable::Direction::Vertical(
|
||||||
|
scrollable::Scrollbar::new()
|
||||||
|
.width(frame::SCROLLBAR_WIDTH)
|
||||||
|
.scroller_width(frame::SCROLLBAR_WIDTH)
|
||||||
|
.margin(frame::SCROLLBAR_MARGIN),
|
||||||
|
))
|
||||||
|
.height(Length::Fill)
|
||||||
|
.style(frame::scroll_style(ui))
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 正文段(演示数据才有)与运行状态行(真数据才有)——两者都是可选的,顺序固定。
|
/// 正文段(演示数据才有)与运行状态行(真数据才有)——两者都是可选的,顺序固定。
|
||||||
|
|||||||
@@ -15,12 +15,10 @@
|
|||||||
//!
|
//!
|
||||||
//! 文案全走 [`Texts`](守门见 `instances/tests/i18n.rs` 的白名单与死 key 扫描)。
|
//! 文案全走 [`Texts`](守门见 `instances/tests/i18n.rs` 的白名单与死 key 扫描)。
|
||||||
|
|
||||||
use iced::widget::{column, container, row};
|
use iced::widget::{column, row};
|
||||||
use iced::{Background, Element, Length};
|
use iced::{Element, Length};
|
||||||
|
|
||||||
use unlucky_design::color::Role;
|
use unlucky_design::color::Role;
|
||||||
use unlucky_design::elevation::MaterialLayer;
|
|
||||||
use unlucky_design::shape::ShapeScale;
|
|
||||||
use unlucky_design::spacing::Space;
|
use unlucky_design::spacing::Space;
|
||||||
use unlucky_design::typography::TypeRole;
|
use unlucky_design::typography::TypeRole;
|
||||||
|
|
||||||
@@ -47,8 +45,10 @@ pub(super) fn section<'a>(
|
|||||||
form: &'a LaunchForm,
|
form: &'a LaunchForm,
|
||||||
texts: Texts,
|
texts: Texts,
|
||||||
) -> Element<'a, PageMessage> {
|
) -> Element<'a, PageMessage> {
|
||||||
|
// 段间距 X2(8dp):卡内 5 个字段 + 三态 + 动作行在 424 宽下已经很长,
|
||||||
|
// 用 X3 会让详情列更长一屏;行内间距仍是 X1(4dp),读起来不挤。
|
||||||
let mut body = column![frame_title(ui, texts.launch_title())]
|
let mut body = column![frame_title(ui, texts.launch_title())]
|
||||||
.spacing(ui.space(Space::X3))
|
.spacing(ui.space(Space::X2))
|
||||||
.width(Length::Fill);
|
.width(Length::Fill);
|
||||||
|
|
||||||
body = body.push(args_field(
|
body = body.push(args_field(
|
||||||
@@ -94,22 +94,17 @@ pub(super) fn section<'a>(
|
|||||||
body = body.push(backend_row(ui, facts, form, texts));
|
body = body.push(backend_row(ui, facts, form, texts));
|
||||||
body = body.push(actions_row(ui, texts));
|
body = body.push(actions_row(ui, texts));
|
||||||
|
|
||||||
container(body)
|
// 与相邻信息卡**同一套**卡壳(`frame::card`:`card_padding` 21dp + OutlinedCard 的圆角/描边)。
|
||||||
.width(Length::Fill)
|
super::super::frame::card(ui, body)
|
||||||
.padding(ui.space(Space::X3))
|
|
||||||
.style(move |_theme| container::Style {
|
|
||||||
background: Some(Background::Color(ui.layer(MaterialLayer::Card))),
|
|
||||||
border: ui.outlined(ShapeScale::Medium),
|
|
||||||
..container::Style::default()
|
|
||||||
})
|
|
||||||
.into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 卡片标题:**与信息卡的标签同款**(`LabelMedium` 不加粗、`OnSurfaceVariant`),
|
||||||
|
/// 复审 ③⑤ 抓的就是这里(原来用了 `emphasized = true`,比同屏其它标签重一档)。
|
||||||
fn frame_title<'a>(ui: &'a Ui, title: &'a str) -> Element<'a, PageMessage> {
|
fn frame_title<'a>(ui: &'a Ui, title: &'a str) -> Element<'a, PageMessage> {
|
||||||
super::super::frame::text_role(
|
super::super::frame::text_role(
|
||||||
ui,
|
ui,
|
||||||
TypeRole::LabelMedium,
|
TypeRole::LabelMedium,
|
||||||
true,
|
false,
|
||||||
title,
|
title,
|
||||||
ui.color(Role::OnSurfaceVariant),
|
ui.color(Role::OnSurfaceVariant),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ const PAGE_SOURCES: [(&str, &str); 6] = [
|
|||||||
/// | `isolated` / `shared` | core 的隔离档位**稳定 id**(`IsolationMode::as_str`),`isolation()` 只认这两档,其余原样上屏 |
|
/// | `isolated` / `shared` | core 的隔离档位**稳定 id**(`IsolationMode::as_str`),`isolation()` 只认这两档,其余原样上屏 |
|
||||||
/// | `pid` / `reason` | `Catalog::render` 的**占位符名**(与 catalog 里的 `{pid}` / `{reason}` 对应) |
|
/// | `pid` / `reason` | `Catalog::render` 的**占位符名**(与 catalog 里的 `{pid}` / `{reason}` 对应) |
|
||||||
/// | `Instances` | `Texts::keys()` 的**族名前缀**(`Key::ALL` 的过滤条件,不是文案) |
|
/// | `Instances` | `Texts::keys()` 的**族名前缀**(`Key::ALL` 的过滤条件,不是文案) |
|
||||||
const ALLOWED_LITERALS: [&str; 17] = [
|
const ALLOWED_LITERALS: [&str; 18] = [
|
||||||
"{date} {time} UTC",
|
"{date} {time} UTC",
|
||||||
"isolated",
|
"isolated",
|
||||||
"shared",
|
"shared",
|
||||||
@@ -79,6 +79,8 @@ const ALLOWED_LITERALS: [&str; 17] = [
|
|||||||
// M157:`instances/demo.rs` 的**出图夹具**(用户数据的形状,不是界面文案):
|
// M157:`instances/demo.rs` 的**出图夹具**(用户数据的形状,不是界面文案):
|
||||||
// 一个示例 JVM 参数、两个示例 MC 版本、一个示例 Java 路径,以及夹具开关的环境变量名与取值。
|
// 一个示例 JVM 参数、两个示例 MC 版本、一个示例 Java 路径,以及夹具开关的环境变量名与取值。
|
||||||
"-XX:+UseG1GC",
|
"-XX:+UseG1GC",
|
||||||
|
// M157 r2:示例游戏参数(同上,是夹具不是文案)。
|
||||||
|
"--fullscreen",
|
||||||
"26.2-snapshot-2",
|
"26.2-snapshot-2",
|
||||||
"1.20.4",
|
"1.20.4",
|
||||||
"C:/Java/temurin-21/bin/java.exe",
|
"C:/Java/temurin-21/bin/java.exe",
|
||||||
|
|||||||
@@ -203,6 +203,7 @@ mod tests {
|
|||||||
/// 最小的 tempdir(与本 crate 其它 host 测试同款:不引第三方 tempfile)。
|
/// 最小的 tempdir(与本 crate 其它 host 测试同款:不引第三方 tempfile)。
|
||||||
mod tempdir {
|
mod tempdir {
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::sync::atomic::{AtomicU64, Ordering};
|
||||||
|
|
||||||
pub struct Dir {
|
pub struct Dir {
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
@@ -210,7 +211,14 @@ mod tests {
|
|||||||
|
|
||||||
impl Dir {
|
impl Dir {
|
||||||
pub fn new(tag: &str) -> Self {
|
pub fn new(tag: &str) -> Self {
|
||||||
let path = std::env::temp_dir().join(format!("{tag}-{}", std::process::id()));
|
// 每个用例一个目录:同一进程里跑多个用例时,只用 PID 命名会互相 `remove_dir_all`
|
||||||
|
// (并行跑就是「系统找不到指定的路径」——M157 r2 实测)。
|
||||||
|
static COUNTER: AtomicU64 = AtomicU64::new(0);
|
||||||
|
let seq = COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||||
|
let path = std::env::temp_dir().join(format!(
|
||||||
|
"{tag}-{}-{seq}",
|
||||||
|
std::process::id()
|
||||||
|
));
|
||||||
let _ = std::fs::remove_dir_all(&path);
|
let _ = std::fs::remove_dir_all(&path);
|
||||||
std::fs::create_dir_all(&path).expect("建临时目录");
|
std::fs::create_dir_all(&path).expect("建临时目录");
|
||||||
Self { path }
|
Self { path }
|
||||||
|
|||||||
Reference in new issue
Block a user