forked from Ninjalama/streamyfin_mirror
feat: [StreamyfinPlugin] Subtitle Toggles settings
- Used stepper & dropdown components to simplify page
This commit is contained in:
@@ -1,14 +1,16 @@
|
||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
||||
import {TouchableOpacity, View, ViewProps} from "react-native";
|
||||
import {Text} from "@/components/common/Text";
|
||||
import React, {PropsWithChildren, useEffect, useState} from "react";
|
||||
import React, {PropsWithChildren, ReactNode, useEffect, useState} from "react";
|
||||
import DisabledSetting from "@/components/settings/DisabledSetting";
|
||||
|
||||
interface Props<T> {
|
||||
data: T[]
|
||||
disabled?: boolean
|
||||
placeholderText?: string,
|
||||
keyExtractor: (item: T) => string
|
||||
titleExtractor: (item: T) => string
|
||||
title: string,
|
||||
titleExtractor: (item: T) => string | undefined
|
||||
title: string | ReactNode,
|
||||
label: string,
|
||||
onSelected: (...item: T[]) => void
|
||||
multi?: boolean
|
||||
@@ -16,6 +18,7 @@ interface Props<T> {
|
||||
|
||||
const Dropdown = <T extends unknown>({
|
||||
data,
|
||||
disabled,
|
||||
placeholderText,
|
||||
keyExtractor,
|
||||
titleExtractor,
|
||||
@@ -34,20 +37,30 @@ const Dropdown = <T extends unknown>({
|
||||
}, [selected]);
|
||||
|
||||
return (
|
||||
<View {...props}>
|
||||
<DisabledSetting
|
||||
disabled={disabled === true}
|
||||
showText={false}
|
||||
{...props}
|
||||
>
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger>
|
||||
<View className="flex flex-col">
|
||||
<Text className="opacity-50 mb-1 text-xs">
|
||||
{title}
|
||||
</Text>
|
||||
<TouchableOpacity
|
||||
className="bg-neutral-900 h-10 rounded-xl border-neutral-800 border px-3 py-2 flex flex-row items-center justify-between">
|
||||
<Text style={{}} className="" numberOfLines={1}>
|
||||
{selected?.length !== undefined ? selected.map(titleExtractor).join(",") : placeholderText}
|
||||
{typeof title === 'string' ? (
|
||||
<View className="flex flex-col">
|
||||
<Text className="opacity-50 mb-1 text-xs">
|
||||
{title}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
className="bg-neutral-900 h-10 rounded-xl border-neutral-800 border px-3 py-2 flex flex-row items-center justify-between">
|
||||
<Text style={{}} className="" numberOfLines={1}>
|
||||
{selected?.length !== undefined ? selected.map(titleExtractor).join(",") : placeholderText}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
) : (
|
||||
<>
|
||||
{title}
|
||||
</>
|
||||
)}
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content
|
||||
loop={false}
|
||||
@@ -88,7 +101,7 @@ const Dropdown = <T extends unknown>({
|
||||
))}
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
</View>
|
||||
</DisabledSetting>
|
||||
)
|
||||
};
|
||||
|
||||
|
||||
@@ -7,11 +7,15 @@ import { ListGroup } from "../list/ListGroup";
|
||||
import { ListItem } from "../list/ListItem";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { SubtitlePlaybackMode } from "@jellyfin/sdk/lib/generated-client";
|
||||
import {useSettings} from "@/utils/atoms/settings";
|
||||
import {Stepper} from "@/components/inputs/Stepper";
|
||||
import Dropdown from "@/components/common/Dropdown";
|
||||
|
||||
interface Props extends ViewProps {}
|
||||
|
||||
export const SubtitleToggles: React.FC<Props> = ({ ...props }) => {
|
||||
const media = useMedia();
|
||||
const [_, __, pluginSettings] = useSettings();
|
||||
const { settings, updateSettings } = media;
|
||||
const cultures = media.cultures;
|
||||
|
||||
@@ -36,8 +40,11 @@ export const SubtitleToggles: React.FC<Props> = ({ ...props }) => {
|
||||
}
|
||||
>
|
||||
<ListItem title="Subtitle language">
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger>
|
||||
<Dropdown
|
||||
data={[{DisplayName: "None", ThreeLetterISOLanguageName: "none-subs" },...(cultures ?? [])]}
|
||||
keyExtractor={(item) => item?.ThreeLetterISOLanguageName ?? "unknown"}
|
||||
titleExtractor={(item) => item?.DisplayName}
|
||||
title={
|
||||
<TouchableOpacity className="flex flex-row items-center justify-between py-3 pl-3">
|
||||
<Text className="mr-1 text-[#8E8D91]">
|
||||
{settings?.defaultSubtitleLanguage?.DisplayName || "None"}
|
||||
@@ -48,48 +55,28 @@ export const SubtitleToggles: React.FC<Props> = ({ ...props }) => {
|
||||
color="#5A5960"
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content
|
||||
loop={true}
|
||||
side="bottom"
|
||||
align="start"
|
||||
alignOffset={0}
|
||||
avoidCollisions={true}
|
||||
collisionPadding={8}
|
||||
sideOffset={8}
|
||||
>
|
||||
<DropdownMenu.Label>Languages</DropdownMenu.Label>
|
||||
<DropdownMenu.Item
|
||||
key={"none-subs"}
|
||||
onSelect={() => {
|
||||
updateSettings({
|
||||
defaultSubtitleLanguage: null,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<DropdownMenu.ItemTitle>None</DropdownMenu.ItemTitle>
|
||||
</DropdownMenu.Item>
|
||||
{cultures?.map((l) => (
|
||||
<DropdownMenu.Item
|
||||
key={l?.ThreeLetterISOLanguageName ?? "unknown"}
|
||||
onSelect={() => {
|
||||
updateSettings({
|
||||
defaultSubtitleLanguage: l,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<DropdownMenu.ItemTitle>
|
||||
{l.DisplayName}
|
||||
</DropdownMenu.ItemTitle>
|
||||
</DropdownMenu.Item>
|
||||
))}
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
}
|
||||
label="Languages"
|
||||
onSelected={(defaultSubtitleLanguage) =>
|
||||
updateSettings({
|
||||
defaultSubtitleLanguage: defaultSubtitleLanguage.DisplayName === "None"
|
||||
? null
|
||||
: defaultSubtitleLanguage
|
||||
})
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
<ListItem title="Subtitle Mode">
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger>
|
||||
<ListItem
|
||||
title="Subtitle Mode"
|
||||
disabled={pluginSettings?.subtitleMode?.locked}
|
||||
>
|
||||
<Dropdown
|
||||
data={subtitleModes}
|
||||
disabled={pluginSettings?.subtitleMode?.locked}
|
||||
keyExtractor={String}
|
||||
titleExtractor={String}
|
||||
title={
|
||||
<TouchableOpacity className="flex flex-row items-center justify-between py-3 pl-3">
|
||||
<Text className="mr-1 text-[#8E8D91]">
|
||||
{settings?.subtitleMode || "Loading"}
|
||||
@@ -100,68 +87,39 @@ export const SubtitleToggles: React.FC<Props> = ({ ...props }) => {
|
||||
color="#5A5960"
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content
|
||||
loop={true}
|
||||
side="bottom"
|
||||
align="start"
|
||||
alignOffset={0}
|
||||
avoidCollisions={true}
|
||||
collisionPadding={8}
|
||||
sideOffset={8}
|
||||
>
|
||||
<DropdownMenu.Label>Subtitle Mode</DropdownMenu.Label>
|
||||
{subtitleModes?.map((l) => (
|
||||
<DropdownMenu.Item
|
||||
key={l}
|
||||
onSelect={() => {
|
||||
updateSettings({
|
||||
subtitleMode: l,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<DropdownMenu.ItemTitle>{l}</DropdownMenu.ItemTitle>
|
||||
</DropdownMenu.Item>
|
||||
))}
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
}
|
||||
label="Subtitle Mode"
|
||||
onSelected={(subtitleMode) =>
|
||||
updateSettings({subtitleMode})
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
<ListItem title="Set Subtitle Track From Previous Item">
|
||||
<ListItem
|
||||
title="Set Subtitle Track From Previous Item"
|
||||
disabled={pluginSettings?.rememberSubtitleSelections?.locked}
|
||||
>
|
||||
<Switch
|
||||
value={settings.rememberSubtitleSelections}
|
||||
disabled={pluginSettings?.rememberSubtitleSelections?.locked}
|
||||
onValueChange={(value) =>
|
||||
updateSettings({ rememberSubtitleSelections: value })
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
<ListItem title="Subtitle Size">
|
||||
<View className="flex flex-row items-center">
|
||||
<TouchableOpacity
|
||||
onPress={() =>
|
||||
updateSettings({
|
||||
subtitleSize: Math.max(0, settings.subtitleSize - 5),
|
||||
})
|
||||
}
|
||||
className="w-8 h-8 bg-neutral-800 rounded-l-lg flex items-center justify-center"
|
||||
>
|
||||
<Text>-</Text>
|
||||
</TouchableOpacity>
|
||||
<Text className="w-12 h-8 bg-neutral-800 px-3 py-2 flex items-center justify-center">
|
||||
{settings.subtitleSize}
|
||||
</Text>
|
||||
<TouchableOpacity
|
||||
className="w-8 h-8 bg-neutral-800 rounded-r-lg flex items-center justify-center"
|
||||
onPress={() =>
|
||||
updateSettings({
|
||||
subtitleSize: Math.min(120, settings.subtitleSize + 5),
|
||||
})
|
||||
}
|
||||
>
|
||||
<Text>+</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<ListItem
|
||||
title="Subtitle Size"
|
||||
disabled={pluginSettings?.subtitleSize?.locked}
|
||||
>
|
||||
<Stepper
|
||||
value={settings.subtitleSize}
|
||||
disabled={pluginSettings?.subtitleSize?.locked}
|
||||
step={5}
|
||||
min={0}
|
||||
max={120}
|
||||
onUpdate={(subtitleSize) => updateSettings({subtitleSize})}
|
||||
/>
|
||||
</ListItem>
|
||||
</ListGroup>
|
||||
</View>
|
||||
|
||||
Reference in New Issue
Block a user