wip: design refactor

This commit is contained in:
Fredrik Burmester
2024-08-28 22:00:50 +02:00
parent 309345c834
commit 4641ff726c
16 changed files with 580 additions and 334 deletions

View File

@@ -3,7 +3,7 @@ import { runtimeTicksToMinutes } from "@/utils/time";
import { useActionSheet } from "@expo/react-native-action-sheet";
import { Feather, Ionicons } from "@expo/vector-icons";
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
import { useMemo } from "react";
import { useEffect, useMemo, useRef, useState } from "react";
import { TouchableOpacity, View } from "react-native";
import CastContext, {
PlayServicesState,
@@ -13,6 +13,14 @@ import { Button } from "./Button";
import { Text } from "./common/Text";
import { useAtom } from "jotai";
import { itemThemeColorAtom } from "@/utils/atoms/primaryColor";
import Animated, {
useSharedValue,
useAnimatedStyle,
withTiming,
interpolateColor,
runOnJS,
useAnimatedReaction,
} from "react-native-reanimated";
interface Props extends React.ComponentProps<typeof Button> {
item?: BaseItemDto | null;
@@ -26,6 +34,47 @@ export const PlayButton: React.FC<Props> = ({ item, url, ...props }) => {
const [color] = useAtom(itemThemeColorAtom);
// Create a shared value for animation progress
const progress = useSharedValue(0);
// Create shared values for start and end colors
const startColor = useSharedValue(color);
const endColor = useSharedValue(color);
useEffect(() => {
// When color changes, update end color and animate progress
endColor.value = color;
progress.value = 0; // Reset progress
progress.value = withTiming(1, { duration: 300 }); // Animate to 1 over 500ms
}, [color]);
// Animated style for primary color
const animatedPrimaryStyle = useAnimatedStyle(() => ({
backgroundColor: interpolateColor(
progress.value,
[0, 1],
[startColor.value.average, endColor.value.average]
),
}));
// Animated style for text color
const animatedTextStyle = useAnimatedStyle(() => ({
color: interpolateColor(
progress.value,
[0, 1],
[startColor.value.text, endColor.value.text]
),
}));
// Update start color after animation completes
useEffect(() => {
const timeout = setTimeout(() => {
startColor.value = color;
}, 500); // Should match the duration in withTiming
return () => clearTimeout(timeout);
}, [color]);
const onPress = async () => {
if (!url || !item) return;
@@ -85,37 +134,43 @@ export const PlayButton: React.FC<Props> = ({ item, url, ...props }) => {
return (
<TouchableOpacity onPress={onPress} className="relative" {...props}>
<Animated.View
style={[
animatedPrimaryStyle,
{
width:
playbackPercent === 0
? "100%"
: `${Math.max(playbackPercent, 15)}%`,
height: "100%",
},
]}
className="absolute w-full h-full top-0 left-0 rounded-xl z-10"
/>
<Animated.View
style={[animatedPrimaryStyle]}
className="absolute w-full h-full top-0 left-0 rounded-xl "
/>
<View
style={{
width:
playbackPercent === 0
? "100%"
: `${Math.max(playbackPercent, 15)}%`,
height: "100%",
backgroundColor: color.primary,
borderWidth: 1,
borderColor: color.primary,
borderStyle: "solid",
}}
className="absolute w-full h-full top-0 left-0 rounded-xl z-10"
></View>
<View
style={{
height: "100%",
width: "100%",
backgroundColor: color.primary,
}}
className="absolute w-full h-full top-0 left-0 rounded-xl opacity-40"
></View>
<View className="flex flex-row items-center justify-center bg-transparent rounded-xl z-20 h-12 w-full ">
className="flex flex-row items-center justify-center bg-transparent rounded-xl z-20 h-12 w-full "
>
<View className="flex flex-row items-center space-x-2">
<Text
className="font-bold"
style={{
color: color.text,
}}
>
<Animated.Text style={[animatedTextStyle, { fontWeight: "bold" }]}>
{runtimeTicksToMinutes(item?.RunTimeTicks)}
</Text>
<Ionicons name="play-circle" size={24} color={color.text} />
{client && <Feather name="cast" size={22} color={color.text} />}
</Animated.Text>
<Animated.Text style={animatedTextStyle}>
<Ionicons name="play-circle" size={24} />
</Animated.Text>
{client && (
<Animated.Text style={animatedTextStyle}>
<Feather name="cast" size={22} />
</Animated.Text>
)}
</View>
</View>
</TouchableOpacity>