feat(app-iced): M114 账户页三轨登录(微软正版 / 第三方皮肤站 / 本地档案)

- 账户页:当前账户卡 + 全部账户列表 + 空态三入口 + 皮肤区;五项动作(添加/切换/删除/重新登录/校验)
- 三轨添加流程:设备码(用户码+链接+倒计时+过期重试+取消)、授权码(浏览器+可复制链接+取消)、
  本地档案(名字校验)、第三方站(服务地址 + 服务发现校验 + 密码登录,密码掩码且用完即弃)
- 导航:账户为一等页,入口是轨底头像位(未登录=描边剪影 / 已登录=首字母块+名字;窄高收成图标条)
- 凭据红线:DTO 侧形状脱敏 + 状态层二次脱敏 + 密码掩码;Inject-JWT 测试断言视图模型干净(已做变异取证)
- presenter:authlib 登录/服务发现/皮肤抓取(复用下载引擎的 HTTP 客户端,无新增依赖)、
  皮肤原图经 DTO 到 UI 裁剪成头像(既有 image 依赖,未改 Cargo.toml)
- i18n:新增 account 域 51 条中英文案(离线档案口径全量写入),金表同步
This commit is contained in:
AskaEth committed 2026-11-05 05:08:35 +08:00
1 parent e7b04c4afe
commit 1ff00bbe50
43 files changed
+4343 -117

No files matched your search

+20 -13
View File
@@ -6,9 +6,11 @@
use crate::agent::AgentRail;
use crate::dialogs::DialogQueue;
use crate::dto::{
AccountView, AgentEvent, AppEvent, CoreEvent, DeviceLoginView, DiagnosisReport,
InstallProgressView, InstanceRuntime, InstanceSummary, JavaPageView, LoaderKind, LogLine,
LogSession, NoticeView, PackState, Progress, SettingGroupView, VersionSummary,
// 主线(M105 的 `LoaderKind` / M113 的 `PackState`)与 M114 的 `AuthlibLoginView` 并集。
AccountView, AgentEvent, AppEvent, AuthlibLoginView, CoreEvent, DeviceLoginView,
DiagnosisReport, InstallProgressView, InstanceRuntime, InstanceSummary, JavaPageView,
LoaderKind, LogLine, LogSession, NoticeView, PackState, Progress, SettingGroupView,
VersionSummary,
};
use crate::prefs::UiPrefs;
// 内容库的视图态与其 DTO 放一起(`dto/content.rs`),路径 `state::ContentState` 不变。
@@ -17,6 +19,13 @@ use crate::router::{AiPanelMode, Route, Router};
use crate::toast::{ToastCenter, ToastKind};
use crate::wizard::WizardState;
// 账户/登录状态(倒计时、上屏前二次脱敏)拆在 `state/accounts.rs`,守 400 行硬线。
//
// `AiSession` 不再存在:M104 把它换成了 `crate::agent::AgentRail`(agent 栏的视图模型),
// 所以这里没有 `mod ai;` / `pub use ai::AiSession;`——M114 r1 曾把旧结构搬到 `state/ai.rs`,
// 该文件已随 rebase 删除,**以 main 的 agent 契约为准**。
mod accounts;
/// 磁贴网格单元:位置由 [`grid_positions`] 算好,UI 侧只消费 row/col。
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct TileCell<'a> {
@@ -79,6 +88,10 @@ pub struct AppState {
pub accounts: Vec<AccountView>,
/// 微软登录状态
pub device_login: DeviceLoginView,
/// 第三方轨(authlib-injector)登录/校验状态
pub authlib_login: AuthlibLoginView,
/// 设备码等待态的开始时刻(倒计时;`None` = 没有在等)
pub device_login_started: Option<std::time::Instant>,
/// Java 页快照(发行版 / 回退链 / 运行时)
pub java: JavaPageView,
/// 安装进度(None = 没有安装任务)
@@ -140,6 +153,8 @@ impl AppState {
download_query: String::new(),
accounts: Vec::new(),
device_login: DeviceLoginView::new(),
authlib_login: AuthlibLoginView::new(),
device_login_started: None,
java: JavaPageView::new(),
install: None,
install_cancelled: 0,
@@ -237,16 +252,8 @@ impl AppState {
}
CoreEvent::DiagnosisReady(report) => self.diagnosis = Some(report),
CoreEvent::AccountsChanged(accounts) => self.accounts = accounts,
CoreEvent::DeviceLoginChanged(view) => {
if view.phase == crate::dto::DeviceLoginPhase::Succeeded {
self.toasts
.push(ToastKind::Success, format!("已登录:{}", view.account_name));
}
if view.phase == crate::dto::DeviceLoginPhase::Failed {
self.toasts.push(ToastKind::Error, view.message.clone());
}
self.device_login = view;
}
CoreEvent::DeviceLoginChanged(view) => self.apply_device_login(view),
CoreEvent::AuthlibLoginChanged(view) => self.apply_authlib_login(view),
CoreEvent::JavaChanged(page) => self.java = page,
CoreEvent::InstallProgress(progress) => match progress {
Some(progress) => {