snapshot of https://github.com/jitsi/jitsi-meet.git @ fd1749dd28f4138aa80234fc7f311b19aaffa0e7 (2026-09-15)
This commit is contained in:
99
react/features/reactions/components/native/ReactionEmoji.tsx
Normal file
99
react/features/reactions/components/native/ReactionEmoji.tsx
Normal file
@@ -0,0 +1,99 @@
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { Animated } from 'react-native';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import ColorSchemeRegistry from '../../../base/color-scheme/ColorSchemeRegistry';
|
||||
import { removeReaction } from '../../actions.any';
|
||||
import { IReactionEmojiProps, REACTIONS } from '../../constants';
|
||||
|
||||
interface IProps extends IReactionEmojiProps {
|
||||
|
||||
/**
|
||||
* Index of reaction on the queue.
|
||||
* Used to differentiate between first and other animations.
|
||||
*/
|
||||
index: number;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Animated reaction emoji.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
function ReactionEmoji({ reaction, uid, index }: IProps) {
|
||||
const _styles: any = useSelector((state: IReduxState) => ColorSchemeRegistry.get(state, 'Toolbox'));
|
||||
const _height = useSelector((state: IReduxState) => state['features/base/responsive-ui'].clientHeight);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const animationVal = useRef(new Animated.Value(0)).current;
|
||||
|
||||
const vh = useState(_height / 100)[0];
|
||||
|
||||
const randomInt = (min: number, max: number) => Math.floor((Math.random() * (max - min + 1)) + min);
|
||||
|
||||
const animationIndex = useMemo(() => index % 21, [ index ]);
|
||||
|
||||
const coordinates = useState({
|
||||
topX: animationIndex === 0 ? 40 : randomInt(-100, 100),
|
||||
topY: animationIndex === 0 ? -70 : randomInt(-65, -75),
|
||||
bottomX: animationIndex === 0 ? 140 : randomInt(150, 200),
|
||||
bottomY: animationIndex === 0 ? -50 : randomInt(-40, -50)
|
||||
})[0];
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const animation = Animated.timing(
|
||||
animationVal,
|
||||
{
|
||||
toValue: 1,
|
||||
duration: 5000,
|
||||
useNativeDriver: true
|
||||
}
|
||||
);
|
||||
|
||||
// Remove only after the animation finishes, so unmount does not race it.
|
||||
animation.start(({ finished }) => finished && dispatch(removeReaction(uid)));
|
||||
|
||||
return () => animation.stop();
|
||||
}, [ animationVal ]);
|
||||
|
||||
|
||||
if (!(reaction in REACTIONS)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Animated.Text
|
||||
style = {{
|
||||
..._styles.emojiAnimation,
|
||||
transform: [
|
||||
{ translateY: animationVal.interpolate({
|
||||
inputRange: [ 0, 0.70, 0.75, 1 ],
|
||||
outputRange: [ 0, coordinates.topY * vh, coordinates.topY * vh, coordinates.bottomY * vh ]
|
||||
})
|
||||
}, {
|
||||
translateX: animationVal.interpolate({
|
||||
inputRange: [ 0, 0.70, 0.75, 1 ],
|
||||
outputRange: [ 0, coordinates.topX, coordinates.topX,
|
||||
coordinates.topX < 0 ? -coordinates.bottomX : coordinates.bottomX ]
|
||||
})
|
||||
}, {
|
||||
scale: animationVal.interpolate({
|
||||
inputRange: [ 0, 0.70, 0.75, 1 ],
|
||||
outputRange: [ 0.6, 1.5, 1.5, 1 ]
|
||||
})
|
||||
}
|
||||
],
|
||||
opacity: animationVal.interpolate({
|
||||
inputRange: [ 0, 0.7, 0.75, 1 ],
|
||||
outputRange: [ 1, 1, 1, 0 ]
|
||||
})
|
||||
}}>
|
||||
{REACTIONS[reaction].emoji}
|
||||
</Animated.Text>
|
||||
);
|
||||
}
|
||||
|
||||
export default ReactionEmoji;
|
||||
Reference in New Issue
Block a user