forked from akai/readest
Add a "Highlight Current Sentence" keyboard action (default Shift+M, in the Text to Speech shortcut section) that persists the sentence TTS is reading aloud as a normal highlight using the user's default style/color — no text selection, eyes-off, silent, and idempotent (a repeat press on the same sentence is a no-op rather than a duplicate). Flow: the shortcut handler in useBookShortcuts dispatches tts-highlight-sentence → useTTSControl (which owns the TTSController) resolves the current sentence via the new TTSController.getSpokenSentence() and relays create-tts-highlight → Annotator builds the BookNote with the pure, unit-tested buildTTSSentenceHighlight helper and persists/renders it like any other highlight. Closes #4085 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { HIGHLIGHT_COLOR_HEX } from '@/services/constants';
|
||||
import { BookNote, DEFAULT_HIGHLIGHT_COLORS, HighlightColor } from '@/types/book';
|
||||
import { BookNote, DEFAULT_HIGHLIGHT_COLORS, HighlightColor, HighlightStyle } from '@/types/book';
|
||||
import { uniqueId } from '@/utils/misc';
|
||||
import { SystemSettings } from '@/types/settings';
|
||||
import { FoliateView, NOTE_PREFIX } from '@/types/view';
|
||||
import { Point } from '@/utils/sel';
|
||||
@@ -86,3 +87,38 @@ export function removeBookNoteOverlays(view: FoliateView | null, note: BookNote)
|
||||
view.addAnnotation({ ...note, value: `${NOTE_PREFIX}${note.cfi}` }, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a persistent highlight BookNote for a TTS-spoken sentence, or return
|
||||
* `null` when one already exists at the same CFI (idempotent — pressing the
|
||||
* hotkey twice on the same sentence must not create a duplicate).
|
||||
*
|
||||
* `now` is injected so the result is deterministic for tests. A soft-deleted
|
||||
* note (`deletedAt`) or a non-annotation note (e.g. a bookmark) at the same CFI
|
||||
* does not block creation — it mirrors the live-annotation predicate used by
|
||||
* the selection-based highlight path in Annotator.tsx.
|
||||
*/
|
||||
export function buildTTSSentenceHighlight(
|
||||
annotations: BookNote[],
|
||||
params: {
|
||||
cfi: string;
|
||||
text: string;
|
||||
style: HighlightStyle;
|
||||
color: HighlightColor;
|
||||
page?: number;
|
||||
},
|
||||
now: number,
|
||||
): BookNote | null {
|
||||
const exists = annotations.some(
|
||||
(a) => a.cfi === params.cfi && a.type === 'annotation' && a.style && !a.deletedAt,
|
||||
);
|
||||
if (exists) return null;
|
||||
return {
|
||||
id: uniqueId(),
|
||||
type: 'annotation',
|
||||
note: '',
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
...params,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user