Files
Ichino/CLAUDE.md
T
Bad0RANG3 45214b11a0 refactor: 抽取高危功能页共享脚手架与传输层日志
诊断:功能票 / 解锁歌曲 / 收藏品 / 旅行伙伴 / 数值修改 / 一键跑图 /
万花筒 / 高危 hub 这些页面各自抄了一份同样的脚手架——冷却计时器、_Step
枚举、自动退登开关、卡片/提示/进度卡;TitleApiService.getUserPreview 还
重复实现了整套传输层;服务层有 37 处裸 print 会把 token / JSESSIONID
打进日志。

- 新增共享原语,7 个功能页切换到:
  * widgets/cooldown_mixin.dart  CooldownMixin(登录后冷却倒计时)
  * widgets/step_progress.dart   RiskStep + StepProgressCard
  * widgets/app_card.dart        AppCard / SectionTitle / AutoLogoutToggle
  * widgets/app_notice.dart      AppNotice + context.showSnack
- TitleApiService: getUserPreview 收敛进通用 _callApi;新增 fromHolder()
  工厂与 config getter,消除散落的 isConfigured + config!
- 传输层 print -> ApiLog(仅 debug 输出),删除全部 avoid_print 忽略
- UserAllPayloadBuilder 新增 placeholderMusicData()(原 5 处重复)
- LoginPage 从 main.dart 抽到 pages/login_page.dart,入口只留 main + MyApp
- 更新 README / CLAUDE.md 目录结构与已过时的 web/依赖说明

验证:flutter analyze 0 issue(含 info);flutter test 96/96 通过。
纯结构重构,行为保持不变;仅有意统一了功能票 / 音乐风险 / hub 的
卡片与步骤视觉样式。

净删除约 2176 行重复代码。
2026-09-28 14:50:51 +08:00

88 lines
3.6 KiB
Markdown
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.
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Build & Development Commands
```bash
# Run the app (launches on connected device)
flutter run
# Run analyzer
flutter analyze
# Run tests
flutter test
# Run a single test file
flutter test test/widget_test.dart
# Build release artifacts
flutter build apk --release # Android
flutter build windows --release # Windows
flutter build macos --release # macOS
flutter build linux --release # Linux
flutter build ios --release --no-codesign # iOS(无证书时只验证可编译)
# Check for outdated dependencies
flutter pub outdated
# Upgrade dependencies
flutter pub upgrade --major-versions
```
## Architecture
This is a Flutter app (Android / iOS / Windows / macOS / Linux) that serves as a QR-code-based
login client for the maimai DX arcade game network.
### Code Layout
```
lib/
├── main.dart # 入口:main() + MyApp(MaterialApp)
├── pages/
│ ├── login_page.dart # 登录页(QR 粘贴 / 图片识别)
│ ├── home_page.dart # 主页骨架(底部导航 + 各 tab)
│ ├── settings_page.dart # Title Server / 机器参数配置
│ └── ... # 各功能页(ticket / best50 / 风险操作等)
├── widgets/
│ ├── cooldown_mixin.dart # CooldownMixin:登录后冷却倒计时
│ ├── step_progress.dart # RiskStep + StepProgressCard
│ ├── app_card.dart # AppCard / SectionTitle / AutoLogoutToggle
│ ├── app_notice.dart # AppNotice + context.showSnack
│ └── best50_poster.dart # B50 成绩图
└── services/
├── api_service.dart # Aime 登录 API 客户端
├── title_api_service.dart # 游戏服务器传输层(加解密 / 会话 / 各 Api)
├── user_all_payload_builder.dart # UpsertUserAll 组装与各补丁
├── api_log.dart # 传输层调试日志(仅 debug)
└── ...
```
### Key Design Decisions
- **Risk-flow scaffolding is shared**: the feature pages (ticket / unlock music / collectibles /
travel partner / number patch / map traverse / kaleidx / risk hub) all use `CooldownMixin`,
`RiskStep`, `StepProgressCard`, `AppCard`, `AppNotice` and `AutoLogoutToggle` instead of
copy-pasting the same timer / step / banner / card code. Keep new pages on these primitives.
- **QR decoding is native-only**: `services/qr_service.dart` calls the
`dev.naominet.ichino/qr_scanner` MethodChannel, implemented by Android's `MainActivity` and
iOS's `SceneDelegate`. Desktop has no handler, so image-based QR scanning is mobile-only.
- **Auth flow**: `ApiService.login()` takes a QR code token (last 64 chars), builds a SHA-256 key
from `chipID + JST-timestamp + chimeSalt`, and POSTs JSON to the configured Aime URL. A successful
response has `errorID: 0` and returns `userID` + `token`.
- **Title server transport**: `TitleApiService` derives the URL path from
`MD5(apiName + salt + obfuscateParam)`, JSON → ZLib → AES-CBC encodes/decodes, and keeps the
`JSESSIONID` cookie. `getUserPreview` and every other API go through the same `_callApi` helper.
- **Timestamp is JST (UTC+9)** for Aime key derivation, formatted `yyMMddHHmmss`.
### Notable Dependencies
- `http` — API calls
- `crypto` — MD5 URL hash + SHA-256 Aime key
- `pointycastle` / `archive` — AES-CBC + ZLib for the title-server wire format
- `image_picker` — picking QR images from the device gallery
- `shared_preferences` — persisted `TitleServerConfig`
- `share_plus` — exporting the B50 PNG