animating carousel

This commit is contained in:
balzack 2025-01-03 21:03:15 -08:00
parent b259f11155
commit 91d46432a4
4 changed files with 43 additions and 14 deletions

View File

@ -14,6 +14,7 @@ export const styles = StyleSheet.create({
carousel: { carousel: {
paddingLeft: 8, paddingLeft: 8,
paddingBottom: 8, paddingBottom: 8,
height: 80,
}, },
assets: { assets: {
display: 'flex', display: 'flex',

View File

@ -1,5 +1,5 @@
import React, { useEffect, useState, useRef } from 'react'; import React, { useEffect, useState, useRef } from 'react';
import {KeyboardAvoidingView, Modal, Platform, ScrollView, SafeAreaView, Pressable, View, FlatList, TouchableOpacity} from 'react-native'; import {Animated, useAnimatedValue, KeyboardAvoidingView, Modal, Platform, ScrollView, SafeAreaView, Pressable, View, FlatList, TouchableOpacity} from 'react-native';
import {styles} from './Conversation.styled'; import {styles} from './Conversation.styled';
import {useConversation} from './useConversation.hook'; import {useConversation} from './useConversation.hook';
import {Message} from '../message/Message'; import {Message} from '../message/Message';
@ -40,6 +40,7 @@ export function Conversation({close}: {close: ()=>void}) {
const contentLead = useRef(null); const contentLead = useRef(null);
const scrollOffset = useRef(0); const scrollOffset = useRef(0);
const busy = useRef(false); const busy = useRef(false);
const scale = useAnimatedValue(0)
const alertParams = { const alertParams = {
title: state.strings.error, title: state.strings.error,
@ -52,6 +53,25 @@ export function Conversation({close}: {close: ()=>void}) {
}, },
}; };
useEffect(() => {
console.log(">>>> ", state.assets.length);
if (state.assets.length > 0) {
Animated.timing(scale, {
toValue: 80,
duration: 100,
useNativeDriver: false,
}).start();
} else {
Animated.timing(scale, {
toValue: 0,
duration: 100,
useNativeDriver: false,
}).start();
}
}, [state.assets]);
const sendMessage = async () => { const sendMessage = async () => {
if (!busy.current && (state.message || state.assets.length > 0)) { if (!busy.current && (state.message || state.assets.length > 0)) {
busy.current = true; busy.current = true;
@ -156,7 +176,7 @@ export function Conversation({close}: {close: ()=>void}) {
const media = state.assets.map((asset, index) => { const media = state.assets.map((asset, index) => {
if (asset.type === 'image') { if (asset.type === 'image') {
return <ImageFile key={index} path={asset.path} disabled={false} remove={()=>{}} /> return <ImageFile key={index} path={asset.path} disabled={false} remove={()=>actions.removeAsset(index)} />
} else if (asset.type === 'video') { } else if (asset.type === 'video') {
return <VideoFile key={index} path={asset.path} disabled={false} remove={()=>{}} /> return <VideoFile key={index} path={asset.path} disabled={false} remove={()=>{}} />
} else if (asset.type === 'audio') { } else if (asset.type === 'audio') {
@ -238,11 +258,11 @@ export function Conversation({close}: {close: ()=>void}) {
</Divider> </Divider>
<Confirm show={alert} params={alertParams} /> <Confirm show={alert} params={alertParams} />
<View style={styles.add}> <View style={styles.add}>
{ media.length > 0 && ( <Animated.View style={[{},{height: scale}]}>
<ScrollView horizontal={true} showsHorizontalScrollIndicator={false} style={styles.carousel} contentContainerStyle={styles.assets}> <ScrollView horizontal={true} showsHorizontalScrollIndicator={false} style={styles.carousel} contentContainerStyle={styles.assets}>
{ media } { media }
</ScrollView> </ScrollView>
)} </Animated.View>
<TextInput multiline={true} mode="outlined" style={{ ...styles.message, fontSize: state.textSize }} <TextInput multiline={true} mode="outlined" style={{ ...styles.message, fontSize: state.textSize }}
textColor={state.textColorSet ? state.textColor : undefined} outlineColor="transparent" activeOutlineColor="transparent"spellcheck={false} 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} autoComplete="off" autoCapitalize="none" autoCorrect={false} placeholder={state.strings.newMessage} placeholderTextColor={state.textColorSet ? state.textColor : undefined}

View File

@ -8,4 +8,10 @@ export const styles = StyleSheet.create({
thumb: { thumb: {
height: 72, height: 72,
}, },
icon: {
position: 'absolute',
top: 0,
right: 0,
borderRadius: 4,
},
}); });

View File

@ -1,6 +1,6 @@
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import { View, Animated, useAnimatedValue } from 'react-native' import { Image, View, Animated, useAnimatedValue } from 'react-native'
import { Text } from 'react-native-paper'; import { IconButton, Text } from 'react-native-paper';
import { useImageFile } from './useImageFile.hook'; import { useImageFile } from './useImageFile.hook';
import {styles} from './ImageFile.styled' import {styles} from './ImageFile.styled'
@ -30,14 +30,16 @@ export function ImageFile({ path, disabled, remove }: {path: string, disabled: b
return ( return (
<View style={styles.image}> <View style={styles.image}>
<Animated.Image <Animated.View style={[styles.thumb,{opacity},]}>
style={[styles.thumb,{opacity},]} <Image
resizeMode="contain" resizeMode="contain"
height={72} height={72}
width={72 * state.ratio} width={72 * state.ratio}
source={{ uri: path }} source={{ uri: path }}
onLoad={actions.loaded} onLoad={actions.loaded}
/> />
<IconButton style={styles.icon} mode="contained" icon="close" size={20} onPress={remove} />
</Animated.View>
</View> </View>
); );
} }