Files
Unlucky-Launcher/crates/app/ui/models.slint
T
AskaEth ddc0577f83 feat(app): GUI 全量接线,五页改吃 core 真实数据(M43)
app 从「mock 骨架」切到「真实 core host」:新增 src/host 装配层(env/job/
game/launch/identity/versions/install/meter/java/accounts/logs/settings/engine/
dispatch),是 app 里除 settings_bridge 外唯一 use unlucky_core 的地方,出口只有
crate::dto 的 DTO/事件(三通道纪律,AGENTS §6)。

页面接线:
- 实例页:profiles+版本 JSON 继承链+会话索引 → 磁贴(真实版本/加载器徽标/最后启动/
  隔离档位/载荷缺失);启动按钮走 LaunchRequest 装配 → Launcher::spawn → JSONL
  尾随 → 运行/失败回写;M30 ModeChangeWarning 进横幅通知条。
- 新建实例向导:版本 → 加载器 → 名字 → 确认 → 真实安装进度;Fabric/Quilt 可装,
  Forge/NeoForge 因需要 installer processors(仅 CLI 有)显式拒装并给出 CLI 命令。
- 下载页:远端 manifest(12h 缓存)+ 内嵌 unlisted → 分类(正式/预览/远古四子类);
  安装进度(文件数/字节/速度/ETA,速度由相邻采样差分)+ 阶段边界可取消;
  Java 分组:四家发行版 + 回退链可视化(计划链/真实 ChainLog)+ 本地运行时。
- 账户页:三轨账户列表(只读公开字段)+ 离线新增 + 删除/切换 + 微软设备码登录
  (用户码/链接/轮询状态;取消后丢弃结果)。凭据只在 host/identity 与 host/accounts
  出现,DTO 无 token 字段(单测钉住)。
- 设置页:新增 download/java/data/ai/mcp 五组,行由 core::setting schema 键生成,
  写回走 SettingStore::set(与 ull config set / AI set_config 同源 launcher.json)。
- 日志页:会话索引 → 列表;事件 JSONL → 日志行(等级高亮)+ D8 规则引擎诊断卡片;
  启动中实时尾随(600ms/拍,只读新增字节);崩溃日志导入分析(hs_err/crash/latest)。

架构与守线:
- 新页面状态走 ui/page_state.slint 的 PageState global(main.slint 再导出),
  Rust 侧 page_sync.rs 灌入、callbacks_pages.rs 接线;避免属性逐层转发顶破 400 行。
- DTO 全部 Serialize+Deserialize(IPC 契约),新增 accounts/java/settings/install/
  notices 五个子模块;事件扩展 LogAppended/LaunchFinished/AccountsChanged/
  DeviceLoginChanged/JavaChanged/InstallProgress/SettingsChanged/NoticesChanged。
- 截图通道扩展:--data-dir(钉数据根且 settings 同源)/--mock/--screenshot-page/
  --screenshot-wizard/--screenshot-session/--screenshot-install/--screenshot-launch
  (真实中间态,取图后自动 stop 防孤儿进程)。

已知边界:GUI 账户「当前启动账户」仅内存态(core schema 无 auth.* 键,app 不自建键);
Forge/NeoForge GUI 安装待 processors 执行器上移。
2026-10-31 21:55:58 +08:00

365 lines
8.1 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// UI 视图模型:Rust 的 dto.rs 做单向转换后喂给 Slint(app 不 import core 内部类型,01c §5)。
// 命名一律 kebab-case,Rust 侧 slint-build 会生成 snake_case 字段。
// 约定:这里只放「界面要显示什么」,不放领域语义(版本继承链、下载源健康度等留在 core)。
// ── 共享枚举 ─────────────────────────────────────────────────────
export enum RouteKind {
instances,
download,
logs,
settings,
detail,
agent,
}
export enum TileSize {
small,
medium,
large,
}
export enum InstanceView {
tiles,
list,
}
/// D17 主题三态:auto 跟随系统(Slint Palette.color-scheme 热更),light/dark 钉死。
/// 键值 `appearance.theme_mode ∈ {light, dark, auto}`,出厂 auto。
export enum ThemeMode {
auto,
light,
dark,
}
/// 背景图填充模式(09 §101:cover / contain / tile)。与 `core::setting::appearance::BgFill` 同序。
export enum BgFillKind {
cover,
contain,
tile,
}
export enum LoaderKind {
vanilla,
fabric,
quilt,
forge,
neoforge,
optifine,
liteloader,
}
export enum RuntimePhase {
idle,
downloading,
verifying,
launching,
running,
failed,
}
export enum ChatRole {
user,
assistant,
tool,
system,
}
export enum DialogKind {
confirm,
input,
progress,
error,
}
export enum ToastKind {
info,
success,
warn,
error,
}
export enum VersionKind {
release,
snapshot,
ancientClassic,
ancientAlpha,
ancientBeta,
ancientUnlisted,
modpack,
mod,
}
// 下载页分类侧栏的选中项(远古版把四个子类提升为平级枚值,便于单选高亮)
export enum DownloadCategory {
release,
snapshot,
ancientClassic,
ancientAlpha,
ancientBeta,
ancientUnlisted,
modpack,
mod,
}
export enum LogOutcome {
ok,
crashed,
silentFail,
}
export enum LogLevel {
debug,
info,
warn,
error,
}
export enum SettingSection {
general,
/// D17「外观(高级)」:主题三态 / 背景图 / 半透明度 / 玻璃拟态 / 强调色 / 动画强度
appearance,
data,
download,
java,
account,
ai,
proxy,
about,
}
// ── 磁贴 ────────────────────────────────────────────────────────
// row/col 由 Rust state.rs 的 tile_grid() 按当前磁贴尺寸算好(小 6 / 中 4 / 大 3 列),
// 这样 Slint 侧 GridLayout 只消费整数位置,不必在 DSL 里做除法。
export struct UiTile {
id: string,
name: string,
mc_version: string,
loader: LoaderKind,
loader_version: string,
/// 加载器徽标文字(「原版」/「Fabric 0.16.5」):由 Rust 侧用 `LoaderInfo::badge()` 拼好,
/// DSL 不做枚举→字符串映射(少一处双份真相)。
loader_label: string,
last_played: string,
phase: RuntimePhase,
/// 启动中阶段文案(「下载资源」/「校验文件」/「启动中」),idle 时为空。
phase_label: string,
/// 0.0~1.0;<= 0 表示进度未知(进度环转为不确定态)。
progress: float,
/// 实例图标;空 image 时退回「名字首字 + hue 底色」占位。
icon: image,
hue: color,
/// 名字首字,无图标时的占位字母(Rust 侧取首个字素)。
initial: string,
row: int,
col: int,
}
// ── 下载页 ──────────────────────────────────────────────────────
export struct UiVersion {
id: string,
kind: VersionKind,
released: string,
installed: bool,
/// 远古版(classic/alpha/beta/unlisted)——列表行带徽标 + 页顶兼容性提示。
ancient: bool,
}
// ── 日志页 ──────────────────────────────────────────────────────
export struct UiLogSession {
id: string,
when: string,
instance: string,
outcome: LogOutcome,
duration: string,
}
export struct UiLogLine {
text: string,
level: LogLevel,
}
/// D8 规则引擎结论(core::diagnose 的 DTO,app 只负责展示)。
export struct UiDiagnosis {
rule: string,
title: string,
confidence: int,
hint: string,
has_fix: bool,
}
// ── AI 栏 ───────────────────────────────────────────────────────
export struct UiChatMessage {
role: ChatRole,
text: string,
/// role == tool 时的工具名。
tool_name: string,
tool_ok: bool,
/// 流式未完成时 true(末尾显示光标块)。
streaming: bool,
}
// ── 对话框 / Toast ──────────────────────────────────────────────
export struct UiDialog {
id: string,
kind: DialogKind,
title: string,
body: string,
primary: string,
secondary: string,
progress: float,
input_label: string,
input_value: string,
}
export struct UiToast {
id: string,
kind: ToastKind,
text: string,
}
// ── P3 全量接线的视图模型(账户 / Java / 安装 / 设置分组 / 通知 / 向导)──────────
// 这些类型由 Rust 的 dto 单向转换(`conv/pages.rs`),Slint 只读不写业务真相。
// 全部经 `page_state.slint` 的 `PageState` global 下发(避免 main/shell 的属性转发膨胀)。
export enum AccountKind {
offline,
microsoft,
authlib,
}
export struct UiAccount {
id: string,
name: string,
kind: AccountKind,
kind_label: string,
profile_id: string,
login_name: string,
created: string,
active: bool,
}
/// 设备码登录面板(用户码/链接不是凭据,可直接展示)。
export struct UiDeviceCode {
visible: bool,
busy: bool,
user_code: string,
verification_uri: string,
qr_link: string,
expires: int,
message: string,
phase_label: string,
}
export enum JavaStepOutcome {
pending,
skip,
failed,
hit,
}
export struct UiJavaStep {
vendor: string,
outcome: JavaStepOutcome,
outcome_label: string,
detail: string,
}
export struct UiJavaVendor {
id: string,
display: string,
rank: int,
majors: string,
sources: string,
installed: bool,
}
export struct UiJavaRuntime {
binary: string,
version: string,
vendor: string,
origin: string,
}
export enum InstallStage {
planning,
downloading,
installing,
registering,
done,
failed,
cancelled,
}
export struct UiInstallProgress {
visible: bool,
version: string,
instance: string,
loader: string,
stage: InstallStage,
stage_label: string,
ratio: float,
known: bool,
files_label: string,
bytes_label: string,
speed: string,
eta: string,
message: string,
terminal: bool,
failed: bool,
}
export enum SettingControl {
toggle,
choice,
text,
readonly,
action,
}
export struct UiSettingRow {
key: string,
label: string,
description: string,
control: SettingControl,
flag: bool,
selected: int,
options: [string],
value_text: string,
action: string,
}
export struct UiSettingGroup {
id: string,
title: string,
rows: [UiSettingRow],
}
export enum NoticeKind {
info,
warn,
error,
}
export struct UiNotice {
id: string,
kind: NoticeKind,
title: string,
body: string,
}
export struct UiWizard {
open: bool,
step: int,
step_label: string,
step_index: int,
step_total: int,
version: string,
loader: int,
loader_label: string,
loader_version: string,
name: string,
error: string,
busy: bool,
can-next: bool,
}