mirror of
https://github.com/balzack/databag.git
synced 2025-04-24 10:35:23 +00:00
adding audio and video attachments
This commit is contained in:
parent
0c2de2e00d
commit
c244c1f92d
@ -8,6 +8,8 @@ import { Message } from '../message/Message';
|
||||
import { modals } from '@mantine/modals'
|
||||
import { ImageFile } from './imageFile/ImageFile';
|
||||
import { VideoFile } from './videoFile/VideoFile';
|
||||
import { AudioFile } from './audioFile/AudioFile';
|
||||
import { BinaryFile } from './binaryFile/BinaryFile';
|
||||
|
||||
const PAD_HEIGHT = (1024 - 64);
|
||||
const LOAD_DEBOUNCE = 1000;
|
||||
@ -28,6 +30,8 @@ export function Conversation() {
|
||||
const { state, actions } = useConversation();
|
||||
const attachImage = useRef({ click: ()=>{} } as HTMLInputElement);
|
||||
const attachVideo = useRef({ click: ()=>{} } as HTMLInputElement);
|
||||
const attachAudio = useRef({ click: ()=>{} } as HTMLInputElement);
|
||||
const attachBinary = useRef({ click: ()=>{} } as HTMLInputElement);
|
||||
|
||||
const addImage = (image: File | undefined) => {
|
||||
if (image) {
|
||||
@ -41,6 +45,18 @@ export function Conversation() {
|
||||
}
|
||||
}
|
||||
|
||||
const addAudio = (audio: File | undefined) => {
|
||||
if (audio) {
|
||||
actions.addAudio(audio);
|
||||
}
|
||||
}
|
||||
|
||||
const addBinary = (binary: File | undefined) => {
|
||||
if (binary) {
|
||||
actions.addBinary(binary);
|
||||
}
|
||||
}
|
||||
|
||||
const sendMessage = async () => {
|
||||
if (!sending) {
|
||||
setSending(true);
|
||||
@ -111,14 +127,13 @@ export function Conversation() {
|
||||
return <ImageFile key={index} source={asset.file} />
|
||||
} else if (asset.type === 'video') {
|
||||
return <VideoFile key={index} source={asset.file} thumbPosition={(position: number) => actions.setThumbPosition(index, position)} disabled={sending} />
|
||||
} else if (asset.type === 'audio') {
|
||||
return <AudioFile key={index} source={asset.file} />
|
||||
} else {
|
||||
return <div key={index}></div>
|
||||
return <BinaryFile key={index} source={asset.file} />
|
||||
}
|
||||
});
|
||||
|
||||
console.log(state.assets);
|
||||
|
||||
|
||||
return (
|
||||
<div className={classes.conversation}>
|
||||
<div className={classes.header}>
|
||||
@ -180,6 +195,8 @@ console.log(state.assets);
|
||||
<div className={classes.add}>
|
||||
<input type='file' name="asset" accept="image/*" ref={attachImage} onChange={e => addImage(e.target?.files?.[0])} style={{display: 'none'}}/>
|
||||
<input type='file' name="asset" accept="video/*" ref={attachVideo} onChange={e => addVideo(e.target?.files?.[0])} style={{display: 'none'}}/>
|
||||
<input type='file' name="asset" accept="audio/*" ref={attachAudio} onChange={e => addAudio(e.target?.files?.[0])} style={{display: 'none'}}/>
|
||||
<input type='file' name="asset" accept="*/*" ref={attachBinary} onChange={e => addBinary(e.target?.files?.[0])} style={{display: 'none'}}/>
|
||||
<div className={classes.files}>
|
||||
{ media }
|
||||
</div>
|
||||
@ -191,10 +208,10 @@ console.log(state.assets);
|
||||
<ActionIcon className={classes.attach} variant="light" disabled={!state.detail || state.detail.locked || sending} onClick={() => attachVideo.current.click()}>
|
||||
<IconVideo />
|
||||
</ActionIcon>
|
||||
<ActionIcon className={classes.attach} variant="light" disabled={!state.detail || state.detail.locked || sending}>
|
||||
<ActionIcon className={classes.attach} variant="light" disabled={!state.detail || state.detail.locked || sending} onClick={() => attachAudio.current.click()}>
|
||||
<IconDisc />
|
||||
</ActionIcon>
|
||||
<ActionIcon className={classes.attach} variant="light" disabled={!state.detail || state.detail.locked || sending}>
|
||||
<ActionIcon className={classes.attach} variant="light" disabled={!state.detail || state.detail.locked || sending} onClick={() => attachBinary.current.click()}>
|
||||
<IconFile />
|
||||
</ActionIcon>
|
||||
<Divider size="sm" orientation="vertical" />
|
||||
|
@ -0,0 +1,9 @@
|
||||
.asset {
|
||||
padding-top: 16px;
|
||||
|
||||
.thumb {
|
||||
width: auto;
|
||||
height: 92px;
|
||||
}
|
||||
}
|
||||
|
16
app/client/web/src/conversation/audioFile/AudioFile.tsx
Normal file
16
app/client/web/src/conversation/audioFile/AudioFile.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import React from 'react';
|
||||
import { Image } from '@mantine/core'
|
||||
import { useAudioFile } from './useAudioFile.hook';
|
||||
import classes from './AudioFile.module.css'
|
||||
import audio from '../../images/audio.png'
|
||||
|
||||
export function AudioFile({ source }: {source: File}) {
|
||||
const { state, actions } = useAudioFile(source);
|
||||
|
||||
return (
|
||||
<div className={classes.asset}>
|
||||
<Image radius="sm" className={classes.thumb} src={audio} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
|
||||
export function useAudioFile(source: File) {
|
||||
const [state, setState] = useState({
|
||||
thumbUrl: null,
|
||||
})
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const updateState = (value: any) => {
|
||||
setState((s) => ({ ...s, ...value }))
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const thumbUrl = URL.createObjectURL(source);
|
||||
updateState({ thumbUrl });
|
||||
return () => { URL.revokeObjectURL(thumbUrl) };
|
||||
}, [source]);
|
||||
|
||||
const actions = {
|
||||
}
|
||||
|
||||
return { state, actions }
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
.asset {
|
||||
padding-top: 16px;
|
||||
|
||||
.thumb {
|
||||
width: auto;
|
||||
height: 92px;
|
||||
}
|
||||
}
|
||||
|
16
app/client/web/src/conversation/binaryFile/BinaryFile.tsx
Normal file
16
app/client/web/src/conversation/binaryFile/BinaryFile.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import React from 'react';
|
||||
import { Image } from '@mantine/core'
|
||||
import { useBinaryFile } from './useBinaryFile.hook';
|
||||
import classes from './BinaryFile.module.css'
|
||||
import binary from '../../images/binary.png'
|
||||
|
||||
export function BinaryFile({ source }: {source: File}) {
|
||||
const { state, actions } = useBinaryFile(source);
|
||||
|
||||
return (
|
||||
<div className={classes.asset}>
|
||||
<Image radius="sm" className={classes.thumb} src={binary} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -0,0 +1,19 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
|
||||
export function useBinaryFile(source: File) {
|
||||
const [state, setState] = useState({
|
||||
})
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const updateState = (value: any) => {
|
||||
setState((s) => ({ ...s, ...value }))
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
}, [source]);
|
||||
|
||||
const actions = {
|
||||
}
|
||||
|
||||
return { state, actions }
|
||||
}
|
@ -32,7 +32,7 @@ function getImageThumb(file: File) {
|
||||
});
|
||||
}
|
||||
|
||||
function getVideoThumb(file: File, position: number) {
|
||||
function getVideoThumb(file: File, position?: number) {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
const url = URL.createObjectURL(file);
|
||||
var video = document.createElement("video");
|
||||
@ -71,7 +71,7 @@ function getVideoThumb(file: File, position: number) {
|
||||
video.src = url;
|
||||
video.muted = true;
|
||||
video.playsInline = true;
|
||||
video.currentTime = position;
|
||||
video.currentTime = position ? position : 0;
|
||||
video.play();
|
||||
});
|
||||
}
|
||||
@ -98,7 +98,7 @@ export function useConversation() {
|
||||
subjectNames: [],
|
||||
unknownContacts: 0,
|
||||
message: '',
|
||||
assets: [] as {type: string, file: File}[],
|
||||
assets: [] as {type: string, file: File, position?: number}[],
|
||||
})
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
@ -106,7 +106,7 @@ export function useConversation() {
|
||||
setState((s) => ({ ...s, ...value }))
|
||||
}
|
||||
|
||||
const updateAsset = (index, value) => {
|
||||
const updateAsset = (index: number, value: any) => {
|
||||
setState((s) => {
|
||||
s.assets[index] = { ...s.assets[index], ...value };
|
||||
return { ...s };
|
||||
@ -270,7 +270,11 @@ export function useConversation() {
|
||||
const type = asset.encrypted.type;
|
||||
const thumb = uploaded.find(upload => upload.appId === asset.encrypted.thumb)?.assetId;
|
||||
const parts = uploaded.find(upload => upload.appId === asset.encrypted.parts)?.assetId;
|
||||
return { encrypted: { type, thumb, parts }};
|
||||
if (type === 'image' || type === 'video') {
|
||||
return { encrypted: { type, thumb, parts }};
|
||||
} else {
|
||||
return { encrypted: { type, thumb, parts }};
|
||||
}
|
||||
} else if (asset.image) {
|
||||
const thumb = uploaded.find(upload => upload.appId === asset.image.thumb)?.assetId;
|
||||
const full = uploaded.find(upload => upload.appId === asset.image.full)?.assetId;
|
||||
@ -288,6 +292,8 @@ export function useConversation() {
|
||||
return { binary: { data } };
|
||||
}
|
||||
});
|
||||
console.log(assets, uploaded);
|
||||
|
||||
return { text: state.message, assets };
|
||||
}
|
||||
const progress = (precent: number) => {};
|
||||
@ -303,6 +309,14 @@ export function useConversation() {
|
||||
const type = 'video';
|
||||
updateState({ assets: [ ...state.assets, { type, file } ]});
|
||||
},
|
||||
addAudio: (file: File) => {
|
||||
const type = 'audio';
|
||||
updateState({ assets: [ ...state.assets, { type, file } ]});
|
||||
},
|
||||
addBinary: (file: File) => {
|
||||
const type = 'binary';
|
||||
updateState({ assets: [ ...state.assets, { type, file } ]});
|
||||
},
|
||||
}
|
||||
|
||||
return { state, actions }
|
||||
|
@ -8,7 +8,7 @@ export function VideoFile({ source, thumbPosition, disabled }: {source: File, th
|
||||
const { state, actions } = useVideoFile(source);
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
const position = useRef(0);
|
||||
const player = useRef();
|
||||
const player = useRef(null as null | HTMLVideoElement);
|
||||
|
||||
const seek = (offset: number) => {
|
||||
if (player.current) {
|
||||
@ -29,13 +29,15 @@ export function VideoFile({ source, thumbPosition, disabled }: {source: File, th
|
||||
}
|
||||
|
||||
const onPause = () => {
|
||||
player.current.pause();
|
||||
if (player.current) {
|
||||
player.current.pause();
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classes.asset}>
|
||||
{ state.videoUrl && (
|
||||
<video ref={player} muted onLoadedMetadata={() => setLoaded(true)} onPlay={onPause} src={state.videoUrl} width={'auto'} height={'100%'} playsinline="true" />
|
||||
<video ref={player} muted onLoadedMetadata={() => setLoaded(true)} onPlay={onPause} src={state.videoUrl} width={'auto'} height={'100%'} playsInline={true} />
|
||||
)}
|
||||
{ loaded && !disabled && (
|
||||
<ActionIcon className={classes.right} variant="light" onClick={() => seek(1)}>
|
||||
|
@ -21,8 +21,6 @@ export function useVideoAsset(topicId: string, asset: MediaAsset) {
|
||||
if (focus && assetId != null) {
|
||||
try {
|
||||
const thumbUrl = await focus.getTopicAssetUrl(topicId, assetId);
|
||||
console.log("THUMB:", thumbUrl);
|
||||
|
||||
updateState({ thumbUrl });
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
|
@ -526,7 +526,11 @@ export class FocusModule implements Focus {
|
||||
const mapped = filtered.map((asset: any) => {
|
||||
if (asset.encrypted) {
|
||||
const { type, thumb, parts } = asset.encrypted;
|
||||
return { encrypted: { type, thumb: getAsset(thumb), parts: getAsset(parts) } };
|
||||
if (type === 'image' || type === 'video') {
|
||||
return { encrypted: { type, thumb: getAsset(thumb), parts: getAsset(parts) } };
|
||||
} else {
|
||||
return { encrypted: { type, parts: getAsset(parts) } };
|
||||
}
|
||||
} else if (asset.image) {
|
||||
const { thumb, full } = asset.image;
|
||||
return { image: { thumb: getAsset(thumb), full: getAsset(full) } };
|
||||
|
Loading…
x
Reference in New Issue
Block a user