IO-1165 Add video playback support.
This commit is contained in:
@@ -1,4 +1,3 @@
|
|||||||
import { Video } from "expo-av";
|
|
||||||
import React, { useMemo, useState } from "react";
|
import React, { useMemo, useState } from "react";
|
||||||
import {
|
import {
|
||||||
FlatList,
|
FlatList,
|
||||||
@@ -11,15 +10,8 @@ import {
|
|||||||
import env from "../../env";
|
import env from "../../env";
|
||||||
import { DetermineFileType } from "../../util/document-upload.utility";
|
import { DetermineFileType } from "../../util/document-upload.utility";
|
||||||
import MediaCacheOverlay from "../media-cache-overlay/media-cache-overlay.component";
|
import MediaCacheOverlay from "../media-cache-overlay/media-cache-overlay.component";
|
||||||
|
|
||||||
export default function JobDocumentsComponent({ job, loading, refetch }) {
|
export default function JobDocumentsComponent({ job, loading, refetch }) {
|
||||||
const [previewVisible, setPreviewVisible] = useState(false);
|
const [previewVisible, setPreviewVisible] = useState(false);
|
||||||
const [videoUri, setVideoUri] = useState(null);
|
|
||||||
const [status, setStatus] = React.useState({});
|
|
||||||
console.log(
|
|
||||||
"🚀 ~ file: job-documents.component.jsx ~ line 19 ~ status",
|
|
||||||
status
|
|
||||||
);
|
|
||||||
|
|
||||||
const [imgIndex, setImgIndex] = useState(0);
|
const [imgIndex, setImgIndex] = useState(0);
|
||||||
const onRefresh = async () => {
|
const onRefresh = async () => {
|
||||||
@@ -30,9 +22,12 @@ export default function JobDocumentsComponent({ job, loading, refetch }) {
|
|||||||
() =>
|
() =>
|
||||||
job.documents.map((doc) => {
|
job.documents.map((doc) => {
|
||||||
return {
|
return {
|
||||||
source: {
|
videoUrl:
|
||||||
uri: GenerateSrcUrl(doc),
|
DetermineFileType(doc.type) === "video" && GenerateSrcUrl(doc),
|
||||||
},
|
source:
|
||||||
|
DetermineFileType(doc.type) === "video"
|
||||||
|
? { uri: GenerateThumbUrl(doc) }
|
||||||
|
: { uri: GenerateSrcUrl(doc) },
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
[job.documents]
|
[job.documents]
|
||||||
@@ -50,16 +45,10 @@ export default function JobDocumentsComponent({ job, loading, refetch }) {
|
|||||||
keyExtractor={(item) => item.id}
|
keyExtractor={(item) => item.id}
|
||||||
renderItem={(object) => (
|
renderItem={(object) => (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={{ flex: 1 / 4, aspectRatio: 1 }}
|
style={{ flex: 1 / 4, aspectRatio: 1, margin: 4 }}
|
||||||
onPress={() => {
|
onPress={async () => {
|
||||||
if (DetermineFileType(object.item.type) === "image") {
|
setImgIndex(object.index);
|
||||||
//If image
|
setPreviewVisible(true);
|
||||||
setImgIndex(object.index);
|
|
||||||
setPreviewVisible(true);
|
|
||||||
} else {
|
|
||||||
//If Video
|
|
||||||
setVideoUri(GenerateSrcUrl(object.item));
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Image
|
<Image
|
||||||
@@ -74,18 +63,7 @@ export default function JobDocumentsComponent({ job, loading, refetch }) {
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Text>{job.documents.length}</Text>
|
<Text>{job.documents.length}</Text>
|
||||||
<Video
|
|
||||||
source={
|
|
||||||
videoUri
|
|
||||||
? {
|
|
||||||
uri: videoUri,
|
|
||||||
}
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
useNativeControls
|
|
||||||
isLooping
|
|
||||||
onPlaybackStatusUpdate={(status) => setStatus(() => status)}
|
|
||||||
/>
|
|
||||||
<MediaCacheOverlay
|
<MediaCacheOverlay
|
||||||
photos={fullphotos}
|
photos={fullphotos}
|
||||||
imgIndex={imgIndex}
|
imgIndex={imgIndex}
|
||||||
@@ -99,7 +77,7 @@ export default function JobDocumentsComponent({ job, loading, refetch }) {
|
|||||||
|
|
||||||
export const GenerateSrcUrl = (value) => {
|
export const GenerateSrcUrl = (value) => {
|
||||||
let extension = value.extension;
|
let extension = value.extension;
|
||||||
if (extension && extension.includes("heic")) extension = "jpg";
|
if (extension && extension.toLowerCase().includes("heic")) extension = "jpg";
|
||||||
|
|
||||||
return `${env.REACT_APP_CLOUDINARY_ENDPOINT}/${DetermineFileType(
|
return `${env.REACT_APP_CLOUDINARY_ENDPOINT}/${DetermineFileType(
|
||||||
value.type
|
value.type
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
import { Ionicons } from "@expo/vector-icons";
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
import React from "react";
|
import { Video } from "expo-av";
|
||||||
import { Modal, SafeAreaView, TouchableOpacity, View } from "react-native";
|
import React, { useState } from "react";
|
||||||
|
import {
|
||||||
|
Dimensions,
|
||||||
|
Modal,
|
||||||
|
SafeAreaView,
|
||||||
|
TouchableOpacity,
|
||||||
|
} from "react-native";
|
||||||
import Gallery from "react-native-image-gallery";
|
import Gallery from "react-native-image-gallery";
|
||||||
|
|
||||||
export default function MediaCacheOverlay({
|
export default function MediaCacheOverlay({
|
||||||
photos,
|
photos,
|
||||||
previewVisible,
|
previewVisible,
|
||||||
@@ -9,6 +16,11 @@ export default function MediaCacheOverlay({
|
|||||||
imgIndex,
|
imgIndex,
|
||||||
setImgIndex,
|
setImgIndex,
|
||||||
}) {
|
}) {
|
||||||
|
const [currentIndex, setcurrentIndex] = useState(0);
|
||||||
|
const [dragging, setDragging] = useState(false);
|
||||||
|
|
||||||
|
const videoRef = React.useRef(null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
onDismiss={() => setPreviewVisible(false)}
|
onDismiss={() => setPreviewVisible(false)}
|
||||||
@@ -17,7 +29,14 @@ export default function MediaCacheOverlay({
|
|||||||
transparent={false}
|
transparent={false}
|
||||||
>
|
>
|
||||||
<SafeAreaView style={{ flex: 1, backgroundColor: "black" }}>
|
<SafeAreaView style={{ flex: 1, backgroundColor: "black" }}>
|
||||||
<Gallery initialPage={imgIndex} images={photos} />
|
<Gallery
|
||||||
|
initialPage={imgIndex}
|
||||||
|
images={photos}
|
||||||
|
onPageScroll={({ position }) => setcurrentIndex(position)}
|
||||||
|
onPageScrollStateChanged={(state) =>
|
||||||
|
state === "idle" ? setDragging(false) : setDragging(true)
|
||||||
|
}
|
||||||
|
/>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={{ position: "absolute" }}
|
style={{ position: "absolute" }}
|
||||||
onPress={() => setPreviewVisible(false)}
|
onPress={() => setPreviewVisible(false)}
|
||||||
@@ -29,7 +48,29 @@ export default function MediaCacheOverlay({
|
|||||||
style={{ margin: 20 }}
|
style={{ margin: 20 }}
|
||||||
/>
|
/>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
{!dragging && photos[currentIndex] && photos[currentIndex].videoUrl && (
|
||||||
|
<TouchableOpacity
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
left: Dimensions.get("window").width / 2 - 32,
|
||||||
|
top: Dimensions.get("window").height / 2 - 32,
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
onPress={async () => {
|
||||||
|
await videoRef.current.loadAsync(
|
||||||
|
{ uri: photos[currentIndex].videoUrl },
|
||||||
|
{},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
videoRef.current.presentFullscreenPlayer();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Ionicons name="play" size={64} color="white" />
|
||||||
|
</TouchableOpacity>
|
||||||
|
)}
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
|
<Video ref={videoRef} useNativeControls />
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -154,7 +154,6 @@ export function UploadProgress({
|
|||||||
//Sequentially await the proms.
|
//Sequentially await the proms.
|
||||||
|
|
||||||
for (var i = 0; i < data.length + 4; i = i + 4) {
|
for (var i = 0; i < data.length + 4; i = i + 4) {
|
||||||
console.log("i :>> ", i);
|
|
||||||
let proms = [];
|
let proms = [];
|
||||||
if (data[i]) {
|
if (data[i]) {
|
||||||
proms.push(CreateUploadProm(data[i]));
|
proms.push(CreateUploadProm(data[i]));
|
||||||
@@ -168,9 +167,8 @@ export function UploadProgress({
|
|||||||
if (data[i + 3]) {
|
if (data[i + 3]) {
|
||||||
proms.push(CreateUploadProm(data[i + 3]));
|
proms.push(CreateUploadProm(data[i + 3]));
|
||||||
}
|
}
|
||||||
console.log("Proms Length", proms.length);
|
|
||||||
await Promise.all(proms);
|
await Promise.all(proms);
|
||||||
console.log("Await done.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deleteAfterUpload) {
|
if (deleteAfterUpload) {
|
||||||
@@ -196,7 +194,6 @@ export function UploadProgress({
|
|||||||
const CreateUploadProm = async (p) => {
|
const CreateUploadProm = async (p) => {
|
||||||
let filename;
|
let filename;
|
||||||
filename = p.filename || p.uri.split("/").pop();
|
filename = p.filename || p.uri.split("/").pop();
|
||||||
console.log("Start upping.", p.id);
|
|
||||||
|
|
||||||
await handleUpload(
|
await handleUpload(
|
||||||
{
|
{
|
||||||
@@ -214,7 +211,7 @@ export function UploadProgress({
|
|||||||
photo: p,
|
photo: p,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
console.log("Done upping.", p.id);
|
|
||||||
//Set the state to mark that it's done.
|
//Set the state to mark that it's done.
|
||||||
setProgress((progress) => ({
|
setProgress((progress) => ({
|
||||||
...progress,
|
...progress,
|
||||||
|
|||||||
@@ -218,6 +218,7 @@ export const GET_JOB_BY_PK = gql`
|
|||||||
key
|
key
|
||||||
created_at
|
created_at
|
||||||
type
|
type
|
||||||
|
extension
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user