Add badge to differentiate a movie/series

fixes #332
This commit is contained in:
herrrta
2025-01-04 17:11:01 -05:00
parent 5dc86d4765
commit 39f2735756
5 changed files with 55 additions and 14 deletions

View File

@@ -1,6 +1,6 @@
// GenreTags.tsx // GenreTags.tsx
import React from "react"; import React from "react";
import {View, ViewProps} from "react-native"; import {StyleProp, TextStyle, View, ViewProps} from "react-native";
import { Text } from "./common/Text"; import { Text } from "./common/Text";
interface TagProps { interface TagProps {
@@ -8,14 +8,15 @@ interface TagProps {
textClass?: ViewProps["className"] textClass?: ViewProps["className"]
} }
export const Tag: React.FC<{ text: string, textClass?: ViewProps["className"]} & ViewProps> = ({ export const Tag: React.FC<{ text: string, textClass?: ViewProps["className"], textStyle?: StyleProp<TextStyle>} & ViewProps> = ({
text, text,
textClass, textClass,
textStyle,
...props ...props
}) => { }) => {
return ( return (
<View className="bg-neutral-800 rounded-full px-2 py-1" {...props}> <View className="bg-neutral-800 rounded-full px-2 py-1" {...props}>
<Text className={textClass}>{text}</Text> <Text className={textClass} style={textStyle}>{text}</Text>
</View> </View>
); );
}; };

View File

@@ -0,0 +1,37 @@
import {useMemo} from "react";
import {MediaType} from "@/utils/jellyseerr/server/constants/media";
import {Feather, MaterialCommunityIcons} from "@expo/vector-icons";
import {View, ViewProps} from "react-native";
const JellyseerrMediaIcon: React.FC<{ mediaType: "tv" | "movie" } & ViewProps> = ({
mediaType,
className,
...props
}) => {
const style = useMemo(
() => mediaType === MediaType.MOVIE
? 'bg-blue-600/90 border-blue-400/40'
: 'bg-purple-600/90 border-purple-400/40',
[mediaType]
);
return (
mediaType &&
<View className={`${className} border ${style} rounded-full p-1`} {...props}>
{mediaType === MediaType.MOVIE ? (
<MaterialCommunityIcons
name="movie-open"
size={16}
color="white"
/>
) : (
<Feather
size={16}
name="tv"
color="white"
/>
)}
</View>
)
}
export default JellyseerrMediaIcon;

View File

@@ -2,7 +2,6 @@ import {useEffect, useState} from "react";
import {MediaStatus} from "@/utils/jellyseerr/server/constants/media"; import {MediaStatus} from "@/utils/jellyseerr/server/constants/media";
import {MaterialCommunityIcons} from "@expo/vector-icons"; import {MaterialCommunityIcons} from "@expo/vector-icons";
import {TouchableOpacity, View, ViewProps} from "react-native"; import {TouchableOpacity, View, ViewProps} from "react-native";
import {MovieResult, TvResult} from "@/utils/jellyseerr/server/models/Search";
interface Props { interface Props {
mediaStatus?: MediaStatus; mediaStatus?: MediaStatus;
@@ -10,7 +9,7 @@ interface Props {
onPress?: () => void; onPress?: () => void;
} }
const JellyseerrIconStatus: React.FC<Props & ViewProps> = ({ const JellyseerrStatusIcon: React.FC<Props & ViewProps> = ({
mediaStatus, mediaStatus,
showRequestIcon, showRequestIcon,
onPress, onPress,
@@ -69,4 +68,4 @@ const JellyseerrIconStatus: React.FC<Props & ViewProps> = ({
) )
} }
export default JellyseerrIconStatus; export default JellyseerrStatusIcon;

View File

@@ -1,14 +1,14 @@
import {View, ViewProps} from "react-native"; import {View, ViewProps} from "react-native";
import {Image} from "expo-image"; import {Image} from "expo-image";
import {MaterialCommunityIcons} from "@expo/vector-icons";
import {Text} from "@/components/common/Text"; import {Text} from "@/components/common/Text";
import {useEffect, useMemo, useState} from "react"; import {useMemo} from "react";
import {MovieResult, Results, TvResult} from "@/utils/jellyseerr/server/models/Search"; import {MovieResult, TvResult} from "@/utils/jellyseerr/server/models/Search";
import {MediaStatus, MediaType} from "@/utils/jellyseerr/server/constants/media"; import {MediaStatus, MediaType} from "@/utils/jellyseerr/server/constants/media";
import {useJellyseerr} from "@/hooks/useJellyseerr"; import {useJellyseerr} from "@/hooks/useJellyseerr";
import {hasPermission, Permission} from "@/utils/jellyseerr/server/lib/permissions"; import {hasPermission, Permission} from "@/utils/jellyseerr/server/lib/permissions";
import {TouchableJellyseerrRouter} from "@/components/common/JellyseerrItemRouter"; import {TouchableJellyseerrRouter} from "@/components/common/JellyseerrItemRouter";
import JellyseerrIconStatus from "@/components/icons/JellyseerrIconStatus"; import JellyseerrStatusIcon from "@/components/jellyseerr/JellyseerrStatusIcon";
import JellyseerrMediaIcon from "@/components/jellyseerr/JellyseerrMediaIcon";
interface Props extends ViewProps { interface Props extends ViewProps {
item: MovieResult | TvResult; item: MovieResult | TvResult;
} }
@@ -72,16 +72,20 @@ const JellyseerrPoster: React.FC<Props> = ({
width: "100%", width: "100%",
}} }}
/> />
<JellyseerrIconStatus <JellyseerrStatusIcon
className="absolute bottom-1 right-1" className="absolute bottom-1 right-1"
showRequestIcon={canRequest} showRequestIcon={canRequest}
mediaStatus={item?.mediaInfo?.status} mediaStatus={item?.mediaInfo?.status}
/> />
<JellyseerrMediaIcon
className="absolute top-1 left-1"
mediaType={item?.mediaType}
/>
</View> </View>
<View className="mt-2 flex flex-col"> <View className="mt-2 flex flex-col">
<Text numberOfLines={2}>{title}</Text> <Text numberOfLines={2}>{title}</Text>
<Text className="text-xs opacity-50">{releaseYear}</Text> <Text className="text-xs opacity-50 align-bottom">{releaseYear}</Text>
</View> </View>
</View> </View>
</TouchableJellyseerrRouter> </TouchableJellyseerrRouter>

View File

@@ -5,7 +5,7 @@ import { TvDetails } from "@/utils/jellyseerr/server/models/Tv";
import { FlashList } from "@shopify/flash-list"; import { FlashList } from "@shopify/flash-list";
import { orderBy } from "lodash"; import { orderBy } from "lodash";
import { Tags } from "@/components/GenreTags"; import { Tags } from "@/components/GenreTags";
import JellyseerrIconStatus from "@/components/icons/JellyseerrIconStatus"; import JellyseerrStatusIcon from "@/components/jellyseerr/JellyseerrStatusIcon";
import Season from "@/utils/jellyseerr/server/entity/Season"; import Season from "@/utils/jellyseerr/server/entity/Season";
import { import {
MediaStatus, MediaStatus,
@@ -246,7 +246,7 @@ const JellyseerrSeasons: React.FC<{
seasons?.find((s) => s.seasonNumber === season.seasonNumber) seasons?.find((s) => s.seasonNumber === season.seasonNumber)
?.status === MediaStatus.UNKNOWN; ?.status === MediaStatus.UNKNOWN;
return ( return (
<JellyseerrIconStatus <JellyseerrStatusIcon
key={0} key={0}
onPress={() => requestSeason(canRequest, season.seasonNumber)} onPress={() => requestSeason(canRequest, season.seasonNumber)}
className={canRequest ? "bg-gray-700/40" : undefined} className={canRequest ? "bg-gray-700/40" : undefined}