feat(reader): add TTS highlight granularity setting (word or sentence) (#4807)

This commit is contained in:
Huang Xin
2026-06-26 18:48:57 +08:00
committed by GitHub
parent dced42912f
commit 4874eb9ae7
42 changed files with 236 additions and 37 deletions
@@ -6,7 +6,7 @@ import { useResetViewSettings } from '@/hooks/useResetSettings';
import { useTranslation } from '@/hooks/useTranslation';
import { saveViewSettings } from '@/helpers/settings';
import { SettingsPanelPanelProp } from './SettingsDialog';
import { TTSMediaMetadataMode } from '@/services/tts/types';
import { TTSHighlightGranularity, TTSMediaMetadataMode } from '@/services/tts/types';
import { BoxedList, SettingsRow, SettingsSelect } from './primitives';
import TTSHighlightStyleEditor, { TTSHighlightStyle } from './color/TTSHighlightStyleEditor';
@@ -20,6 +20,9 @@ const TTSPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterReset }
const [ttsMediaMetadata, setTtsMediaMetadata] = useState<TTSMediaMetadataMode>(
viewSettings.ttsMediaMetadata ?? 'sentence',
);
const [ttsHighlightGranularity, setTtsHighlightGranularity] = useState<TTSHighlightGranularity>(
viewSettings.ttsHighlightGranularity ?? 'word',
);
const [ttsHighlightStyle, setTtsHighlightStyle] = useState(
viewSettings.ttsHighlightOptions.style,
);
@@ -35,6 +38,9 @@ const TTSPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterReset }
const handleReset = () => {
resetToDefaults({
ttsMediaMetadata: setTtsMediaMetadata as React.Dispatch<React.SetStateAction<string>>,
ttsHighlightGranularity: setTtsHighlightGranularity as React.Dispatch<
React.SetStateAction<string>
>,
});
};
@@ -49,6 +55,19 @@ const TTSPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterReset }
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ttsMediaMetadata]);
useEffect(() => {
if (ttsHighlightGranularity === viewSettings.ttsHighlightGranularity) return;
saveViewSettings(
envConfig,
bookKey,
'ttsHighlightGranularity',
ttsHighlightGranularity,
false,
false,
);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ttsHighlightGranularity]);
const handleTTSStyleChange = (style: TTSHighlightStyle) => {
setTtsHighlightStyle(style);
saveViewSettings(envConfig, bookKey, 'ttsHighlightOptions', {
@@ -76,12 +95,18 @@ const TTSPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterReset }
setTtsMediaMetadata(event.target.value as TTSMediaMetadataMode);
};
const handleTTSGranularityChange = (granularity: TTSHighlightGranularity) => {
setTtsHighlightGranularity(granularity);
};
return (
<div className='my-4 w-full space-y-6'>
<TTSHighlightStyleEditor
granularity={ttsHighlightGranularity}
style={ttsHighlightStyle}
color={ttsHighlightColor}
customColors={customTtsHighlightColors}
onGranularityChange={handleTTSGranularityChange}
onStyleChange={handleTTSStyleChange}
onColorChange={handleTTSColorChange}
onCustomColorsChange={handleCustomTtsColorsChange}
@@ -1,6 +1,7 @@
import React from 'react';
import { MdClose } from 'react-icons/md';
import { useTranslation } from '@/hooks/useTranslation';
import { TTSHighlightGranularity } from '@/services/tts/types';
import { BoxedList, SettingsRow, SettingsSelect } from '../primitives';
import ColorInput from './ColorInput';
@@ -12,18 +13,22 @@ export type TTSHighlightStyle =
| 'outline';
interface TTSHighlightStyleEditorProps {
granularity: TTSHighlightGranularity;
style: TTSHighlightStyle;
color: string;
customColors: string[];
onGranularityChange: (granularity: TTSHighlightGranularity) => void;
onStyleChange: (style: TTSHighlightStyle) => void;
onColorChange: (color: string) => void;
onCustomColorsChange: (colors: string[]) => void;
}
const TTSHighlightStyleEditor: React.FC<TTSHighlightStyleEditorProps> = ({
granularity,
style,
color,
customColors,
onGranularityChange,
onStyleChange,
onColorChange,
onCustomColorsChange,
@@ -60,6 +65,18 @@ const TTSHighlightStyleEditor: React.FC<TTSHighlightStyleEditorProps> = ({
return (
<BoxedList title={_('TTS Highlighting')}>
<SettingsRow label={_('Granularity')}>
<SettingsSelect
value={granularity}
onChange={(e) => onGranularityChange(e.target.value as TTSHighlightGranularity)}
ariaLabel={_('Granularity')}
options={[
{ value: 'word', label: _('Word') },
{ value: 'sentence', label: _('Sentence') },
]}
/>
</SettingsRow>
<SettingsRow label={_('Style')}>
<SettingsSelect
value={style}