fix(m162-rebase): M161 合入后三处越线文件回到 400 行内
rebase 到 0241f79(M161)之后,两侧各加了几行,这三个文件同时越过 400 行硬线 (guards.yml::file-size 会红)。处理原则:**不删语义、只搬位置**。 - `app-iced/src/pages/content/parts.rs` 410 → **240**:把状态层(loading / empty / failed / offline / centered / status_body)搬到新文件 `pages/content/parts/status.rs`(200 行)。 状态层本来就是「一屏只有一个」的独立东西,拆开后 parts.rs 只剩筛选条、列表、图标与排序文案。 - `presenter/src/dto/events.rs` 402 → **399**:`CoreEvent::ContentDetail` 的文档由 4 行压成 1 行 (字段说明一个不少,`project` 是请求时选中的 id 这句保留)。 - `presenter/src/state.rs` 404 → **400**:把 `ContentFailed` / `ContentDetail` 两个事件的落地 搬进 `state/content.rs`(`apply_content_failure` / `apply_content_detail`),state.rs 只剩 一行投递——与既有的 `apply_content` 同一个形状。 `state/content.rs` 58 → 64(两个新方法),仍在 400 内。语义零改动:只是投递点换文件。
This commit is contained in:
1 parent
47ed270293
commit
c319f9dbfd
5 files changed
+228
-186
No files matched your search
@@ -21,13 +21,12 @@ use unlucky_presenter::dto::ContentSort;
|
||||
use unlucky_presenter::router::Route;
|
||||
|
||||
use crate::app::components::buttons::{self, Button};
|
||||
use crate::app::components::feedback::{empty_state, EmptyState};
|
||||
use crate::app::components::navigation::list_item::{list_item, ListItem};
|
||||
use crate::app::components::selection::{chip, Chip};
|
||||
use crate::theme::Ui;
|
||||
|
||||
use super::layout::Rails;
|
||||
use super::model::{Content, Hit, Status};
|
||||
use super::model::{Content, Hit};
|
||||
|
||||
mod detail;
|
||||
mod filters;
|
||||
@@ -209,111 +208,6 @@ pub(super) fn more<'a>(ui: &'a Ui, catalog: Catalog, model: &Content) -> Element
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn loading<'a>(ui: &'a Ui, catalog: Catalog) -> Element<'a, PageMessage> {
|
||||
centered(
|
||||
column![
|
||||
frame::text_role_centered(
|
||||
ui,
|
||||
TypeRole::TitleMedium,
|
||||
true,
|
||||
catalog.text(Key::ContentLoading),
|
||||
ui.color(Role::OnSurface)
|
||||
),
|
||||
frame::text_role_centered(
|
||||
ui,
|
||||
TypeRole::BodySmall,
|
||||
false,
|
||||
catalog.text(Key::ContentLoadingHint),
|
||||
ui.color(Role::OnSurfaceVariant)
|
||||
),
|
||||
buttons::text(
|
||||
ui,
|
||||
Button::new(
|
||||
catalog.text(Key::ContentRetry),
|
||||
intent(ContentMessage::Retry)
|
||||
)
|
||||
),
|
||||
]
|
||||
.spacing(ui.space(Space::X3))
|
||||
.width(Length::Fill)
|
||||
.align_x(Alignment::Center),
|
||||
)
|
||||
}
|
||||
|
||||
/// 空态(真 `EmptyState`:CTA 是标准 Filled 按钮)。
|
||||
pub(super) fn empty<'a>(ui: &'a Ui, catalog: Catalog) -> Element<'a, PageMessage> {
|
||||
centered(empty_state(
|
||||
ui,
|
||||
EmptyState::new(
|
||||
IconKind::Search,
|
||||
catalog.text(Key::ContentEmptyTitle),
|
||||
catalog.text(Key::ContentEmptyBody),
|
||||
)
|
||||
.action(
|
||||
catalog.text(Key::ContentRetry),
|
||||
intent(ContentMessage::Retry),
|
||||
),
|
||||
))
|
||||
}
|
||||
|
||||
/// 失败态(带原因与重试出口;原因来自 host,不打码不打折)。
|
||||
pub(super) fn failed<'a>(
|
||||
ui: &'a Ui,
|
||||
catalog: Catalog,
|
||||
reason: &'a str,
|
||||
) -> Element<'a, PageMessage> {
|
||||
centered(
|
||||
column![
|
||||
row![
|
||||
frame::glyph(IconKind::Error, ui.color(Role::Error), frame::ICON_PX),
|
||||
frame::text_role(
|
||||
ui,
|
||||
TypeRole::TitleSmall,
|
||||
true,
|
||||
catalog.text(Key::ContentFailedTitle),
|
||||
ui.color(Role::Error)
|
||||
),
|
||||
]
|
||||
.spacing(ui.space(Space::X2))
|
||||
.align_y(Alignment::Center),
|
||||
frame::text_role(
|
||||
ui,
|
||||
TypeRole::BodySmall,
|
||||
false,
|
||||
reason,
|
||||
ui.color(Role::OnSurfaceVariant)
|
||||
),
|
||||
frame::text_role(
|
||||
ui,
|
||||
TypeRole::BodySmall,
|
||||
false,
|
||||
catalog.text(Key::ContentFailedBody),
|
||||
ui.color(Role::OnSurfaceVariant)
|
||||
),
|
||||
buttons::filled(
|
||||
ui,
|
||||
Button::new(
|
||||
catalog.text(Key::ContentRetry),
|
||||
intent(ContentMessage::Retry)
|
||||
)
|
||||
.leading(IconKind::Refresh)
|
||||
),
|
||||
]
|
||||
.spacing(ui.space(Space::X3))
|
||||
.width(Length::Fill)
|
||||
.align_x(Alignment::Center),
|
||||
)
|
||||
}
|
||||
|
||||
fn centered<'a>(content: impl Into<Element<'a, PageMessage>>) -> Element<'a, PageMessage> {
|
||||
container(content)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.align_x(Alignment::Center)
|
||||
.align_y(Alignment::Center)
|
||||
.into()
|
||||
}
|
||||
|
||||
/// 内容类型 → 图标(**借用**现有字形:图标集里还没有「整合包/Mod/资源包/光影」四枚专用图标,
|
||||
/// 已在报告里登记为偏离)。
|
||||
pub(super) const fn kind_icon(kind: unlucky_presenter::dto::ContentKind) -> IconKind {
|
||||
@@ -341,70 +235,6 @@ pub(super) fn sort_label(sort: ContentSort, catalog: Catalog) -> &'static str {
|
||||
}
|
||||
}
|
||||
|
||||
/// 未联网态(M162):与失败态同一套骨架,只是说清「要么联网、要么真的没有」这件事。
|
||||
pub(super) fn offline<'a>(
|
||||
ui: &'a Ui,
|
||||
catalog: Catalog,
|
||||
reason: &'a str,
|
||||
) -> Element<'a, PageMessage> {
|
||||
centered(
|
||||
column![
|
||||
row![
|
||||
frame::glyph(
|
||||
IconKind::Warn,
|
||||
ui.color(Role::OnSurfaceVariant),
|
||||
frame::ICON_PX
|
||||
),
|
||||
frame::text_role(
|
||||
ui,
|
||||
TypeRole::TitleSmall,
|
||||
true,
|
||||
catalog.text(Key::ContentOfflineTitle),
|
||||
ui.color(Role::OnSurface)
|
||||
),
|
||||
]
|
||||
.spacing(ui.space(Space::X2))
|
||||
.align_y(Alignment::Center),
|
||||
frame::text_role(
|
||||
ui,
|
||||
TypeRole::BodySmall,
|
||||
false,
|
||||
catalog.text(Key::ContentOfflineBody),
|
||||
ui.color(Role::OnSurfaceVariant)
|
||||
),
|
||||
frame::text_role(
|
||||
ui,
|
||||
TypeRole::BodySmall,
|
||||
false,
|
||||
reason,
|
||||
ui.color(Role::OnSurfaceVariant)
|
||||
),
|
||||
buttons::outlined(
|
||||
ui,
|
||||
Button::new(
|
||||
catalog.text(Key::ContentRetry),
|
||||
intent(ContentMessage::Retry)
|
||||
)
|
||||
.leading(IconKind::Refresh),
|
||||
),
|
||||
]
|
||||
.spacing(ui.space(Space::X2))
|
||||
.align_x(Alignment::Center),
|
||||
)
|
||||
}
|
||||
mod status;
|
||||
|
||||
/// 状态分派(四态各一支;`Ready` 由调用方画列表 + 详情)。
|
||||
pub(super) fn status_body<'a>(
|
||||
ui: &'a Ui,
|
||||
catalog: Catalog,
|
||||
model: &'a Content,
|
||||
) -> Option<Element<'a, PageMessage>> {
|
||||
match &model.status {
|
||||
Status::Loading => Some(loading(ui, catalog)),
|
||||
Status::Empty => Some(empty(ui, catalog)),
|
||||
Status::Failed(reason) => Some(failed(ui, catalog, reason.as_str())),
|
||||
// M162:未联网不是「没有结果」,也不是普通失败——单独一屏(标题/正文/图标都不同)
|
||||
Status::Offline(reason) => Some(offline(ui, catalog, reason.as_str())),
|
||||
Status::Ready => None,
|
||||
}
|
||||
}
|
||||
pub(crate) use status::status_body;
|
||||
@@ -0,0 +1,200 @@
|
||||
//! 内容库页的**状态层**:加载 / 空 / 失败 / 未联网 / 状态分派。
|
||||
//!
|
||||
//! 从 `parts.rs` 拆出(M161 合入后那份越过了 400 行;状态层本来就是「一屏只有一个」的
|
||||
//! 独立东西,拆开后 `parts.rs` 只剩筛选条与列表)。四态各一支,判据在
|
||||
//! `model::Status`,这里只负责画。
|
||||
//!
|
||||
//! **未联网(M162)与失败是两屏**:前者说「要么联网、要么真的没有」,后者说「拉取失败了」。
|
||||
|
||||
use iced::widget::{column, container, row};
|
||||
use iced::{Alignment, Element, Length};
|
||||
|
||||
use unlucky_design::color::Role;
|
||||
use unlucky_design::icons::IconKind;
|
||||
use unlucky_design::spacing::Space;
|
||||
use unlucky_design::typography::TypeRole;
|
||||
|
||||
use unlucky_i18n::{Catalog, Key};
|
||||
|
||||
use crate::app::components::buttons::{self, Button};
|
||||
use crate::app::components::feedback::{empty_state, EmptyState};
|
||||
use crate::theme::Ui;
|
||||
|
||||
use super::super::model::{Content, Status};
|
||||
use super::intent;
|
||||
use crate::pages::content::Message as ContentMessage;
|
||||
use crate::pages::frame;
|
||||
use crate::pages::Message as PageMessage;
|
||||
|
||||
pub(crate) fn loading<'a>(ui: &'a Ui, catalog: Catalog) -> Element<'a, PageMessage> {
|
||||
centered(
|
||||
column![
|
||||
frame::text_role_centered(
|
||||
ui,
|
||||
TypeRole::TitleMedium,
|
||||
true,
|
||||
catalog.text(Key::ContentLoading),
|
||||
ui.color(Role::OnSurface)
|
||||
),
|
||||
frame::text_role_centered(
|
||||
ui,
|
||||
TypeRole::BodySmall,
|
||||
false,
|
||||
catalog.text(Key::ContentLoadingHint),
|
||||
ui.color(Role::OnSurfaceVariant)
|
||||
),
|
||||
buttons::text(
|
||||
ui,
|
||||
Button::new(
|
||||
catalog.text(Key::ContentRetry),
|
||||
intent(ContentMessage::Retry)
|
||||
)
|
||||
),
|
||||
]
|
||||
.spacing(ui.space(Space::X3))
|
||||
.width(Length::Fill)
|
||||
.align_x(Alignment::Center),
|
||||
)
|
||||
}
|
||||
|
||||
/// 空态(真 `EmptyState`:CTA 是标准 Filled 按钮)。
|
||||
pub(crate) fn empty<'a>(ui: &'a Ui, catalog: Catalog) -> Element<'a, PageMessage> {
|
||||
centered(empty_state(
|
||||
ui,
|
||||
EmptyState::new(
|
||||
IconKind::Search,
|
||||
catalog.text(Key::ContentEmptyTitle),
|
||||
catalog.text(Key::ContentEmptyBody),
|
||||
)
|
||||
.action(
|
||||
catalog.text(Key::ContentRetry),
|
||||
intent(ContentMessage::Retry),
|
||||
),
|
||||
))
|
||||
}
|
||||
|
||||
/// 失败态(带原因与重试出口;原因来自 host,不打码不打折)。
|
||||
pub(crate) fn failed<'a>(
|
||||
ui: &'a Ui,
|
||||
catalog: Catalog,
|
||||
reason: &'a str,
|
||||
) -> Element<'a, PageMessage> {
|
||||
centered(
|
||||
column![
|
||||
row![
|
||||
frame::glyph(IconKind::Error, ui.color(Role::Error), frame::ICON_PX),
|
||||
frame::text_role(
|
||||
ui,
|
||||
TypeRole::TitleSmall,
|
||||
true,
|
||||
catalog.text(Key::ContentFailedTitle),
|
||||
ui.color(Role::Error)
|
||||
),
|
||||
]
|
||||
.spacing(ui.space(Space::X2))
|
||||
.align_y(Alignment::Center),
|
||||
frame::text_role(
|
||||
ui,
|
||||
TypeRole::BodySmall,
|
||||
false,
|
||||
reason,
|
||||
ui.color(Role::OnSurfaceVariant)
|
||||
),
|
||||
frame::text_role(
|
||||
ui,
|
||||
TypeRole::BodySmall,
|
||||
false,
|
||||
catalog.text(Key::ContentFailedBody),
|
||||
ui.color(Role::OnSurfaceVariant)
|
||||
),
|
||||
buttons::filled(
|
||||
ui,
|
||||
Button::new(
|
||||
catalog.text(Key::ContentRetry),
|
||||
intent(ContentMessage::Retry)
|
||||
)
|
||||
.leading(IconKind::Refresh)
|
||||
),
|
||||
]
|
||||
.spacing(ui.space(Space::X3))
|
||||
.width(Length::Fill)
|
||||
.align_x(Alignment::Center),
|
||||
)
|
||||
}
|
||||
|
||||
fn centered<'a>(content: impl Into<Element<'a, PageMessage>>) -> Element<'a, PageMessage> {
|
||||
container(content)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.align_x(Alignment::Center)
|
||||
.align_y(Alignment::Center)
|
||||
.into()
|
||||
}
|
||||
|
||||
/// 未联网态(M162):与失败态同一套骨架,只是说清「要么联网、要么真的没有」这件事。
|
||||
pub(crate) fn offline<'a>(
|
||||
ui: &'a Ui,
|
||||
catalog: Catalog,
|
||||
reason: &'a str,
|
||||
) -> Element<'a, PageMessage> {
|
||||
centered(
|
||||
column![
|
||||
row![
|
||||
frame::glyph(
|
||||
IconKind::Warn,
|
||||
ui.color(Role::OnSurfaceVariant),
|
||||
frame::ICON_PX
|
||||
),
|
||||
frame::text_role(
|
||||
ui,
|
||||
TypeRole::TitleSmall,
|
||||
true,
|
||||
catalog.text(Key::ContentOfflineTitle),
|
||||
ui.color(Role::OnSurface)
|
||||
),
|
||||
]
|
||||
.spacing(ui.space(Space::X2))
|
||||
.align_y(Alignment::Center),
|
||||
frame::text_role(
|
||||
ui,
|
||||
TypeRole::BodySmall,
|
||||
false,
|
||||
catalog.text(Key::ContentOfflineBody),
|
||||
ui.color(Role::OnSurfaceVariant)
|
||||
),
|
||||
frame::text_role(
|
||||
ui,
|
||||
TypeRole::BodySmall,
|
||||
false,
|
||||
reason,
|
||||
ui.color(Role::OnSurfaceVariant)
|
||||
),
|
||||
buttons::outlined(
|
||||
ui,
|
||||
Button::new(
|
||||
catalog.text(Key::ContentRetry),
|
||||
intent(ContentMessage::Retry)
|
||||
)
|
||||
.leading(IconKind::Refresh),
|
||||
),
|
||||
]
|
||||
.spacing(ui.space(Space::X2))
|
||||
.align_x(Alignment::Center),
|
||||
)
|
||||
}
|
||||
|
||||
/// 状态分派(四态各一支;`Ready` 由调用方画列表 + 详情)。
|
||||
pub(crate) fn status_body<'a>(
|
||||
ui: &'a Ui,
|
||||
catalog: Catalog,
|
||||
model: &'a Content,
|
||||
) -> Option<Element<'a, PageMessage>> {
|
||||
match &model.status {
|
||||
Status::Loading => Some(loading(ui, catalog)),
|
||||
Status::Empty => Some(empty(ui, catalog)),
|
||||
Status::Failed(reason) => Some(failed(ui, catalog, reason.as_str())),
|
||||
// M162:未联网不是「没有结果」,也不是普通失败——单独一屏(标题/正文/图标都不同)
|
||||
Status::Offline(reason) => Some(offline(ui, catalog, reason.as_str())),
|
||||
Status::Ready => None,
|
||||
}
|
||||
}
|
||||
@@ -139,10 +139,7 @@ pub enum CoreEvent {
|
||||
ContentResults(Box<ContentResults>),
|
||||
/// 内容库检索失败(M109;M162 起带大类):没网 / 站点 5xx / 缺密钥要能分开画
|
||||
ContentFailed(Box<crate::dto::ContentFailure>),
|
||||
/// 内容库项目详情 + 版本列表(M162):选中项目后单独一条通道。
|
||||
///
|
||||
/// `project` 是**请求时选中的那个 id**:迟到的结果要靠它判「还算不算当前这次」
|
||||
/// (用户可能已经切到别的项目了)。
|
||||
/// 内容库项目详情 + 版本列表(M162):`project` 是**请求时**选中的 id,迟到结果靠它判。
|
||||
ContentDetail {
|
||||
/// 请求时选中的项目 id
|
||||
project: String,
|
||||
|
||||
@@ -296,15 +296,11 @@ impl AppState {
|
||||
// M113: import/export
|
||||
CoreEvent::Pack(event) => self.pack.apply(*event),
|
||||
CoreEvent::ContentResults(results) => self.apply_content(*results),
|
||||
CoreEvent::ContentFailed(failure) => {
|
||||
self.content.pending = false;
|
||||
self.content.failed = Some(*failure);
|
||||
CoreEvent::ContentFailed(failure) => self.apply_content_failure(*failure),
|
||||
// M162:详情/版本列表(判断逻辑在 `state/content.rs`,这里只有一行投递)
|
||||
CoreEvent::ContentDetail { project, result } => {
|
||||
self.apply_content_detail(&project, *result);
|
||||
}
|
||||
// M162:详情/版本列表(选中项才拉;迟到结果按项目 id 丢)
|
||||
CoreEvent::ContentDetail { project, result } => match *result {
|
||||
Ok(detail) => self.content.apply_detail(&project, detail),
|
||||
Err(failure) => self.content.fail_detail(&project, failure),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//! 从 `state.rs` 拆出(那个文件重新合流 M105 之后贴着 400 行上限)。放在 `impl AppState` 的
|
||||
//! **另一个 impl 块**里,路径与可见性都不变:`apply_core` 直接调 `self.apply_content(..)`。
|
||||
|
||||
use crate::dto::{ContentQuery, ContentResults};
|
||||
use crate::dto::{ContentDetail, ContentFailure, ContentQuery, ContentResults};
|
||||
|
||||
use super::AppState;
|
||||
|
||||
@@ -31,6 +31,25 @@ impl AppState {
|
||||
}
|
||||
}
|
||||
|
||||
/// 检索失败落地(M162 起带大类):清掉「在飞」并记下失败。
|
||||
pub(super) fn apply_content_failure(&mut self, failure: ContentFailure) {
|
||||
self.content.pending = false;
|
||||
self.content.failed = Some(failure);
|
||||
}
|
||||
|
||||
/// 详情事件落地(M162):`Ok` 走 `apply_detail`、`Err` 走 `fail_detail`,两者都按
|
||||
/// **请求时的项目 id** 判迟到(用户可能已经切到别的项目了)。
|
||||
pub(super) fn apply_content_detail(
|
||||
&mut self,
|
||||
project: &str,
|
||||
result: Result<ContentDetail, ContentFailure>,
|
||||
) {
|
||||
match result {
|
||||
Ok(detail) => self.content.apply_detail(project, detail),
|
||||
Err(failure) => self.content.fail_detail(project, failure),
|
||||
}
|
||||
}
|
||||
|
||||
/// 记下新的检索条件并进入「请求在飞」态(指令由调用方随后 dispatch)。
|
||||
pub fn set_content_query(&mut self, query: ContentQuery) {
|
||||
self.content.pending = true;
|
||||
|
||||
Reference in new issue
Block a user