mirror of
https://github.com/streamyfin/streamyfin.git
synced 2025-08-20 18:37:18 +02:00
fix more import for tv
This commit is contained in:
@@ -26,14 +26,18 @@ export default function IndexLayout() {
|
|||||||
headerShadowVisible: false,
|
headerShadowVisible: false,
|
||||||
headerRight: () => (
|
headerRight: () => (
|
||||||
<View className="flex flex-row items-center space-x-2">
|
<View className="flex flex-row items-center space-x-2">
|
||||||
{!Platform.isTV && <Chromecast />}
|
{!Platform.isTV && (
|
||||||
<TouchableOpacity
|
<>
|
||||||
onPress={() => {
|
<Chromecast />
|
||||||
router.push("/(auth)/settings");
|
<TouchableOpacity
|
||||||
}}
|
onPress={() => {
|
||||||
>
|
router.push("/(auth)/settings");
|
||||||
<Feather name="settings" color={"white"} size={22} />
|
}}
|
||||||
</TouchableOpacity>
|
>
|
||||||
|
<Feather name="settings" color={"white"} size={22} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { Feather, Ionicons } from "@expo/vector-icons";
|
|||||||
import { Image } from "expo-image";
|
import { Image } from "expo-image";
|
||||||
import { useFocusEffect, useRouter } from "expo-router";
|
import { useFocusEffect, useRouter } from "expo-router";
|
||||||
import { useCallback } from "react";
|
import { useCallback } from "react";
|
||||||
import {useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Linking, TouchableOpacity, View } from "react-native";
|
import { Linking, TouchableOpacity, View } from "react-native";
|
||||||
|
|
||||||
export default function page() {
|
export default function page() {
|
||||||
@@ -30,10 +30,10 @@ export default function page() {
|
|||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View>
|
<View>
|
||||||
<Text className="text-lg font-bold">{t("home.intro.features_title")}</Text>
|
<Text className="text-lg font-bold">
|
||||||
<Text className="text-xs">
|
{t("home.intro.features_title")}
|
||||||
{t("home.intro.features_description")}
|
|
||||||
</Text>
|
</Text>
|
||||||
|
<Text className="text-xs">{t("home.intro.features_description")}</Text>
|
||||||
<View className="flex flex-row items-center mt-4">
|
<View className="flex flex-row items-center mt-4">
|
||||||
<Image
|
<Image
|
||||||
source={require("@/assets/icons/jellyseerr-logo.svg")}
|
source={require("@/assets/icons/jellyseerr-logo.svg")}
|
||||||
@@ -60,7 +60,9 @@ export default function page() {
|
|||||||
<Ionicons name="cloud-download-outline" size={32} color="white" />
|
<Ionicons name="cloud-download-outline" size={32} color="white" />
|
||||||
</View>
|
</View>
|
||||||
<View className="shrink ml-2">
|
<View className="shrink ml-2">
|
||||||
<Text className="font-bold mb-1">{t("home.intro.downloads_feature_title")}</Text>
|
<Text className="font-bold mb-1">
|
||||||
|
{t("home.intro.downloads_feature_title")}
|
||||||
|
</Text>
|
||||||
<Text className="shrink text-xs">
|
<Text className="shrink text-xs">
|
||||||
{t("home.intro.downloads_feature_description")}
|
{t("home.intro.downloads_feature_description")}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -94,7 +96,9 @@ export default function page() {
|
|||||||
<Feather name="settings" size={28} color={"white"} />
|
<Feather name="settings" size={28} color={"white"} />
|
||||||
</View>
|
</View>
|
||||||
<View className="shrink ml-2">
|
<View className="shrink ml-2">
|
||||||
<Text className="font-bold mb-1">{t("home.intro.centralised_settings_plugin_title")}</Text>
|
<Text className="font-bold mb-1">
|
||||||
|
{t("home.intro.centralised_settings_plugin_title")}
|
||||||
|
</Text>
|
||||||
<Text className="shrink text-xs">
|
<Text className="shrink text-xs">
|
||||||
{t("home.intro.centralised_settings_plugin_description")}{" "}
|
{t("home.intro.centralised_settings_plugin_description")}{" "}
|
||||||
<Text
|
<Text
|
||||||
@@ -127,7 +131,9 @@ export default function page() {
|
|||||||
}}
|
}}
|
||||||
className="mt-4"
|
className="mt-4"
|
||||||
>
|
>
|
||||||
<Text className="text-purple-600 text-center">{t("home.intro.go_to_settings_button")}</Text>
|
<Text className="text-purple-600 text-center">
|
||||||
|
{t("home.intro.go_to_settings_button")}
|
||||||
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -36,9 +36,9 @@ import React, {
|
|||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { TouchableOpacity, View } from "react-native";
|
import { Platform, TouchableOpacity, View } from "react-native";
|
||||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
const DropdownMenu = !Platform.isTV ? require("zeego/dropdown-menu") : null;
|
||||||
import RequestModal from "@/components/jellyseerr/RequestModal";
|
import RequestModal from "@/components/jellyseerr/RequestModal";
|
||||||
import { ANIME_KEYWORD_ID } from "@/utils/jellyseerr/server/api/themoviedb/constants";
|
import { ANIME_KEYWORD_ID } from "@/utils/jellyseerr/server/api/themoviedb/constants";
|
||||||
import { MediaRequestBody } from "@/utils/jellyseerr/server/interfaces/api/requestInterfaces";
|
import { MediaRequestBody } from "@/utils/jellyseerr/server/interfaces/api/requestInterfaces";
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { MediaSourceInfo } from "@jellyfin/sdk/lib/generated-client/models";
|
import { MediaSourceInfo } from "@jellyfin/sdk/lib/generated-client/models";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { TouchableOpacity, View } from "react-native";
|
import { Platform, TouchableOpacity, View } from "react-native";
|
||||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
const DropdownMenu = !Platform.isTV ? require("zeego/dropdown-menu") : null;
|
||||||
import { Text } from "./common/Text";
|
import { Text } from "./common/Text";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
@@ -17,6 +17,7 @@ export const AudioTrackSelector: React.FC<Props> = ({
|
|||||||
selected,
|
selected,
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
|
if (Platform.isTV) return null;
|
||||||
const audioStreams = useMemo(
|
const audioStreams = useMemo(
|
||||||
() => source?.MediaStreams?.filter((x) => x.Type === "Audio"),
|
() => source?.MediaStreams?.filter((x) => x.Type === "Audio"),
|
||||||
[source]
|
[source]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { TouchableOpacity, View } from "react-native";
|
import { Platform, TouchableOpacity, View } from "react-native";
|
||||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
const DropdownMenu = !Platform.isTV ? require("zeego/dropdown-menu") : null;
|
||||||
import { Text } from "./common/Text";
|
import { Text } from "./common/Text";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -54,6 +54,7 @@ export const BitrateSelector: React.FC<Props> = ({
|
|||||||
inverted,
|
inverted,
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
|
if (Platform.isTV) return null;
|
||||||
const sorted = useMemo(() => {
|
const sorted = useMemo(() => {
|
||||||
if (inverted)
|
if (inverted)
|
||||||
return BITRATES.sort(
|
return BITRATES.sort(
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import {
|
|||||||
MediaSourceInfo,
|
MediaSourceInfo,
|
||||||
} from "@jellyfin/sdk/lib/generated-client/models";
|
} from "@jellyfin/sdk/lib/generated-client/models";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { TouchableOpacity, View } from "react-native";
|
import { Platform, TouchableOpacity, View } from "react-native";
|
||||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
const DropdownMenu = !Platform.isTV ? require("zeego/dropdown-menu") : null;
|
||||||
import { Text } from "./common/Text";
|
import { Text } from "./common/Text";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
@@ -20,6 +20,7 @@ export const MediaSourceSelector: React.FC<Props> = ({
|
|||||||
selected,
|
selected,
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
|
if (Platform.isTV) return null;
|
||||||
const selectedName = useMemo(
|
const selectedName = useMemo(
|
||||||
() =>
|
() =>
|
||||||
item.MediaSources?.find((x) => x.Id === selected?.Id)?.MediaStreams?.find(
|
item.MediaSources?.find((x) => x.Id === selected?.Id)?.MediaStreams?.find(
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { tc } from "@/utils/textTools";
|
|||||||
import { MediaSourceInfo } from "@jellyfin/sdk/lib/generated-client/models";
|
import { MediaSourceInfo } from "@jellyfin/sdk/lib/generated-client/models";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { Platform, TouchableOpacity, View } from "react-native";
|
import { Platform, TouchableOpacity, View } from "react-native";
|
||||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
const DropdownMenu = !Platform.isTV ? require("zeego/dropdown-menu") : null;
|
||||||
import { Text } from "./common/Text";
|
import { Text } from "./common/Text";
|
||||||
import { SubtitleHelper } from "@/utils/SubtitleHelper";
|
import { SubtitleHelper } from "@/utils/SubtitleHelper";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -21,6 +21,7 @@ export const SubtitleTrackSelector: React.FC<Props> = ({
|
|||||||
isTranscoding,
|
isTranscoding,
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
|
if (Platform.isTV) return null;
|
||||||
const subtitleStreams = useMemo(() => {
|
const subtitleStreams = useMemo(() => {
|
||||||
const subtitleHelper = new SubtitleHelper(source?.MediaStreams ?? []);
|
const subtitleHelper = new SubtitleHelper(source?.MediaStreams ?? []);
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,27 @@
|
|||||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
const DropdownMenu = !Platform.isTV ? require("zeego/dropdown-menu") : null;
|
||||||
import {TouchableOpacity, View, ViewProps} from "react-native";
|
import { Platform, TouchableOpacity, View, ViewProps } from "react-native";
|
||||||
import {Text} from "@/components/common/Text";
|
import { Text } from "@/components/common/Text";
|
||||||
import React, {PropsWithChildren, ReactNode, useEffect, useState} from "react";
|
import React, {
|
||||||
|
PropsWithChildren,
|
||||||
|
ReactNode,
|
||||||
|
useEffect,
|
||||||
|
useState,
|
||||||
|
} from "react";
|
||||||
import DisabledSetting from "@/components/settings/DisabledSetting";
|
import DisabledSetting from "@/components/settings/DisabledSetting";
|
||||||
|
|
||||||
interface Props<T> {
|
interface Props<T> {
|
||||||
data: T[]
|
data: T[];
|
||||||
disabled?: boolean
|
disabled?: boolean;
|
||||||
placeholderText?: string,
|
placeholderText?: string;
|
||||||
keyExtractor: (item: T) => string
|
keyExtractor: (item: T) => string;
|
||||||
titleExtractor: (item: T) => string | undefined
|
titleExtractor: (item: T) => string | undefined;
|
||||||
title: string | ReactNode,
|
title: string | ReactNode;
|
||||||
label: string,
|
label: string;
|
||||||
onSelected: (...item: T[]) => void
|
onSelected: (...item: T[]) => void;
|
||||||
multi?: boolean
|
multi?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Dropdown = <T extends unknown>({
|
const Dropdown = <T extends unknown>({
|
||||||
data,
|
data,
|
||||||
disabled,
|
disabled,
|
||||||
placeholderText,
|
placeholderText,
|
||||||
@@ -28,38 +33,32 @@ const Dropdown = <T extends unknown>({
|
|||||||
multi = false,
|
multi = false,
|
||||||
...props
|
...props
|
||||||
}: PropsWithChildren<Props<T> & ViewProps>) => {
|
}: PropsWithChildren<Props<T> & ViewProps>) => {
|
||||||
|
if (Platform.isTV) return null;
|
||||||
const [selected, setSelected] = useState<T[]>();
|
const [selected, setSelected] = useState<T[]>();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selected !== undefined) {
|
if (selected !== undefined) {
|
||||||
onSelected(...selected)
|
onSelected(...selected);
|
||||||
}
|
}
|
||||||
}, [selected]);
|
}, [selected]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DisabledSetting
|
<DisabledSetting disabled={disabled === true} showText={false} {...props}>
|
||||||
disabled={disabled === true}
|
|
||||||
showText={false}
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
<DropdownMenu.Root>
|
<DropdownMenu.Root>
|
||||||
<DropdownMenu.Trigger>
|
<DropdownMenu.Trigger>
|
||||||
{typeof title === 'string' ? (
|
{typeof title === "string" ? (
|
||||||
<View className="flex flex-col">
|
<View className="flex flex-col">
|
||||||
<Text className="opacity-50 mb-1 text-xs">
|
<Text className="opacity-50 mb-1 text-xs">{title}</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>
|
|
||||||
<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}>
|
<Text style={{}} className="" numberOfLines={1}>
|
||||||
{selected?.length !== undefined ? selected.map(titleExtractor).join(",") : placeholderText}
|
{selected?.length !== undefined
|
||||||
|
? selected.map(titleExtractor).join(",")
|
||||||
|
: placeholderText}
|
||||||
</Text>
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>{title}</>
|
||||||
{title}
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
</DropdownMenu.Trigger>
|
</DropdownMenu.Trigger>
|
||||||
<DropdownMenu.Content
|
<DropdownMenu.Content
|
||||||
@@ -72,37 +71,48 @@ const Dropdown = <T extends unknown>({
|
|||||||
sideOffset={0}
|
sideOffset={0}
|
||||||
>
|
>
|
||||||
<DropdownMenu.Label>{label}</DropdownMenu.Label>
|
<DropdownMenu.Label>{label}</DropdownMenu.Label>
|
||||||
{data.map((item, idx) => (
|
{data.map((item, idx) =>
|
||||||
multi ? (
|
multi ? (
|
||||||
<DropdownMenu.CheckboxItem
|
<DropdownMenu.CheckboxItem
|
||||||
value={selected?.some(s => keyExtractor(s) == keyExtractor(item)) ? 'on' : 'off'}
|
value={
|
||||||
key={keyExtractor(item)}
|
selected?.some((s) => keyExtractor(s) == keyExtractor(item))
|
||||||
onValueChange={(next, previous) =>
|
? "on"
|
||||||
setSelected((p) => {
|
: "off"
|
||||||
const prev = p || []
|
}
|
||||||
if (next == 'on') {
|
key={keyExtractor(item)}
|
||||||
return [...prev, item]
|
onValueChange={(next, previous) =>
|
||||||
}
|
setSelected((p) => {
|
||||||
return [...prev.filter(p => keyExtractor(p) !== keyExtractor(item))]
|
const prev = p || [];
|
||||||
})
|
if (next == "on") {
|
||||||
}
|
return [...prev, item];
|
||||||
>
|
}
|
||||||
<DropdownMenu.ItemTitle>{titleExtractor(item)}</DropdownMenu.ItemTitle>
|
return [
|
||||||
</DropdownMenu.CheckboxItem>
|
...prev.filter(
|
||||||
)
|
(p) => keyExtractor(p) !== keyExtractor(item)
|
||||||
: (
|
),
|
||||||
<DropdownMenu.Item
|
];
|
||||||
key={keyExtractor(item)}
|
})
|
||||||
onSelect={() => setSelected([item])}
|
}
|
||||||
>
|
>
|
||||||
<DropdownMenu.ItemTitle>{titleExtractor(item)}</DropdownMenu.ItemTitle>
|
<DropdownMenu.ItemTitle>
|
||||||
</DropdownMenu.Item>
|
{titleExtractor(item)}
|
||||||
)
|
</DropdownMenu.ItemTitle>
|
||||||
))}
|
</DropdownMenu.CheckboxItem>
|
||||||
|
) : (
|
||||||
|
<DropdownMenu.Item
|
||||||
|
key={keyExtractor(item)}
|
||||||
|
onSelect={() => setSelected([item])}
|
||||||
|
>
|
||||||
|
<DropdownMenu.ItemTitle>
|
||||||
|
{titleExtractor(item)}
|
||||||
|
</DropdownMenu.ItemTitle>
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
)
|
||||||
|
)}
|
||||||
</DropdownMenu.Content>
|
</DropdownMenu.Content>
|
||||||
</DropdownMenu.Root>
|
</DropdownMenu.Root>
|
||||||
</DisabledSetting>
|
</DisabledSetting>
|
||||||
)
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Dropdown;
|
export default Dropdown;
|
||||||
@@ -7,7 +7,7 @@ import { useRouter, useSegments } from "expo-router";
|
|||||||
import { PropsWithChildren, useCallback } from "react";
|
import { PropsWithChildren, useCallback } from "react";
|
||||||
import { TouchableOpacity, TouchableOpacityProps } from "react-native";
|
import { TouchableOpacity, TouchableOpacityProps } from "react-native";
|
||||||
import { useActionSheet } from "@expo/react-native-action-sheet";
|
import { useActionSheet } from "@expo/react-native-action-sheet";
|
||||||
import * as Haptics from "expo-haptics";
|
import { useHaptic } from "@/hooks/useHaptic";
|
||||||
|
|
||||||
interface Props extends TouchableOpacityProps {
|
interface Props extends TouchableOpacityProps {
|
||||||
item: BaseItemDto;
|
item: BaseItemDto;
|
||||||
@@ -74,10 +74,10 @@ export const TouchableItemRouter: React.FC<PropsWithChildren<Props>> = ({
|
|||||||
async (selectedIndex) => {
|
async (selectedIndex) => {
|
||||||
if (selectedIndex === 0) {
|
if (selectedIndex === 0) {
|
||||||
await markAsPlayedStatus(true);
|
await markAsPlayedStatus(true);
|
||||||
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
|
// Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
|
||||||
} else if (selectedIndex === 1) {
|
} else if (selectedIndex === 1) {
|
||||||
await markAsPlayedStatus(false);
|
await markAsPlayedStatus(false);
|
||||||
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
|
// Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
|
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
|
||||||
import { useEffect, useMemo } from "react";
|
import { useEffect, useMemo } from "react";
|
||||||
import { TouchableOpacity, View } from "react-native";
|
import { Platform, TouchableOpacity, View } from "react-native";
|
||||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
const DropdownMenu = !Platform.isTV ? require("zeego/dropdown-menu") : null;
|
||||||
import { Text } from "../common/Text";
|
import { Text } from "../common/Text";
|
||||||
import { t } from "i18next";
|
import { t } from "i18next";
|
||||||
|
|
||||||
@@ -30,6 +30,8 @@ export const SeasonDropdown: React.FC<Props> = ({
|
|||||||
state,
|
state,
|
||||||
onSelect,
|
onSelect,
|
||||||
}) => {
|
}) => {
|
||||||
|
if (Platform.isTV) return null;
|
||||||
|
|
||||||
const keys = useMemo<SeasonKeys>(
|
const keys = useMemo<SeasonKeys>(
|
||||||
() =>
|
() =>
|
||||||
item.Type === "Episode"
|
item.Type === "Episode"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
const DropdownMenu = !Platform.isTV ? require("zeego/dropdown-menu") : null;
|
||||||
import { Platform, TouchableOpacity, View, ViewProps } from "react-native";
|
import { Platform, TouchableOpacity, View, ViewProps } from "react-native";
|
||||||
import { Text } from "../common/Text";
|
import { Text } from "../common/Text";
|
||||||
import { useSettings } from "@/utils/atoms/settings";
|
import { useSettings } from "@/utils/atoms/settings";
|
||||||
@@ -10,14 +10,12 @@ import { APP_LANGUAGES } from "@/i18n";
|
|||||||
interface Props extends ViewProps {}
|
interface Props extends ViewProps {}
|
||||||
|
|
||||||
export const AppLanguageSelector: React.FC<Props> = ({ ...props }) => {
|
export const AppLanguageSelector: React.FC<Props> = ({ ...props }) => {
|
||||||
|
if (Platform.isTV) return null;
|
||||||
const [settings, updateSettings] = useSettings();
|
const [settings, updateSettings] = useSettings();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
if (!settings) return null;
|
if (!settings) return null;
|
||||||
|
|
||||||
// todo: fix
|
|
||||||
if (Platform.isTV) return null;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View>
|
<View>
|
||||||
<ListGroup title={t("home.settings.languages.title")}>
|
<ListGroup title={t("home.settings.languages.title")}>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { TouchableOpacity, View, ViewProps } from "react-native";
|
import { Platform, TouchableOpacity, View, ViewProps } from "react-native";
|
||||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
const DropdownMenu = !Platform.isTV ? require("zeego/dropdown-menu") : null;
|
||||||
import { Text } from "../common/Text";
|
import { Text } from "../common/Text";
|
||||||
import { useMedia } from "./MediaContext";
|
import { useMedia } from "./MediaContext";
|
||||||
import { Switch } from "react-native-gesture-handler";
|
import { Switch } from "react-native-gesture-handler";
|
||||||
@@ -12,6 +12,7 @@ import { useSettings } from "@/utils/atoms/settings";
|
|||||||
interface Props extends ViewProps {}
|
interface Props extends ViewProps {}
|
||||||
|
|
||||||
export const AudioToggles: React.FC<Props> = ({ ...props }) => {
|
export const AudioToggles: React.FC<Props> = ({ ...props }) => {
|
||||||
|
if (Platform.isTV) return null;
|
||||||
const media = useMedia();
|
const media = useMedia();
|
||||||
const [_, __, pluginSettings] = useSettings();
|
const [_, __, pluginSettings] = useSettings();
|
||||||
const { settings, updateSettings } = media;
|
const { settings, updateSettings } = media;
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import { Ionicons } from "@expo/vector-icons";
|
|||||||
import { useQueryClient } from "@tanstack/react-query";
|
import { useQueryClient } from "@tanstack/react-query";
|
||||||
import { useRouter } from "expo-router";
|
import { useRouter } from "expo-router";
|
||||||
import React, { useMemo } from "react";
|
import React, { useMemo } from "react";
|
||||||
import { Switch, TouchableOpacity } from "react-native";
|
import { Platform, Switch, TouchableOpacity } from "react-native";
|
||||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
const DropdownMenu = !Platform.isTV ? require("zeego/dropdown-menu") : null;
|
||||||
import { Text } from "../common/Text";
|
import { Text } from "../common/Text";
|
||||||
import { ListGroup } from "../list/ListGroup";
|
import { ListGroup } from "../list/ListGroup";
|
||||||
import { ListItem } from "../list/ListItem";
|
import { ListItem } from "../list/ListItem";
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { TouchableOpacity, View, ViewProps } from "react-native";
|
import { Platform, TouchableOpacity, View, ViewProps } from "react-native";
|
||||||
import * as DropdownMenu from "@/components/DropdownMenu";
|
const DropdownMenu = !Platform.isTV ? require("zeego/dropdown-menu") : null;
|
||||||
import { Text } from "../common/Text";
|
import { Text } from "../common/Text";
|
||||||
import { useMedia } from "./MediaContext";
|
import { useMedia } from "./MediaContext";
|
||||||
import { Switch } from "react-native-gesture-handler";
|
import { Switch } from "react-native-gesture-handler";
|
||||||
@@ -8,13 +8,14 @@ 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 { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import {useSettings} from "@/utils/atoms/settings";
|
import { useSettings } from "@/utils/atoms/settings";
|
||||||
import {Stepper} from "@/components/inputs/Stepper";
|
import { Stepper } from "@/components/inputs/Stepper";
|
||||||
import Dropdown from "@/components/common/Dropdown";
|
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 }) => {
|
||||||
|
if (Platform.isTV) return null;
|
||||||
const media = useMedia();
|
const media = useMedia();
|
||||||
const [_, __, pluginSettings] = useSettings();
|
const [_, __, pluginSettings] = useSettings();
|
||||||
const { settings, updateSettings } = media;
|
const { settings, updateSettings } = media;
|
||||||
@@ -34,7 +35,8 @@ export const SubtitleToggles: React.FC<Props> = ({ ...props }) => {
|
|||||||
const subtitleModeKeys = {
|
const subtitleModeKeys = {
|
||||||
[SubtitlePlaybackMode.Default]: "home.settings.subtitles.modes.Default",
|
[SubtitlePlaybackMode.Default]: "home.settings.subtitles.modes.Default",
|
||||||
[SubtitlePlaybackMode.Smart]: "home.settings.subtitles.modes.Smart",
|
[SubtitlePlaybackMode.Smart]: "home.settings.subtitles.modes.Smart",
|
||||||
[SubtitlePlaybackMode.OnlyForced]: "home.settings.subtitles.modes.OnlyForced",
|
[SubtitlePlaybackMode.OnlyForced]:
|
||||||
|
"home.settings.subtitles.modes.OnlyForced",
|
||||||
[SubtitlePlaybackMode.Always]: "home.settings.subtitles.modes.Always",
|
[SubtitlePlaybackMode.Always]: "home.settings.subtitles.modes.Always",
|
||||||
[SubtitlePlaybackMode.None]: "home.settings.subtitles.modes.None",
|
[SubtitlePlaybackMode.None]: "home.settings.subtitles.modes.None",
|
||||||
};
|
};
|
||||||
@@ -51,13 +53,22 @@ export const SubtitleToggles: React.FC<Props> = ({ ...props }) => {
|
|||||||
>
|
>
|
||||||
<ListItem title={t("home.settings.subtitles.subtitle_language")}>
|
<ListItem title={t("home.settings.subtitles.subtitle_language")}>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
data={[{DisplayName: t("home.settings.subtitles.none"), ThreeLetterISOLanguageName: "none-subs" },...(cultures ?? [])]}
|
data={[
|
||||||
keyExtractor={(item) => item?.ThreeLetterISOLanguageName ?? "unknown"}
|
{
|
||||||
|
DisplayName: t("home.settings.subtitles.none"),
|
||||||
|
ThreeLetterISOLanguageName: "none-subs",
|
||||||
|
},
|
||||||
|
...(cultures ?? []),
|
||||||
|
]}
|
||||||
|
keyExtractor={(item) =>
|
||||||
|
item?.ThreeLetterISOLanguageName ?? "unknown"
|
||||||
|
}
|
||||||
titleExtractor={(item) => item?.DisplayName}
|
titleExtractor={(item) => item?.DisplayName}
|
||||||
title={
|
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 || t("home.settings.subtitles.none")}
|
{settings?.defaultSubtitleLanguage?.DisplayName ||
|
||||||
|
t("home.settings.subtitles.none")}
|
||||||
</Text>
|
</Text>
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name="chevron-expand-sharp"
|
name="chevron-expand-sharp"
|
||||||
@@ -69,11 +80,13 @@ export const SubtitleToggles: React.FC<Props> = ({ ...props }) => {
|
|||||||
label={t("home.settings.subtitles.language")}
|
label={t("home.settings.subtitles.language")}
|
||||||
onSelected={(defaultSubtitleLanguage) =>
|
onSelected={(defaultSubtitleLanguage) =>
|
||||||
updateSettings({
|
updateSettings({
|
||||||
defaultSubtitleLanguage: defaultSubtitleLanguage.DisplayName === t("home.settings.subtitles.none")
|
defaultSubtitleLanguage:
|
||||||
? null
|
defaultSubtitleLanguage.DisplayName ===
|
||||||
: defaultSubtitleLanguage
|
t("home.settings.subtitles.none")
|
||||||
|
? null
|
||||||
|
: defaultSubtitleLanguage,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
|
||||||
@@ -89,7 +102,8 @@ export const SubtitleToggles: React.FC<Props> = ({ ...props }) => {
|
|||||||
title={
|
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]">
|
||||||
{t(subtitleModeKeys[settings?.subtitleMode]) || t("home.settings.subtitles.loading")}
|
{t(subtitleModeKeys[settings?.subtitleMode]) ||
|
||||||
|
t("home.settings.subtitles.loading")}
|
||||||
</Text>
|
</Text>
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name="chevron-expand-sharp"
|
name="chevron-expand-sharp"
|
||||||
@@ -99,9 +113,7 @@ export const SubtitleToggles: React.FC<Props> = ({ ...props }) => {
|
|||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
}
|
}
|
||||||
label={t("home.settings.subtitles.subtitle_mode")}
|
label={t("home.settings.subtitles.subtitle_mode")}
|
||||||
onSelected={(subtitleMode) =>
|
onSelected={(subtitleMode) => updateSettings({ subtitleMode })}
|
||||||
updateSettings({subtitleMode})
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
|
||||||
@@ -128,7 +140,7 @@ export const SubtitleToggles: React.FC<Props> = ({ ...props }) => {
|
|||||||
step={5}
|
step={5}
|
||||||
min={0}
|
min={0}
|
||||||
max={120}
|
max={120}
|
||||||
onUpdate={(subtitleSize) => updateSettings({subtitleSize})}
|
onUpdate={(subtitleSize) => updateSettings({ subtitleSize })}
|
||||||
/>
|
/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</ListGroup>
|
</ListGroup>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import {
|
|||||||
} from "@jellyfin/sdk/lib/generated-client";
|
} from "@jellyfin/sdk/lib/generated-client";
|
||||||
import { Image } from "expo-image";
|
import { Image } from "expo-image";
|
||||||
import { useLocalSearchParams, useRouter } from "expo-router";
|
import { useLocalSearchParams, useRouter } from "expo-router";
|
||||||
import * as ScreenOrientation from "expo-screen-orientation";
|
import * as ScreenOrientation from "@/packages/expo-screen-orientation";
|
||||||
import { useAtom } from "jotai";
|
import { useAtom } from "jotai";
|
||||||
import { debounce } from "lodash";
|
import { debounce } from "lodash";
|
||||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { useMemo, useState } from "react";
|
import React, { useMemo, useState } from "react";
|
||||||
import { View, TouchableOpacity } from "react-native";
|
import { View, TouchableOpacity, Platform } from "react-native";
|
||||||
import { Ionicons } from "@expo/vector-icons";
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
const DropdownMenu = !Platform.isTV ? require("zeego/dropdown-menu") : null;
|
||||||
import { useControlContext } from "../contexts/ControlContext";
|
import { useControlContext } from "../contexts/ControlContext";
|
||||||
import { useVideoContext } from "../contexts/VideoContext";
|
import { useVideoContext } from "../contexts/VideoContext";
|
||||||
import { EmbeddedSubtitle, ExternalSubtitle } from "../types";
|
import { EmbeddedSubtitle, ExternalSubtitle } from "../types";
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { useCallback, useMemo, useState } from "react";
|
import React, { useCallback, useMemo, useState } from "react";
|
||||||
import { View, TouchableOpacity } from "react-native";
|
import { View, TouchableOpacity, Platform } from "react-native";
|
||||||
import { Ionicons } from "@expo/vector-icons";
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
const DropdownMenu = !Platform.isTV ? require("zeego/dropdown-menu") : null;
|
||||||
import { useControlContext } from "../contexts/ControlContext";
|
import { useControlContext } from "../contexts/ControlContext";
|
||||||
import { useVideoContext } from "../contexts/VideoContext";
|
import { useVideoContext } from "../contexts/VideoContext";
|
||||||
import { TranscodedSubtitle } from "../types";
|
import { TranscodedSubtitle } from "../types";
|
||||||
|
|||||||
@@ -56,7 +56,7 @@
|
|||||||
"expo-keep-awake": "~13.0.2",
|
"expo-keep-awake": "~13.0.2",
|
||||||
"expo-linear-gradient": "~13.0.2",
|
"expo-linear-gradient": "~13.0.2",
|
||||||
"expo-linking": "~6.3.1",
|
"expo-linking": "~6.3.1",
|
||||||
"expo-localization": "~15.0.3",
|
"expo-localization": "~16.0.1",
|
||||||
"expo-network": "~6.0.1",
|
"expo-network": "~6.0.1",
|
||||||
"expo-notifications": "~0.28.19",
|
"expo-notifications": "~0.28.19",
|
||||||
"expo-router": "~3.5.24",
|
"expo-router": "~3.5.24",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { atom, useAtom } from "jotai";
|
import { atom, useAtom } from "jotai";
|
||||||
import { useCallback, useEffect, useMemo } from "react";
|
import { useCallback, useEffect, useMemo } from "react";
|
||||||
import * as ScreenOrientation from "expo-screen-orientation";
|
import * as ScreenOrientation from "@/packages/expo-screen-orientation";
|
||||||
import { storage } from "../mmkv";
|
import { storage } from "../mmkv";
|
||||||
import { Platform } from "react-native";
|
import { Platform } from "react-native";
|
||||||
import {
|
import {
|
||||||
|
|||||||
Reference in New Issue
Block a user