mirror of
https://github.com/balzack/databag.git
synced 2025-05-05 07:55:15 +00:00
supporting binary download
This commit is contained in:
parent
ee8169f168
commit
39b4a98c39
@ -1259,6 +1259,8 @@ PODS:
|
|||||||
- React-logger (= 0.74.3)
|
- React-logger (= 0.74.3)
|
||||||
- React-perflogger (= 0.74.3)
|
- React-perflogger (= 0.74.3)
|
||||||
- React-utils (= 0.74.3)
|
- React-utils (= 0.74.3)
|
||||||
|
- rn-fetch-blob (0.12.0):
|
||||||
|
- React-Core
|
||||||
- RNCClipboard (1.15.0):
|
- RNCClipboard (1.15.0):
|
||||||
- React-Core
|
- React-Core
|
||||||
- RNFS (2.20.0):
|
- RNFS (2.20.0):
|
||||||
@ -1493,6 +1495,7 @@ DEPENDENCIES:
|
|||||||
- React-runtimescheduler (from `../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler`)
|
- React-runtimescheduler (from `../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler`)
|
||||||
- React-utils (from `../node_modules/react-native/ReactCommon/react/utils`)
|
- React-utils (from `../node_modules/react-native/ReactCommon/react/utils`)
|
||||||
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
|
- 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`)"
|
- "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)"
|
||||||
- RNFS (from `../node_modules/react-native-fs`)
|
- RNFS (from `../node_modules/react-native-fs`)
|
||||||
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
|
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
|
||||||
@ -1632,6 +1635,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: "../node_modules/react-native/ReactCommon/react/utils"
|
:path: "../node_modules/react-native/ReactCommon/react/utils"
|
||||||
ReactCommon:
|
ReactCommon:
|
||||||
:path: "../node_modules/react-native/ReactCommon"
|
:path: "../node_modules/react-native/ReactCommon"
|
||||||
|
rn-fetch-blob:
|
||||||
|
:path: "../node_modules/rn-fetch-blob"
|
||||||
RNCClipboard:
|
RNCClipboard:
|
||||||
:path: "../node_modules/@react-native-clipboard/clipboard"
|
:path: "../node_modules/@react-native-clipboard/clipboard"
|
||||||
RNFS:
|
RNFS:
|
||||||
@ -1713,6 +1718,7 @@ SPEC CHECKSUMS:
|
|||||||
React-runtimescheduler: 0c80752bceb80924cb8a4babc2a8e3ed70d41e87
|
React-runtimescheduler: 0c80752bceb80924cb8a4babc2a8e3ed70d41e87
|
||||||
React-utils: a06061b3887c702235d2dac92dacbd93e1ea079e
|
React-utils: a06061b3887c702235d2dac92dacbd93e1ea079e
|
||||||
ReactCommon: f00e436b3925a7ae44dfa294b43ef360fbd8ccc4
|
ReactCommon: f00e436b3925a7ae44dfa294b43ef360fbd8ccc4
|
||||||
|
rn-fetch-blob: f065bb7ab7fb48dd002629f8bdcb0336602d3cba
|
||||||
RNCClipboard: 69ab8e51324d5b351f6ba72bbdb72478087a2c64
|
RNCClipboard: 69ab8e51324d5b351f6ba72bbdb72478087a2c64
|
||||||
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
|
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
|
||||||
RNGestureHandler: 6fee3422fd8c81c5ee756fa72e3d1780e9943d9d
|
RNGestureHandler: 6fee3422fd8c81c5ee756fa72e3d1780e9943d9d
|
||||||
|
@ -43,7 +43,8 @@
|
|||||||
"react-native-video": "^6.8.2",
|
"react-native-video": "^6.8.2",
|
||||||
"react-native-wheel-color-picker": "^1.3.1",
|
"react-native-wheel-color-picker": "^1.3.1",
|
||||||
"react-router-dom": "^6.26.0",
|
"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": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.20.0",
|
"@babel/core": "^7.20.0",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import {StyleSheet} from 'react-native';
|
import {StyleSheet} from 'react-native';
|
||||||
import {Colors} from '../constants/Colors';
|
import {Colors} from '../../constants/Colors';
|
||||||
|
|
||||||
export const styles = StyleSheet.create({
|
export const styles = StyleSheet.create({
|
||||||
modal: {
|
modal: {
|
||||||
@ -14,6 +14,9 @@ export const styles = StyleSheet.create({
|
|||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
backgroundColor: '#444444',
|
backgroundColor: '#444444',
|
||||||
},
|
},
|
||||||
|
control: {
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
},
|
||||||
container: {
|
container: {
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
width: 92,
|
width: 92,
|
||||||
@ -30,6 +33,11 @@ export const styles = StyleSheet.create({
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
},
|
},
|
||||||
|
info: {
|
||||||
|
fontSize: 12,
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
},
|
||||||
blur: {
|
blur: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: 0,
|
top: 0,
|
||||||
@ -52,10 +60,29 @@ export const styles = StyleSheet.create({
|
|||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
},
|
},
|
||||||
|
label: {
|
||||||
|
flexGrow: 1,
|
||||||
|
fontSize: 32,
|
||||||
|
paddingLeft: 16,
|
||||||
|
minWidth: 0,
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
flexShrink: 1,
|
||||||
|
},
|
||||||
close: {
|
close: {
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'row',
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
|
alignItems: 'center',
|
||||||
top: 0,
|
top: 0,
|
||||||
right: 0,
|
minWidth: 0,
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
alert: {
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: 0,
|
||||||
|
},
|
||||||
|
alertLabel: {
|
||||||
|
color: Colors.offsync,
|
||||||
},
|
},
|
||||||
closeIcon: {
|
closeIcon: {
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: 'transparent',
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
import React, { useState, useEffect, useRef } from 'react';
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
import { SafeAreaView, Modal, Pressable, View, Image, Animated, useAnimatedValue } from 'react-native'
|
import { SafeAreaView, Modal, Share, Pressable, View, Image, Animated, useAnimatedValue } from 'react-native'
|
||||||
import { Icon, ProgressBar, IconButton } from 'react-native-paper'
|
import { Text, Icon, ProgressBar, IconButton } from 'react-native-paper'
|
||||||
import { useBinaryAsset } from './useBinaryAsset.hook';
|
import { useBinaryAsset } from './useBinaryAsset.hook';
|
||||||
import { MediaAsset } from '../../conversation/Conversation';
|
import { MediaAsset } from '../../conversation/Conversation';
|
||||||
import { styles } from './BinaryAsset.styled'
|
import { styles } from './BinaryAsset.styled'
|
||||||
import {BlurView} from '@react-native-community/blur';
|
import {BlurView} from '@react-native-community/blur';
|
||||||
import Video from 'react-native-video'
|
import Video from 'react-native-video'
|
||||||
import thumb from '../../images/binary.png';
|
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 }) {
|
export function BinaryAsset({ topicId, asset, loaded, show }: { topicId: string, asset: MediaAsset, loaded: ()=>void, show: boolean }) {
|
||||||
const { state, actions } = useBinaryAsset(topicId, asset);
|
const { state, actions } = useBinaryAsset(topicId, asset);
|
||||||
const [modal, setModal] = useState(false);
|
const [modal, setModal] = useState(false);
|
||||||
const opacity = useAnimatedValue(0);
|
const opacity = useAnimatedValue(0);
|
||||||
|
const [alert, setAlert] = useState('');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (show) {
|
if (show) {
|
||||||
@ -23,7 +25,21 @@ export function BinaryAsset({ topicId, asset, loaded, show }: { topicId: string,
|
|||||||
}
|
}
|
||||||
}, [show]);
|
}, [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 = () => {
|
const showBinary = () => {
|
||||||
|
setAlert('');
|
||||||
setModal(true);
|
setModal(true);
|
||||||
actions.loadBinary();
|
actions.loadBinary();
|
||||||
};
|
};
|
||||||
@ -48,6 +64,7 @@ export function BinaryAsset({ topicId, asset, loaded, show }: { topicId: string,
|
|||||||
<View style={styles.button}>
|
<View style={styles.button}>
|
||||||
<Icon size={28} source="download-outline" />
|
<Icon size={28} source="download-outline" />
|
||||||
</View>
|
</View>
|
||||||
|
<Text style={styles.info} numberOfLines={1}>{ asset.binary?.label || asset.encrypted?.label }</Text>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
<Modal animationType="fade" transparent={true} supportedOrientations={['portrait', 'landscape']} visible={modal} onRequestClose={hideBinary}>
|
<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"
|
resizeMode="contain"
|
||||||
source={thumb}
|
source={thumb}
|
||||||
/>
|
/>
|
||||||
<View style={styles.button}>
|
{ state.dataUrl && (
|
||||||
<Icon size={64} source="download-outline" />
|
<View style={styles.button}>
|
||||||
</View>
|
<IconButton style={styles.control} size={64} icon="download-outline" onPress={share} />
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
{ state.loading && (
|
{ state.loading && (
|
||||||
<View style={styles.progress}>
|
<View style={styles.progress}>
|
||||||
<ProgressBar progress={state.loadPercent / 100} />
|
<ProgressBar progress={state.loadPercent / 100} />
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
<SafeAreaView style={styles.alert}>
|
||||||
|
<Text style={styles.alertLabel}>{ alert }</Text>
|
||||||
|
</SafeAreaView>
|
||||||
<SafeAreaView style={styles.close}>
|
<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} />
|
<IconButton style={styles.closeIcon} icon="close" compact="true" mode="contained" size={28} onPress={hideBinary} />
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
</View>
|
</View>
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
import { useState, useContext, useEffect, useRef } from 'react'
|
import { useState, useContext, useEffect, useRef } from 'react'
|
||||||
import { AppContext } from '../../context/AppContext'
|
import { AppContext } from '../../context/AppContext'
|
||||||
|
import { DisplayContext } from '../../context/DisplayContext';
|
||||||
import { Focus } from 'databag-client-sdk'
|
import { Focus } from 'databag-client-sdk'
|
||||||
import { ContextType } from '../../context/ContextType'
|
import { ContextType } from '../../context/ContextType'
|
||||||
import { MediaAsset } from '../../conversation/Conversation';
|
import { MediaAsset } from '../../conversation/Conversation';
|
||||||
|
|
||||||
export function useBinaryAsset(topicId: string, asset: MediaAsset) {
|
export function useBinaryAsset(topicId: string, asset: MediaAsset) {
|
||||||
const app = useContext(AppContext) as ContextType
|
const app = useContext(AppContext) as ContextType
|
||||||
|
const display = useContext(DisplayContext) as ContextType
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
|
strings: display.state.strings,
|
||||||
dataUrl: null,
|
dataUrl: null,
|
||||||
loading: false,
|
loading: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
@ -25,7 +28,7 @@ export function useBinaryAsset(topicId: string, asset: MediaAsset) {
|
|||||||
},
|
},
|
||||||
loadBinary: async () => {
|
loadBinary: async () => {
|
||||||
const { focus } = app.state;
|
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) {
|
if (focus && assetId != null && !state.loading && !state.dataUrl) {
|
||||||
cancelled.current = false;
|
cancelled.current = false;
|
||||||
updateState({ loading: true, loadPercent: 0 });
|
updateState({ loading: true, loadPercent: 0 });
|
||||||
|
@ -3471,6 +3471,7 @@ __metadata:
|
|||||||
react-router-dom: ^6.26.0
|
react-router-dom: ^6.26.0
|
||||||
react-router-native: ^6.26.0
|
react-router-native: ^6.26.0
|
||||||
react-test-renderer: 18.2.0
|
react-test-renderer: 18.2.0
|
||||||
|
rn-fetch-blob: ^0.12.0
|
||||||
typescript: 5.0.4
|
typescript: 5.0.4
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
@ -3946,7 +3947,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"base-64@npm:^0.1.0":
|
"base-64@npm:0.1.0, base-64@npm:^0.1.0":
|
||||||
version: 0.1.0
|
version: 0.1.0
|
||||||
resolution: "base-64@npm:0.1.0"
|
resolution: "base-64@npm:0.1.0"
|
||||||
checksum: 5a42938f82372ab5392cbacc85a5a78115cbbd9dbef9f7540fa47d78763a3a8bd7d598475f0d92341f66285afd377509851a9bb5c67bbecb89686e9255d5b3eb
|
checksum: 5a42938f82372ab5392cbacc85a5a78115cbbd9dbef9f7540fa47d78763a3a8bd7d598475f0d92341f66285afd377509851a9bb5c67bbecb89686e9255d5b3eb
|
||||||
@ -5734,6 +5735,20 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"glob@npm:^10.2.2, glob@npm:^10.3.10, glob@npm:^10.3.7":
|
||||||
version: 10.4.5
|
version: 10.4.5
|
||||||
resolution: "glob@npm:10.4.5"
|
resolution: "glob@npm:10.4.5"
|
||||||
@ -9598,6 +9613,16 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"run-parallel@npm:^1.1.9":
|
||||||
version: 1.2.0
|
version: 1.2.0
|
||||||
resolution: "run-parallel@npm:1.2.0"
|
resolution: "run-parallel@npm:1.2.0"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user