feat: add in-reader search and restructure documentation

- Add RDEPUBReaderSearchBarView with animated show/hide, keyword
  navigation, and match counting integrated into the reader controller
- Restructure docs: replace scattered design docs with consolidated
  BUSINESS_LOGIC.md and UML_CLASS_DIAGRAMS.md; update ARCHITECTURE.md
- Add SearchTests and FanrenParseTimeTest; enhance LargeBookOnDemandTests
- Add scripts/run_ui_regression.sh and summarize_ui_results.py for
  automated UI test execution and reporting

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-06-05 17:34:50 +08:00
co-authored by Claude Opus 4.7
parent d20196ee34
commit 0e7c0577e3
37 changed files with 4941 additions and 7621 deletions
@@ -70,6 +70,79 @@ final class LargeBookOnDemandTests: XCTestCase {
XCTAssertEqual(reopenedState.knownChapters, reopenedState.buildableChapters)
}
func testMiddleChapterOpenPositionStableAfterFullParse() throws {
//
app.launchAndOpenSampleBook(
bookTitleQuery: largeBookQuery,
pageNumber: 50,
resetsReaderState: true
)
app.waitForReader(timeout: 20)
let partialState = app.waitForDemoReaderState(timeout: 15, description: "中间章节首开进入局部分页") { state in
state.mode == "bookPageMap" && state.pagination == "partial" && (state.page ?? 0) >= 1
}
let pageAfterOpen = partialState.page ?? 0
XCTAssertGreaterThan(pageAfterOpen, 1, "应从中间章节打开,当前页=\(pageAfterOpen)")
//
let fullState = app.waitForDemoReaderState(timeout: 90, description: "后台解析完成") { state in
state.pagination == "full"
}
XCTAssertEqual(fullState.pagination, "full", "后台解析应完成")
// Cpending map
let pageAfterParse = fullState.page ?? 0
XCTAssertEqual(pageAfterParse, pageAfterOpen,
"后台解析完成后页码不应跳转:解析前=\(pageAfterOpen) 解析后=\(pageAfterParse)")
// pending map
let paging = app.collectionViews[IDs.readerPaging]
if paging.waitForExistence(timeout: 5) {
paging.swipeLeft()
}
let afterSwipe = app.waitForDemoReaderState(timeout: 10, description: "翻页后页码推进") { state in
state.page != nil && state.page != pageAfterParse
}
XCTAssertGreaterThan(afterSwipe.page ?? 0, pageAfterParse,
"翻页后页码应前进:翻页前=\(pageAfterParse) 翻页后=\(afterSwipe.page ?? 0)")
}
func testMiddleChapterOpenSwipeAfterFullParseResolvesCorrectly() throws {
//
app.launchAndOpenSampleBook(
bookTitleQuery: largeBookQuery,
pageNumber: 30,
resetsReaderState: true
)
app.waitForReader(timeout: 20)
_ = app.waitForDemoReaderState(timeout: 15, description: "局部分页就绪") { state in
state.mode == "bookPageMap" && state.pagination == "partial"
}
//
_ = app.waitForDemoReaderState(timeout: 90, description: "后台解析完成") { state in
state.pagination == "full"
}
// 3
let paging = app.collectionViews[IDs.readerPaging]
XCTAssertTrue(paging.waitForExistence(timeout: 5), "分页视图不存在")
var previousPage = app.currentDemoReaderState()?.page ?? 0
for i in 0..<3 {
paging.swipeLeft()
RunLoop.current.run(until: Date().addingTimeInterval(1))
let currentState = app.currentDemoReaderState()
let currentPage = currentState?.page ?? 0
XCTAssertGreaterThan(currentPage, previousPage,
"\(i + 1) 次翻页后页码应递增:前=\(previousPage) 后=\(currentPage)")
previousPage = currentPage
}
}
func testLargeBookContinuousPagingExtendsKnownPageMap() throws {
app.launchAndOpenSampleBook(bookTitleQuery: largeBookQuery, displayType: "scroll", resetsReaderState: true)
app.waitForReader(timeout: 20)