From 3cfaf4981814025e4eccdced0414d5c37e892264 Mon Sep 17 00:00:00 2001 From: balzack Date: Thu, 2 Jan 2025 16:42:31 -0800 Subject: [PATCH] adding support for video upload --- app/client/mobile/ios/Podfile.lock | 6 +++++ app/client/mobile/package.json | 1 + .../mobile/src/conversation/Conversation.tsx | 15 ++++++++++- .../src/conversation/useConversation.hook.ts | 27 ++++++++----------- app/client/mobile/yarn.lock | 10 +++++++ .../src/conversation/useConversation.hook.ts | 10 +------ app/sdk/src/focus.ts | 3 +++ 7 files changed, 46 insertions(+), 26 deletions(-) diff --git a/app/client/mobile/ios/Podfile.lock b/app/client/mobile/ios/Podfile.lock index d7e78a14..82bf5178 100644 --- a/app/client/mobile/ios/Podfile.lock +++ b/app/client/mobile/ios/Podfile.lock @@ -956,6 +956,8 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga + - react-native-create-thumbnail (2.0.1): + - React-Core - react-native-image-resizer (3.0.11): - React-Core - react-native-rsa-native (2.0.5): @@ -1440,6 +1442,7 @@ DEPENDENCIES: - React-logger (from `../node_modules/react-native/ReactCommon/logger`) - React-Mapbuffer (from `../node_modules/react-native/ReactCommon`) - "react-native-blur (from `../node_modules/@react-native-community/blur`)" + - react-native-create-thumbnail (from `../node_modules/react-native-create-thumbnail`) - "react-native-image-resizer (from `../node_modules/@bam.tech/react-native-image-resizer`)" - react-native-rsa-native (from `../node_modules/react-native-rsa-native`) - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) @@ -1547,6 +1550,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon" react-native-blur: :path: "../node_modules/@react-native-community/blur" + react-native-create-thumbnail: + :path: "../node_modules/react-native-create-thumbnail" react-native-image-resizer: :path: "../node_modules/@bam.tech/react-native-image-resizer" react-native-rsa-native: @@ -1654,6 +1659,7 @@ SPEC CHECKSUMS: React-logger: fa92ba4d3a5d39ac450f59be2a3cec7b099f0304 React-Mapbuffer: 9f68550e7c6839d01411ac8896aea5c868eff63a react-native-blur: 30d91a67da86a4d4d924b0c7c36f6e01479a246b + react-native-create-thumbnail: 4ffd51a6c02a9313edc74e2460cd07264221f554 react-native-image-resizer: 6260ba497fb8d1a593c1c92ccd593f570df6f5b7 react-native-rsa-native: 12132eb627797529fdb1f0d22fd0f8f9678df64a react-native-safe-area-context: 4532f1a0c5d34a46b9324ccaaedcb5582a302b7d diff --git a/app/client/mobile/package.json b/app/client/mobile/package.json index 5a230ca1..68091893 100644 --- a/app/client/mobile/package.json +++ b/app/client/mobile/package.json @@ -25,6 +25,7 @@ "react": "18.2.0", "react-dom": "^18.3.1", "react-native": "0.74.3", + "react-native-create-thumbnail": "^2.0.1", "react-native-file-type": "^1.0.0", "react-native-fs": "^2.20.0", "react-native-gesture-handler": "^2.19.0", diff --git a/app/client/mobile/src/conversation/Conversation.tsx b/app/client/mobile/src/conversation/Conversation.tsx index ef4bd2e2..478ecd55 100644 --- a/app/client/mobile/src/conversation/Conversation.tsx +++ b/app/client/mobile/src/conversation/Conversation.tsx @@ -11,6 +11,7 @@ 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'; +import { VideoFile } from './videoFile/VideoFile'; const SCROLL_THRESHOLD = 16; @@ -114,9 +115,21 @@ export function Conversation({close}: {close: ()=>void}) { } } + const addVideo = async () => { + try { + const { path, mime } = await ImagePicker.openPicker({ mediaType: 'video' }); + actions.addVideo(path, mime); + } + catch (err) { + console.log(err); + } + } + const media = state.assets.map((asset, index) => { if (asset.type === 'image') { return {}} /> + } else if (asset.type === 'video') { + return {}} /> } else { return <> } @@ -202,7 +215,7 @@ export function Conversation({close}: {close: ()=>void}) { - + diff --git a/app/client/mobile/src/conversation/useConversation.hook.ts b/app/client/mobile/src/conversation/useConversation.hook.ts index a1ca8ad9..50ed2d3b 100644 --- a/app/client/mobile/src/conversation/useConversation.hook.ts +++ b/app/client/mobile/src/conversation/useConversation.hook.ts @@ -6,6 +6,7 @@ import { ContextType } from '../context/ContextType' import { placeholder } from '../constants/Icons'; import RNFS from 'react-native-fs'; import ImageResizer from '@bam.tech/react-native-image-resizer'; +import { createThumbnail } from "react-native-create-thumbnail"; const IMAGE_SCALE_SIZE = (128 * 1024); const GIF_TYPE = 'image/gif'; @@ -18,10 +19,12 @@ async function getImageThumb(path: string) { return `data:image/jpeg;base64,${base}`; } -function getVideoThumb(file: File, position?: number) { - return new Promise((resolve, reject) => { - resolve(''); - }); +async function getVideoThumb(path: string, position?: number) { + const timeStamp = position ? position * 1000 : 0; + const shot = await createThumbnail({ url: path.slice(7), timeStamp }) + const thumb = await ImageResizer.createResizedImage('file://' + shot.path, 192, 192, "JPEG", 50, 0, null); + const base = await RNFS.readFile(thumb.path, 'base64') + return `data:image/jpeg;base64,${base}`; } export function useConversation() { @@ -181,7 +184,7 @@ export function useConversation() { if (asset.type === 'image') { if (sealed) { sources.push({ type: AssetType.Image, source: asset.path, transforms: [ - { type: TransformType.Thumb, appId: `it${sources.length}`, thumb: () => getImageThumb(asset.path) }, + { type: TransformType.Thumb, appId: `it${sources.length}`, thumb: async () => await getImageThumb(asset.path) }, { type: TransformType.Copy, appId: `ic${sources.length}` } ]}); return { encrypted: { type: 'image', thumb: `it${sources.length-1}`, parts: `ic${sources.length-1}` } }; @@ -194,16 +197,8 @@ export function useConversation() { } } else if (asset.type === 'video') { if (sealed) { - const videoThumb = async () => { - try { - return await getVideoThumb(asset.path, asset.position); - } catch (err) { - console.log(err); - return placeholder; - } - }; sources.push({ type: AssetType.Video, source: asset.path, transforms: [ - { type: TransformType.Thumb, appId: `vt${sources.length}`, thumb: videoThumb }, + { type: TransformType.Thumb, appId: `vt${sources.length}`, thumb: async () => await getVideoThumb(asset.path, asset.position) }, { type: TransformType.Copy, appId: `vc${sources.length}` } ]}); return { encrypted: { type: 'video', thumb: `vt${sources.length-1}`, parts: `vc${sources.length-1}` } }; @@ -288,9 +283,9 @@ export function useConversation() { const type = 'image'; updateState({ assets: [ ...state.assets, { type, path, mime } ]}); }, - addVideo: (file: File) => { + addVideo: (path: string, mime: string) => { const type = 'video'; - updateState({ assets: [ ...state.assets, { type, file } ]}); + updateState({ assets: [ ...state.assets, { type, path, mime } ]}); }, addAudio: (file: File) => { const type = 'audio'; diff --git a/app/client/mobile/yarn.lock b/app/client/mobile/yarn.lock index 3f4d799e..8de53cbb 100644 --- a/app/client/mobile/yarn.lock +++ b/app/client/mobile/yarn.lock @@ -3451,6 +3451,7 @@ __metadata: react: 18.2.0 react-dom: ^18.3.1 react-native: 0.74.3 + react-native-create-thumbnail: ^2.0.1 react-native-file-type: ^1.0.0 react-native-fs: ^2.20.0 react-native-gesture-handler: ^2.19.0 @@ -8872,6 +8873,15 @@ __metadata: languageName: node linkType: hard +"react-native-create-thumbnail@npm:^2.0.1": + version: 2.0.1 + resolution: "react-native-create-thumbnail@npm:2.0.1" + peerDependencies: + react-native: ">=0.59.0" + checksum: 2feb7d36fa02620b0e3f8a4d2275ddface6126f4788d62637fcac9d285caedcb1e967f769d4daf901f4085282e5afee75176d35209870842ea941efea5c77377 + languageName: node + linkType: hard + "react-native-elevation@npm:^1.0.0": version: 1.0.0 resolution: "react-native-elevation@npm:1.0.0" diff --git a/app/client/web/src/conversation/useConversation.hook.ts b/app/client/web/src/conversation/useConversation.hook.ts index c4227eb8..b1dede0d 100644 --- a/app/client/web/src/conversation/useConversation.hook.ts +++ b/app/client/web/src/conversation/useConversation.hook.ts @@ -251,16 +251,8 @@ export function useConversation() { } } else if (asset.type === 'video') { if (sealed) { - const videoThumb = async () => { - try { - return await getVideoThumb(asset.file, asset.position); - } catch (err) { - console.log(err); - return placeholder; - } - }; sources.push({ type: AssetType.Video, source: asset.file, transforms: [ - { type: TransformType.Thumb, appId: `vt${sources.length}`, thumb: videoThumb }, + { type: TransformType.Thumb, appId: `vt${sources.length}`, thumb: () => getVideoThumb(asset.file, asset.position) }, { type: TransformType.Copy, appId: `vc${sources.length}` } ]}); return { encrypted: { type: 'video', thumb: `vt${sources.length-1}`, parts: `vc${sources.length-1}` } }; diff --git a/app/sdk/src/focus.ts b/app/sdk/src/focus.ts index ce15aac8..a167db24 100644 --- a/app/sdk/src/focus.ts +++ b/app/sdk/src/focus.ts @@ -414,12 +414,14 @@ export class FocusModule implements Focus { for (const asset of files) { for (const transform of asset.transforms) { if (transform.type === TransformType.Thumb && transform.thumb) { +console.log("GET THUMB??"); const assetItem = { assetId: `${assetItems.length}`, encrytped: true, hosting: HostingMode.Inline, inline: await transform.thumb(), } +console.log("GOT THUMB!!"); appAsset.push({appId: transform.appId, assetId: assetItem.assetId}); assetItems.push(assetItem); } else if (transform.type === TransformType.Copy) { @@ -589,6 +591,7 @@ export class FocusModule implements Focus { await this.setRemoteChannelTopicSubject(topicId, type, updated); } } catch (err) { +console.log("THROWING!"); this.log.error(err); await this.removeRemoteChannelTopic(topicId); throw new Error('failed to add topic');