mirror of
https://github.com/balzack/databag.git
synced 2025-04-20 08:35:15 +00:00
adding generic file attachment to mobile app
This commit is contained in:
parent
25f5a55510
commit
f2919bface
@ -9,9 +9,11 @@ import avatar from 'images/avatar.png';
|
||||
import { VideoThumb } from './videoThumb/VideoThumb';
|
||||
import { AudioThumb } from './audioThumb/AudioThumb';
|
||||
import { ImageThumb } from './imageThumb/ImageThumb';
|
||||
import { BinaryThumb } from './binaryThumb/BinaryThumb';
|
||||
import { ImageAsset } from './imageAsset/ImageAsset';
|
||||
import { AudioAsset } from './audioAsset/AudioAsset';
|
||||
import { VideoAsset } from './videoAsset/VideoAsset';
|
||||
import { BinaryAsset } from './binaryAsset/BinaryAsset';
|
||||
import Carousel from 'react-native-reanimated-carousel';
|
||||
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
||||
import { SafeAreaView, SafeAreaProvider } from 'react-native-safe-area-context';
|
||||
@ -120,7 +122,10 @@ export function TopicItem({ item, focused, focus, hosting, remove, update, block
|
||||
<VideoThumb url={thumb.item.thumb} onAssetView={() => actions.showCarousel(thumb.index)} />
|
||||
)}
|
||||
{ thumb.item.type === 'audio' && (
|
||||
<AudioThumb labe={thumb.item.label} onAssetView={() => actions.showCarousel(thumb.index)} />
|
||||
<AudioThumb label={thumb.item.label} onAssetView={() => actions.showCarousel(thumb.index)} />
|
||||
)}
|
||||
{ thumb.item.type === 'binary' && (
|
||||
<BinaryThumb label={thumb.item.label} extension={thumb.item.extension} onAssetView={() => actions.showCarousel(thumb.index)} />
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
@ -234,6 +239,9 @@ export function TopicItem({ item, focused, focus, hosting, remove, update, block
|
||||
{ state.assets[index].type === 'audio' && (
|
||||
<AudioAsset asset={state.assets[index]} dismiss={actions.hideCarousel} />
|
||||
)}
|
||||
{ state.assets[index].type === 'binary' && (
|
||||
<BinaryAsset asset={state.assets[index]} dismiss={actions.hideCarousel} />
|
||||
)}
|
||||
</View>
|
||||
)} />
|
||||
</GestureHandlerRootView>
|
||||
|
@ -0,0 +1,55 @@
|
||||
import { ActivityIndicator, Alert, View, Text, TouchableOpacity } from 'react-native';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import Colors from 'constants/Colors';
|
||||
import { useBinaryAsset } from './useBinaryAsset.hook';
|
||||
import { styles } from './BinaryAsset.styled';
|
||||
import MatIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
import AntIcons from 'react-native-vector-icons/AntDesign';
|
||||
|
||||
export function BinaryAsset({ asset, dismiss }) {
|
||||
|
||||
const { state, actions } = useBinaryAsset();
|
||||
|
||||
|
||||
const download = async () => {
|
||||
try {
|
||||
const url = asset.encrypted ? `file://${asset.decrypted}` : asset.data;
|
||||
await actions.download(asset.label, asset.extension, url);
|
||||
}
|
||||
catch (err) {
|
||||
Alert.alert(
|
||||
'Download Failed',
|
||||
'Please try again.'
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={{ ...styles.container, width: state.width, height: state.height }}>
|
||||
<Text style={styles.label}>{ asset.label }</Text>
|
||||
<TouchableOpacity style={styles.close} onPress={dismiss}>
|
||||
<MatIcons name="window-close" size={32} color={Colors.white} />
|
||||
</TouchableOpacity>
|
||||
<View style={styles.action}>
|
||||
{ asset.encrypted && !asset.decrypted && (
|
||||
<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>
|
||||
)}
|
||||
{ !state.downloading && (!asset.encrypted || asset.decrypted) && (
|
||||
<TouchableOpacity onPress={download}>
|
||||
<AntIcons name="download" size={64} color={Colors.white} />
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
{ state.downloading && (
|
||||
<ActivityIndicator color={Colors.white} size="large" />
|
||||
)}
|
||||
</View>
|
||||
<Text style={styles.extension}>{ asset.extension }</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
@ -0,0 +1,53 @@
|
||||
import { StyleSheet } from 'react-native';
|
||||
import { Colors } from 'constants/Colors';
|
||||
|
||||
export const styles = StyleSheet.create({
|
||||
container: {
|
||||
position: 'relative',
|
||||
borderRadius: 8,
|
||||
backgroundColor: Colors.grey,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
},
|
||||
label: {
|
||||
textAlign: 'center',
|
||||
fontSize: 20,
|
||||
paddingTop: 8,
|
||||
paddingLeft: 48,
|
||||
paddingRight: 48,
|
||||
color: Colors.white,
|
||||
},
|
||||
action: {
|
||||
display: 'flex',
|
||||
flexGrow: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
extension: {
|
||||
textAlign: 'center',
|
||||
fontSize: 48,
|
||||
paddingBottom: 8,
|
||||
paddingLeft: 48,
|
||||
paddingRight: 48,
|
||||
color: Colors.white,
|
||||
},
|
||||
close: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
right: 0,
|
||||
paddingTop: 4,
|
||||
paddingBottom: 4,
|
||||
paddingLeft: 8,
|
||||
paddingRight: 8,
|
||||
},
|
||||
decrypting: {
|
||||
fontVariant: ["tabular-nums"],
|
||||
paddingTop: 16,
|
||||
fontSize: 12,
|
||||
color: '#888888',
|
||||
},
|
||||
})
|
||||
|
@ -0,0 +1,79 @@
|
||||
import { useState, useRef, useEffect, useContext } from 'react';
|
||||
import { ConversationContext } from 'context/ConversationContext';
|
||||
import { Image } from 'react-native';
|
||||
import { useWindowDimensions } from 'react-native';
|
||||
import { Platform } from 'react-native';
|
||||
import RNFetchBlob from "rn-fetch-blob";
|
||||
import Share from 'react-native-share';
|
||||
|
||||
export function useBinaryAsset() {
|
||||
|
||||
const [state, setState] = useState({
|
||||
width: 1,
|
||||
height: 1,
|
||||
downloading: false,
|
||||
});
|
||||
|
||||
const dimensions = useWindowDimensions();
|
||||
|
||||
const updateState = (value) => {
|
||||
setState((s) => ({ ...s, ...value }));
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const { width, height } = dimensions;
|
||||
if (width < height) {
|
||||
updateState({ width, height: width });
|
||||
}
|
||||
else {
|
||||
updateState({ widht: height, height });
|
||||
}
|
||||
}, [dimensions]);
|
||||
|
||||
const actions = {
|
||||
download: async (label, extension, url) => {
|
||||
if (!state.downloading) {
|
||||
try {
|
||||
updateState({ downloading: true });
|
||||
|
||||
const blob = await RNFetchBlob.config({ fileCache: true }).fetch("GET", url);
|
||||
const src = blob.path();
|
||||
if (Platform.OS === 'ios') {
|
||||
const path = `${RNFetchBlob.fs.dirs.DocumentDir}`
|
||||
const dst = `${path}/${label}.${extension.toLowerCase()}`
|
||||
if (RNFetchBlob.fs.exists(dst)) {
|
||||
RNFetchBlob.fs.unlink(dst);
|
||||
}
|
||||
await RNFetchBlob.fs.mv(src, dst);
|
||||
try {
|
||||
await Share.open({ url: dst, message: `${label}.${extension}`, subject: `${label}.${extension}` })
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
RNFetchBlob.fs.unlink(dst);
|
||||
}
|
||||
else {
|
||||
const path = `${RNFetchBlob.fs.dirs.DownloadDir}`
|
||||
const dst = `${path}/${label}.${extension.toLowerCase()}`
|
||||
if (RNFetchBlob.fs.exists(dst)) {
|
||||
RNFetchBlob.fs.unlink(dst);
|
||||
}
|
||||
await RNFetchBlob.fs.mv(src, dst);
|
||||
RNFetchBlob.fs.unlink(dst);
|
||||
}
|
||||
|
||||
updateState({ downloading: false });
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
updateState({ downloading: false });
|
||||
throw new Error('download failed');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return { state, actions };
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
import { View, Text, Image } from 'react-native';
|
||||
import { TouchableOpacity } from 'react-native-gesture-handler';
|
||||
import { styles } from './BinaryThumb.styled';
|
||||
import Colors from 'constants/Colors';
|
||||
import AntIcons from 'react-native-vector-icons/AntDesign';
|
||||
|
||||
export function BinaryThumb({ label, extension, onAssetView }) {
|
||||
|
||||
return (
|
||||
<TouchableOpacity activeOpacity={1} style={styles.canvas} onPress={onAssetView}>
|
||||
<Text style={styles.label}>{ label }</Text>
|
||||
<View style={styles.action}>
|
||||
<AntIcons name="download" size={28} color={Colors.white} />
|
||||
</View>
|
||||
<Text style={styles.extension}>{ extension }</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
import { StyleSheet } from 'react-native';
|
||||
import { Colors } from 'constants/Colors';
|
||||
|
||||
export const styles = StyleSheet.create({
|
||||
canvas: {
|
||||
borderRadius: 4,
|
||||
width: 92,
|
||||
height: 92,
|
||||
marginRight: 16,
|
||||
backgroundColor: Colors.grey,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
},
|
||||
action: {
|
||||
flexGrow: 1,
|
||||
},
|
||||
label: {
|
||||
textAlign: 'center',
|
||||
color: Colors.white,
|
||||
padding: 4,
|
||||
fontSize: 14,
|
||||
},
|
||||
extension: {
|
||||
textAlign: 'center',
|
||||
color: Colors.white,
|
||||
fontSize: 20,
|
||||
}
|
||||
})
|
||||
|
@ -61,8 +61,8 @@ export function useTopicItem(item, hosting, remove, contentKey) {
|
||||
const asset = parsed[i];
|
||||
if (asset.encrypted) {
|
||||
const encrypted = true;
|
||||
const { type, thumb, label, parts } = asset.encrypted;
|
||||
assets.push({ type, thumb, label, encrypted, decrypted: null, parts });
|
||||
const { type, thumb, label, extension, parts } = asset.encrypted;
|
||||
assets.push({ type, thumb, label, extension, encrypted, decrypted: null, parts });
|
||||
}
|
||||
else {
|
||||
const encrypted = false
|
||||
@ -85,6 +85,12 @@ export function useTopicItem(item, hosting, remove, contentKey) {
|
||||
const full = conversation.actions.getTopicAssetUrl(item.topicId, asset.audio.full);
|
||||
assets.push({ type, label, encrypted, full });
|
||||
}
|
||||
else if (asset.binary) {
|
||||
const type = 'binary';
|
||||
const { label, extension } = asset.binary;
|
||||
const data = conversation.actions.getTopicAssetUrl(item.topicId, asset.binary.data);
|
||||
assets.push({ type, label, extension, data });
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user