mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-06-02 03:58:36 +01:00
merge with master
This commit is contained in:
@@ -31,6 +31,7 @@ import Animated, {
|
||||
} from "react-native-reanimated";
|
||||
import { Button } from "./Button";
|
||||
import { SelectedOptions } from "./ItemContent";
|
||||
import { chromecastProfile } from "@/utils/profiles/chromecast";
|
||||
|
||||
interface Props extends React.ComponentProps<typeof Button> {
|
||||
item: BaseItemDto;
|
||||
@@ -111,18 +112,11 @@ export const PlayButton: React.FC<Props> = ({
|
||||
if (state && state !== PlayServicesState.SUCCESS)
|
||||
CastContext.showPlayServicesErrorDialog(state);
|
||||
else {
|
||||
// If we're opening a currently playing item, don't restart the media.
|
||||
// Instead just open controls.
|
||||
if (isOpeningCurrentlyPlayingMedia) {
|
||||
CastContext.showExpandedControls();
|
||||
return;
|
||||
}
|
||||
|
||||
// Get a new URL with the Chromecast device profile:
|
||||
const data = await getStreamUrl({
|
||||
api,
|
||||
item,
|
||||
deviceProfile: ios,
|
||||
deviceProfile: chromecastProfile,
|
||||
startTimeTicks: item?.UserData?.PlaybackPositionTicks!,
|
||||
userId: user?.Id,
|
||||
audioStreamIndex: selectedOptions.audioIndex,
|
||||
|
||||
@@ -2,9 +2,10 @@ import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
|
||||
import React, {useEffect, useMemo, useState} from "react";
|
||||
import {Text} from "@/components/common/Text";
|
||||
import useDownloadHelper from "@/utils/download";
|
||||
import {useDownload} from "@/providers/DownloadProvider";
|
||||
import {bytesToReadable, useDownload} from "@/providers/DownloadProvider";
|
||||
import {TextProps} from "react-native";
|
||||
|
||||
interface DownloadSizeProps {
|
||||
interface DownloadSizeProps extends TextProps {
|
||||
items: BaseItemDto[];
|
||||
}
|
||||
|
||||
@@ -13,7 +14,7 @@ interface DownloadSizes {
|
||||
itemsNeedingSize: BaseItemDto[];
|
||||
}
|
||||
|
||||
export const DownloadSize: React.FC<DownloadSizeProps> = ({ items }) => {
|
||||
export const DownloadSize: React.FC<DownloadSizeProps> = ({ items, ...props }) => {
|
||||
const { downloadedFiles, saveDownloadedItemInfo } = useDownload();
|
||||
const { getDownloadSize } = useDownloadHelper();
|
||||
const [size, setSize] = useState<string | undefined>();
|
||||
@@ -53,17 +54,9 @@ export const DownloadSize: React.FC<DownloadSizeProps> = ({ items }) => {
|
||||
return size
|
||||
}, [size])
|
||||
|
||||
const bytesToReadable = (bytes: number) => {
|
||||
const gb = bytes / 1e+9;
|
||||
|
||||
if (gb >= 1)
|
||||
return `${gb.toFixed(2)} GB`
|
||||
return `${(bytes / 1024 / 1024).toFixed(2)} MB`
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Text className="text-xs text-neutral-500">{sizeText}</Text>
|
||||
<Text className="text-xs text-neutral-500" {...props}>{sizeText}</Text>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,20 +1,49 @@
|
||||
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
|
||||
import {TouchableOpacity, View} from "react-native";
|
||||
import { Text } from "../common/Text";
|
||||
import React, {useEffect, useMemo, useState} from "react";
|
||||
import React, {useCallback, useMemo} from "react";
|
||||
import {storage} from "@/utils/mmkv";
|
||||
import {Image} from "expo-image";
|
||||
import {Ionicons} from "@expo/vector-icons";
|
||||
import {router} from "expo-router";
|
||||
import {DownloadSize} from "@/components/downloads/DownloadSize";
|
||||
import {useDownload} from "@/providers/DownloadProvider";
|
||||
import {useActionSheet} from "@expo/react-native-action-sheet";
|
||||
|
||||
export const SeriesCard: React.FC<{ items: BaseItemDto[] }> = ({items}) => {
|
||||
const { deleteItems } = useDownload();
|
||||
const { showActionSheetWithOptions } = useActionSheet();
|
||||
|
||||
const base64Image = useMemo(() => {
|
||||
return storage.getString(items[0].SeriesId!);
|
||||
}, []);
|
||||
|
||||
const deleteSeries = useCallback(
|
||||
async () => deleteItems(items),
|
||||
[items]
|
||||
);
|
||||
|
||||
const showActionSheet = useCallback(() => {
|
||||
const options = ["Delete", "Cancel"];
|
||||
const destructiveButtonIndex = 0;
|
||||
|
||||
showActionSheetWithOptions({
|
||||
options,
|
||||
destructiveButtonIndex,
|
||||
},
|
||||
(selectedIndex) => {
|
||||
if (selectedIndex == destructiveButtonIndex) {
|
||||
deleteSeries();
|
||||
}
|
||||
}
|
||||
);
|
||||
}, [showActionSheetWithOptions, deleteSeries]);
|
||||
|
||||
return (
|
||||
<TouchableOpacity onPress={() => router.push(`/downloads/${items[0].SeriesId}`)}>
|
||||
<TouchableOpacity
|
||||
onPress={() => router.push(`/downloads/${items[0].SeriesId}`)}
|
||||
onLongPress={showActionSheet}
|
||||
>
|
||||
{base64Image ? (
|
||||
<View className="w-28 aspect-[10/15] rounded-lg overflow-hidden mr-2 border border-neutral-900">
|
||||
<Image
|
||||
|
||||
Reference in New Issue
Block a user