rendering image asset

This commit is contained in:
balzack 2024-12-30 17:04:18 -08:00
parent ce2ffabe9b
commit 219c04e213
10 changed files with 88 additions and 22 deletions

View File

@ -44,7 +44,7 @@ export const styles = StyleSheet.create({
alignItems: 'center',
justifyContent: 'center',
},
back: {
icon: {
flexShrink: 0,
marginRight: 0,
marginLeft: 0,
@ -59,15 +59,14 @@ export const styles = StyleSheet.create({
header: {
display: 'flex',
flexDirection: 'row',
},
iconSpace: {
width: '10%',
width: '100%',
minWidth: 0,
},
title: {
width: '80%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
flexGrow: 1,
},
label: {
fontSize: 24,

View File

@ -19,7 +19,7 @@ export type MediaAsset = {
export function Conversation({close}: {close: ()=>void}) {
const { state, actions } = useConversation();
const [ more, setMore ] = useState(false);
const [ selected, setSelected ] = useState(null);
const [ selected, setSelected ] = useState(null as null | string);
const thread = useRef();
const scrolled = useRef(false);
@ -71,11 +71,7 @@ export function Conversation({close}: {close: ()=>void}) {
return (
<View style={styles.conversation}>
<SafeAreaView style={styles.header}>
{close && (
<View style={styles.iconSpace}>
<IconButton style={styles.back} compact="true" mode="contained" icon="arrow-left" size={28} onPress={onClose} />
</View>
)}
<IconButton style={styles.icon} compact="true" mode="contained" icon="arrow-left" size={28} onPress={onClose} />
<View style={styles.title}>
{ state.detailSet && state.subject && (
<Text adjustsFontSizeToFit={true} numberOfLines={1} style={styles.label}>{ state.subject }</Text>
@ -90,7 +86,7 @@ export function Conversation({close}: {close: ()=>void}) {
<Text adjustsFontSizeToFit={true} numberOfLines={1} style={styles.unknown}>{ `, ${state.strings.unknownContact} (${state.unknownContacts})` }</Text>
)}
</View>
{close && <View style={styles.iconSpace} />}
<IconButton style={styles.icon} compact="true" mode="contained" icon="cog-outline" size={28} onPress={()=>{}} />
</SafeAreaView>
<Divider style={styles.border} bold={true} />
<View style={styles.thread}>
@ -116,7 +112,7 @@ export function Conversation({close}: {close: ()=>void}) {
card={card}
profile={profile}
host={host}
select={(id: string)=>setSelected(id)}
select={(id)=>setSelected(id)}
selected={selected}
/>
)

View File

@ -79,4 +79,18 @@ export const styles = StyleSheet.create({
paddingRight: 12,
paddingTop: 4,
},
carousel: {
paddingLeft: 8,
paddingBottom: 8,
},
assets: {
display: 'flex',
flexDirection: 'row',
gap: 16,
},
item: {
width: 64,
height: 64,
backgroundColor: 'yellow',
}
})

View File

@ -1,6 +1,6 @@
import { useRef, useEffect, useState, useCallback } from 'react';
import { avatar } from '../constants/Icons'
import { Pressable, View, Image } from 'react-native';
import { Pressable, ScrollView, View, Image } from 'react-native';
import {Icon, Text, IconButton, Surface, Divider} from 'react-native-paper';
import { Topic, Card, Profile } from 'databag-client-sdk';
import { ImageAsset } from './imageAsset/ImageAsset';
@ -9,8 +9,9 @@ import { VideoAsset } from './videoAsset/VideoAsset';
import { BinaryAsset } from './binaryAsset/BinaryAsset';
import { useMessage } from './useMessage.hook';
import {styles} from './Message.styled';
import { MediaAsset } from '../conversation/Conversatin';
export function Message({ topic, card, profile, host, select, selected }: { topic: Topic, card: Card | null, profile: Profile | null, host: boolean, select: (id: string)=>void, selected: string }) {
export function Message({ topic, card, profile, host, select, selected }: { topic: Topic, card: Card | null, profile: Profile | null, host: boolean, select: (id: null | string)=>void, selected: string }) {
const { state, actions } = useMessage();
const { locked, data, created, topicId, status, transform } = topic;
const { name, handle, node } = profile || card || { name: null, handle: null, node: null }
@ -23,13 +24,27 @@ export function Message({ topic, card, profile, host, select, selected }: { topi
const [editText, setEditText] = useState('');
const [saving, setSaving] = useState(false);
const media = !assets ? [] : assets.map((asset: MediaAsset, index: number) => {
if (asset.image || asset.encrypted?.type === 'image') {
return <ImageAsset key={index} topicId={topicId} asset={asset as MediaAsset} />
} else if (asset.audio || asset.encrypted?.type === 'audio') {
return <AudioAsset key={index} topicId={topicId} asset={asset as MediaAsset} />
} else if (asset.video || asset.encrypted?.type === 'video') {
return <VideoAsset key={index} topicId={topicId} asset={asset as MediaAsset} />
} else if (asset.binary || asset.encrypted?.type === 'binary') {
return <BinaryAsset key={index} topicId={topicId} asset={asset as MediaAsset} />
} else {
return <View key={index}></View>
}
});
return (
<View style={styles.message}>
<View style={styles.topic}>
<View style={styles.content}>
<Image style={styles.logo} resizeMode={'contain'} source={{uri: logoUrl}} />
<View style={styles.body}>
<Pressable style={styles.header} onPress={()=>select(topicId)}>
<Pressable style={styles.header} onPress={()=>select(topicId == selected ? null : topicId)}>
<View style={styles.name}>
{ name && (
<Text style={styles.handle}>{ name }</Text>
@ -62,6 +77,11 @@ export function Message({ topic, card, profile, host, select, selected }: { topi
</View>
</View>
</View>
{ assets?.length > 0 && (
<ScrollView horizontal={true} showsHorizontalScrollIndicator={false} style={styles.carousel} contentContainerStyle={styles.assets}>
{ media }
</ScrollView>
)}
{ topicId === selected && (
<Surface style={styles.options}>
<IconButton style={styles.option} loading={false} compact="true" mode="contained" icon="share-variant-outline" size={24} onPress={() => {}} />

View File

@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react';
import { Text } from 'react-native'
import { Text } from 'react-native-paper'
import { useAudioAsset } from './useAudioAsset.hook';
import { MediaAsset } from '../../conversation/Conversation';

View File

@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react';
import { Text } from 'react-native'
import { Text } from 'react-native-paper'
import { useBinaryAsset } from './useBinaryAsset.hook';
import { MediaAsset } from '../../conversation/Conversation';

View File

@ -2,4 +2,9 @@ import {StyleSheet} from 'react-native';
import {Colors} from '../constants/Colors';
export const styles = StyleSheet.create({
image: {
},
thumb: {
borderRadius: 4,
},
});

View File

@ -1,11 +1,37 @@
import React, { useState, useEffect } from 'react';
import { Text } from 'react-native'
import React, { useState, useEffect, useRef } from 'react';
import { Animated, View, Image, useAnimatedValue } from 'react-native'
import { Text } from 'react-native-paper'
import { useImageAsset } from './useImageAsset.hook';
import { MediaAsset } from '../../conversation/Conversation';
import { styles } from './ImageAsset.styled'
export function ImageAsset({ topicId, asset }: { topicId: string, asset: MediaAsset }) {
const { state, actions } = useImageAsset(topicId, asset);
const fadeAnim = useAnimatedValue(0);
return (<Text>IMAGE</Text>);
useEffect(() => {
if (state.loaded) {
Animated.timing(fadeAnim, {
toValue: 1,
duration: 100,
useNativeDriver: true,
}).start();
}
}, [state.loaded]);
return (
<View style={styles.image}>
{ state.thumbUrl && (
<Animated.Image
style={[styles.thumb,{opacity: fadeAnim,},]}
resizeMode="contain"
height={92}
width={92 * state.ratio}
source={{ uri: state.thumbUrl }}
onLoad={actions.loaded}
/>
)}
</View>
);
}

View File

@ -9,7 +9,9 @@ export function useImageAsset(topicId: string, asset: MediaAsset) {
const [state, setState] = useState({
thumbUrl: null,
dataUrl: null,
ratio: 1,
loading: false,
loaded: false,
loadPercent: 0,
})
@ -36,6 +38,10 @@ export function useImageAsset(topicId: string, asset: MediaAsset) {
}, [asset]);
const actions = {
loaded: (e) => {
const { width, height } = e.nativeEvent.source;
updateState({ loaded: true, ratio: width / height });
},
unloadImage: () => {
updateState({ dataUrl: null });
},

View File

@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react';
import { Text } from 'react-native'
import { Text } from 'react-native-paper'
import { useVideoAsset } from './useVideoAsset.hook';
import { MediaAsset } from '../../conversation/Conversation';