mirror of
https://github.com/balzack/databag.git
synced 2025-04-23 01:55:17 +00:00
playback sealed videos
This commit is contained in:
parent
a31094d7ac
commit
2cb9b5a180
@ -962,6 +962,49 @@ PODS:
|
||||
- React-Core
|
||||
- react-native-sqlite-storage (6.0.1):
|
||||
- React-Core
|
||||
- react-native-video (6.8.2):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- hermes-engine
|
||||
- RCT-Folly (= 2024.01.01.00)
|
||||
- RCTRequired
|
||||
- RCTTypeSafety
|
||||
- React-Codegen
|
||||
- React-Core
|
||||
- React-debug
|
||||
- React-Fabric
|
||||
- React-featureflags
|
||||
- React-graphics
|
||||
- React-ImageManager
|
||||
- react-native-video/Video (= 6.8.2)
|
||||
- React-NativeModulesApple
|
||||
- React-RCTFabric
|
||||
- React-rendererdebug
|
||||
- React-utils
|
||||
- ReactCommon/turbomodule/bridging
|
||||
- ReactCommon/turbomodule/core
|
||||
- Yoga
|
||||
- react-native-video/Video (6.8.2):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- hermes-engine
|
||||
- RCT-Folly (= 2024.01.01.00)
|
||||
- RCTRequired
|
||||
- RCTTypeSafety
|
||||
- React-Codegen
|
||||
- React-Core
|
||||
- React-debug
|
||||
- React-Fabric
|
||||
- React-featureflags
|
||||
- React-graphics
|
||||
- React-ImageManager
|
||||
- React-NativeModulesApple
|
||||
- React-RCTFabric
|
||||
- React-rendererdebug
|
||||
- React-utils
|
||||
- ReactCommon/turbomodule/bridging
|
||||
- ReactCommon/turbomodule/core
|
||||
- Yoga
|
||||
- React-nativeconfig (0.74.3)
|
||||
- React-NativeModulesApple (0.74.3):
|
||||
- glog
|
||||
@ -1398,6 +1441,7 @@ DEPENDENCIES:
|
||||
- react-native-rsa-native (from `../node_modules/react-native-rsa-native`)
|
||||
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
|
||||
- react-native-sqlite-storage (from `../node_modules/react-native-sqlite-storage`)
|
||||
- react-native-video (from `../node_modules/react-native-video`)
|
||||
- React-nativeconfig (from `../node_modules/react-native/ReactCommon`)
|
||||
- React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`)
|
||||
- React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`)
|
||||
@ -1506,6 +1550,8 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/react-native-safe-area-context"
|
||||
react-native-sqlite-storage:
|
||||
:path: "../node_modules/react-native-sqlite-storage"
|
||||
react-native-video:
|
||||
:path: "../node_modules/react-native-video"
|
||||
React-nativeconfig:
|
||||
:path: "../node_modules/react-native/ReactCommon"
|
||||
React-NativeModulesApple:
|
||||
@ -1606,6 +1652,7 @@ SPEC CHECKSUMS:
|
||||
react-native-rsa-native: 12132eb627797529fdb1f0d22fd0f8f9678df64a
|
||||
react-native-safe-area-context: 4532f1a0c5d34a46b9324ccaaedcb5582a302b7d
|
||||
react-native-sqlite-storage: f6d515e1c446d1e6d026aa5352908a25d4de3261
|
||||
react-native-video: 0d5d432c94ee0dafe05ed4927db19ed89b8c3ea5
|
||||
React-nativeconfig: fa5de9d8f4dbd5917358f8ad3ad1e08762f01dcb
|
||||
React-NativeModulesApple: 585d1b78e0597de364d259cb56007052d0bda5e5
|
||||
React-perflogger: 7bb9ba49435ff66b666e7966ee10082508a203e8
|
||||
|
@ -17,12 +17,14 @@
|
||||
"@react-navigation/native": "^6.1.18",
|
||||
"@react-navigation/native-stack": "^6.11.0",
|
||||
"@react-navigation/stack": "^6.4.1",
|
||||
"@types/react-native-video": "^5.0.20",
|
||||
"crypto-js": "^3.3.0",
|
||||
"databag-client-sdk": "^0.0.22",
|
||||
"jsencrypt": "^3.3.2",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-native": "0.74.3",
|
||||
"react-native-file-type": "^1.0.0",
|
||||
"react-native-fs": "^2.20.0",
|
||||
"react-native-gesture-handler": "^2.19.0",
|
||||
"react-native-image-crop-picker": "^0.41.2",
|
||||
@ -35,6 +37,7 @@
|
||||
"react-native-securerandom": "^1.0.1",
|
||||
"react-native-sqlite-storage": "^6.0.1",
|
||||
"react-native-vector-icons": "^10.1.0",
|
||||
"react-native-video": "^6.8.2",
|
||||
"react-router-dom": "^6.26.0",
|
||||
"react-router-native": "^6.26.0"
|
||||
},
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Media } from 'databag-client-sdk'
|
||||
import RNFS from 'react-native-fs';
|
||||
import fileType from 'react-native-file-type'
|
||||
|
||||
export class MediaFiles implements Media {
|
||||
|
||||
@ -15,15 +16,27 @@ export class MediaFiles implements Media {
|
||||
}
|
||||
|
||||
public async write(): Promise<{ setData: (data: string)=>Promise<void>, getUrl: ()=>Promise<string>, close: ()=>Promise<void> }> {
|
||||
const path = RNFS.DocumentDirectoryPath + `/${Date.now()}.dat`
|
||||
let extension = '';
|
||||
const path = RNFS.DocumentDirectoryPath + `/${Date.now()}`
|
||||
const setData = async (data: string) => {
|
||||
await RNFS.appendFile(path, data, 'base64');
|
||||
}
|
||||
const getUrl = async () => {
|
||||
return `${path}`
|
||||
if (!extension) {
|
||||
try {
|
||||
const type = await fileType(path);
|
||||
await RNFS.moveFile(path, `${path}.${type.ext}`);
|
||||
extension = `.${type.ext}`;
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
await RNFS.moveFile(path, `${path}.dat`);
|
||||
extension = '.dat';
|
||||
}
|
||||
}
|
||||
return `file://${path}${extension}`
|
||||
}
|
||||
const close = async () => {
|
||||
await RNFS.unlink(path);
|
||||
await RNFS.unlink(`${path}${extension}`);
|
||||
}
|
||||
return { setData, getUrl, close };
|
||||
}
|
||||
|
@ -2,4 +2,53 @@ import {StyleSheet} from 'react-native';
|
||||
import {Colors} from '../constants/Colors';
|
||||
|
||||
export const styles = StyleSheet.create({
|
||||
modal: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
container: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
padding: 16,
|
||||
backgroundColor: 'yellow',
|
||||
},
|
||||
button: {
|
||||
position: 'absolute',
|
||||
},
|
||||
blur: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
},
|
||||
video: {
|
||||
},
|
||||
thumb: {
|
||||
borderRadius: 4,
|
||||
},
|
||||
full: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
},
|
||||
close: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
right: 0,
|
||||
},
|
||||
closeIcon: {
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
progress: {
|
||||
position: 'absolute',
|
||||
bottom: '10%',
|
||||
width: '50%',
|
||||
},
|
||||
});
|
||||
|
@ -1,11 +1,74 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Text } from 'react-native-paper'
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { SafeAreaView, Modal, Pressable, Animated, View, Image, useAnimatedValue } from 'react-native'
|
||||
import { Icon, ProgressBar, IconButton } from 'react-native-paper'
|
||||
import { useVideoAsset } from './useVideoAsset.hook';
|
||||
import { MediaAsset } from '../../conversation/Conversation';
|
||||
import { styles } from './VideoAsset.styled'
|
||||
import {BlurView} from '@react-native-community/blur';
|
||||
import Video from 'react-native-video'
|
||||
|
||||
export function VideoAsset({ topicId, asset }: { topicId: string, asset: MediaAsset }) {
|
||||
const { state, actions } = useVideoAsset(topicId, asset);
|
||||
const [modal, setModal] = useState(false);
|
||||
const opacity = useAnimatedValue(0);
|
||||
|
||||
return (<Text>VIDEO</Text>);
|
||||
useEffect(() => {
|
||||
if (state.loaded) {
|
||||
Animated.timing(opacity, {
|
||||
toValue: 1,
|
||||
duration: 100,
|
||||
useNativeDriver: true,
|
||||
}).start();
|
||||
}
|
||||
}, [state.loaded]);
|
||||
|
||||
const showVideo = () => {
|
||||
setModal(true);
|
||||
actions.loadVideo();
|
||||
};
|
||||
|
||||
const hideVideo = () => {
|
||||
setModal(false);
|
||||
actions.cancelLoad();
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.image}>
|
||||
{ state.thumbUrl && (
|
||||
<Pressable onPress={showVideo}>
|
||||
<Animated.Image
|
||||
style={[styles.thumb,{opacity},]}
|
||||
resizeMode="contain"
|
||||
height={92}
|
||||
width={92 * state.ratio}
|
||||
source={{ uri: state.thumbUrl }}
|
||||
onLoad={actions.loaded}
|
||||
/>
|
||||
</Pressable>
|
||||
)}
|
||||
<Modal animationType="fade" transparent={true} supportedOrientations={['portrait', 'landscape']} visible={modal} onRequestClose={hideVideo}>
|
||||
<View style={styles.modal}>
|
||||
<BlurView style={styles.blur} blurType="dark" blurAmount={16} reducedTransparencyFallbackColor="dark" />
|
||||
<Image
|
||||
style={styles.full}
|
||||
resizeMode="contain"
|
||||
source={{ uri: state.thumbUrl }}
|
||||
/>
|
||||
{ state.dataUrl && (
|
||||
<Video source={{ uri: state.dataUrl }} style={styles.full}
|
||||
controls={false} onLoad={(e)=>console.log("LOAD", e)} onError={(e)=>console.log("ERR", e)} resizeMode="contain" />
|
||||
)}
|
||||
{ state.loading && (
|
||||
<View style={styles.progress}>
|
||||
<ProgressBar progress={state.loadPercent / 100} />
|
||||
</View>
|
||||
)}
|
||||
<SafeAreaView style={styles.close}>
|
||||
<IconButton style={styles.closeIcon} icon="close" compact="true" mode="contained" size={28} onPress={hideVideo} />
|
||||
</SafeAreaView>
|
||||
</View>
|
||||
</Modal>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useState, useContext, useEffect } from 'react'
|
||||
import { useState, useContext, useEffect, useRef } from 'react'
|
||||
import { AppContext } from '../../context/AppContext'
|
||||
import { Focus } from 'databag-client-sdk'
|
||||
import { ContextType } from '../../context/ContextType'
|
||||
@ -9,9 +9,12 @@ export function useVideoAsset(topicId: string, asset: MediaAsset) {
|
||||
const [state, setState] = useState({
|
||||
thumbUrl: null,
|
||||
dataUrl: null,
|
||||
ratio: 1,
|
||||
loading: false,
|
||||
loaded: false,
|
||||
loadPercent: 0,
|
||||
})
|
||||
const cancelled = useRef(false);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const updateState = (value: any) => {
|
||||
@ -36,21 +39,26 @@ export function useVideoAsset(topicId: string, asset: MediaAsset) {
|
||||
}, [asset]);
|
||||
|
||||
const actions = {
|
||||
unloadVideo: () => {
|
||||
updateState({ dataUrl: null });
|
||||
loaded: (e) => {
|
||||
const { width, height } = e.nativeEvent.source;
|
||||
updateState({ loaded: true, ratio: width / height });
|
||||
},
|
||||
cancelLoad: () => {
|
||||
cancelled.current = true;
|
||||
},
|
||||
loadVideo: async () => {
|
||||
const { focus } = app.state;
|
||||
const assetId = asset.video ? asset.video.hd : asset.encrypted ? asset.encrypted.parts : null;
|
||||
if (focus && assetId != null && !state.loading) {
|
||||
const assetId = asset.video ? asset.video.hd || asset.video.lq : asset.encrypted ? asset.encrypted.parts : null;
|
||||
if (focus && assetId != null && !state.loading && !state.dataUrl) {
|
||||
cancelled.current = false;
|
||||
updateState({ loading: true, loadPercent: 0 });
|
||||
try {
|
||||
const dataUrl = await focus.getTopicAssetUrl(topicId, assetId, (loadPercent: number)=>{ updateState({ loadPercent }) });
|
||||
updateState({ dataUrl, loading: false });
|
||||
const dataUrl = await focus.getTopicAssetUrl(topicId, assetId, (loadPercent: number)=>{ updateState({ loadPercent }); return !cancelled.current });
|
||||
updateState({ dataUrl });
|
||||
} catch (err) {
|
||||
updateState({ loading: false });
|
||||
console.log(err);
|
||||
}
|
||||
updateState({ loading: false });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user