mirror of
https://github.com/p-stream/p-stream.git
synced 2026-05-10 15:41:03 +00:00
make native subtitles a proper setting
This commit is contained in:
parent
30f0d4ac52
commit
0edb4ece08
6 changed files with 260 additions and 189 deletions
|
|
@ -23,6 +23,7 @@ export interface SettingsInput {
|
||||||
enableSourceOrder?: boolean;
|
enableSourceOrder?: boolean;
|
||||||
proxyTmdb?: boolean;
|
proxyTmdb?: boolean;
|
||||||
enableLowPerformanceMode?: boolean;
|
enableLowPerformanceMode?: boolean;
|
||||||
|
enableNativeSubtitles?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SettingsResponse {
|
export interface SettingsResponse {
|
||||||
|
|
@ -44,6 +45,7 @@ export interface SettingsResponse {
|
||||||
enableSourceOrder?: boolean;
|
enableSourceOrder?: boolean;
|
||||||
proxyTmdb?: boolean;
|
proxyTmdb?: boolean;
|
||||||
enableLowPerformanceMode?: boolean;
|
enableLowPerformanceMode?: boolean;
|
||||||
|
enableNativeSubtitles?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateSettings(
|
export function updateSettings(
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import { Menu } from "@/components/player/internals/ContextMenu";
|
||||||
import { useOverlayRouter } from "@/hooks/useOverlayRouter";
|
import { useOverlayRouter } from "@/hooks/useOverlayRouter";
|
||||||
import { useProgressBar } from "@/hooks/useProgressBar";
|
import { useProgressBar } from "@/hooks/useProgressBar";
|
||||||
import { usePlayerStore } from "@/stores/player/store";
|
import { usePlayerStore } from "@/stores/player/store";
|
||||||
|
import { usePreferencesStore } from "@/stores/preferences";
|
||||||
import { SubtitleStyling, useSubtitleStore } from "@/stores/subtitles";
|
import { SubtitleStyling, useSubtitleStore } from "@/stores/subtitles";
|
||||||
|
|
||||||
export function ColorOption(props: {
|
export function ColorOption(props: {
|
||||||
|
|
@ -229,6 +230,7 @@ export function CaptionSettingsView({
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const router = useOverlayRouter(id);
|
const router = useOverlayRouter(id);
|
||||||
const subtitleStore = useSubtitleStore();
|
const subtitleStore = useSubtitleStore();
|
||||||
|
const preferencesStore = usePreferencesStore();
|
||||||
const styling = subtitleStore.styling;
|
const styling = subtitleStore.styling;
|
||||||
const overrideCasing = subtitleStore.overrideCasing;
|
const overrideCasing = subtitleStore.overrideCasing;
|
||||||
const delay = subtitleStore.delay;
|
const delay = subtitleStore.delay;
|
||||||
|
|
@ -236,12 +238,17 @@ export function CaptionSettingsView({
|
||||||
const setDelay = subtitleStore.setDelay;
|
const setDelay = subtitleStore.setDelay;
|
||||||
const updateStyling = subtitleStore.updateStyling;
|
const updateStyling = subtitleStore.updateStyling;
|
||||||
const setCaptionAsTrack = usePlayerStore((s) => s.setCaptionAsTrack);
|
const setCaptionAsTrack = usePlayerStore((s) => s.setCaptionAsTrack);
|
||||||
const captionAsTrack = usePlayerStore((s) => s.caption.asTrack);
|
const enableNativeSubtitles = preferencesStore.enableNativeSubtitles;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
subtitleStore.updateStyling(styling);
|
subtitleStore.updateStyling(styling);
|
||||||
}, [styling, subtitleStore]);
|
}, [styling, subtitleStore]);
|
||||||
|
|
||||||
|
// Sync preferences with player store
|
||||||
|
useEffect(() => {
|
||||||
|
setCaptionAsTrack(enableNativeSubtitles);
|
||||||
|
}, [enableNativeSubtitles, setCaptionAsTrack]);
|
||||||
|
|
||||||
const handleStylingChange = (newStyling: SubtitleStyling) => {
|
const handleStylingChange = (newStyling: SubtitleStyling) => {
|
||||||
updateStyling(newStyling);
|
updateStyling(newStyling);
|
||||||
};
|
};
|
||||||
|
|
@ -267,7 +274,7 @@ export function CaptionSettingsView({
|
||||||
{t("player.menus.subtitles.settings.backlink")}
|
{t("player.menus.subtitles.settings.backlink")}
|
||||||
</Menu.BackLink>
|
</Menu.BackLink>
|
||||||
<Menu.Section className="space-y-6 pb-5">
|
<Menu.Section className="space-y-6 pb-5">
|
||||||
{!captionAsTrack ? (
|
{!enableNativeSubtitles ? (
|
||||||
<>
|
<>
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<Menu.FieldTitle>
|
<Menu.FieldTitle>
|
||||||
|
|
@ -275,8 +282,12 @@ export function CaptionSettingsView({
|
||||||
</Menu.FieldTitle>
|
</Menu.FieldTitle>
|
||||||
<div className="flex justify-center items-center">
|
<div className="flex justify-center items-center">
|
||||||
<Toggle
|
<Toggle
|
||||||
enabled={captionAsTrack}
|
enabled={enableNativeSubtitles}
|
||||||
onClick={() => setCaptionAsTrack(!captionAsTrack)}
|
onClick={() =>
|
||||||
|
preferencesStore.setEnableNativeSubtitles(
|
||||||
|
!enableNativeSubtitles,
|
||||||
|
)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -478,8 +489,12 @@ export function CaptionSettingsView({
|
||||||
</Menu.FieldTitle>
|
</Menu.FieldTitle>
|
||||||
<div className="flex justify-center items-center">
|
<div className="flex justify-center items-center">
|
||||||
<Toggle
|
<Toggle
|
||||||
enabled={captionAsTrack}
|
enabled={enableNativeSubtitles}
|
||||||
onClick={() => setCaptionAsTrack(!captionAsTrack)}
|
onClick={() =>
|
||||||
|
preferencesStore.setEnableNativeSubtitles(
|
||||||
|
!enableNativeSubtitles,
|
||||||
|
)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,9 @@ export function useAuthData() {
|
||||||
const setEnableLowPerformanceMode = usePreferencesStore(
|
const setEnableLowPerformanceMode = usePreferencesStore(
|
||||||
(s) => s.setEnableLowPerformanceMode,
|
(s) => s.setEnableLowPerformanceMode,
|
||||||
);
|
);
|
||||||
|
const setEnableNativeSubtitles = usePreferencesStore(
|
||||||
|
(s) => s.setEnableNativeSubtitles,
|
||||||
|
);
|
||||||
|
|
||||||
const login = useCallback(
|
const login = useCallback(
|
||||||
async (
|
async (
|
||||||
|
|
@ -164,6 +167,10 @@ export function useAuthData() {
|
||||||
if (settings.enableLowPerformanceMode !== undefined) {
|
if (settings.enableLowPerformanceMode !== undefined) {
|
||||||
setEnableLowPerformanceMode(settings.enableLowPerformanceMode);
|
setEnableLowPerformanceMode(settings.enableLowPerformanceMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (settings.enableNativeSubtitles !== undefined) {
|
||||||
|
setEnableNativeSubtitles(settings.enableNativeSubtitles);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
replaceBookmarks,
|
replaceBookmarks,
|
||||||
|
|
@ -185,6 +192,7 @@ export function useAuthData() {
|
||||||
setProxyTmdb,
|
setProxyTmdb,
|
||||||
setFebboxKey,
|
setFebboxKey,
|
||||||
setEnableLowPerformanceMode,
|
setEnableLowPerformanceMode,
|
||||||
|
setEnableNativeSubtitles,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,8 @@ export function VerifyPassphrase(props: VerifyPassphraseProps) {
|
||||||
enableSourceOrder: store.enableSourceOrder,
|
enableSourceOrder: store.enableSourceOrder,
|
||||||
proxyTmdb: store.proxyTmdb,
|
proxyTmdb: store.proxyTmdb,
|
||||||
febboxKey: store.febboxKey,
|
febboxKey: store.febboxKey,
|
||||||
|
enableLowPerformanceMode: store.enableLowPerformanceMode,
|
||||||
|
enableNativeSubtitles: store.enableNativeSubtitles,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const backendUrl = useBackendUrl();
|
const backendUrl = useBackendUrl();
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ import { Menu } from "@/components/player/internals/ContextMenu";
|
||||||
import { CaptionCue } from "@/components/player/Player";
|
import { CaptionCue } from "@/components/player/Player";
|
||||||
import { Heading1 } from "@/components/utils/Text";
|
import { Heading1 } from "@/components/utils/Text";
|
||||||
import { Transition } from "@/components/utils/Transition";
|
import { Transition } from "@/components/utils/Transition";
|
||||||
|
import { usePlayerStore } from "@/stores/player/store";
|
||||||
|
import { usePreferencesStore } from "@/stores/preferences";
|
||||||
import { SubtitleStyling, useSubtitleStore } from "@/stores/subtitles";
|
import { SubtitleStyling, useSubtitleStore } from "@/stores/subtitles";
|
||||||
|
|
||||||
export function CaptionPreview(props: {
|
export function CaptionPreview(props: {
|
||||||
|
|
@ -86,11 +88,19 @@ export function CaptionsPart(props: {
|
||||||
const [fullscreenPreview, setFullscreenPreview] = useState(false);
|
const [fullscreenPreview, setFullscreenPreview] = useState(false);
|
||||||
|
|
||||||
const subtitleStore = useSubtitleStore();
|
const subtitleStore = useSubtitleStore();
|
||||||
|
const preferencesStore = usePreferencesStore();
|
||||||
|
const setCaptionAsTrack = usePlayerStore((s) => s.setCaptionAsTrack);
|
||||||
|
const enableNativeSubtitles = preferencesStore.enableNativeSubtitles;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
subtitleStore.updateStyling(props.styling);
|
subtitleStore.updateStyling(props.styling);
|
||||||
}, [props.styling, subtitleStore, subtitleStore.updateStyling]);
|
}, [props.styling, subtitleStore, subtitleStore.updateStyling]);
|
||||||
|
|
||||||
|
// Sync preferences with player store
|
||||||
|
useEffect(() => {
|
||||||
|
setCaptionAsTrack(enableNativeSubtitles);
|
||||||
|
}, [enableNativeSubtitles, setCaptionAsTrack]);
|
||||||
|
|
||||||
const handleStylingChange = (newStyling: SubtitleStyling) => {
|
const handleStylingChange = (newStyling: SubtitleStyling) => {
|
||||||
props.setStyling(newStyling);
|
props.setStyling(newStyling);
|
||||||
subtitleStore.updateStyling(newStyling);
|
subtitleStore.updateStyling(newStyling);
|
||||||
|
|
@ -114,203 +124,229 @@ export function CaptionsPart(props: {
|
||||||
<Heading1 border>{t("settings.subtitles.title")}</Heading1>
|
<Heading1 border>{t("settings.subtitles.title")}</Heading1>
|
||||||
<div className="grid md:grid-cols-[1fr,356px] gap-8">
|
<div className="grid md:grid-cols-[1fr,356px] gap-8">
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<CaptionSetting
|
|
||||||
label={t("settings.subtitles.backgroundLabel")}
|
|
||||||
max={100}
|
|
||||||
min={0}
|
|
||||||
onChange={(v) =>
|
|
||||||
handleStylingChange({
|
|
||||||
...props.styling,
|
|
||||||
backgroundOpacity: v / 100,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
value={props.styling.backgroundOpacity * 100}
|
|
||||||
textTransformer={(s) => `${s}%`}
|
|
||||||
/>
|
|
||||||
<CaptionSetting
|
|
||||||
label={t("settings.subtitles.backgroundBlurLabel")}
|
|
||||||
max={100}
|
|
||||||
min={0}
|
|
||||||
onChange={(v) =>
|
|
||||||
handleStylingChange({
|
|
||||||
...props.styling,
|
|
||||||
backgroundBlur: v / 100,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
value={props.styling.backgroundBlur * 100}
|
|
||||||
textTransformer={(s) => `${s}%`}
|
|
||||||
/>
|
|
||||||
<CaptionSetting
|
|
||||||
label={t("settings.subtitles.textSizeLabel")}
|
|
||||||
max={200}
|
|
||||||
min={1}
|
|
||||||
textTransformer={(s) => `${s}%`}
|
|
||||||
onChange={(v) =>
|
|
||||||
handleStylingChange({
|
|
||||||
...props.styling,
|
|
||||||
size: v / 100,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
value={props.styling.size * 100}
|
|
||||||
/>
|
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<Menu.FieldTitle>
|
<Menu.FieldTitle>
|
||||||
{t("settings.subtitles.textStyle.title")}
|
{t("player.menus.subtitles.useNativeSubtitles")}
|
||||||
</Menu.FieldTitle>
|
|
||||||
<div className="w-30">
|
|
||||||
<Dropdown
|
|
||||||
options={[
|
|
||||||
{
|
|
||||||
id: "default",
|
|
||||||
name: t("settings.subtitles.textStyle.default"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "raised",
|
|
||||||
name: t("settings.subtitles.textStyle.raised"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "depressed",
|
|
||||||
name: t("settings.subtitles.textStyle.depressed"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "uniform",
|
|
||||||
name: t("settings.subtitles.textStyle.uniform"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "dropShadow",
|
|
||||||
name: t("settings.subtitles.textStyle.dropShadow"),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
selectedItem={{
|
|
||||||
id: props.styling.fontStyle,
|
|
||||||
name:
|
|
||||||
t(
|
|
||||||
`settings.subtitles.textStyle.${props.styling.fontStyle}`,
|
|
||||||
) || props.styling.fontStyle,
|
|
||||||
}}
|
|
||||||
setSelectedItem={(item) =>
|
|
||||||
handleStylingChange({
|
|
||||||
...props.styling,
|
|
||||||
fontStyle: item.id,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex justify-between items-center">
|
|
||||||
<Menu.FieldTitle>
|
|
||||||
{t("settings.subtitles.textBoldLabel")}
|
|
||||||
</Menu.FieldTitle>
|
</Menu.FieldTitle>
|
||||||
<div className="flex justify-center items-center">
|
<div className="flex justify-center items-center">
|
||||||
<Toggle
|
<Toggle
|
||||||
enabled={props.styling.bold}
|
enabled={enableNativeSubtitles}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
handleStylingChange({
|
preferencesStore.setEnableNativeSubtitles(
|
||||||
...props.styling,
|
!enableNativeSubtitles,
|
||||||
bold: !props.styling.bold,
|
)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between items-center">
|
<span className="text-xs text-type-secondary">
|
||||||
<Menu.FieldTitle>
|
{t("player.menus.subtitles.useNativeSubtitlesDescription")}
|
||||||
{t("settings.subtitles.colorLabel")}
|
</span>
|
||||||
</Menu.FieldTitle>
|
{!enableNativeSubtitles && (
|
||||||
<div className="flex justify-center items-center space-x-2">
|
<>
|
||||||
{colors.map((v) => (
|
<CaptionSetting
|
||||||
<ColorOption
|
label={t("settings.subtitles.backgroundLabel")}
|
||||||
onClick={() =>
|
max={100}
|
||||||
handleStylingChange({
|
min={0}
|
||||||
...props.styling,
|
onChange={(v) =>
|
||||||
color: v,
|
handleStylingChange({
|
||||||
})
|
...props.styling,
|
||||||
}
|
backgroundOpacity: v / 100,
|
||||||
color={v}
|
})
|
||||||
active={props.styling.color === v}
|
}
|
||||||
key={v}
|
value={props.styling.backgroundOpacity * 100}
|
||||||
/>
|
textTransformer={(s) => `${s}%`}
|
||||||
))}
|
/>
|
||||||
<div className="relative">
|
<CaptionSetting
|
||||||
<input
|
label={t("settings.subtitles.backgroundBlurLabel")}
|
||||||
type="color"
|
max={100}
|
||||||
value={props.styling.color}
|
min={0}
|
||||||
onChange={(e) => {
|
onChange={(v) =>
|
||||||
const color = e.target.value;
|
handleStylingChange({
|
||||||
handleStylingChange({ ...props.styling, color });
|
...props.styling,
|
||||||
subtitleStore.updateStyling({
|
backgroundBlur: v / 100,
|
||||||
...props.styling,
|
})
|
||||||
color,
|
}
|
||||||
});
|
value={props.styling.backgroundBlur * 100}
|
||||||
}}
|
textTransformer={(s) => `${s}%`}
|
||||||
className="absolute opacity-0 cursor-pointer w-8 h-8"
|
/>
|
||||||
/>
|
<CaptionSetting
|
||||||
<div style={{ color: props.styling.color }}>
|
label={t("settings.subtitles.textSizeLabel")}
|
||||||
<Icon icon={Icons.BRUSH} className="text-2xl" />
|
max={200}
|
||||||
|
min={1}
|
||||||
|
textTransformer={(s) => `${s}%`}
|
||||||
|
onChange={(v) =>
|
||||||
|
handleStylingChange({
|
||||||
|
...props.styling,
|
||||||
|
size: v / 100,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
value={props.styling.size * 100}
|
||||||
|
/>
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<Menu.FieldTitle>
|
||||||
|
{t("settings.subtitles.textStyle.title")}
|
||||||
|
</Menu.FieldTitle>
|
||||||
|
<div className="w-30">
|
||||||
|
<Dropdown
|
||||||
|
options={[
|
||||||
|
{
|
||||||
|
id: "default",
|
||||||
|
name: t("settings.subtitles.textStyle.default"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "raised",
|
||||||
|
name: t("settings.subtitles.textStyle.raised"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "depressed",
|
||||||
|
name: t("settings.subtitles.textStyle.depressed"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "uniform",
|
||||||
|
name: t("settings.subtitles.textStyle.uniform"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "dropShadow",
|
||||||
|
name: t("settings.subtitles.textStyle.dropShadow"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
selectedItem={{
|
||||||
|
id: props.styling.fontStyle,
|
||||||
|
name:
|
||||||
|
t(
|
||||||
|
`settings.subtitles.textStyle.${props.styling.fontStyle}`,
|
||||||
|
) || props.styling.fontStyle,
|
||||||
|
}}
|
||||||
|
setSelectedItem={(item) =>
|
||||||
|
handleStylingChange({
|
||||||
|
...props.styling,
|
||||||
|
fontStyle: item.id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="flex justify-between items-center">
|
||||||
</div>
|
<Menu.FieldTitle>
|
||||||
<div className="flex justify-between items-center">
|
{t("settings.subtitles.textBoldLabel")}
|
||||||
<Menu.FieldTitle>
|
</Menu.FieldTitle>
|
||||||
{t("settings.subtitles.verticalPositionLabel")}
|
<div className="flex justify-center items-center">
|
||||||
</Menu.FieldTitle>
|
<Toggle
|
||||||
<div className="flex justify-center items-center space-x-2">
|
enabled={props.styling.bold}
|
||||||
<button
|
onClick={() =>
|
||||||
type="button"
|
handleStylingChange({
|
||||||
className={classNames(
|
...props.styling,
|
||||||
"px-3 py-1 rounded transition-colors duration-100",
|
bold: !props.styling.bold,
|
||||||
props.styling.verticalPosition === 3
|
})
|
||||||
? "bg-video-context-buttonFocus"
|
}
|
||||||
: "bg-video-context-buttonFocus bg-opacity-0 hover:bg-opacity-50",
|
/>
|
||||||
)}
|
</div>
|
||||||
onClick={() =>
|
</div>
|
||||||
handleStylingChange({
|
<div className="flex justify-between items-center">
|
||||||
...props.styling,
|
<Menu.FieldTitle>
|
||||||
verticalPosition: 3,
|
{t("settings.subtitles.colorLabel")}
|
||||||
})
|
</Menu.FieldTitle>
|
||||||
}
|
<div className="flex justify-center items-center space-x-2">
|
||||||
|
{colors.map((v) => (
|
||||||
|
<ColorOption
|
||||||
|
onClick={() =>
|
||||||
|
handleStylingChange({
|
||||||
|
...props.styling,
|
||||||
|
color: v,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
color={v}
|
||||||
|
active={props.styling.color === v}
|
||||||
|
key={v}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
<div className="relative">
|
||||||
|
<input
|
||||||
|
type="color"
|
||||||
|
value={props.styling.color}
|
||||||
|
onChange={(e) => {
|
||||||
|
const color = e.target.value;
|
||||||
|
handleStylingChange({ ...props.styling, color });
|
||||||
|
subtitleStore.updateStyling({
|
||||||
|
...props.styling,
|
||||||
|
color,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
className="absolute opacity-0 cursor-pointer w-8 h-8"
|
||||||
|
/>
|
||||||
|
<div style={{ color: props.styling.color }}>
|
||||||
|
<Icon icon={Icons.BRUSH} className="text-2xl" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<Menu.FieldTitle>
|
||||||
|
{t("settings.subtitles.verticalPositionLabel")}
|
||||||
|
</Menu.FieldTitle>
|
||||||
|
<div className="flex justify-center items-center space-x-2">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={classNames(
|
||||||
|
"px-3 py-1 rounded transition-colors duration-100",
|
||||||
|
props.styling.verticalPosition === 3
|
||||||
|
? "bg-video-context-buttonFocus"
|
||||||
|
: "bg-video-context-buttonFocus bg-opacity-0 hover:bg-opacity-50",
|
||||||
|
)}
|
||||||
|
onClick={() =>
|
||||||
|
handleStylingChange({
|
||||||
|
...props.styling,
|
||||||
|
verticalPosition: 3,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{t("settings.subtitles.default")}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={classNames(
|
||||||
|
"px-3 py-1 rounded transition-colors duration-100",
|
||||||
|
props.styling.verticalPosition === 1
|
||||||
|
? "bg-video-context-buttonFocus"
|
||||||
|
: "bg-video-context-buttonFocus bg-opacity-0 hover:bg-opacity-50",
|
||||||
|
)}
|
||||||
|
onClick={() =>
|
||||||
|
handleStylingChange({
|
||||||
|
...props.styling,
|
||||||
|
verticalPosition: 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{t("settings.subtitles.low")}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
className="w-full md:w-auto"
|
||||||
|
theme="secondary"
|
||||||
|
onClick={resetSubStyling}
|
||||||
>
|
>
|
||||||
{t("settings.subtitles.default")}
|
{t("settings.reset")}
|
||||||
</button>
|
</Button>
|
||||||
<button
|
</>
|
||||||
type="button"
|
)}
|
||||||
className={classNames(
|
|
||||||
"px-3 py-1 rounded transition-colors duration-100",
|
|
||||||
props.styling.verticalPosition === 1
|
|
||||||
? "bg-video-context-buttonFocus"
|
|
||||||
: "bg-video-context-buttonFocus bg-opacity-0 hover:bg-opacity-50",
|
|
||||||
)}
|
|
||||||
onClick={() =>
|
|
||||||
handleStylingChange({
|
|
||||||
...props.styling,
|
|
||||||
verticalPosition: 1,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{t("settings.subtitles.low")}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<CaptionPreview
|
{!enableNativeSubtitles && (
|
||||||
show
|
<>
|
||||||
styling={props.styling}
|
<CaptionPreview
|
||||||
onToggle={() => setFullscreenPreview((s) => !s)}
|
show
|
||||||
/>
|
styling={props.styling}
|
||||||
<CaptionPreview
|
onToggle={() => setFullscreenPreview((s) => !s)}
|
||||||
show={fullscreenPreview}
|
/>
|
||||||
fullscreen
|
<CaptionPreview
|
||||||
styling={props.styling}
|
show={fullscreenPreview}
|
||||||
onToggle={() => setFullscreenPreview((s) => !s)}
|
fullscreen
|
||||||
/>
|
styling={props.styling}
|
||||||
<Button
|
onToggle={() => setFullscreenPreview((s) => !s)}
|
||||||
className="w-full md:w-auto"
|
/>
|
||||||
theme="secondary"
|
</>
|
||||||
onClick={resetSubStyling}
|
)}
|
||||||
>
|
|
||||||
{t("settings.reset")}
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ export interface PreferencesStore {
|
||||||
febboxKey: string | null;
|
febboxKey: string | null;
|
||||||
realDebridKey: string | null;
|
realDebridKey: string | null;
|
||||||
enableLowPerformanceMode: boolean;
|
enableLowPerformanceMode: boolean;
|
||||||
|
enableNativeSubtitles: boolean;
|
||||||
|
|
||||||
setEnableThumbnails(v: boolean): void;
|
setEnableThumbnails(v: boolean): void;
|
||||||
setEnableAutoplay(v: boolean): void;
|
setEnableAutoplay(v: boolean): void;
|
||||||
|
|
@ -34,6 +35,7 @@ export interface PreferencesStore {
|
||||||
setFebboxKey(v: string | null): void;
|
setFebboxKey(v: string | null): void;
|
||||||
setRealDebridKey(v: string | null): void;
|
setRealDebridKey(v: string | null): void;
|
||||||
setEnableLowPerformanceMode(v: boolean): void;
|
setEnableLowPerformanceMode(v: boolean): void;
|
||||||
|
setEnableNativeSubtitles(v: boolean): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const usePreferencesStore = create(
|
export const usePreferencesStore = create(
|
||||||
|
|
@ -54,6 +56,7 @@ export const usePreferencesStore = create(
|
||||||
febboxKey: null,
|
febboxKey: null,
|
||||||
realDebridKey: null,
|
realDebridKey: null,
|
||||||
enableLowPerformanceMode: false,
|
enableLowPerformanceMode: false,
|
||||||
|
enableNativeSubtitles: false,
|
||||||
setEnableThumbnails(v) {
|
setEnableThumbnails(v) {
|
||||||
set((s) => {
|
set((s) => {
|
||||||
s.enableThumbnails = v;
|
s.enableThumbnails = v;
|
||||||
|
|
@ -129,6 +132,11 @@ export const usePreferencesStore = create(
|
||||||
s.enableLowPerformanceMode = v;
|
s.enableLowPerformanceMode = v;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
setEnableNativeSubtitles(v) {
|
||||||
|
set((s) => {
|
||||||
|
s.enableNativeSubtitles = v;
|
||||||
|
});
|
||||||
|
},
|
||||||
})),
|
})),
|
||||||
{
|
{
|
||||||
name: "__MW::preferences",
|
name: "__MW::preferences",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue