adding loading indicators for sealed asset

This commit is contained in:
balzack 2023-05-05 00:07:05 -07:00
parent c205cec28c
commit 2e28584ae1
9 changed files with 108 additions and 9 deletions

View File

@ -1,4 +1,4 @@
import { Image, View, Text, TouchableOpacity } from 'react-native';
import { ActivityIndicator, Image, View, Text, TouchableOpacity } from 'react-native';
import { useEffect, useRef } from 'react';
import Colors from 'constants/Colors';
import Video from 'react-native-video';
@ -37,6 +37,14 @@ export function AudioAsset({ asset, dismiss }) {
<Video ref={player} source={{ uri: state.url }} repeat={true}
paused={!state.playing} onLoad={actions.loaded} style={styles.player} />
)}
{ !state.loaded && (
<TouchableOpacity style={styles.loading} onPress={dismiss}>
<ActivityIndicator color={Colors.black} size="large" />
{ asset.total > 1 && (
<Text style={styles.decrypting}>{ asset.block } / { asset.total }</Text>
)}
</TouchableOpacity>
)}
</View>
);
}

View File

@ -37,5 +37,18 @@ export const styles = StyleSheet.create({
player: {
display: 'none',
},
loading: {
position: 'absolute',
display: 'flex',
flexAlign: 'center',
justifyContent: 'center',
flexDirection: 'column',
},
decrypting: {
fontVariant: ["tabular-nums"],
paddingTop: 16,
fontSize: 12,
color: '#888888',
},
})

View File

@ -1,4 +1,4 @@
import { View, Image, ActivityIndicator, TouchableOpacity } from 'react-native';
import { Text, View, Image, ActivityIndicator, TouchableOpacity } from 'react-native';
import { useImageAsset } from './useImageAsset.hook';
import { styles } from './ImageAsset.styled';
import Colors from 'constants/Colors';
@ -10,9 +10,12 @@ export function ImageAsset({ asset, dismiss }) {
return (
<TouchableOpacity style={styles.container} activeOpacity={1} onPress={actions.showControls}>
<FastImage source={{ uri: asset.thumb }} onLoad={actions.setRatio}
style={{ ...styles.thumb, width: state.imageWidth, height: state.imageHeight }}
resizeMode={FastImage.resizeMode.contain} />
{ state.url && (
<FastImage source={{ uri: state.url }} onLoad={actions.loaded} onError={actions.failed}
style={{ borderRadius: 4, width: state.imageWidth, height: state.imageHeight }}
style={{ ...styles.main, width: state.imageWidth, height: state.imageHeight }}
resizeMode={FastImage.resizeMode.contain} />
)}
@ -30,6 +33,9 @@ export function ImageAsset({ asset, dismiss }) {
{ !state.loaded && !state.failed && (
<TouchableOpacity style={styles.loading} onPress={dismiss}>
<ActivityIndicator color={Colors.white} size="large" />
{ asset.total > 1 && (
<Text style={styles.decrypting}>{ asset.block } / { asset.total }</Text>
)}
</TouchableOpacity>
)}
</TouchableOpacity>

View File

@ -9,6 +9,16 @@ export const styles = StyleSheet.create({
},
loading: {
position: 'absolute',
display: 'flex',
flexAlign: 'center',
justifyContent: 'center',
flexDirection: 'column',
},
decrypting: {
fontVariant: ["tabular-nums"],
paddingTop: 16,
fontSize: 12,
color: '#dddddd',
},
overlay: {
marginRight: 16,
@ -21,6 +31,16 @@ export const styles = StyleSheet.create({
borderWidth: 1,
borderColor: Colors.divider,
},
thumb: {
borderRadius: 4,
opacity: 0.3,
},
main: {
borderRadius: 4,
position: 'absolute',
top: 0,
left: 0,
},
close: {
position: 'absolute',
opacity: 0.9,

View File

@ -63,9 +63,12 @@ export function useImageAsset(asset) {
}, [asset]);
const actions = {
loaded: (e) => {
setRatio: (e) => {
const { width, height } = e.nativeEvent;
updateState({ loaded: true, imageRatio: width / height });
updateState({ imageRatio: width / height });
},
loaded: () => {
updateState({ loaded: true });
},
failed: () => {
updateState({ failed: true });

View File

@ -290,6 +290,8 @@ export function useTopicItem(item, hosting, remove, contentKey) {
if (exists) {
RNFS.unlink(path);
}
assets[cur] = { ...asset, block: 0, total: asset.parts.length };
updateState({ assets: [ ...assets ]});
for (let j = 0; j < asset.parts.length; j++) {
const part = asset.parts[j];
const url = conversation.actions.getTopicAssetUrl(item.topicId, part.partId);
@ -300,6 +302,9 @@ export function useTopicItem(item, hosting, remove, contentKey) {
throw new Error("unseal assets cancelled");
}
await RNFS.appendFile(path, decrypted, 'base64');
assets[cur] = { ...asset, block: j+1, total: asset.parts.length };
updateState({ assets: [ ...assets ]});
};
asset.decrypted = path;

View File

@ -1,10 +1,11 @@
import { ActivityIndicator, Image, View, TouchableOpacity } from 'react-native';
import { ActivityIndicator, Image, Text, View, TouchableOpacity } from 'react-native';
import Colors from 'constants/Colors';
import Video from 'react-native-video';
import { useVideoAsset } from './useVideoAsset.hook';
import { styles } from './VideoAsset.styled';
import Icons from 'react-native-vector-icons/MaterialCommunityIcons';
import { useKeepAwake } from '@sayem314/react-native-keep-awake';
import FastImage from 'react-native-fast-image'
import { useEffect } from 'react';
@ -17,9 +18,12 @@ export function VideoAsset({ asset, dismiss }) {
return (
<View style={styles.container}>
<TouchableOpacity activeOpacity={1} style={styles.container} onPress={actions.showControls}>
<FastImage source={{ uri: asset.thumb }} onLoad={actions.setRatio}
style={{ ...styles.thumb, width: state.thumbWidth, height: state.thumbHeight }}
resizeMode={FastImage.resizeMode.contain} />
{ state.url && (
<Video source={{ uri: state.url, type: 'video/mp4' }} style={{ width: state.width, height: state.height }} resizeMode={'cover'}
onReadyForDisplay={(e) => { console.log(e) }}
<Video source={{ uri: state.url, type: 'video/mp4' }} style={{ ...styles.main, width: state.width, height: state.height }}
resizeMode={'cover'} onReadyForDisplay={(e) => { console.log(e) }}
onLoad={actions.loaded} repeat={true} paused={!state.playing} resizeMode="contain" />
)}
{ (!state.playing || state.controls) && (
@ -44,6 +48,9 @@ export function VideoAsset({ asset, dismiss }) {
{ !state.loaded && (
<TouchableOpacity style={styles.loading} onPress={dismiss}>
<ActivityIndicator color={Colors.white} size="large" />
{ asset.total > 0 && (
<Text style={styles.decrypting}>{ asset.block } / { asset.total }</Text>
)}
</TouchableOpacity>
)}
</View>

View File

@ -16,6 +16,13 @@ export const styles = StyleSheet.create({
paddingRight: 8,
paddingTop: 4,
},
thumb: {
borderRadius: 4,
opacity: 0.6,
},
main: {
position: 'absolute',
},
close: {
position: 'absolute',
top: 0,
@ -27,6 +34,16 @@ export const styles = StyleSheet.create({
},
loading: {
position: 'absolute',
display: 'flex',
flexAlign: 'center',
justifyContent: 'center',
flexDirection: 'column',
},
decrypting: {
fontVariant: ["tabular-nums"],
paddingTop: 16,
fontSize: 12,
color: '#dddddd',
},
})

View File

@ -9,7 +9,11 @@ export function useVideoAsset(asset) {
frameWidth: 1,
frameHeight: 1,
videoRatio: 1,
thumbRatio: 1,
width: 1,
height: 1,
thumbWidth: 64,
thumbHeight: 64,
url: null,
playing: false,
loaded: false,
@ -27,6 +31,18 @@ export function useVideoAsset(asset) {
useEffect(() => {
const frameRatio = state.frameWidth / state.frameHeight;
if (frameRatio > state.thumbRatio) {
//thumbHeight constrained
const thumbHeight = 0.9 * state.frameHeight;
const thumbWidth = thumbHeight * state.thumbRatio;
updateState({ thumbWidth, thumbHeight });
}
else {
//thumbWidth constrained
const thumbWidth = 0.9 * state.frameWidth;
const thumbHeight = thumbWidth / state.thumbRatio;
updateState({ thumbWidth, thumbHeight });
}
if (frameRatio > state.videoRatio) {
//height constrained
const height = 0.9 * state.frameHeight;
@ -39,7 +55,7 @@ export function useVideoAsset(asset) {
const height = width / state.videoRatio;
updateState({ width, height });
}
}, [state.frameWidth, state.frameHeight, state.videoRatio]);
}, [state.frameWidth, state.frameHeight, state.videoRatio, state.thumbRatio]);
useEffect(() => {
updateState({ frameWidth: dimensions.width, frameHeight: dimensions.height });
@ -55,6 +71,10 @@ export function useVideoAsset(asset) {
}, [asset]);
const actions = {
setRatio: (e) => {
const { width, height } = e.nativeEvent;
updateState({ thumbRatio: width / height });
},
setResolution: (width, height) => {
updateState({ display: {}, videoRatio: width / height });
},