Skip to content

feat: expose reader activity and stable content coverage - #5

Open
Eoic wants to merge 1 commit into
developmentfrom
feat/goals-redesign
Open

Eoic wants to merge 1 commit into
developmentfrom
feat/goals-redesign

Conversation

@Eoic

@Eoic Eoic commented Oct 6, 2026 •

Copy link
Copy Markdown
Member

Summary

Expose optional, Goals-independent activity observations from the reader: content readiness, visibility, stable EPUB coverage, exposed PDF pages/spreads, navigation cause, and end-of-document state. Existing locator callbacks, version-1 locators, custom engines, and worker parsing remain compatible. Coverage reporting preserves exact EPUB content offsets during restoration/reflow.

Testing

  • Package analysis and all 145 package tests pass, including panel visibility, custom engines, navigation, restoration, and large text.
  • Example analysis/tests/web build and worker drift check pass.
  • Browser smoke checks passed with worker, local-file, pagination, focus, settings, and theme coverage.
  • Real EPUB/PDF Android and Chromium host integration passed in client #40.

Compatibility and migration

Additive callback and snapshot fields; no Goals dependency or package version change. Target development. Merge before the client pins this revision.

Notes

The host owns clocks, lifecycle, persistence, calibration, aggregation, and explicit completion. EPUB coverage is chapter-local normalized content, not screen pagination.

Coordinated server #12 and workspace integration pin these changes without a version bump.

Workspace integration #13 pins all three component revisions and documents release order.

Copilot AI balanced review requested due to automatic review settings October 6, 2026 13:32

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-06T13:37:33.654960Z bc617de PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bc617deeaf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


@override
Widget build(BuildContext context) {
WidgetsBinding.instance.addPostFrameCallback((_) => _reportActivity());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Emit activity only when the observed state changes

When an onActivity consumer updates parent or store state, that update rebuilds PapyrusReader, this unconditional post-frame callback emits a fresh event, and the consumer schedules another rebuild; the cycle can continue every frame even though reader state is unchanged. Deduplicate activity state or schedule reporting only from actual controller, panel, and route transitions rather than from every build.

Useful? React with 👍 / 👎.

_panel == _ReaderPanel.none &&
_compactPanelRoute == null &&
(ModalRoute.of(context)?.isCurrent ?? true),
cause: _controller.navigationCause,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Report direct viewport navigation as viewport

When the reader moves through a direct EPUB swipe/scroll or a pdfrx position update, the engine reaches _syncFromEngine without invoking any controller navigation method, so navigationCause remains restore or the previous command and this event reports a stale cause. Hosts will consequently misclassify ordinary reading activity, while ReaderNavigationCause.viewport is never emitted; engine-originated position changes need to select that cause unless they belong to a currently scoped command.

Useful? React with 👍 / 👎.

Comment on lines +23 to +24
final class ReaderActivityEvent {
const ReaderActivityEvent({

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Make the new activity domain types serializable

The newly exported ReaderActivityEvent and its nested ReaderContentCoverage provide no toJson/fromJson representation, so hosts cannot serialize the new host-facing observations through the package's domain API and must invent incompatible enum and field encodings. Add a stable versioned serialization format for both types.

AGENTS.md reference: AGENTS.md:L7-L7

Useful? React with 👍 / 👎.

Comment on lines +383 to +386
final intersection = rect.intersect(visible);
if (intersection.width * intersection.height >=
rect.width * rect.height * .25) {
exposed.add(i);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep zoomed PDF content ready while it is visible

When a PDF page is zoomed enough that the viewport covers less than 25% of the page, this filter returns no exposed pages even though the user is actively reading a visible portion. PdfReaderEngine then derives contentReady: false, which also forces activity visible to false and stops host time tracking throughout zoomed reading; readiness should remain true after the viewer is ready even if the stable-coverage threshold excludes the current fragment.

Useful? React with 👍 / 👎.

Comment on lines 93 to 98
List<ReaderTocEntry> toc = const [],
this.locationLabel,
this.coverage = const [],
this.contentReady = true,
this.atEnd = false,
}) : toc = List.unmodifiable(toc);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve snapshot immutability for coverage

When a host modifies snapshot.coverage or the same list received through ReaderActivityEvent, this constructor has retained the caller's mutable list rather than copying it as it does for toc. For EPUB this can also mutate the engine's _coverage list directly, silently changing the published snapshot without notification and corrupting subsequent activity observations; wrap coverage with List.unmodifiable in the initializer.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants