add back button and header layout to player

This commit is contained in:
Jorrin
2024-02-11 22:58:39 +01:00
parent 2dd7eb49bb
commit 5773f00cd3
12 changed files with 171 additions and 55 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

View File

@@ -42,7 +42,7 @@ export default function Searchbar({
ref={inputRef}
placeholder="What are you looking for?"
placeholderTextColor={Colors.secondary[200]}
className="w-full rounded-3xl py-3 pr-5 text-white focus-visible:outline-none"
className="w-full rounded-3xl py-3 pr-5 text-white"
/>
</View>
);

View File

@@ -17,14 +17,19 @@ import {
import { fetchMediaDetails } from "@movie-web/tmdb";
import type { ItemData } from "~/components/item/item";
import { usePlayer } from "../hooks/usePlayer";
import { Header } from "~/components/player/Header";
import { PlayerProvider, usePlayer } from "~/context/player.context";
export default function VideoPlayerWrapper() {
const params = useLocalSearchParams();
const data = params.data
? (JSON.parse(params.data as string) as ItemData)
: null;
return <VideoPlayer data={data} />;
return (
<PlayerProvider>
<VideoPlayer data={data} />
</PlayerProvider>
);
}
interface VideoPlayerProps {
@@ -37,7 +42,7 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({ data }) => {
const [isLoading, setIsLoading] = useState(true);
const router = useRouter();
const {
videoRef,
setVideoRef,
unlockOrientation,
presentFullscreenPlayer,
dismissFullscreenPlayer,
@@ -99,6 +104,8 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({ data }) => {
: [],
);
console.log("stream", url);
setVideoSrc({
uri: url,
headers: {
@@ -143,17 +150,19 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({ data }) => {
return (
<View className="flex-1 items-center justify-center bg-black">
<Video
ref={videoRef}
ref={setVideoRef}
source={videoSrc}
// textTracks={textTracks} // breaks playback
className="absolute inset-0"
fullscreen={true}
fullscreen
paused={false}
controls={true}
controls
useSecureView
onLoadStart={onVideoLoadStart}
onReadyForDisplay={onReadyForDisplay}
/>
{isLoading && <ActivityIndicator size="large" color="#0000ff" />}
{!isLoading && <Header title="S8 E11 Rocky 8" />}
</View>
);
};

View File

@@ -0,0 +1,29 @@
import { useRouter } from "expo-router";
import { Ionicons } from "@expo/vector-icons";
import { usePlayer } from "~/context/player.context";
export const BackButton = ({
className,
}: Partial<React.ComponentProps<typeof Ionicons>>) => {
const { unlockOrientation } = usePlayer();
const router = useRouter();
return (
<Ionicons
name="arrow-back"
onPress={() => {
unlockOrientation()
.then(() => {
return router.back();
})
.catch(() => {
return router.back();
});
}}
size={36}
color="white"
className={className}
/>
);
};

View File

@@ -0,0 +1,22 @@
import { Image, View } from "react-native";
import Icon from "../../../assets/images/icon-transparent.png";
import { Text } from "../ui/Text";
import { BackButton } from "./BackButton";
interface HeaderProps {
title: string;
}
export const Header = ({ title }: HeaderProps) => {
return (
<View className="absolute top-0 flex w-full flex-row items-center justify-between px-6 pt-6">
<BackButton className="w-36" />
<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-50">
<Image source={Icon} className="h-6 w-6" />
<Text className="font-bold">movie-web</Text>
</View>
</View>
);
};

View File

@@ -0,0 +1,77 @@
import type { VideoRef } from "react-native-video";
import React, { createContext, useCallback, useContext, useState } from "react";
import * as ScreenOrientation from "expo-screen-orientation";
interface PlayerContextProps {
videoRef: VideoRef | null;
setVideoRef: (ref: VideoRef | null) => void;
lockOrientation: () => Promise<void>;
unlockOrientation: () => Promise<void>;
presentFullscreenPlayer: () => Promise<void>;
dismissFullscreenPlayer: () => Promise<void>;
}
interface PlayerProviderProps {
children: React.ReactNode;
}
const PlayerContext = createContext<PlayerContextProps | undefined>(undefined);
export const PlayerProvider = ({ children }: PlayerProviderProps) => {
const [internalVideoRef, setInternalVideoRef] = useState<VideoRef | null>(
null,
);
const setVideoRef = useCallback((ref: VideoRef | null) => {
setInternalVideoRef(ref);
}, []);
const lockOrientation = useCallback(async () => {
await ScreenOrientation.lockAsync(
ScreenOrientation.OrientationLock.LANDSCAPE,
);
}, []);
const unlockOrientation = useCallback(async () => {
await ScreenOrientation.lockAsync(
ScreenOrientation.OrientationLock.PORTRAIT_UP,
);
}, []);
const presentFullscreenPlayer = useCallback(async () => {
if (internalVideoRef) {
internalVideoRef.presentFullscreenPlayer();
await lockOrientation();
}
}, [internalVideoRef, lockOrientation]);
const dismissFullscreenPlayer = useCallback(async () => {
if (internalVideoRef) {
internalVideoRef.dismissFullscreenPlayer();
await unlockOrientation();
}
}, [internalVideoRef, unlockOrientation]);
const contextValue: PlayerContextProps = {
videoRef: internalVideoRef,
setVideoRef,
lockOrientation,
unlockOrientation,
presentFullscreenPlayer,
dismissFullscreenPlayer,
};
return (
<PlayerContext.Provider value={contextValue}>
{children}
</PlayerContext.Provider>
);
};
export const usePlayer = (): PlayerContextProps => {
const context = useContext(PlayerContext);
if (!context) {
throw new Error("usePlayer must be used within a PlayerProvider");
}
return context;
};

View File

@@ -1,41 +0,0 @@
import type { VideoRef } from "react-native-video";
import { useCallback, useRef } from "react";
import * as ScreenOrientation from "expo-screen-orientation";
export const usePlayer = () => {
const ref = useRef<VideoRef>(null);
const lockOrientation = useCallback(async () => {
await ScreenOrientation.lockAsync(
ScreenOrientation.OrientationLock.LANDSCAPE,
);
}, []);
const unlockOrientation = useCallback(async () => {
await ScreenOrientation.lockAsync(
ScreenOrientation.OrientationLock.PORTRAIT_UP,
);
}, []);
const presentFullscreenPlayer = useCallback(async () => {
if (ref.current) {
ref.current.presentFullscreenPlayer();
await lockOrientation();
}
}, [lockOrientation]);
const dismissFullscreenPlayer = useCallback(async () => {
if (ref.current) {
ref.current.dismissFullscreenPlayer();
await unlockOrientation();
}
}, [unlockOrientation]);
return {
videoRef: ref,
lockOrientation,
unlockOrientation,
presentFullscreenPlayer,
dismissFullscreenPlayer,
} as const;
};

11
apps/expo/src/types/globals.d.ts vendored Normal file
View File

@@ -0,0 +1,11 @@
declare module "*.svg" {
import type { ImageSourcePropType } from "react-native";
const content: ImageSourcePropType;
export default content;
}
declare module "*.png" {
import type { ImageSourcePropType } from "react-native";
const content: ImageSourcePropType;
export default content;
}