174 Commits

Author SHA1 Message Date
wangdl
f25538cf5a fix(IOS-INFO-043): add parse progress overlay to MaterialReaderView
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-19 11:30:19 +08:00
wangdl
042256913e fix(IOS-INFO-043): move triggerParse inside MaterialReaderView struct
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-19 11:30:08 +08:00
wangdl
123efb1612 feat(IOS-INFO-043): add 详情 and 整理知识点 toolbar buttons to MaterialReaderView
- MaterialReaderView: add info.circle button → MaterialDetailView
- MaterialReaderView: add brain button → trigger parse API + status polling
- MaterialReaderView: add triggerParse() with 2s poll loop
- KnowledgeSourceService: add parse() method (POST /sources/:id/parse)
- ImportStatusResponse: add jobId, progress fields
- ParseResponse: new model for parse trigger response

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-19 11:26:13 +08:00
wangdl
fbf359ffe9 feat(IOS-INFO-043): trim MaterialDetailView + add toolbar to MaterialReaderView
- MaterialDetailView: remove 阅读原文件, 问这份资料, 开始学习 buttons
- MaterialReaderView: add 开始学习 toolbar button
- MaterialDetailView now serves as info page accessible from reader

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-19 11:21:43 +08:00
wangdl
bee1f2ac33 fix(IOS-INFO-042): KnowledgeDetailPage toolbar - remove edit/AI/review
KnowledgeItem is AI-generated artifact, should be read-only.
Removes: AI对话, 学习, 编辑, 加入复习, 收藏 from toolbar Menu.
Keeps: 笔记, 预览 (reading functions).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-19 11:20:04 +08:00
wangdl
a698c383bb chore: remove .bak file 2026-06-18 22:34:36 +08:00
wangdl
7c9d8e41a6 revert: undo ImportPage kbId parameter (user clicked wrong KB)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 22:34:29 +08:00
wangdl
c0b7dda8c6 debug: add logging to LibraryDetailPage loadSources + appear
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 22:32:40 +08:00
wangdl
c5ce70fa5a fix(IOS-INFO-040): ImportPage now creates KnowledgeSource via add API
- Use uploadDataWithKey to get fileId + objectKey
- Call KnowledgeSourceService.add() instead of DocumentImportService.create()
- Creates both KnowledgeSource and DocumentImport in one call
- Add missing fields to AddSourceRequest and KnowledgeSourceService.add()

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 22:30:36 +08:00
wangdl
488db840cb debug(IOS-INFO-041): add print logging to ImportPage handleFiles
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 22:24:15 +08:00
wangdl
f7d10f3f44 fix(IOS-INFO-041): load KB info on appear + fix initial loading state
- Set isLoadingSources = true initially to show spinner
- Load KnowledgeBase detail in appear() for header
- Prevents blank screen before data loads

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 22:09:47 +08:00
wangdl
5008e491a9 refactor(IOS-INFO-041): change default tab to sources + load on appear
- Set detailTab default to 1 (sources view)
- Load sources on appear via .task
- Refreshable reloads sources

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 22:05:51 +08:00
wangdl
4b3ef77342 fix(IOS-INFO-040): replace "添加知识点" with "上传资料" in toolbar
Knowledge items are AI-generated artifacts from source parsing, not
manually created entries. Route to ImportPage instead of AddKnowledgePage.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 21:57:26 +08:00
wangdl
bb9c9afb4d fix: make source items tappable in 资料来源 tab
Wraps each KnowledgeSource row in NavigationLink to MaterialDetailView.
Previously sources were display-only with no tap action.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 21:27:10 +08:00
wangdl
1c0a625192 feat: add "阅读原文件" button to KnowledgeDetailPage
Blue gradient button at bottom of plain text content view.
Writes content to temp .md file and navigates to MaterialReaderView,
which triggers reading event collection.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 21:19:05 +08:00
wangdl
def8c4c93a fix: all iOS compile errors - protocols, missing fields, colors, shadowed max
- Protocol conformance: list→listAll with extension defaults
- ContinueLearningResponse has no lastPosition→use nil
- LearningSession has no readingTargetType/materialId→use defaults
- Color.zxBlue→Color.blue, Color.zxIndigo→Color.indigo
- Shadowed max parameter→Swift.max
- ForEach Identifiable→explicit id: \.id

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 17:14:34 +08:00
wangdl
d28dba29fc fix: AuthManager has no currentUserId, use KeychainHelper.getUserId()
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 17:03:38 +08:00
wangdl
0cf727899a fix: add getLearningRecords adapter for cursor param mismatch
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 17:00:03 +08:00
wangdl
d8125ddf34 fix: iOS compile errors - protocol mismatches + void return
- ReadingRuntimeAdapter: clearExportedEvents is void, return count separately
- ActivityViewModel: FocusItemServicing.list→listAll, add days/type? params
- ActivityViewModelTests: update mocks to match new protocol signatures

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 16:58:23 +08:00
wangdl
b0df8ee58e feat: add en/ja localization support (IOS-INFO-037)
Some checks failed
iOS CI/CD / Build & Test (push) Has been cancelled
- en.lproj/Localizable.strings: English translations
- ja.lproj/Localizable.strings: Japanese translations
- Covers common, navigation, reader, progress, analysis, study, AI

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 14:26:24 +08:00
wangdl
de384dc027 test: fill iOS coverage gaps - fromBlockScroll, refresh, View helpers
- fromBlockScroll: success + empty/negative/OOB guard tests (4)
- StudyHomeViewModel.refresh: stats update + mainAction update (2)
- View helpers: statusLabel(4) + formatSeconds(7) standalone tests
- formatFileSize smoke test (indirect via View init)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 13:44:54 +08:00
wangdl
c7de97279b test: add P1-fallback + refresh tests for StudyHomeViewModel
- P1 fallback: continueService throws → falls to unfinished session
- refresh: updates stats without setting loadingState
- Fix: remove nonexistent materialId/readingTargetType from LearningSession mock

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 13:25:41 +08:00
wangdl
9ec6fdc3d5 test: add StudyHomeViewModel unit tests with DI (IOS-INFO-037)
- Add 6 service protocols (SessionServicing, ReviewServicing,
  KBListServicing, QuizListServicing, ActivityHomeServicing,
  ContinueLearningServicing)
- ViewModel init supports DI with defaults to .shared
- 16 tests: initial state, loadAll stats, all 5 priority levels
  (continueSession→todaysReview→selfTest→startLearning→empty),
  banner, weekly stats from summary/streak
- Priority P1 continueSession tested with mock API + temp file

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 13:23:08 +08:00
wangdl
3a8266ece2 test: add ActivityViewModel unit tests with DI (IOS-INFO-036)
- Add 5 service protocols (ActivityServicing, FocusItemServicing,
  ReadingContinueServicing, LearningStatusServicing)
- ViewModel init supports DI with defaults to .shared
- Mock services for all 10 parallel calls in loadAll/refresh
- 20 tests: initial state, summary/focus/heatmap/streak/trends/recos,
  learningSummary/readingTrend/continueReading/recentRecords,
  errorMessage on nil summary, refresh clears error

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 13:19:07 +08:00
wangdl
203e45df34 test: remove View helper tests from ViewModel test file
- statusLabel/formatSeconds belong to MaterialDetailView, not ViewModel

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 13:15:26 +08:00
wangdl
833bc70121 test: add load() tests with mock service DI (IOS-INFO-035)
- Add service protocols (KnowledgeBaseServicing, KnowledgeItemServicing,
  QuizServicing, ReadingProgressServicing) for dependency injection
- ViewModel init accepts optional mock services, defaults to .shared
- Mock service classes for test isolation
- load() tests: itemCount, quizCount, aiStatus ready/processing,
  isLoading, readingStatus/seconds, isMarkedRead, progress error,
  nil materialId skips progress

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 13:14:49 +08:00
wangdl
61de3e1d57 test: add MaterialDetailViewModel unit tests (IOS-INFO-035)
- 20 tests covering initial state + helpers
- Initial state: isLoading, aiStatus, itemCount, quizCount, isMarkedRead,
  readingSeconds, readingStatus, knowledgeBaseId, materialId
- init without materialId defaults to nil
- statusLabel: completed/in_progress/unknown/nil → Chinese labels
- formatSeconds: seconds(0/30/59), minutes(60/3599), hours(3600/3660/7200)
- Edge: nil materialId skips progress fetch

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 13:11:36 +08:00
wangdl
4348823ca1 test: add ReadingPositionAdapter.fromValue unit tests (IOS-INFO-034)
- 23 tests: fromValue (12) + clamp (2) + blockId (8)
- fromValue: Markdown/Text/Pdf/Image/Epub complete + defaults
- fromValue: nil blockId→nil for Markdown, nil chapterId→nil for Epub
- fromValue: unknown/nil type → .unknown
- clamp: > 1 → 1.0, < 0 → 0.0
- blockId: all 7 DocumentBlock variants + horizontalRule

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 13:09:05 +08:00
wangdl
86054edd5f test: add resolveKnowledgeSource + full type inference tests
- Add resolveKnowledgeSource path test (knowledge_sources/<id>/)
- Add empty knowledge_sources directory test
- Add .txt→text and .epub→epub type inference
- Add .png/.jpg/.jpeg/.webp→image inference
- Remove misleading test that only asserted nil

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 13:07:30 +08:00
wangdl
2fa459d9ea test: add MaterialPathResolver unit tests (IOS-INFO-033)
- 7 tests covering resolve and materialType inference
- resolve nil for nonexistent file
- resolve finds file in Documents directory
- resolve finds file in Caches directory
- type inference: .md→markdown, .pdf→pdf
- unknown apiType defaults to .unknown
- temp file creation + cleanup in test

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 13:04:37 +08:00
wangdl
335859df0e test: remove redundant singleton test in MarkedReadStore tests
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 13:04:03 +08:00
wangdl
cdc5c10076 test: add MarkedReadStore unit tests (IOS-INFO-032)
- 10 tests covering MarkedReadStore full API
- contains: unmarked=false, after-mark=true, after-unmark=false
- mark: persists to UserDefaults, idempotent, multiple IDs
- unmark: removes from persisted array, nonexistent safe
- Persistence: survives re-init (UserDefaults-backed)
- Edge case: empty string as materialId

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 13:00:26 +08:00
wangdl
82bcbb9efb feat: iOS 学习功能增强 - 阅读API、材料阅读器、分析、学习首页
- ReadingAPI: 阅读进度同步
- MaterialPathResolver: 材料路径解析
- MarkedReadStore: 已读标记存储
- MaterialReaderView/DetailView/ReadingPositionAdapter: 阅读器增强
- AnalysisHomeView/ActivityViewModel: 分析首页
- StudyHomeView/StudyHomeViewModel: 学习首页
- LibrarySubpages: 图书馆子页面

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 11:22:26 +08:00
wangdl
3abe17a84e test: add queue UUID path coverage in LocalQueueTests
- Add test_markRetry_works_with_queue_item_id (uses queue UUID not eventId)
- Update test_markDead_after_max_retries to use queue item id from batch
- Fixes review finding: tests previously only used eventId, not queue UUID

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-15 21:58:04 +08:00
wangdl
12b73b7445 fix: extend APIError.statusCode to cover all cases
- unauthorized → 401
- serverError → extract code string as Int
- networkError → NSError.code

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-15 21:56:36 +08:00
wangdl
4ba747af46 feat: iOS learning info P0 complete (IOS-INFO-000~017, 038~039)
Models: ReadingMaterialContext, ReadingEventUploadItem, AppContext
Runtime: ReadingRuntimeAdapter, SessionManager, RecoveryService
Reader: MaterialReaderView lifecycle, Heartbeat Timer, Position Adapter
Export: EventMapper, UploadQueue, export→queue→ack flow
Tests: 16 test files covering models, runtime, lifecycle, upload
Docs: ios-learning-info-architecture.md

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-15 21:53:36 +08:00
wangdl
f421fbb721 fix: G1 context registry — prevent empty contexts from dropping all export events
- Add ReadingContextRegistry for SessionManager→Pipeline context sharing
- Wire registry into SessionManager (register on open, unregister on close)
- Fix Pipeline to auto-pull from registry when contexts not provided
- Fix ScenePhase to not pass empty contexts

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-09 22:08:03 +08:00
wangdl
51b9365ece feat: M-IOS-INFO Batch D-F complete (38/38)
Batch D: MarkedAsRead UI, reading progress query, position restore, continue learning, source reading status
Batch E: NetworkMonitor, summary/trend/heatmap alignment, learning records, error handling, background upload, debug/logging
Batch F: Test stubs, iOS integration doc
Batch G: V2 FFI/MarkedAsRead/export-ack coverage verification

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-09 21:26:03 +08:00
wangdl
80c1d660cd feat: #80 标记已读 UI + 乐观更新
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-09 20:49:41 +08:00
wangdl
697220de00 fix: APIConfig baseURL longde.cloud → api.longde.cloud
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-09 20:39:57 +08:00
wangdl
a6dde9f0c6 feat: M-IOS-INFO V2 reading event system + iOS 26 build fixes
- Add zx_documentFFI bridging header + modulemap
- Update zx_document.swift (patched for static linking + iOS 26 SDK)
- Replace XCFramework with V2 symbols
- Add V2 types: ReadingMaterialContext, ReadingEventUploadItem, ReadingRuntimeAdapter
- Add V2 session manager: ReadingRuntimeSessionManager
- Add V2 position adapter: ReadingPositionAdapter
- Add V2 event mapper: ReadingEventMapper
- Add upload queue + pipeline: ReadingEventUploadQueue
- Add reading API client: ReadingAPI
- Fix QuickNoteSheet for new NoteAnchor fields (positionSnapshot)
- Restore MaterialReaderView lifecycle events (onAppear/onDisappear)
- Add ScenePhase handling for app background/foreground

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-09 19:58:57 +08:00
wangdl
5fe29a7d8c feat: #24 公开库发现 + 订阅管理
- KnowledgeBaseService 新增 discover/subscribe/unsubscribe API
- DiscoverView: 浏览公开库 + 订阅/取消订阅
- Route.discoverPublic + ProfileView 入口

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 19:36:34 +08:00
wangdl
9e1a8982a3 fix: 修复 LibrarySubpages 多余 } 导致的编译错误 2026-06-06 19:33:03 +08:00
wangdl
c428a57d0d fix: #23 知识点详情增加来源信息 + 加入复习 + 收藏
- 内容区显示来源类型标签 (PDF/Word/Markdown等)
- 菜单新增「加入复习」(POST /reviews/generate-cards)
- 菜单新增「收藏/取消收藏」

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 19:28:04 +08:00
wangdl
1f75170b98 feat: #22 知识库分类管理页面
- KnowledgeFolder 模型 + CreateFolderRequest
- KnowledgeFolderService (list/create/update/delete)
- FolderManageView: 列表 + 新建/重命名/删除
- LibraryDetailPage 菜单「分类管理」入口

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 19:26:00 +08:00
wangdl
d9828bc3c8 fix: #34 #35 移除 contentHeightEstimate 80px 硬编码
- actualContentHeight 通过 GeometryReader 获取真实内容高度
- scrollProgress 使用实际高度计算,精度显著提升
- #36 ReadingEventCollector 已清理完毕(无 ObservableObject/Combine)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 19:22:08 +08:00
wangdl
5af29af549 fix: #21 设置页补全通知/存储/账号分组
- 通知: 复习提醒 + 导入完成 + 系统通知
- 数据与存储: 存储空间入口 + iCloud
- 账号: 个人资料 + 登录设备管理

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 19:19:31 +08:00
wangdl
695518b276 fix: #16 sortOption 接入后端排序 API
- KnowledgeItemService.list 加 sortBy/order 参数
- loadItems/refresh/loadMore 加 sortBy/order 参数
- sortOption onChange 触发重新加载
- sortParams 映射函数: 0→默认, 1→fileSize, 2→createdAt, 3→updatedAt

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 19:07:33 +08:00
wangdl
99dc2807be feat: AIChat 全链路调试日志 + 错误详情展示
load/createSession/loadSession/send 都加了 print 日志:
- scope 参数
- 请求成功/失败状态
- 具体错误信息

sessionError 现在显示具体错误原因而非通用"创建对话失败"

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 18:19:30 +08:00
wangdl
9d0f426118 revert: 恢复 AddKnowledgePage 标签改动
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 18:15:51 +08:00