feat: [StreamyfinPlugin] Subtitle Toggles settings

- Used stepper & dropdown components to simplify page
This commit is contained in:
herrrta
2025-01-10 23:16:58 -05:00
parent 0f974ef2a3
commit 455bf08213
2 changed files with 80 additions and 109 deletions

View File

@@ -1,14 +1,16 @@
import * as DropdownMenu from "zeego/dropdown-menu"; import * as DropdownMenu from "zeego/dropdown-menu";
import {TouchableOpacity, View, ViewProps} from "react-native"; import {TouchableOpacity, View, ViewProps} from "react-native";
import {Text} from "@/components/common/Text"; 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> { interface Props<T> {
data: T[] data: T[]
disabled?: boolean
placeholderText?: string, placeholderText?: string,
keyExtractor: (item: T) => string keyExtractor: (item: T) => string
titleExtractor: (item: T) => string titleExtractor: (item: T) => string | undefined
title: string, title: string | ReactNode,
label: string, label: string,
onSelected: (...item: T[]) => void onSelected: (...item: T[]) => void
multi?: boolean multi?: boolean
@@ -16,6 +18,7 @@ interface Props<T> {
const Dropdown = <T extends unknown>({ const Dropdown = <T extends unknown>({
data, data,
disabled,
placeholderText, placeholderText,
keyExtractor, keyExtractor,
titleExtractor, titleExtractor,
@@ -34,20 +37,30 @@ const Dropdown = <T extends unknown>({
}, [selected]); }, [selected]);
return ( return (
<View {...props}> <DisabledSetting
disabled={disabled === true}
showText={false}
{...props}
>
<DropdownMenu.Root> <DropdownMenu.Root>
<DropdownMenu.Trigger> <DropdownMenu.Trigger>
<View className="flex flex-col"> {typeof title === 'string' ? (
<Text className="opacity-50 mb-1 text-xs"> <View className="flex flex-col">
{title} <Text className="opacity-50 mb-1 text-xs">
</Text> {title}
<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> </Text>
</TouchableOpacity> <TouchableOpacity
</View> 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.Trigger>
<DropdownMenu.Content <DropdownMenu.Content
loop={false} loop={false}
@@ -88,7 +101,7 @@ const Dropdown = <T extends unknown>({
))} ))}
</DropdownMenu.Content> </DropdownMenu.Content>
</DropdownMenu.Root> </DropdownMenu.Root>
</View> </DisabledSetting>
) )
}; };

View File

@@ -7,11 +7,15 @@ import { ListGroup } from "../list/ListGroup";
import { ListItem } from "../list/ListItem"; import { ListItem } from "../list/ListItem";
import { Ionicons } from "@expo/vector-icons"; import { Ionicons } from "@expo/vector-icons";
import { SubtitlePlaybackMode } from "@jellyfin/sdk/lib/generated-client"; 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 {} interface Props extends ViewProps {}
export const SubtitleToggles: React.FC<Props> = ({ ...props }) => { export const SubtitleToggles: React.FC<Props> = ({ ...props }) => {
const media = useMedia(); const media = useMedia();
const [_, __, pluginSettings] = useSettings();
const { settings, updateSettings } = media; const { settings, updateSettings } = media;
const cultures = media.cultures; const cultures = media.cultures;
@@ -36,8 +40,11 @@ export const SubtitleToggles: React.FC<Props> = ({ ...props }) => {
} }
> >
<ListItem title="Subtitle language"> <ListItem title="Subtitle language">
<DropdownMenu.Root> <Dropdown
<DropdownMenu.Trigger> 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"> <TouchableOpacity className="flex flex-row items-center justify-between py-3 pl-3">
<Text className="mr-1 text-[#8E8D91]"> <Text className="mr-1 text-[#8E8D91]">
{settings?.defaultSubtitleLanguage?.DisplayName || "None"} {settings?.defaultSubtitleLanguage?.DisplayName || "None"}
@@ -48,48 +55,28 @@ export const SubtitleToggles: React.FC<Props> = ({ ...props }) => {
color="#5A5960" color="#5A5960"
/> />
</TouchableOpacity> </TouchableOpacity>
</DropdownMenu.Trigger> }
<DropdownMenu.Content label="Languages"
loop={true} onSelected={(defaultSubtitleLanguage) =>
side="bottom" updateSettings({
align="start" defaultSubtitleLanguage: defaultSubtitleLanguage.DisplayName === "None"
alignOffset={0} ? null
avoidCollisions={true} : defaultSubtitleLanguage
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>
</ListItem> </ListItem>
<ListItem title="Subtitle Mode"> <ListItem
<DropdownMenu.Root> title="Subtitle Mode"
<DropdownMenu.Trigger> 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"> <TouchableOpacity className="flex flex-row items-center justify-between py-3 pl-3">
<Text className="mr-1 text-[#8E8D91]"> <Text className="mr-1 text-[#8E8D91]">
{settings?.subtitleMode || "Loading"} {settings?.subtitleMode || "Loading"}
@@ -100,68 +87,39 @@ export const SubtitleToggles: React.FC<Props> = ({ ...props }) => {
color="#5A5960" color="#5A5960"
/> />
</TouchableOpacity> </TouchableOpacity>
</DropdownMenu.Trigger> }
<DropdownMenu.Content label="Subtitle Mode"
loop={true} onSelected={(subtitleMode) =>
side="bottom" updateSettings({subtitleMode})
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>
</ListItem> </ListItem>
<ListItem title="Set Subtitle Track From Previous Item"> <ListItem
title="Set Subtitle Track From Previous Item"
disabled={pluginSettings?.rememberSubtitleSelections?.locked}
>
<Switch <Switch
value={settings.rememberSubtitleSelections} value={settings.rememberSubtitleSelections}
disabled={pluginSettings?.rememberSubtitleSelections?.locked}
onValueChange={(value) => onValueChange={(value) =>
updateSettings({ rememberSubtitleSelections: value }) updateSettings({ rememberSubtitleSelections: value })
} }
/> />
</ListItem> </ListItem>
<ListItem title="Subtitle Size"> <ListItem
<View className="flex flex-row items-center"> title="Subtitle Size"
<TouchableOpacity disabled={pluginSettings?.subtitleSize?.locked}
onPress={() => >
updateSettings({ <Stepper
subtitleSize: Math.max(0, settings.subtitleSize - 5), value={settings.subtitleSize}
}) disabled={pluginSettings?.subtitleSize?.locked}
} step={5}
className="w-8 h-8 bg-neutral-800 rounded-l-lg flex items-center justify-center" min={0}
> max={120}
<Text>-</Text> onUpdate={(subtitleSize) => updateSettings({subtitleSize})}
</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> </ListItem>
</ListGroup> </ListGroup>
</View> </View>