mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-01-15 23:59:08 +00:00
chore
This commit is contained in:
@@ -157,43 +157,34 @@ export default function index() {
|
||||
if (!api || !user?.Id) return [];
|
||||
|
||||
const ss: Section[] = [
|
||||
{
|
||||
title: "Continue Watching",
|
||||
queryKey: ["resumeItems", user.Id],
|
||||
queryFn: async () =>
|
||||
(
|
||||
await getItemsApi(api).getResumeItems({
|
||||
userId: user.Id,
|
||||
enableImageTypes: ["Primary", "Backdrop", "Thumb"],
|
||||
})
|
||||
).data.Items || [],
|
||||
type: "ScrollingCollectionList",
|
||||
orientation: "horizontal",
|
||||
},
|
||||
{
|
||||
title: "Next Up",
|
||||
queryKey: ["nextUp-all", user?.Id],
|
||||
queryFn: async () =>
|
||||
(
|
||||
await getTvShowsApi(api).getNextUp({
|
||||
userId: user?.Id,
|
||||
fields: ["MediaSourceCount"],
|
||||
limit: 20,
|
||||
enableImageTypes: ["Primary", "Backdrop", "Thumb"],
|
||||
})
|
||||
).data.Items || [],
|
||||
type: "ScrollingCollectionList",
|
||||
orientation: "horizontal",
|
||||
},
|
||||
...(mediaListCollections?.map(
|
||||
(ml) =>
|
||||
({
|
||||
title: ml.Name || "",
|
||||
queryKey: ["mediaList", ml.Id],
|
||||
queryFn: async () => ml,
|
||||
type: "MediaListSection",
|
||||
} as MediaListSection)
|
||||
) || []),
|
||||
// {
|
||||
// title: "Continue Watching",
|
||||
// queryKey: ["resumeItems", user.Id],
|
||||
// queryFn: async () =>
|
||||
// (
|
||||
// await getItemsApi(api).getResumeItems({
|
||||
// userId: user.Id,
|
||||
// enableImageTypes: ["Primary", "Backdrop", "Thumb"],
|
||||
// })
|
||||
// ).data.Items || [],
|
||||
// type: "ScrollingCollectionList",
|
||||
// orientation: "horizontal",
|
||||
// },
|
||||
// {
|
||||
// title: "Next Up",
|
||||
// queryKey: ["nextUp-all", user?.Id],
|
||||
// queryFn: async () =>
|
||||
// (
|
||||
// await getTvShowsApi(api).getNextUp({
|
||||
// userId: user?.Id,
|
||||
// fields: ["MediaSourceCount"],
|
||||
// limit: 20,
|
||||
// enableImageTypes: ["Primary", "Backdrop", "Thumb"],
|
||||
// })
|
||||
// ).data.Items || [],
|
||||
// type: "ScrollingCollectionList",
|
||||
// orientation: "horizontal",
|
||||
// },
|
||||
{
|
||||
title: "Recently Added in Movies",
|
||||
queryKey: ["recentlyAddedInMovies", user?.Id, movieCollectionId],
|
||||
@@ -228,6 +219,15 @@ export default function index() {
|
||||
).data || [],
|
||||
type: "ScrollingCollectionList",
|
||||
},
|
||||
...(mediaListCollections?.map(
|
||||
(ml) =>
|
||||
({
|
||||
title: ml.Name || "",
|
||||
queryKey: ["mediaList", ml.Id],
|
||||
queryFn: async () => ml,
|
||||
type: "MediaListSection",
|
||||
} as MediaListSection)
|
||||
) || []),
|
||||
{
|
||||
title: "Suggested Movies",
|
||||
queryKey: ["suggestedMovies", user?.Id],
|
||||
@@ -317,7 +317,7 @@ export default function index() {
|
||||
|
||||
const insets = useSafeAreaInsets();
|
||||
|
||||
if (e1 || e2)
|
||||
if (e1 || e2 || !api)
|
||||
return (
|
||||
<View className="flex flex-col items-center justify-center h-full -mt-6">
|
||||
<Text className="text-3xl font-bold mb-2">Oops!</Text>
|
||||
@@ -341,39 +341,69 @@ export default function index() {
|
||||
refreshControl={
|
||||
<RefreshControl refreshing={loading} onRefresh={refetch} />
|
||||
}
|
||||
key={"home"}
|
||||
contentContainerStyle={{
|
||||
paddingLeft: insets.left,
|
||||
paddingRight: insets.right,
|
||||
}}
|
||||
className="flex flex-col space-y-4 mb-20"
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
paddingLeft: insets.left,
|
||||
paddingRight: insets.right,
|
||||
}}
|
||||
className="flex flex-col pt-4 pb-24 gap-y-2"
|
||||
>
|
||||
<LargeMovieCarousel />
|
||||
<LargeMovieCarousel />
|
||||
|
||||
{sections.map((section, index) => {
|
||||
if (section.type === "ScrollingCollectionList") {
|
||||
return (
|
||||
<ScrollingCollectionList
|
||||
key={index}
|
||||
title={section.title}
|
||||
queryKey={section.queryKey}
|
||||
queryFn={section.queryFn}
|
||||
orientation={section.orientation}
|
||||
/>
|
||||
);
|
||||
} else if (section.type === "MediaListSection") {
|
||||
return (
|
||||
<MediaListSection
|
||||
key={index}
|
||||
queryKey={section.queryKey}
|
||||
queryFn={section.queryFn}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
})}
|
||||
</View>
|
||||
<ScrollingCollectionList
|
||||
key="nextUp"
|
||||
title={"Next Up"}
|
||||
queryKey={["nextUp-all", user?.Id]}
|
||||
queryFn={async () =>
|
||||
(
|
||||
await getTvShowsApi(api).getNextUp({
|
||||
userId: user?.Id,
|
||||
fields: ["MediaSourceCount"],
|
||||
limit: 20,
|
||||
enableImageTypes: ["Primary", "Backdrop", "Thumb"],
|
||||
})
|
||||
).data.Items|| []
|
||||
}
|
||||
orientation={"horizontal"}
|
||||
/>
|
||||
|
||||
<ScrollingCollectionList
|
||||
key="continueWatching"
|
||||
title={"Continue Watching"}
|
||||
queryKey={["continueWatching", user?.Id]}
|
||||
queryFn={async () =>
|
||||
(
|
||||
await getItemsApi(api).getResumeItems({
|
||||
userId: user?.Id,
|
||||
enableImageTypes: ["Primary", "Backdrop", "Thumb"],
|
||||
})
|
||||
).data.Items || []
|
||||
}
|
||||
orientation={"horizontal"}
|
||||
/>
|
||||
|
||||
{sections.map((section, index) => {
|
||||
if (section.type === "ScrollingCollectionList") {
|
||||
return (
|
||||
<ScrollingCollectionList
|
||||
key={index}
|
||||
title={section.title}
|
||||
queryKey={section.queryKey}
|
||||
queryFn={section.queryFn}
|
||||
orientation={section.orientation}
|
||||
/>
|
||||
);
|
||||
} else if (section.type === "MediaListSection") {
|
||||
return (
|
||||
<MediaListSection
|
||||
key={index}
|
||||
queryKey={section.queryKey}
|
||||
queryFn={section.queryFn}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
})}
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -76,10 +76,7 @@ const ContinueWatchingPoster: React.FC<ContinueWatchingPosterProps> = ({
|
||||
{progress > 0 && (
|
||||
<>
|
||||
<View
|
||||
style={{
|
||||
width: `100%`,
|
||||
}}
|
||||
className={`absolute bottom-0 left-0 h-1 bg-neutral-700 opacity-80 w-full`}
|
||||
className={`absolute w-100 bottom-0 left-0 h-1 bg-neutral-700 opacity-80 w-full`}
|
||||
></View>
|
||||
<View
|
||||
style={{
|
||||
|
||||
@@ -1,51 +1,41 @@
|
||||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import {
|
||||
View,
|
||||
TouchableOpacity,
|
||||
Alert,
|
||||
Dimensions,
|
||||
BackHandler,
|
||||
Pressable,
|
||||
Touchable,
|
||||
} from "react-native";
|
||||
import Video, { OnProgressData } from "react-native-video";
|
||||
import { Slider } from "react-native-awesome-slider";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { useAdjacentEpisodes } from "@/hooks/useAdjacentEpisodes";
|
||||
import { useCreditSkipper } from "@/hooks/useCreditSkipper";
|
||||
import { useIntroSkipper } from "@/hooks/useIntroSkipper";
|
||||
import { useTrickplay } from "@/hooks/useTrickplay";
|
||||
import { apiAtom } from "@/providers/JellyfinProvider";
|
||||
import { usePlayback } from "@/providers/PlaybackProvider";
|
||||
import { useSettings } from "@/utils/atoms/settings";
|
||||
import { useAdjacentEpisodes } from "@/hooks/useAdjacentEpisodes";
|
||||
import { useTrickplay } from "@/hooks/useTrickplay";
|
||||
import { Text } from "./common/Text";
|
||||
import { Loader } from "./Loader";
|
||||
import { getBackdropUrl } from "@/utils/jellyfin/image/getBackdropUrl";
|
||||
import { getAuthHeaders } from "@/utils/jellyfin/jellyfin";
|
||||
import { writeToLog } from "@/utils/log";
|
||||
import { useRouter, useSegments } from "expo-router";
|
||||
import { itemRouter } from "./common/TouchableItemRouter";
|
||||
import orientationToOrientationLock from "@/utils/OrientationLockConverter";
|
||||
import { secondsToTicks } from "@/utils/secondsToTicks";
|
||||
import { formatTimeString, ticksToSeconds } from "@/utils/time";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { Image } from "expo-image";
|
||||
import { StatusBar } from "expo-status-bar";
|
||||
import { useRouter, useSegments } from "expo-router";
|
||||
import * as ScreenOrientation from "expo-screen-orientation";
|
||||
import { useAtom } from "jotai";
|
||||
import { apiAtom } from "@/providers/JellyfinProvider";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import {
|
||||
Alert,
|
||||
BackHandler,
|
||||
Dimensions,
|
||||
Pressable,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} from "react-native";
|
||||
import { Slider } from "react-native-awesome-slider";
|
||||
import {
|
||||
runOnJS,
|
||||
useAnimatedReaction,
|
||||
useSharedValue,
|
||||
} from "react-native-reanimated";
|
||||
import { secondsToTicks } from "@/utils/secondsToTicks";
|
||||
import { getAuthHeaders } from "@/utils/jellyfin/jellyfin";
|
||||
import { getBackdropUrl } from "@/utils/jellyfin/image/getBackdropUrl";
|
||||
import {
|
||||
useSafeAreaFrame,
|
||||
useSafeAreaInsets,
|
||||
} from "react-native-safe-area-context";
|
||||
import orientationToOrientationLock from "@/utils/OrientationLockConverter";
|
||||
import {
|
||||
formatTimeString,
|
||||
runtimeTicksToSeconds,
|
||||
ticksToSeconds,
|
||||
} from "@/utils/time";
|
||||
import { useIntroSkipper } from "@/hooks/useIntroSkipper";
|
||||
import { useCreditSkipper } from "@/hooks/useCreditSkipper";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
import Video, { OnProgressData } from "react-native-video";
|
||||
import { Text } from "./common/Text";
|
||||
import { itemRouter } from "./common/TouchableItemRouter";
|
||||
import { Loader } from "./Loader";
|
||||
|
||||
const windowDimensions = Dimensions.get("window");
|
||||
const screenDimensions = Dimensions.get("screen");
|
||||
@@ -56,7 +46,6 @@ export const FullScreenVideoPlayer: React.FC = () => {
|
||||
pauseVideo,
|
||||
playVideo,
|
||||
stopPlayback,
|
||||
setVolume,
|
||||
setIsPlaying,
|
||||
isPlaying,
|
||||
videoRef,
|
||||
@@ -77,7 +66,6 @@ export const FullScreenVideoPlayer: React.FC = () => {
|
||||
const [showControls, setShowControls] = useState(true);
|
||||
const [isBuffering, setIsBufferingState] = useState(true);
|
||||
const [ignoreSafeArea, setIgnoreSafeArea] = useState(false);
|
||||
const [isStatusBarHidden, setIsStatusBarHidden] = useState(false);
|
||||
|
||||
// Seconds
|
||||
const [currentTime, setCurrentTime] = useState(0);
|
||||
|
||||
@@ -84,13 +84,7 @@ export const LargeMovieCarousel: React.FC<Props> = ({ ...props }) => {
|
||||
|
||||
const width = Dimensions.get("screen").width;
|
||||
|
||||
if (l1 || l2)
|
||||
return (
|
||||
<View className="h-[242px] flex items-center justify-center">
|
||||
<Loader />
|
||||
</View>
|
||||
);
|
||||
|
||||
if (l1 || l2) return null;
|
||||
if (!popularItems) return null;
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Text } from "@/components/common/Text";
|
||||
import MoviePoster from "@/components/posters/MoviePoster";
|
||||
import { useSettings } from "@/utils/atoms/settings";
|
||||
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
|
||||
import {
|
||||
useQuery,
|
||||
@@ -17,7 +16,6 @@ import SeriesPoster from "../posters/SeriesPoster";
|
||||
interface Props extends ViewProps {
|
||||
title?: string | null;
|
||||
orientation?: "horizontal" | "vertical";
|
||||
height?: "small" | "large";
|
||||
disabled?: boolean;
|
||||
queryKey: QueryKey;
|
||||
queryFn: QueryFunction<BaseItemDto[]>;
|
||||
@@ -26,13 +24,11 @@ interface Props extends ViewProps {
|
||||
export const ScrollingCollectionList: React.FC<Props> = ({
|
||||
title,
|
||||
orientation = "vertical",
|
||||
height = "small",
|
||||
disabled = false,
|
||||
queryFn,
|
||||
queryKey,
|
||||
...props
|
||||
}) => {
|
||||
const [settings] = useSettings();
|
||||
const { data, isLoading } = useQuery({
|
||||
queryKey,
|
||||
queryFn,
|
||||
@@ -49,32 +45,31 @@ export const ScrollingCollectionList: React.FC<Props> = ({
|
||||
</Text>
|
||||
<HorizontalScroll
|
||||
data={data}
|
||||
height={orientation === "vertical" ? 247 : 164}
|
||||
extraData={[orientation, isLoading]}
|
||||
loading={isLoading}
|
||||
renderItem={(item, index) => (
|
||||
<TouchableItemRouter
|
||||
key={index}
|
||||
item={item}
|
||||
className={`flex flex-col
|
||||
${orientation === "horizontal" ? "w-44" : "w-28"}
|
||||
`}
|
||||
key={index}
|
||||
style={{
|
||||
width: orientation === "horizontal" ? 176 : 112,
|
||||
zIndex: 100,
|
||||
}}
|
||||
>
|
||||
<View>
|
||||
{item.Type === "Episode" && orientation === "horizontal" && (
|
||||
<ContinueWatchingPoster item={item} />
|
||||
)}
|
||||
{item.Type === "Episode" && orientation === "vertical" && (
|
||||
<SeriesPoster item={item} />
|
||||
)}
|
||||
{item.Type === "Movie" && orientation === "horizontal" && (
|
||||
<ContinueWatchingPoster item={item} />
|
||||
)}
|
||||
{item.Type === "Movie" && orientation === "vertical" && (
|
||||
<MoviePoster item={item} />
|
||||
)}
|
||||
{item.Type === "Series" && <SeriesPoster item={item} />}
|
||||
<ItemCardText item={item} />
|
||||
</View>
|
||||
{item.Type === "Episode" && orientation === "horizontal" && (
|
||||
<ContinueWatchingPoster item={item} />
|
||||
)}
|
||||
{item.Type === "Episode" && orientation === "vertical" && (
|
||||
<SeriesPoster item={item} />
|
||||
)}
|
||||
{item.Type === "Movie" && orientation === "horizontal" && (
|
||||
<ContinueWatchingPoster item={item} />
|
||||
)}
|
||||
{item.Type === "Movie" && orientation === "vertical" && (
|
||||
<MoviePoster item={item} />
|
||||
)}
|
||||
{item.Type === "Series" && <SeriesPoster item={item} />}
|
||||
<ItemCardText item={item} />
|
||||
</TouchableItemRouter>
|
||||
)}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user