mirror of
https://github.com/movie-web/native-app.git
synced 2025-09-13 16:33:26 +00:00
add play and seek buttons
This commit is contained in:
@@ -13,6 +13,7 @@ import { fetchMediaDetails } from "@movie-web/tmdb";
|
|||||||
|
|
||||||
import type { ItemData } from "~/components/item/item";
|
import type { ItemData } from "~/components/item/item";
|
||||||
import { Header } from "~/components/player/Header";
|
import { Header } from "~/components/player/Header";
|
||||||
|
import { MiddleControls } from "~/components/player/MiddleButtons";
|
||||||
import { usePlayerStore } from "~/stores/player/store";
|
import { usePlayerStore } from "~/stores/player/store";
|
||||||
|
|
||||||
export default function VideoPlayerWrapper() {
|
export default function VideoPlayerWrapper() {
|
||||||
@@ -145,6 +146,7 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({ data }) => {
|
|||||||
/>
|
/>
|
||||||
{isLoading && <ActivityIndicator size="large" color="#0000ff" />}
|
{isLoading && <ActivityIndicator size="large" color="#0000ff" />}
|
||||||
{!isLoading && data && <Header title={data.title} />}
|
{!isLoading && data && <Header title={data.title} />}
|
||||||
|
{!isLoading && <MiddleControls />}
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@@ -1,13 +1,24 @@
|
|||||||
import { View } from "react-native";
|
import React from "react";
|
||||||
|
import { TouchableOpacity } from "react-native";
|
||||||
|
|
||||||
import { usePlayerStore } from "~/stores/player/store";
|
import { usePlayerStore } from "~/stores/player/store";
|
||||||
|
|
||||||
interface ControlsProps {
|
interface ControlsProps extends React.ComponentProps<typeof TouchableOpacity> {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Controls = ({ children }: ControlsProps) => {
|
export const Controls = ({ children, className }: ControlsProps) => {
|
||||||
const idle = usePlayerStore((state) => state.interface.isIdle);
|
const idle = usePlayerStore((state) => state.interface.isIdle);
|
||||||
|
const setIsIdle = usePlayerStore((state) => state.setIsIdle);
|
||||||
|
|
||||||
return <View className="flex-1 items-center">{!idle && children}</View>;
|
return (
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={() => {
|
||||||
|
setIsIdle(false);
|
||||||
|
}}
|
||||||
|
className={className}
|
||||||
|
>
|
||||||
|
{!idle && children}
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
@@ -11,14 +11,12 @@ interface HeaderProps {
|
|||||||
|
|
||||||
export const Header = ({ title }: HeaderProps) => {
|
export const Header = ({ title }: HeaderProps) => {
|
||||||
return (
|
return (
|
||||||
<Controls>
|
<Controls className="absolute top-0 flex w-full flex-row items-center justify-between px-6 pt-6">
|
||||||
<View className="absolute top-0 flex w-full flex-row items-center justify-between px-6 pt-6">
|
<BackButton className="w-36" />
|
||||||
<BackButton className="w-36" />
|
<Text className="font-bold">{title}</Text>
|
||||||
<Text className="font-bold">{title}</Text>
|
<View className="flex w-36 flex-row items-center justify-center gap-2 space-x-2 rounded-full bg-secondary-300 px-4 py-2 opacity-80">
|
||||||
<View className="flex w-36 flex-row items-center justify-center gap-2 space-x-2 rounded-full bg-secondary-300 px-4 py-2 opacity-80">
|
<Image source={Icon} className="h-6 w-6" />
|
||||||
<Image source={Icon} className="h-6 w-6" />
|
<Text className="font-bold">movie-web</Text>
|
||||||
<Text className="font-bold">movie-web</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
</Controls>
|
</Controls>
|
||||||
);
|
);
|
||||||
|
21
apps/expo/src/components/player/MiddleButtons.tsx
Normal file
21
apps/expo/src/components/player/MiddleButtons.tsx
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { View } from "react-native";
|
||||||
|
|
||||||
|
import { Controls } from "./Controls";
|
||||||
|
import { PlayButton } from "./PlayButton";
|
||||||
|
import { SeekButton } from "./SeekButton";
|
||||||
|
|
||||||
|
export const MiddleControls = () => {
|
||||||
|
return (
|
||||||
|
<View className="absolute flex h-full w-full flex-1 flex-row items-center justify-center gap-24">
|
||||||
|
<Controls>
|
||||||
|
<SeekButton type="backward" />
|
||||||
|
</Controls>
|
||||||
|
<Controls>
|
||||||
|
<PlayButton />
|
||||||
|
</Controls>
|
||||||
|
<Controls>
|
||||||
|
<SeekButton type="forward" />
|
||||||
|
</Controls>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
29
apps/expo/src/components/player/PlayButton.tsx
Normal file
29
apps/expo/src/components/player/PlayButton.tsx
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { FontAwesome } from "@expo/vector-icons";
|
||||||
|
|
||||||
|
import { usePlayerStore } from "~/stores/player/store";
|
||||||
|
|
||||||
|
export const PlayButton = () => {
|
||||||
|
const videoRef = usePlayerStore((state) => state.videoRef);
|
||||||
|
const status = usePlayerStore((state) => state.status);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FontAwesome
|
||||||
|
name={status?.isLoaded && status.isPlaying ? "pause" : "play"}
|
||||||
|
size={36}
|
||||||
|
color="white"
|
||||||
|
onPress={() => {
|
||||||
|
if (status?.isLoaded) {
|
||||||
|
if (status.isPlaying) {
|
||||||
|
videoRef?.pauseAsync().catch(() => {
|
||||||
|
console.log("Error pausing video");
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
videoRef?.playAsync().catch(() => {
|
||||||
|
console.log("Error playing video");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
32
apps/expo/src/components/player/SeekButton.tsx
Normal file
32
apps/expo/src/components/player/SeekButton.tsx
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { MaterialIcons } from "@expo/vector-icons";
|
||||||
|
|
||||||
|
import { usePlayerStore } from "~/stores/player/store";
|
||||||
|
|
||||||
|
interface SeekProps {
|
||||||
|
type: "forward" | "backward";
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SeekButton = ({ type }: SeekProps) => {
|
||||||
|
const videoRef = usePlayerStore((state) => state.videoRef);
|
||||||
|
const status = usePlayerStore((state) => state.status);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MaterialIcons
|
||||||
|
name={type === "forward" ? "forward-10" : "replay-10"}
|
||||||
|
size={36}
|
||||||
|
color="white"
|
||||||
|
onPress={() => {
|
||||||
|
if (status?.isLoaded) {
|
||||||
|
const position =
|
||||||
|
type === "forward"
|
||||||
|
? status.positionMillis + 10000
|
||||||
|
: status.positionMillis - 10000;
|
||||||
|
|
||||||
|
videoRef?.setPositionAsync(position).catch(() => {
|
||||||
|
console.log("Error seeking backwards");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
Reference in New Issue
Block a user