import 'package:freezed_annotation/freezed_annotation.dart'; part 'bookmark.freezed.dart'; part 'bookmark.g.dart'; /// A saved location in a document. /// /// "Paragraph precision" (user ask: 精确到段落加书签) is expressed by the optional /// in-page anchor fields below, all normalized to the page in [0,1]: /// /// * [anchorLeft]/[anchorTop]/[anchorRight]/[anchorBottom] — the bounding rect /// of the bookmarked text fragment (the FIRST fragment of the current text /// selection), in NORMALIZED page coords with a top-left origin (the same /// convention `SidecarHighlight` and the editor's highlight rects use). This /// is what jump-to scrolls to (via `goToRectInsidePage`), so the bookmark /// lands on the exact paragraph, not just the page top. /// * [charIndex] — the character index of the selection start in the page's /// `fullText` (the true text-position anchor). Stored for fidelity / future /// reflow-tolerant re-anchoring; not currently used for navigation. /// /// When no text was selected the anchor falls back to the tapped point: only /// [anchorTop]/[anchorLeft] are set (a zero-size rect) and [charIndex] is null. /// All anchor fields are optional and absent from JSON when null, so OLD /// bookmarks (page-only) still decode and re-encode unchanged (back-compat). @freezed abstract class Bookmark with _$Bookmark { const factory Bookmark({ required String id, required String documentId, /// 1-based page number this bookmark lives on. required int pageNumber, @Default('') String label, @Default(0xFF2196F3) int color, required DateTime createdAt, /// Normalized in-page anchor rect (top-left origin, [0,1]). Null for legacy /// page-only bookmarks (and tap-fallback bookmarks set only top/left). Old /// page-only bookmark JSON omits these keys; they decode to null and the /// data round-trips (back-compat). A re-encoded legacy bookmark gains /// explicit null keys, which readers tolerate. double? anchorLeft, double? anchorTop, double? anchorRight, double? anchorBottom, /// Character index of the selection start in the page's `fullText`, or null /// (tap-fallback / legacy bookmarks). int? charIndex, }) = _Bookmark; factory Bookmark.fromJson(Map json) => _$BookmarkFromJson(json); }