mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-05-31 19:18:26 +01:00
chore
This commit is contained in:
@@ -11,7 +11,7 @@ import { FilterButton } from "@/components/filters/FilterButton";
|
|||||||
import { ResetFiltersButton } from "@/components/filters/ResetFiltersButton";
|
import { ResetFiltersButton } from "@/components/filters/ResetFiltersButton";
|
||||||
import { ItemCardText } from "@/components/ItemCardText";
|
import { ItemCardText } from "@/components/ItemCardText";
|
||||||
import { Loader } from "@/components/Loader";
|
import { Loader } from "@/components/Loader";
|
||||||
import MoviePoster from "@/components/posters/MoviePoster";
|
import { ItemPoster } from "@/components/posters/ItemPoster";
|
||||||
import { apiAtom, userAtom } from "@/providers/JellyfinProvider";
|
import { apiAtom, userAtom } from "@/providers/JellyfinProvider";
|
||||||
import {
|
import {
|
||||||
genreFilterAtom,
|
genreFilterAtom,
|
||||||
@@ -36,7 +36,6 @@ import {
|
|||||||
} from "@jellyfin/sdk/lib/utils/api";
|
} from "@jellyfin/sdk/lib/utils/api";
|
||||||
import { FlashList } from "@shopify/flash-list";
|
import { FlashList } from "@shopify/flash-list";
|
||||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||||
import { ItemPoster } from "@/components/posters/ItemPoster";
|
|
||||||
|
|
||||||
const MemoizedTouchableItemRouter = React.memo(TouchableItemRouter);
|
const MemoizedTouchableItemRouter = React.memo(TouchableItemRouter);
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
import { Text } from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import MoviePoster from "@/components/posters/MoviePoster";
|
import MoviePoster from "@/components/posters/MoviePoster";
|
||||||
|
import { useSettings } from "@/utils/atoms/settings";
|
||||||
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
|
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
|
||||||
|
import {
|
||||||
|
useQuery,
|
||||||
|
type QueryFunction,
|
||||||
|
type QueryKey,
|
||||||
|
} from "@tanstack/react-query";
|
||||||
import { View, ViewProps } from "react-native";
|
import { View, ViewProps } from "react-native";
|
||||||
import ContinueWatchingPoster from "../ContinueWatchingPoster";
|
import ContinueWatchingPoster from "../ContinueWatchingPoster";
|
||||||
import { ItemCardText } from "../ItemCardText";
|
import { ItemCardText } from "../ItemCardText";
|
||||||
import { HorizontalScroll } from "../common/HorrizontalScroll";
|
import { HorizontalScroll } from "../common/HorrizontalScroll";
|
||||||
import { TouchableItemRouter } from "../common/TouchableItemRouter";
|
import { TouchableItemRouter } from "../common/TouchableItemRouter";
|
||||||
import {
|
|
||||||
type QueryKey,
|
|
||||||
useQuery,
|
|
||||||
type QueryFunction,
|
|
||||||
} from "@tanstack/react-query";
|
|
||||||
import SeriesPoster from "../posters/SeriesPoster";
|
import SeriesPoster from "../posters/SeriesPoster";
|
||||||
import { EpisodePoster } from "../posters/EpisodePoster";
|
|
||||||
|
|
||||||
interface Props extends ViewProps {
|
interface Props extends ViewProps {
|
||||||
title?: string | null;
|
title?: string | null;
|
||||||
@@ -32,6 +32,7 @@ export const ScrollingCollectionList: React.FC<Props> = ({
|
|||||||
queryKey,
|
queryKey,
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
|
const [settings] = useSettings();
|
||||||
const { data, isLoading } = useQuery({
|
const { data, isLoading } = useQuery({
|
||||||
queryKey,
|
queryKey,
|
||||||
queryFn,
|
queryFn,
|
||||||
|
|||||||
150
components/settings/MediaToggles.tsx
Normal file
150
components/settings/MediaToggles.tsx
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
import { apiAtom, userAtom } from "@/providers/JellyfinProvider";
|
||||||
|
import {
|
||||||
|
DefaultLanguageOption,
|
||||||
|
DownloadOptions,
|
||||||
|
useSettings,
|
||||||
|
} from "@/utils/atoms/settings";
|
||||||
|
import { getItemsApi } from "@jellyfin/sdk/lib/utils/api";
|
||||||
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
|
import { useAtom } from "jotai";
|
||||||
|
import {
|
||||||
|
Linking,
|
||||||
|
Switch,
|
||||||
|
TouchableOpacity,
|
||||||
|
View,
|
||||||
|
ViewProps,
|
||||||
|
} from "react-native";
|
||||||
|
import * as DropdownMenu from "zeego/dropdown-menu";
|
||||||
|
import { Text } from "../common/Text";
|
||||||
|
import { Loader } from "../Loader";
|
||||||
|
import { Input } from "../common/Input";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { Button } from "../Button";
|
||||||
|
|
||||||
|
const LANGUAGES: DefaultLanguageOption[] = [
|
||||||
|
{ label: "eng", value: "eng" },
|
||||||
|
{
|
||||||
|
label: "sv",
|
||||||
|
value: "sv",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
interface Props extends ViewProps {}
|
||||||
|
|
||||||
|
export const MediaToggles: React.FC<Props> = ({ ...props }) => {
|
||||||
|
const [settings, updateSettings] = useSettings();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<Text className="text-lg font-bold mb-2">Media</Text>
|
||||||
|
<View className="flex flex-col rounded-xl mb-4 overflow-hidden divide-y-2 divide-solid divide-neutral-800">
|
||||||
|
<View
|
||||||
|
className={`
|
||||||
|
flex flex-row items-center space-x-2 justify-between bg-neutral-900 p-4
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<View className="flex flex-col shrink">
|
||||||
|
<Text className="font-semibold">Audio language</Text>
|
||||||
|
<Text className="text-xs opacity-50">
|
||||||
|
Choose a default audio language.
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<DropdownMenu.Root>
|
||||||
|
<DropdownMenu.Trigger>
|
||||||
|
<TouchableOpacity className="bg-neutral-800 rounded-lg border-neutral-900 border px-3 py-2 flex flex-row items-center justify-between">
|
||||||
|
<Text>{settings?.defaultAudioLanguage?.label || "None"}</Text>
|
||||||
|
</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-audio"}
|
||||||
|
onSelect={() => {
|
||||||
|
updateSettings({
|
||||||
|
defaultAudioLanguage: null,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DropdownMenu.ItemTitle>None</DropdownMenu.ItemTitle>
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
{LANGUAGES.map((l) => (
|
||||||
|
<DropdownMenu.Item
|
||||||
|
key={l.value}
|
||||||
|
onSelect={() => {
|
||||||
|
updateSettings({
|
||||||
|
defaultAudioLanguage: l,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DropdownMenu.ItemTitle>{l.label}</DropdownMenu.ItemTitle>
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
))}
|
||||||
|
</DropdownMenu.Content>
|
||||||
|
</DropdownMenu.Root>
|
||||||
|
</View>
|
||||||
|
<View
|
||||||
|
className={`
|
||||||
|
flex flex-row items-center space-x-2 justify-between bg-neutral-900 p-4
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<View className="flex flex-col shrink">
|
||||||
|
<Text className="font-semibold">Subtitle language</Text>
|
||||||
|
<Text className="text-xs opacity-50">
|
||||||
|
Choose a default subtitle language.
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<DropdownMenu.Root>
|
||||||
|
<DropdownMenu.Trigger>
|
||||||
|
<TouchableOpacity className="bg-neutral-800 rounded-lg border-neutral-900 border px-3 py-2 flex flex-row items-center justify-between">
|
||||||
|
<Text>
|
||||||
|
{settings?.defaultSubtitleLanguage?.label || "None"}
|
||||||
|
</Text>
|
||||||
|
</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>
|
||||||
|
{LANGUAGES.map((l) => (
|
||||||
|
<DropdownMenu.Item
|
||||||
|
key={l.value}
|
||||||
|
onSelect={() => {
|
||||||
|
updateSettings({
|
||||||
|
defaultSubtitleLanguage: l,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DropdownMenu.ItemTitle>{l.label}</DropdownMenu.ItemTitle>
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
))}
|
||||||
|
</DropdownMenu.Content>
|
||||||
|
</DropdownMenu.Root>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -14,14 +14,7 @@ import { Loader } from "../Loader";
|
|||||||
import { Input } from "../common/Input";
|
import { Input } from "../common/Input";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Button } from "../Button";
|
import { Button } from "../Button";
|
||||||
|
import { MediaToggles } from "./MediaToggles";
|
||||||
const LANGUAGES: DefaultLanguageOption[] = [
|
|
||||||
{ label: "eng", value: "eng" },
|
|
||||||
{
|
|
||||||
label: "sv",
|
|
||||||
value: "sv",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export const SettingToggles: React.FC = () => {
|
export const SettingToggles: React.FC = () => {
|
||||||
const [settings, updateSettings] = useSettings();
|
const [settings, updateSettings] = useSettings();
|
||||||
@@ -57,117 +50,22 @@ export const SettingToggles: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<View>
|
<View>
|
||||||
<View>
|
{/* <View>
|
||||||
<Text className="text-lg font-bold mb-2">Downloads</Text>
|
<Text className="text-lg font-bold mb-2">Look and feel</Text>
|
||||||
<View className="flex flex-col rounded-xl mb-4 overflow-hidden divide-y-2 divide-solid divide-neutral-800">
|
<View className="flex flex-col rounded-xl mb-4 overflow-hidden divide-y-2 divide-solid divide-neutral-800 opacity-50">
|
||||||
<View
|
<View className="flex flex-row items-center justify-between bg-neutral-900 p-4">
|
||||||
className={`
|
<View className="shrink">
|
||||||
flex flex-row items-center space-x-2 justify-between bg-neutral-900 p-4
|
<Text className="font-semibold">Coming soon</Text>
|
||||||
`}
|
<Text className="text-xs opacity-50 max-w-[90%]">
|
||||||
>
|
Options for changing the look and feel of the app.
|
||||||
<View className="flex flex-col shrink">
|
|
||||||
<Text className="font-semibold">Audio language</Text>
|
|
||||||
<Text className="text-xs opacity-50">
|
|
||||||
Choose a default audio language for downloads.
|
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<DropdownMenu.Root>
|
<Switch disabled />
|
||||||
<DropdownMenu.Trigger>
|
|
||||||
<TouchableOpacity className="bg-neutral-800 rounded-lg border-neutral-900 border px-3 py-2 flex flex-row items-center justify-between">
|
|
||||||
<Text>{settings?.defaultAudioLanguage?.label || "None"}</Text>
|
|
||||||
</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-audio"}
|
|
||||||
onSelect={() => {
|
|
||||||
updateSettings({
|
|
||||||
defaultAudioLanguage: null,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<DropdownMenu.ItemTitle>None</DropdownMenu.ItemTitle>
|
|
||||||
</DropdownMenu.Item>
|
|
||||||
{LANGUAGES.map((l) => (
|
|
||||||
<DropdownMenu.Item
|
|
||||||
key={l.value}
|
|
||||||
onSelect={() => {
|
|
||||||
updateSettings({
|
|
||||||
defaultAudioLanguage: l,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<DropdownMenu.ItemTitle>{l.label}</DropdownMenu.ItemTitle>
|
|
||||||
</DropdownMenu.Item>
|
|
||||||
))}
|
|
||||||
</DropdownMenu.Content>
|
|
||||||
</DropdownMenu.Root>
|
|
||||||
</View>
|
|
||||||
<View
|
|
||||||
className={`
|
|
||||||
flex flex-row items-center space-x-2 justify-between bg-neutral-900 p-4
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<View className="flex flex-col shrink">
|
|
||||||
<Text className="font-semibold">Subtitle language</Text>
|
|
||||||
<Text className="text-xs opacity-50">
|
|
||||||
Choose a default subtitle language for downloads.
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
<DropdownMenu.Root>
|
|
||||||
<DropdownMenu.Trigger>
|
|
||||||
<TouchableOpacity className="bg-neutral-800 rounded-lg border-neutral-900 border px-3 py-2 flex flex-row items-center justify-between">
|
|
||||||
<Text>
|
|
||||||
{settings?.defaultSubtitleLanguage?.label || "None"}
|
|
||||||
</Text>
|
|
||||||
</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>
|
|
||||||
{LANGUAGES.map((l) => (
|
|
||||||
<DropdownMenu.Item
|
|
||||||
key={l.value}
|
|
||||||
onSelect={() => {
|
|
||||||
updateSettings({
|
|
||||||
defaultSubtitleLanguage: l,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<DropdownMenu.ItemTitle>{l.label}</DropdownMenu.ItemTitle>
|
|
||||||
</DropdownMenu.Item>
|
|
||||||
))}
|
|
||||||
</DropdownMenu.Content>
|
|
||||||
</DropdownMenu.Root>
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View> */}
|
||||||
|
|
||||||
|
<MediaToggles />
|
||||||
|
|
||||||
<View>
|
<View>
|
||||||
<Text className="text-lg font-bold mb-2">Other</Text>
|
<Text className="text-lg font-bold mb-2">Other</Text>
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ type Settings = {
|
|||||||
libraryOptions: LibraryOptions;
|
libraryOptions: LibraryOptions;
|
||||||
defaultSubtitleLanguage: DefaultLanguageOption | null;
|
defaultSubtitleLanguage: DefaultLanguageOption | null;
|
||||||
defaultAudioLanguage: DefaultLanguageOption | null;
|
defaultAudioLanguage: DefaultLanguageOption | null;
|
||||||
|
showHomeTitles: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -84,6 +85,7 @@ const loadSettings = async (): Promise<Settings> => {
|
|||||||
},
|
},
|
||||||
defaultAudioLanguage: null,
|
defaultAudioLanguage: null,
|
||||||
defaultSubtitleLanguage: null,
|
defaultSubtitleLanguage: null,
|
||||||
|
showHomeTitles: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user