feat(presenter): 新建 unlucky-presenter,把 host/状态/DTO/设置桥从 app 迁出(M85 第 1 块)
D26(iced 重写)的关键一次性动作:UI 框架无关的宿主层独立成 crate, Slint 版(crates/app)与 iced 版(crates/app-iced)共用,Slint 退役后不再重写一遍。 - 新建 crates/presenter(package `unlucky-presenter` / lib `unlucky_presenter`), workspace 登记 + crate 文档头写清「这层为什么存在」、对外表面、UI 侧允许/禁止、 iced 接线骨架、以及哪些东西留在了 crates/app 及为什么。 - `git mv`(保留文件历史)迁入:host/(25 文件)、dto/(11 文件)、state.rs(+tests)、 prefs.rs、settings_bridge.rs、toast.rs、router.rs、dialogs.rs、wizard.rs、 mock.rs、mock_data.rs、backend.rs。模块路径与公开 API 名称不变(`host::install` 等), 内部实现零改动。 - 新增 `theme`:把原本混在 ui_bind/theme_runtime 里的**纯判据**(CONFIG_POLL_TICKS / SYSTEM_THEME_POLL_TICKS / TILE_REGENERATE_STEP / BackgroundKey / tile_viewport / system_theme_value / 两个 poll 判据)抽出来,附 5 个单测;app 侧改成调用它们。 - crates/app 改为消费者:删掉迁走的文件,`crate::host|state|dto|prefs|settings_bridge| toast|router|dialogs|wizard|mock|mock_data|backend` 全部改写为 `unlucky_presenter::*` (64 处),backend.rs 的 config_path/build_backend 提为 pub。 - crates/app-iced 只登记 unlucky-presenter 依赖,本 mission 不接线。 - prefs.rs 的 2 处 slint 文档引用改写;`grep -rn slint crates/presenter` 现在无输出。
This commit is contained in:
1 parent
00f132d8ce
commit
f159529936
69 files changed
+441
-129
No files matched your search
@@ -1,10 +1,10 @@
|
||||
//! AI 页与覆盖层:会话消息、对话框(一次一条)、Toast。
|
||||
|
||||
use crate::dialogs as dlg;
|
||||
use crate::dto::ChatRole as DtoChatRole;
|
||||
use crate::state::AppState;
|
||||
use crate::toast as toast_mod;
|
||||
use crate::{ChatRole, DialogKind, UiChatMessage, UiDialog, UiToast};
|
||||
use unlucky_presenter::dialogs as dlg;
|
||||
use unlucky_presenter::dto::ChatRole as DtoChatRole;
|
||||
use unlucky_presenter::state::AppState;
|
||||
use unlucky_presenter::toast as toast_mod;
|
||||
|
||||
/// AI 会话消息。
|
||||
pub fn chat(state: &AppState) -> Vec<UiChatMessage> {
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
use slint::Color;
|
||||
|
||||
use crate::dto::{self, InstanceRuntime};
|
||||
use crate::state::{AppState, TileCell};
|
||||
use crate::{LoaderKind, RuntimePhase, UiTile};
|
||||
use unlucky_presenter::dto::{self, InstanceRuntime};
|
||||
use unlucky_presenter::state::{AppState, TileCell};
|
||||
|
||||
/// 头像/图标占位的底色池(Metro 强调色系,按 id 哈希稳定取色)。
|
||||
const HUES: [u32; 8] = [
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//! 日志页:会话列表、日志行、D8 诊断卡片。
|
||||
|
||||
use crate::dto::{LogLevel as DtoLogLevel, LogOutcome as DtoLogOutcome};
|
||||
use crate::state::AppState;
|
||||
use crate::{LogLevel, LogOutcome, UiDiagnosis, UiLogLine, UiLogSession};
|
||||
use unlucky_presenter::dto::{LogLevel as DtoLogLevel, LogOutcome as DtoLogOutcome};
|
||||
use unlucky_presenter::state::AppState;
|
||||
|
||||
/// 日志会话列表。
|
||||
pub fn log_sessions(state: &AppState) -> Vec<UiLogSession> {
|
||||
|
||||
@@ -5,17 +5,17 @@
|
||||
|
||||
use slint::{ModelRc, SharedString, VecModel};
|
||||
|
||||
use crate::dto::{
|
||||
AccountKind as DtoAccountKind, DeviceLoginPhase, InstallStage as DtoInstallStage,
|
||||
JavaChainOutcome, NoticeLevel, SettingControl, VersionKind as DtoVersionKind,
|
||||
};
|
||||
use crate::state::AppState;
|
||||
use crate::wizard::WizardStep;
|
||||
use crate::{
|
||||
AccountKind, InstallStage, JavaStepOutcome, NoticeKind, SettingControl as UiControl, UiAccount,
|
||||
UiDeviceCode, UiInstallProgress, UiJavaRuntime, UiJavaStep, UiJavaVendor, UiNotice,
|
||||
UiSettingGroup, UiSettingRow, UiVersion, UiWizard,
|
||||
};
|
||||
use unlucky_presenter::dto::{
|
||||
AccountKind as DtoAccountKind, DeviceLoginPhase, InstallStage as DtoInstallStage,
|
||||
JavaChainOutcome, NoticeLevel, SettingControl, VersionKind as DtoVersionKind,
|
||||
};
|
||||
use unlucky_presenter::state::AppState;
|
||||
use unlucky_presenter::wizard::WizardStep;
|
||||
|
||||
fn strings(items: &[String]) -> ModelRc<SharedString> {
|
||||
ModelRc::new(VecModel::from(
|
||||
@@ -162,8 +162,8 @@ pub fn install(state: &AppState) -> UiInstallProgress {
|
||||
bytes_label: if progress.bytes_total > 0 {
|
||||
format!(
|
||||
"{}/{}",
|
||||
crate::dto::human_bytes(progress.bytes_done),
|
||||
crate::dto::human_bytes(progress.bytes_total)
|
||||
unlucky_presenter::dto::human_bytes(progress.bytes_done),
|
||||
unlucky_presenter::dto::human_bytes(progress.bytes_total)
|
||||
)
|
||||
} else {
|
||||
String::new()
|
||||
@@ -236,7 +236,7 @@ pub fn wizard(state: &AppState) -> UiWizard {
|
||||
let step = wizard.step;
|
||||
let can_next = match step {
|
||||
WizardStep::Version => !wizard.version.trim().is_empty(),
|
||||
WizardStep::Name => crate::wizard::validate_name(&wizard.name).is_ok(),
|
||||
WizardStep::Name => unlucky_presenter::wizard::validate_name(&wizard.name).is_ok(),
|
||||
WizardStep::Loader | WizardStep::Confirm => true,
|
||||
WizardStep::Progress => false,
|
||||
};
|
||||
@@ -248,7 +248,7 @@ pub fn wizard(state: &AppState) -> UiWizard {
|
||||
step_total: 5,
|
||||
version: wizard.version.as_str().into(),
|
||||
loader: loader_index(wizard.loader),
|
||||
loader_label: if wizard.loader == crate::dto::LoaderKind::Vanilla {
|
||||
loader_label: if wizard.loader == unlucky_presenter::dto::LoaderKind::Vanilla {
|
||||
"原版".to_string()
|
||||
} else {
|
||||
format!("{} {}", wizard.loader.label(), wizard.loader_version.trim())
|
||||
@@ -265,14 +265,15 @@ pub fn wizard(state: &AppState) -> UiWizard {
|
||||
}
|
||||
|
||||
/// 加载器在向导里的单选序号(与 `wizard.slint` 的 LoaderChoice 顺序一致)。
|
||||
pub fn loader_index(loader: crate::dto::LoaderKind) -> i32 {
|
||||
pub fn loader_index(loader: unlucky_presenter::dto::LoaderKind) -> i32 {
|
||||
match loader {
|
||||
crate::dto::LoaderKind::Vanilla => 0,
|
||||
crate::dto::LoaderKind::Fabric => 1,
|
||||
crate::dto::LoaderKind::Quilt => 2,
|
||||
crate::dto::LoaderKind::Forge => 3,
|
||||
crate::dto::LoaderKind::NeoForge => 4,
|
||||
crate::dto::LoaderKind::OptiFine | crate::dto::LoaderKind::LiteLoader => 0,
|
||||
unlucky_presenter::dto::LoaderKind::Vanilla => 0,
|
||||
unlucky_presenter::dto::LoaderKind::Fabric => 1,
|
||||
unlucky_presenter::dto::LoaderKind::Quilt => 2,
|
||||
unlucky_presenter::dto::LoaderKind::Forge => 3,
|
||||
unlucky_presenter::dto::LoaderKind::NeoForge => 4,
|
||||
unlucky_presenter::dto::LoaderKind::OptiFine
|
||||
| unlucky_presenter::dto::LoaderKind::LiteLoader => 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
//! conv/pages.rs 的单测(拆文件守 400 行上限)。
|
||||
|
||||
use super::*;
|
||||
use crate::dto::{
|
||||
use slint::Model;
|
||||
use unlucky_presenter::dto::{
|
||||
AccountView, DeviceLoginView, InstallProgressView, JavaPageView, JavaVendorView, NoticeView,
|
||||
SettingGroupView, SettingRowView, VersionSummary,
|
||||
};
|
||||
use crate::wizard::WizardState;
|
||||
use slint::Model;
|
||||
use unlucky_presenter::wizard::WizardState;
|
||||
|
||||
#[test]
|
||||
fn accounts_and_device_login_render() {
|
||||
@@ -90,7 +90,7 @@ fn java_chain_and_vendors_map_outcomes() {
|
||||
sources: vec!["BMCLAPI".to_string(), "GitHub".to_string()],
|
||||
installed: true,
|
||||
}],
|
||||
chain: vec![crate::dto::JavaChainStep {
|
||||
chain: vec![unlucky_presenter::dto::JavaChainStep {
|
||||
vendor: "temurin".to_string(),
|
||||
outcome: JavaChainOutcome::Hit,
|
||||
detail: "21".to_string(),
|
||||
@@ -161,7 +161,7 @@ fn wizard_versions_skip_ancient_ones() {
|
||||
},
|
||||
VersionSummary {
|
||||
id: "rd-132211".to_string(),
|
||||
kind: DtoVersionKind::Ancient(crate::dto::AncientKind::Classic),
|
||||
kind: DtoVersionKind::Ancient(unlucky_presenter::dto::AncientKind::Classic),
|
||||
released: "2009-05-13".to_string(),
|
||||
installed: false,
|
||||
},
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
//! UI 偏好/路由枚举的双向映射(Slint 枚举 ↔ 状态层枚举)。
|
||||
|
||||
use crate::dto::{self, VersionCategory};
|
||||
use crate::prefs;
|
||||
use crate::router;
|
||||
use crate::{BgFillKind, DownloadCategory, InstanceView, RouteKind, ThemeMode, TileSize};
|
||||
use unlucky_presenter::dto::{self, VersionCategory};
|
||||
use unlucky_presenter::prefs;
|
||||
use unlucky_presenter::router;
|
||||
|
||||
/// 路由 → 导航高亮/页面选择。
|
||||
pub fn route(route: &router::Route) -> RouteKind {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
//! 版本列表与下载分类映射(下载页)。
|
||||
|
||||
use crate::dto::{AncientKind, VersionCategory, VersionKind as DtoVersionKind, VersionSummary};
|
||||
use crate::state::AppState;
|
||||
use crate::{UiVersion, VersionKind};
|
||||
use unlucky_presenter::dto::{
|
||||
AncientKind, VersionCategory, VersionKind as DtoVersionKind, VersionSummary,
|
||||
};
|
||||
use unlucky_presenter::state::AppState;
|
||||
|
||||
/// 分类侧栏 → 该分类下的版本(远古版按子类细分)。
|
||||
pub fn in_category(category: VersionCategory, kind: DtoVersionKind) -> bool {
|
||||
@@ -58,8 +60,8 @@ fn version_kind(kind: DtoVersionKind) -> VersionKind {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::versions;
|
||||
use crate::dto::{VersionKind, VersionSummary};
|
||||
use crate::state::AppState;
|
||||
use unlucky_presenter::dto::{VersionKind, VersionSummary};
|
||||
use unlucky_presenter::state::AppState;
|
||||
|
||||
fn state_with_versions() -> AppState {
|
||||
let mut state = AppState::new();
|
||||
|
||||
Reference in new issue
Block a user