forked from akai/readest
fix(tts): scroll more accurately to the highlighted text in TTS when header/footer bars are shown (#2242)
This commit is contained in:
@@ -68,8 +68,8 @@ const SectionInfo: React.FC<SectionInfoProps> = ({
|
||||
}
|
||||
: {
|
||||
top: `${topInset}px`,
|
||||
insetInlineStart: `calc(${horizontalGap / 2}% + ${contentInsets.left}px)`,
|
||||
width: `calc(100% - ${contentInsets.left + contentInsets.right}px)`,
|
||||
paddingInlineStart: `calc(${horizontalGap / 2}% + ${contentInsets.left}px)`,
|
||||
width: '100%',
|
||||
}
|
||||
}
|
||||
>
|
||||
|
||||
@@ -11,7 +11,7 @@ import { BookSearchConfig, BookSearchResult } from '@/types/book';
|
||||
import { useResponsiveSize } from '@/hooks/useResponsiveSize';
|
||||
import { debounce } from '@/utils/debounce';
|
||||
import { isCJKStr } from '@/utils/lang';
|
||||
import { createRejecttFilter } from '@/utils/node';
|
||||
import { createRejectFilter } from '@/utils/node';
|
||||
import Dropdown from '@/components/Dropdown';
|
||||
import SearchOptions from './SearchOptions';
|
||||
|
||||
@@ -127,7 +127,7 @@ const SearchBar: React.FC<SearchBarProps> = ({
|
||||
...searchConfig,
|
||||
index,
|
||||
query: term,
|
||||
acceptNode: createRejecttFilter({
|
||||
acceptNode: createRejectFilter({
|
||||
tags: primaryLang.startsWith('ja') ? ['rt'] : [],
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -208,6 +208,30 @@ const TTSControl: React.FC<TTSControlProps> = ({ bookKey, gridInsets }) => {
|
||||
viewSettings.ttsLocation = cfi || '';
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
}
|
||||
|
||||
if (!view.renderer.scrolled) {
|
||||
view.renderer.scrollToAnchor(range);
|
||||
} else {
|
||||
const rect = range.getBoundingClientRect();
|
||||
const { start, size, viewSize, sideProp } = view.renderer;
|
||||
const positionStart = rect[sideProp === 'height' ? 'y' : 'x'] + viewSettings.marginTopPx;
|
||||
const positionEnd = rect[sideProp === 'height' ? 'height' : 'width'] + positionStart;
|
||||
const offsetStart = view.book.dir === 'rtl' ? viewSize - positionStart : positionStart;
|
||||
const offsetEnd = view.book.dir === 'rtl' ? viewSize - positionEnd : positionEnd;
|
||||
|
||||
const showHeader = viewSettings.showHeader;
|
||||
const showFooter = viewSettings.showFooter;
|
||||
const showBarsOnScroll = viewSettings.showBarsOnScroll;
|
||||
const headerScrollOverlap = showHeader && showBarsOnScroll ? 44 : 0;
|
||||
const footerScrollOverlap = showFooter && showBarsOnScroll ? 44 : 0;
|
||||
const scrollingOverlap = viewSettings.scrollingOverlap;
|
||||
const endInNextView = offsetEnd > start + size - footerScrollOverlap - scrollingOverlap;
|
||||
const startInPrevView = offsetStart < start + headerScrollOverlap + scrollingOverlap;
|
||||
if (endInNextView || startInPrevView) {
|
||||
const scrollTo = offsetStart - headerScrollOverlap - scrollingOverlap;
|
||||
view.renderer.scrollToAnchor(scrollTo / viewSize);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ttsController.addEventListener('tts-speak-mark', handleSpeakMark);
|
||||
|
||||
@@ -3,7 +3,7 @@ import { AppService } from '@/types/system';
|
||||
import { parseSSMLMarks } from '@/utils/ssml';
|
||||
import { Overlayer } from 'foliate-js/overlayer.js';
|
||||
import { TTSGranularity, TTSHighlightOptions, TTSMark, TTSVoice } from './types';
|
||||
import { createRejecttFilter } from '@/utils/node';
|
||||
import { createRejectFilter } from '@/utils/node';
|
||||
import { WebSpeechClient } from './WebSpeechClient';
|
||||
import { NativeTTSClient } from './NativeTTSClient';
|
||||
import { EdgeTTSClient } from './EdgeTTSClient';
|
||||
@@ -85,13 +85,6 @@ export class TTSController extends EventTarget {
|
||||
const { style, color } = options;
|
||||
overlayer?.remove(HIGHLIGHT_KEY);
|
||||
overlayer?.add(HIGHLIGHT_KEY, range, Overlayer[style], { color });
|
||||
const rect = range.getBoundingClientRect();
|
||||
const { start, size, viewSize, sideProp } = this.view.renderer;
|
||||
const position = rect[sideProp === 'height' ? 'y' : 'x'] + 88;
|
||||
const offset = this.view.book.dir === 'rtl' ? viewSize - position : position;
|
||||
if (!this.view.renderer.scrolled || offset < start || offset > start + size) {
|
||||
this.view.renderer.scrollToAnchor(range);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -109,7 +102,7 @@ export class TTSController extends EventTarget {
|
||||
const highlightOptions: TTSHighlightOptions = { style: 'highlight', color: 'gray' };
|
||||
await this.view.initTTS(
|
||||
granularity,
|
||||
createRejecttFilter({
|
||||
createRejectFilter({
|
||||
tags: ['rt', 'sup'],
|
||||
contents: [{ tag: 'a', content: /^\d+$/ }],
|
||||
}),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const createRejecttFilter = ({
|
||||
export const createRejectFilter = ({
|
||||
tags = [],
|
||||
classes = [],
|
||||
attributes = [],
|
||||
|
||||
Reference in New Issue
Block a user