supporting binary download

This commit is contained in:
balzack 2025-01-05 15:52:16 -08:00
parent ee8169f168
commit 39b4a98c39
6 changed files with 95 additions and 10 deletions

View File

@ -1259,6 +1259,8 @@ PODS:
- React-logger (= 0.74.3)
- React-perflogger (= 0.74.3)
- React-utils (= 0.74.3)
- rn-fetch-blob (0.12.0):
- React-Core
- RNCClipboard (1.15.0):
- React-Core
- RNFS (2.20.0):
@ -1493,6 +1495,7 @@ DEPENDENCIES:
- React-runtimescheduler (from `../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler`)
- React-utils (from `../node_modules/react-native/ReactCommon/react/utils`)
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
- rn-fetch-blob (from `../node_modules/rn-fetch-blob`)
- "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)"
- RNFS (from `../node_modules/react-native-fs`)
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
@ -1632,6 +1635,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/react/utils"
ReactCommon:
:path: "../node_modules/react-native/ReactCommon"
rn-fetch-blob:
:path: "../node_modules/rn-fetch-blob"
RNCClipboard:
:path: "../node_modules/@react-native-clipboard/clipboard"
RNFS:
@ -1713,6 +1718,7 @@ SPEC CHECKSUMS:
React-runtimescheduler: 0c80752bceb80924cb8a4babc2a8e3ed70d41e87
React-utils: a06061b3887c702235d2dac92dacbd93e1ea079e
ReactCommon: f00e436b3925a7ae44dfa294b43ef360fbd8ccc4
rn-fetch-blob: f065bb7ab7fb48dd002629f8bdcb0336602d3cba
RNCClipboard: 69ab8e51324d5b351f6ba72bbdb72478087a2c64
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
RNGestureHandler: 6fee3422fd8c81c5ee756fa72e3d1780e9943d9d

View File

@ -43,7 +43,8 @@
"react-native-video": "^6.8.2",
"react-native-wheel-color-picker": "^1.3.1",
"react-router-dom": "^6.26.0",
"react-router-native": "^6.26.0"
"react-router-native": "^6.26.0",
"rn-fetch-blob": "^0.12.0"
},
"devDependencies": {
"@babel/core": "^7.20.0",

View File

@ -1,5 +1,5 @@
import {StyleSheet} from 'react-native';
import {Colors} from '../constants/Colors';
import {Colors} from '../../constants/Colors';
export const styles = StyleSheet.create({
modal: {
@ -14,6 +14,9 @@ export const styles = StyleSheet.create({
borderRadius: 4,
backgroundColor: '#444444',
},
control: {
backgroundColor: 'transparent',
},
container: {
position: 'relative',
width: 92,
@ -30,6 +33,11 @@ export const styles = StyleSheet.create({
alignItems: 'center',
justifyContent: 'center',
},
info: {
fontSize: 12,
position: 'absolute',
top: 0,
},
blur: {
position: 'absolute',
top: 0,
@ -52,10 +60,29 @@ export const styles = StyleSheet.create({
width: '100%',
height: '100%',
},
label: {
flexGrow: 1,
fontSize: 32,
paddingLeft: 16,
minWidth: 0,
textOverflow: 'ellipsis',
flexShrink: 1,
},
close: {
display: 'flex',
flexDirection: 'row',
position: 'absolute',
alignItems: 'center',
top: 0,
right: 0,
minWidth: 0,
width: '100%',
},
alert: {
position: 'absolute',
bottom: 0,
},
alertLabel: {
color: Colors.offsync,
},
closeIcon: {
backgroundColor: 'transparent',

View File

@ -1,17 +1,19 @@
import React, { useState, useEffect, useRef } from 'react';
import { SafeAreaView, Modal, Pressable, View, Image, Animated, useAnimatedValue } from 'react-native'
import { Icon, ProgressBar, IconButton } from 'react-native-paper'
import { SafeAreaView, Modal, Share, Pressable, View, Image, Animated, useAnimatedValue } from 'react-native'
import { Text, Icon, ProgressBar, IconButton } from 'react-native-paper'
import { useBinaryAsset } from './useBinaryAsset.hook';
import { MediaAsset } from '../../conversation/Conversation';
import { styles } from './BinaryAsset.styled'
import {BlurView} from '@react-native-community/blur';
import Video from 'react-native-video'
import thumb from '../../images/binary.png';
import RNFetchBlob from 'rn-fetch-blob';
export function BinaryAsset({ topicId, asset, loaded, show }: { topicId: string, asset: MediaAsset, loaded: ()=>void, show: boolean }) {
const { state, actions } = useBinaryAsset(topicId, asset);
const [modal, setModal] = useState(false);
const opacity = useAnimatedValue(0);
const [alert, setAlert] = useState('');
useEffect(() => {
if (show) {
@ -23,7 +25,21 @@ export function BinaryAsset({ topicId, asset, loaded, show }: { topicId: string,
}
}, [show]);
const share = async () => {
try {
setAlert('');
const extension = asset.binary?.extension || asset.encrypted?.extension;
const options = { fileCache: true, appendExt: extension.toLowerCase() };
const download = await RNFetchBlob.config(options).fetch("GET", state.dataUrl);
await Share.share({ url: download.path() });
} catch (err) {
console.log(err);
setAlert(state.strings.operationFailed)
}
}
const showBinary = () => {
setAlert('');
setModal(true);
actions.loadBinary();
};
@ -48,6 +64,7 @@ export function BinaryAsset({ topicId, asset, loaded, show }: { topicId: string,
<View style={styles.button}>
<Icon size={28} source="download-outline" />
</View>
<Text style={styles.info} numberOfLines={1}>{ asset.binary?.label || asset.encrypted?.label }</Text>
</Animated.View>
</Pressable>
<Modal animationType="fade" transparent={true} supportedOrientations={['portrait', 'landscape']} visible={modal} onRequestClose={hideBinary}>
@ -59,16 +76,22 @@ export function BinaryAsset({ topicId, asset, loaded, show }: { topicId: string,
resizeMode="contain"
source={thumb}
/>
<View style={styles.button}>
<Icon size={64} source="download-outline" />
</View>
{ state.dataUrl && (
<View style={styles.button}>
<IconButton style={styles.control} size={64} icon="download-outline" onPress={share} />
</View>
)}
</View>
{ state.loading && (
<View style={styles.progress}>
<ProgressBar progress={state.loadPercent / 100} />
</View>
)}
<SafeAreaView style={styles.alert}>
<Text style={styles.alertLabel}>{ alert }</Text>
</SafeAreaView>
<SafeAreaView style={styles.close}>
<Text style={styles.label} adjustsFontSizeToFit={true} numberOfLines={1}>{ asset.binary?.label || asset.encrypted?.label }</Text>
<IconButton style={styles.closeIcon} icon="close" compact="true" mode="contained" size={28} onPress={hideBinary} />
</SafeAreaView>
</View>

View File

@ -1,12 +1,15 @@
import { useState, useContext, useEffect, useRef } from 'react'
import { AppContext } from '../../context/AppContext'
import { DisplayContext } from '../../context/DisplayContext';
import { Focus } from 'databag-client-sdk'
import { ContextType } from '../../context/ContextType'
import { MediaAsset } from '../../conversation/Conversation';
export function useBinaryAsset(topicId: string, asset: MediaAsset) {
const app = useContext(AppContext) as ContextType
const display = useContext(DisplayContext) as ContextType
const [state, setState] = useState({
strings: display.state.strings,
dataUrl: null,
loading: false,
loaded: false,
@ -25,7 +28,7 @@ export function useBinaryAsset(topicId: string, asset: MediaAsset) {
},
loadBinary: async () => {
const { focus } = app.state;
const assetId = asset.audio ? asset.audio.full : asset.encrypted ? asset.encrypted.parts : null;
const assetId = asset.binary ? asset.binary.data : asset.encrypted ? asset.encrypted.parts : null;
if (focus && assetId != null && !state.loading && !state.dataUrl) {
cancelled.current = false;
updateState({ loading: true, loadPercent: 0 });

View File

@ -3471,6 +3471,7 @@ __metadata:
react-router-dom: ^6.26.0
react-router-native: ^6.26.0
react-test-renderer: 18.2.0
rn-fetch-blob: ^0.12.0
typescript: 5.0.4
languageName: unknown
linkType: soft
@ -3946,7 +3947,7 @@ __metadata:
languageName: node
linkType: hard
"base-64@npm:^0.1.0":
"base-64@npm:0.1.0, base-64@npm:^0.1.0":
version: 0.1.0
resolution: "base-64@npm:0.1.0"
checksum: 5a42938f82372ab5392cbacc85a5a78115cbbd9dbef9f7540fa47d78763a3a8bd7d598475f0d92341f66285afd377509851a9bb5c67bbecb89686e9255d5b3eb
@ -5734,6 +5735,20 @@ __metadata:
languageName: node
linkType: hard
"glob@npm:7.0.6":
version: 7.0.6
resolution: "glob@npm:7.0.6"
dependencies:
fs.realpath: ^1.0.0
inflight: ^1.0.4
inherits: 2
minimatch: ^3.0.2
once: ^1.3.0
path-is-absolute: ^1.0.0
checksum: 6ad065f51982f9a76f7052984121c95bca376ea02060b21200ad62b400422b05f0dc331f72da89a73c21a2451cbe9bec16bb17dcf37a516dc51bbbb6efe462a1
languageName: node
linkType: hard
"glob@npm:^10.2.2, glob@npm:^10.3.10, glob@npm:^10.3.7":
version: 10.4.5
resolution: "glob@npm:10.4.5"
@ -9598,6 +9613,16 @@ __metadata:
languageName: node
linkType: hard
"rn-fetch-blob@npm:^0.12.0":
version: 0.12.0
resolution: "rn-fetch-blob@npm:0.12.0"
dependencies:
base-64: 0.1.0
glob: 7.0.6
checksum: 56e5832be583e97d58f955c0c4f6dcb0eb62c97dde331182c6effb726253731cb555d4a5f6c81079ed2fcb957f81633cbe95b37d326d063405f912506de20ff4
languageName: node
linkType: hard
"run-parallel@npm:^1.1.9":
version: 1.2.0
resolution: "run-parallel@npm:1.2.0"