import * as React from 'react'; import { Animated, Dimensions, GestureResponderHandlers, StyleProp, StyleSheet, View, ViewStyle, } from 'react-native'; import { UseColors } from '../../hook'; import { I18nContext } from '../../i18n'; import { ChatMessage } from '../../rename.chat'; import { ColorsPalette, PaletteContext, ThemeContext, ThemeType, } from '../../theme'; import { Icon } from '../../ui/Image'; import { SingleLineText } from '../../ui/Text'; import { gMsgPinHeight } from './const'; import { MessagePinList, MessagePinListRef } from './MessagePinList'; export type MessagePinHolderProps = { style?: StyleProp | undefined; }; // !!! ERROR Invariant Violation: `createAnimatedComponent` does not support stateless functional components; use a class component instead. export function MessagePinPlaceholder(props: MessagePinHolderProps) { const { style } = props; return ; } export class MessagePinPlaceholder2 extends React.PureComponent { render(): React.ReactNode { const { style } = this.props; return ; } } export const AnimatedMessagePinPlaceholder = Animated.createAnimatedComponent( MessagePinPlaceholder2 ); export type MessagePinProps = { convId: string; convType: number; style?: StyleProp | undefined; msgPinHeightRef: React.MutableRefObject; msgPinHeightAnimate: ( toValue: number, onFinished?: ((result: any) => void) | undefined, offsetToZero?: boolean ) => void; msgPinLabelTranslateYRef: React.MutableRefObject; msgPinLabelTranslateYAnimate: ( toValue: number, onFinished?: ((result: any) => void) | undefined ) => void; msgPinBackgroundOpacityAnimate: ( toValue: number, onFinished?: ((result: any) => void) | undefined ) => void; msgPinPlaceHolderHeightAnimate: ( toValue: number, onFinished?: ((result: any) => void) | undefined ) => void; msgPinLabelCurrentTranslateY: Animated.Value; msgPinBackgroundCurrentOpacity: Animated.Value; msgPinCurrentHeight: Animated.Value; panHandlers: GestureResponderHandlers; onChangePinMaskHeight?: (height: number) => void; onRequestClose?: () => void; }; export type MessagePinState = { maxListHeight: number; }; export class MessagePin extends React.PureComponent< MessagePinProps, MessagePinState > { private listRef: React.RefObject; private getListRef: React.RefObject< (ref: React.RefObject) => void >; private uc: UseColors; private tr?: (key: string, ...args: any[]) => string; private colors?: ColorsPalette | undefined; private style?: ThemeType | undefined; private _maxListHeight: number; private _hadShow: boolean; constructor(props: MessagePinProps) { super(props); this.uc = new UseColors(); this._maxListHeight = 0; this.listRef = React.createRef() as any; this.getListRef = React.createRef() as any; this.getListRef.current = (ref: React.RefObject) => (this.listRef = ref); this.state = { maxListHeight: 0, }; this._hadShow = false; } componentDidMount?(): void { this.uc.initColor({ bg: { light: this.colors?.neutral[98], dark: this.colors?.neutral[1], }, bg2: { light: this.colors?.neutral[95], dark: this.colors?.neutral[2], }, fg: { light: this.colors?.neutral[1], dark: this.colors?.neutral[98], }, bg4: { light: this.colors?.neutral[9], dark: this.colors?.neutral[3], }, pin: { light: this.colors?.neutral[3], dark: this.colors?.neutral[7], }, }); } componentWillUnmount?(): void {} public show(): void { const { msgPinHeightRef, msgPinPlaceHolderHeightAnimate, msgPinHeightAnimate, msgPinBackgroundOpacityAnimate, onChangePinMaskHeight, msgPinLabelTranslateYAnimate, } = this.props; this._hadShow = true; msgPinHeightRef.current = gMsgPinHeight + this._maxListHeight; msgPinPlaceHolderHeightAnimate(gMsgPinHeight); msgPinHeightAnimate(gMsgPinHeight + this._maxListHeight); msgPinBackgroundOpacityAnimate(1); msgPinLabelTranslateYAnimate(0); onChangePinMaskHeight?.(gMsgPinHeight + this._maxListHeight); } public hide(): void { const { msgPinHeightRef, msgPinPlaceHolderHeightAnimate, msgPinHeightAnimate, msgPinBackgroundOpacityAnimate, onChangePinMaskHeight, msgPinLabelTranslateYAnimate, } = this.props; this._hadShow = false; msgPinHeightRef.current = 0; msgPinPlaceHolderHeightAnimate(0); msgPinHeightAnimate(0); msgPinBackgroundOpacityAnimate(0); msgPinLabelTranslateYAnimate(-gMsgPinHeight); onChangePinMaskHeight?.(0); } private onListCountChanged(count: number): void { const { msgPinHeightAnimate } = this.props; this._maxListHeight = count > 0 ? Math.min( count * 60, Math.min( 8 * 60, (Dimensions.get('window').height * (844 - 176)) / 844 ) ) + 16 : 16; this.setState({ maxListHeight: this._maxListHeight }); if (this._hadShow === false) { return; } if (count > 0) { msgPinHeightAnimate(gMsgPinHeight + this._maxListHeight); } else { msgPinHeightAnimate(gMsgPinHeight); } } private onRequestClose(): void { const { onRequestClose } = this.props; onRequestClose?.(); } public addPinMessage(msg: ChatMessage): void { this.listRef.current?.addPinMessage(msg); } public registerCallback(onClickedItem: (msg: ChatMessage) => void): void { this.listRef.current?.registerCallback(onClickedItem); } private _render(): React.ReactNode { const { convId, convType, style, msgPinHeightRef, msgPinLabelCurrentTranslateY, msgPinBackgroundCurrentOpacity, msgPinCurrentHeight, // panHandlers, } = this.props; return ( <> true} onResponderRelease={this.onRequestClose.bind(this)} /> true} onResponderRelease={() => { this.onRequestClose(); }} > {this.tr?.('_uikit_pin_message_title')} ); } render(): React.ReactNode { return ( {(palette) => { this.colors = palette?.colors; return ( {(theme) => { this.style = theme?.style; return ( {(i18n) => { this.tr = i18n?.tr; return this._render(); }} ); }} ); }} ); } } export const AnimatedMessagePin = Animated.createAnimatedComponent(MessagePin);