feat(app-iced): M95 日志页接真组件 + 诊断面板(等宽折行 / 按严重度分组 / 一行摘要)
日志页从 M84 占位换成真组件,数据全部来自 presenter 快照(页面不读盘):
- 日志行列表:`pages/logs/lines.rs`,等宽(`BodySmall` 12/16 + mono 族)+ 按词或字形
折行 + 等级色条;**选折行不选横滚**的理由写在模块文档(424px × 200 字符的现实 +
mono 族的 CJK 回退会毁掉横滚唯一的收益「列对齐」)。
- 诊断面板:`pages/logs/diagnostic.rs`,按严重度分组(CRITICAL → WARNING → NOTICE),
每条给规则 id / 结论 / 说明 / 建议动作 / 置信度;卡片头钉住「Copy summary」,
摘要是稳定单行的 `ULL-LOGS v1 | …`(崩溃日志换 issue 时直接粘)。
- 空态:真组件 `feedback::EmptyState`(图标块 + 标题 + 说明 + CTA 回实例页)。
- 两块都在 `pages/logs/panel.rs` 里**定高 + 内部独立滚动**(`FillPortion(3):(2)`):
第一版让诊断卡按内容撑开,三条结论就把日志卡压成 0 高度(实拍复现后改的)。
- 视图模型:`pages/logs/model.rs`(纯展示字段)+ `app/view.rs::logs_model` 做快照转换。
- 接线(只追加):`pages/mod.rs` 的 `pub use logs::…` / `page()` 那行 /
`Message::CopySummary` / `demo_model` 一行;`pages::Model` 加 `logs` 与 `lang` 两个字段;
`app/update.rs` 把 `CopySummary` 落到 `iced::clipboard::write`、`ClearLogs` 清 presenter 的
`log_lines`(呈现层操作,不造命令)。
- i18n:`crates/i18n/src/catalog.rs` 自己锚点下 16 个 key(中英同表);按塔裁决把
`#[cfg(test)] mod tests` 逐字外置到 `crates/i18n/src/catalog/tests.rs`
(catalog.rs 415 → 257 行,tests.rs 164 行;7 个用例逐字未动、i18n 23 个用例全绿)。
验证:`fmt --check` / `clippy -p unlucky-app-iced --all-targets -- -D warnings` 干净;
`test -p unlucky-app-iced` 272 + 6 全绿、`-p unlucky-i18n` 23 全绿;截图
`.screens/logs-{empty,crash,live}-{light,dark}.png`(1180×760,本地 gitignore)。
遗留(已报 finding):`dto::Diagnosis` 缺 core 的 `severity` 与规则表 `cause.key`;
`Action::OpenLogs` 没有对应 `AppCommand`(点了只有占位日志)。
This commit is contained in:
1 parent
c0396544c5
commit
063a1dba39
16 files changed
+1392
-157
No files matched your search
@@ -0,0 +1,63 @@
|
||||
//! 两块的共用外壳:**定高的卡片 + 内部独立滚动**。
|
||||
//!
|
||||
//! ## 为什么必须定高(M95 r1 的实拍 bug)
|
||||
//!
|
||||
//! 第一版把诊断卡按内容自然高度画、日志卡吃剩余高度。三条结论在 424×540 的正文里就要
|
||||
//! ~500px,结果:诊断卡被裁掉尾部(一行摘要整块消失)、日志卡拿到 **0** 高度(整块不见)。
|
||||
//! 截图见报告里的「r1 崩了」。
|
||||
//!
|
||||
//! 所以两块都**由调用方给定高**(`FillPortion`),各自内部滚动:
|
||||
//!
|
||||
//! | 块 | 高度 | 为什么 |
|
||||
//! |---|---|---|
|
||||
//! | 诊断 | `FillPortion(3)` | 崩溃时先读结论;结论通常比日志短,给 3 份 |
|
||||
//! | 日志 | `FillPortion(2)` | 日志是长流水,滚就是了 |
|
||||
//!
|
||||
//! 两者都是**兄弟**滚动区(不是嵌套):滚轮归属清楚,不存在「滚动条套滚动条」。
|
||||
|
||||
use iced::widget::{container, scrollable};
|
||||
use iced::{Background, Border, Element, Length};
|
||||
|
||||
use unlucky_design::elevation::MaterialLayer;
|
||||
use unlucky_design::shape::ShapeScale;
|
||||
|
||||
use crate::theme::Ui;
|
||||
|
||||
use super::super::frame;
|
||||
use super::super::Message;
|
||||
|
||||
/// 定高卡片(`Card` 材质层 + `OutlinedCard` 形状,令牌与 `frame::card` 同源)。
|
||||
pub fn card<'a>(
|
||||
ui: &'a Ui,
|
||||
height: Length,
|
||||
content: impl Into<Element<'a, Message>>,
|
||||
) -> Element<'a, Message> {
|
||||
container(content)
|
||||
.width(Length::Fill)
|
||||
.height(height)
|
||||
.padding(ui.metrics().card_padding)
|
||||
.style(move |_theme| container::Style {
|
||||
background: Some(Background::Color(ui.layer(MaterialLayer::Card))),
|
||||
border: Border {
|
||||
radius: ui.radius_dp(ShapeScale::Large),
|
||||
..Border::default()
|
||||
},
|
||||
..container::Style::default()
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
||||
/// 卡片内的竖向滚动区(滚条样式与实例页列表列同源)。
|
||||
pub fn scroll<'a>(ui: &'a Ui, content: impl Into<Element<'a, Message>>) -> Element<'a, Message> {
|
||||
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)
|
||||
.width(Length::Fill)
|
||||
.style(frame::scroll_style(ui))
|
||||
.into()
|
||||
}
|
||||
Reference in new issue
Block a user