mirror of
https://github.com/balzack/databag.git
synced 2025-04-23 01:55:17 +00:00
support unsealed image asset upload
This commit is contained in:
parent
f1033777db
commit
25e4e68ded
@ -14,6 +14,7 @@ export const styles = StyleSheet.create({
|
||||
whiteSpace: 'nowrap',
|
||||
textOverflow: 'ellipsis',
|
||||
overflow: 'hidden',
|
||||
height: 16,
|
||||
},
|
||||
messageUnset: {
|
||||
fontSize: 12,
|
||||
|
@ -11,6 +11,15 @@ export const styles = StyleSheet.create({
|
||||
right: 0,
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
carousel: {
|
||||
paddingLeft: 8,
|
||||
paddingBottom: 8,
|
||||
},
|
||||
assets: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
gap: 16,
|
||||
},
|
||||
modal: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useEffect, useState, useRef } from 'react';
|
||||
import {KeyboardAvoidingView, Modal, Platform, SafeAreaView, Pressable, View, FlatList, TouchableOpacity} from 'react-native';
|
||||
import {KeyboardAvoidingView, Modal, Platform, ScrollView, SafeAreaView, Pressable, View, FlatList, TouchableOpacity} from 'react-native';
|
||||
import {styles} from './Conversation.styled';
|
||||
import {useConversation} from './useConversation.hook';
|
||||
import {Message} from '../message/Message';
|
||||
@ -9,6 +9,8 @@ import { Colors } from '../constants/Colors';
|
||||
import { Confirm } from '../confirm/Confirm';
|
||||
import ColorPicker from 'react-native-wheel-color-picker'
|
||||
import {BlurView} from '@react-native-community/blur';
|
||||
import ImagePicker from 'react-native-image-crop-picker'
|
||||
import { ImageFile } from './imageFile/ImageFile';
|
||||
|
||||
const SCROLL_THRESHOLD = 16;
|
||||
|
||||
@ -102,6 +104,24 @@ export function Conversation({close}: {close: ()=>void}) {
|
||||
scrollOffset.current = offset;
|
||||
}
|
||||
|
||||
const addImage = async () => {
|
||||
try {
|
||||
const { path, mime } = await ImagePicker.openPicker({ mediaType: 'photo' });
|
||||
actions.addImage(`file://${path}`, mime);
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
|
||||
const media = state.assets.map((asset, index) => {
|
||||
if (asset.type === 'image') {
|
||||
return <ImageFile key={index} path={asset.path} disabled={false} remove={()=>{}} />
|
||||
} else {
|
||||
return <></>
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : 'height'} keyboardVerticalOffset={Platform.OS === 'ios' ? 64 : 50} style={styles.conversation}>
|
||||
<SafeAreaView style={styles.header}>
|
||||
@ -170,13 +190,18 @@ export function Conversation({close}: {close: ()=>void}) {
|
||||
<Divider style={styles.border} bold={true} />
|
||||
<Confirm show={alert} params={alertParams} />
|
||||
<View style={styles.add}>
|
||||
{ media.length > 0 && (
|
||||
<ScrollView horizontal={true} showsHorizontalScrollIndicator={false} style={styles.carousel} contentContainerStyle={styles.assets}>
|
||||
{ media }
|
||||
</ScrollView>
|
||||
)}
|
||||
<TextInput multiline={true} mode="outlined" style={{ ...styles.message, fontSize: state.textSize }}
|
||||
textColor={state.textColorSet ? state.textColor : undefined} outlineColor="transparent" activeOutlineColor="transparent"spellcheck={false}
|
||||
autoComplete="off" autoCapitalize="none" autoCorrect={false} placeholder={state.strings.newMessage} placeholderTextColor={state.textColorSet ? state.textColor : undefined}
|
||||
cursorColor={state.textColorSet ? state.textColor : undefined} value={state.message} onChangeText={value => actions.setMessage(value)} />
|
||||
|
||||
<View style={styles.controls}>
|
||||
<Pressable style={styles.control}><Surface style={styles.surface} elevation={2}><Icon style={styles.button} source="camera" size={24} color={Colors.primary} /></Surface></Pressable>
|
||||
<Pressable style={styles.control} onPress={addImage}><Surface style={styles.surface} elevation={2}><Icon style={styles.button} source="camera" size={24} color={Colors.primary} /></Surface></Pressable>
|
||||
<Pressable style={styles.control}><Surface style={styles.surface} elevation={2}><Icon style={styles.button} source="video-outline" size={24} color={Colors.primary} /></Surface></Pressable>
|
||||
<Pressable style={styles.control}><Surface style={styles.surface} elevation={2}><Icon style={styles.button} source="volume-high" size={24} color={Colors.primary} /></Surface></Pressable>
|
||||
<Pressable style={styles.control}><Surface style={styles.surface} elevation={2}><Icon style={styles.button} source="file-outline" size={24} color={Colors.primary} /></Surface></Pressable>
|
||||
|
@ -44,7 +44,7 @@ export function useConversation() {
|
||||
subjectNames: [],
|
||||
unknownContacts: 0,
|
||||
message: '',
|
||||
assets: [] as {type: string, file: File, position?: number, label?: string}[],
|
||||
assets: [] as {type: string, path: string, mime?: string, position?: number, label?: string}[],
|
||||
textColor: '#444444',
|
||||
textColorSet: false,
|
||||
textSize: 16,
|
||||
@ -178,13 +178,13 @@ export function useConversation() {
|
||||
const uploadAssets = state.assets.map(asset => {
|
||||
if (asset.type === 'image') {
|
||||
if (sealed) {
|
||||
sources.push({ type: AssetType.Image, source: asset.file, transforms: [
|
||||
{ type: TransformType.Thumb, appId: `it${sources.length}`, thumb: () => getImageThumb(asset.file) },
|
||||
sources.push({ type: AssetType.Image, source: asset.path, transforms: [
|
||||
{ type: TransformType.Thumb, appId: `it${sources.length}`, thumb: () => getImageThumb(asset.path) },
|
||||
{ type: TransformType.Copy, appId: `ic${sources.length}` }
|
||||
]});
|
||||
return { encrypted: { type: 'image', thumb: `it${sources.length-1}`, parts: `ic${sources.length-1}` } };
|
||||
} else {
|
||||
sources.push({ type: AssetType.Image, source: asset.file, transforms: [
|
||||
sources.push({ type: AssetType.Image, source: asset.path, transforms: [
|
||||
{ type: TransformType.Thumb, appId: `it${sources.length}` },
|
||||
{ type: TransformType.Copy, appId: `ic${sources.length}` }
|
||||
]});
|
||||
@ -194,19 +194,19 @@ export function useConversation() {
|
||||
if (sealed) {
|
||||
const videoThumb = async () => {
|
||||
try {
|
||||
return await getVideoThumb(asset.file, asset.position);
|
||||
return await getVideoThumb(asset.path, asset.position);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return placeholder;
|
||||
}
|
||||
};
|
||||
sources.push({ type: AssetType.Video, source: asset.file, transforms: [
|
||||
sources.push({ type: AssetType.Video, source: asset.path, transforms: [
|
||||
{ type: TransformType.Thumb, appId: `vt${sources.length}`, thumb: videoThumb },
|
||||
{ type: TransformType.Copy, appId: `vc${sources.length}` }
|
||||
]});
|
||||
return { encrypted: { type: 'video', thumb: `vt${sources.length-1}`, parts: `vc${sources.length-1}` } };
|
||||
} else {
|
||||
sources.push({ type: AssetType.Video, source: asset.file, transforms: [
|
||||
sources.push({ type: AssetType.Video, source: asset.path, transforms: [
|
||||
{ type: TransformType.Thumb, appId: `vt${sources.length}`, position: asset.position},
|
||||
{ type: TransformType.HighQuality, appId: `vh${sources.length}` },
|
||||
{ type: TransformType.LowQuality, appId: `vl${sources.length}` }
|
||||
@ -215,26 +215,26 @@ export function useConversation() {
|
||||
}
|
||||
} else if (asset.type === 'audio') {
|
||||
if (sealed) {
|
||||
sources.push({ type: AssetType.Audio, source: asset.file, transforms: [
|
||||
sources.push({ type: AssetType.Audio, source: asset.path, transforms: [
|
||||
{ type: TransformType.Copy, appId: `ac${sources.length}` }
|
||||
]});
|
||||
return { encrypted: { type: 'audio', label: asset.label, parts: `ac${sources.length-1}` } };
|
||||
} else {
|
||||
sources.push({ type: AssetType.Video, source: asset.file, transforms: [
|
||||
sources.push({ type: AssetType.Video, source: asset.path, transforms: [
|
||||
{ type: TransformType.Copy, appId: `ac${sources.length}` }
|
||||
]});
|
||||
return { audio: { label: asset.label, full: `ac${sources.length-1}` } };
|
||||
}
|
||||
} else {
|
||||
const extension = asset.file.name.split('.').pop();
|
||||
const label = asset.file.name.split('.').shift();
|
||||
const extension = asset.path.name.split('.').pop();
|
||||
const label = asset.path.name.split('.').shift();
|
||||
if (sealed) {
|
||||
sources.push({ type: AssetType.Binary, source: asset.file, transforms: [
|
||||
sources.push({ type: AssetType.Binary, source: asset.path, transforms: [
|
||||
{ type: TransformType.Copy, appId: `bc${sources.length}` }
|
||||
]});
|
||||
return { encrypted: { type: 'binary', label, extension, parts: `bc${sources.length-1}` } };
|
||||
} else {
|
||||
sources.push({ type: AssetType.Binary, source: asset.file, transforms: [
|
||||
sources.push({ type: AssetType.Binary, source: asset.path, transforms: [
|
||||
{ type: TransformType.Copy, appId: `bc${sources.length}` }
|
||||
]});
|
||||
return { binary: { label, extension, data: `bc${sources.length-1}` } };
|
||||
@ -282,9 +282,9 @@ export function useConversation() {
|
||||
updateState({ message: '', assets: [], progress: 0 });
|
||||
}
|
||||
},
|
||||
addImage: (file: File) => {
|
||||
addImage: (path: string, mime: string) => {
|
||||
const type = 'image';
|
||||
updateState({ assets: [ ...state.assets, { type, file } ]});
|
||||
updateState({ assets: [ ...state.assets, { type, path, mime } ]});
|
||||
},
|
||||
addVideo: (file: File) => {
|
||||
const type = 'video';
|
||||
|
@ -303,7 +303,7 @@ export class FocusModule implements Focus {
|
||||
});
|
||||
}
|
||||
|
||||
private mirrorFile(source: any, topicId: string, progress: (percent: number)=>boolean): Promise<string> {
|
||||
private mirrorFile(source: File|string, topicId: string, progress: (percent: number)=>boolean): Promise<string> {
|
||||
const { cardId, channelId, connection } = this;
|
||||
if (!connection) {
|
||||
throw new Error('disconnected from channel');
|
||||
@ -312,7 +312,11 @@ export class FocusModule implements Focus {
|
||||
const params = `${cardId ? 'contact' : 'agent'}=${token}&body=multipart`
|
||||
const url = `http${secure ? 's' : ''}://${node}/content/channels/${channelId}/topics/${topicId}/blocks?${params}`
|
||||
const formData = new FormData();
|
||||
formData.append('asset', source);
|
||||
if (typeof source === 'string') { // file path used in mobile
|
||||
formData.append("asset", {uri: source, name: 'asset', type: 'application/octent-stream'});
|
||||
} else { // file object used in browser
|
||||
formData.append('asset', source);
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
const xhr = new XMLHttpRequest();
|
||||
@ -336,7 +340,7 @@ export class FocusModule implements Focus {
|
||||
});
|
||||
}
|
||||
|
||||
private transformFile(source: any, topicId: string, transforms: string[], progress: (percent: number)=>boolean): Promise<{assetId: string, transform: string}[]> {
|
||||
private transformFile(source: File|string, topicId: string, transforms: string[], progress: (percent: number)=>boolean): Promise<{assetId: string, transform: string}[]> {
|
||||
const { cardId, channelId, connection } = this;
|
||||
if (!connection) {
|
||||
throw new Error('disconnected from channel');
|
||||
@ -345,7 +349,12 @@ export class FocusModule implements Focus {
|
||||
const params = `${cardId ? 'contact' : 'agent'}=${token}&transforms=${encodeURIComponent(JSON.stringify(transforms))}`
|
||||
const url = `http${secure ? 's' : ''}://${node}/content/channels/${channelId}/topics/${topicId}/assets?${params}`
|
||||
const formData = new FormData();
|
||||
formData.append('asset', source);
|
||||
|
||||
if (typeof source === 'string') { // file path used in mobile
|
||||
formData.append("asset", {uri: source, name: 'asset', type: 'application/octent-stream'});
|
||||
} else { // file object used in browser
|
||||
formData.append('asset', source);
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
@ -148,7 +148,7 @@ export enum AssetType {
|
||||
|
||||
export type AssetSource = {
|
||||
type: AssetType;
|
||||
source: any;
|
||||
source: File|string;
|
||||
transforms: {type: TransformType, appId: string, position?: number, thumb?: ()=>Promise<string>}[],
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user