Проблема с сообщениями, отрисовывающими представление, указывающее c на onLongPress - PullRequest
0 голосов
/ 24 апреля 2020

Я пытаюсь отобразить View с помощью renderCustomView = {this.displayEmojis} для отдельного сообщения, как только пользователь активировал функцию onLongPress = {}. Однако представление, которое я пытаюсь отобразить, повторяет каждое сообщение на экране, а не нажатое. Я приложил, что происходит, когда я пытаюсь нажать на сообщение с несколькими сообщениями, показывающими: https://i.stack.imgur.com/x8mj9.png

//EventPost
import React from 'react'
import { Platform, View, StatusBar, TouchableOpacity, Text, Image, StyleSheet } from 'react-native'
import { getStatusBarHeight } from 'react-native-status-bar-height';
import { GiftedChat } from 'react-native-gifted-chat'
import emojiUtils from 'emoji-utils'
import KeyboardSpacer from 'react-native-keyboard-spacer';
import SlackMessage from './SlackMessage'
import Keyboard from 'react-native';

export default class EventPosts extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            messages: [],
            toggle: false,
            reactedMessage: 0,
            reacted: false,
            images: [
                require("../assets/emojis/beer_photo.png"),
                require("../assets/emojis/party_photo.png"),
                require("../assets/emojis/laughing-emoji_photo.png"),
                require("../assets/emojis/happy_photo.png"),
                require("../assets/emojis/crying_photo.png"),
            ],
            id: 0,
        }
        this.displayEmojis = this.displayEmojis.bind(this);
    }

    componentDidMount() {
        this.setState({
            messages: [
                {
                    _id: 1,
                    text: 'I cant wait for this birthday party',
                    createdAt: new Date(),
                    user: {
                        _id: 2,
                        name: 'Andrew Garrett',
                        avatar: 'https://placeimg.com/140/140/any',
                    },
                },
            ],
        });
    }

    onSend(messages = []) {
        this.setState(previousState => ({
            messages: GiftedChat.append(previousState.messages, messages),
        }))
    }

    renderMessage(props) {
        const {
            currentMessage: { text: currText },
        } = props
        let messageTextStyle
        if (currText && emojiUtils.isPureEmojiString(currText)) {
            messageTextStyle = {
                fontSize: 28,
                lineHeight: Platform.OS === 'android' ? 34 : 30,
            }
        }

        return (<SlackMessage {...props} messageTextStyle={messageTextStyle} />)
    }

    dismiss = () =>
        Keyboard.dismiss();

    updateEmojiCount(number) {
        switch (number) {
            case 1:
                this.setState({ reactedMessage: 0 });
                break;
            case 2:
                this.setState({ reactedMessage: 1 });
                break;
            case 3:
                this.setState({ reactedMessage: 2 });
                break;
            case 4:
                this.setState({ reactedMessage: 3 });
                break;
            case 5:
                this.setState({ reactedMessage: 4 });
                break;
            default:
                this.forceUpdate();
        }
        this.setState({ reacted: true });
        this.setState({ toggle: false })
    }

    beerEmoji() {
        return (
            <View>
                <TouchableOpacity style={styles.emojiContainer}
                    onPress={() => this.updateEmojiCount(1)}>
                    <Image style={styles.emoji} source={require("../assets/emojis/beer.gif")} />
                </TouchableOpacity>
            </View>
        )
    }
    partyEmoji() {
        return (
            <View>
                <TouchableOpacity style={styles.emojiContainer}
                    onPress={() => this.updateEmojiCount(2)}>
                    <Image style={styles.emoji} source={require("../assets/emojis/party.gif")} />
                </TouchableOpacity>
            </View>
        )
    }
    laughingEmoji() {
        return (
            <View>
                <TouchableOpacity onPress={() => this.updateEmojiCount(3)} style={styles.emojiContainer}>
                    <Image style={[styles.emoji, styles.emojiResize]} source={require("../assets/emojis/laughing-emoji.gif")} />
                </TouchableOpacity>
            </View>
        )
    }
    happyEmoji() {
        return (
            <View>
                <TouchableOpacity onPress={() => this.updateEmojiCount(4)} style={styles.emojiContainer}>
                    <Image style={[styles.emoji, styles.emojiResize]} source={require("../assets/emojis/happy.gif")} />
                </TouchableOpacity>
            </View>
        )
    }
    cryingEmoji() {
        return (
            <View>
                <TouchableOpacity onPress={() => this.updateEmojiCount(5)} style={styles.emojiContainer}>
                    <Image style={[styles.emoji, styles.emojiResize]} source={require("../assets/emojis/crying.gif")} />
                </TouchableOpacity>
            </View>
        )
    }

    displayEmojis() {
        if (this.state.toggle) {
            return (
                <View
                    style={{
                        flexDirection: 'row',
                        right: '35%',
                        backgroundColor: 'white',
                        zIndex: 3,
                        overlayColor: 'white',
                        borderRadius: 30,
                        paddingHorizontal: '10%',
                        bottom: '2%'
                    }}>

                    {this.beerEmoji()}
                    {this.partyEmoji()}
                    {this.laughingEmoji()}
                    {this.happyEmoji()}
                    {this.cryingEmoji()}
                </View>
            )
        }
    }


    toggleEmojis = (context, message) => {
        let temp = this.state.messages.filter(temp => message._id == temp._id);
        let id = temp[0]._id;
        this.setState({ id: temp[0]._id })
        if (this.state.toggle) { this.setState({ toggle: false }) }
        else { this.setState({ toggle: true }) }
    }

    render() {
        return (
            <View style={{ flex: 1 }}>
                <View
                    style={{ paddingTop: Platform.OS === "android" ? StatusBar.currentHeight : getStatusBarHeight() }}>
                    <View style={{ backgroundColor: '#2c3e50', paddingVertical: '4%' }}>
                        <TouchableOpacity style={{ left: "89%", top: '0%' }} onPress={() => this.props.navigation.goBack()}>
                            <Text style={{ color: 'white' }}>Done</Text>
                        </TouchableOpacity>
                    </View>
                </View>
                <GiftedChat
                    keyboardShouldPersistTaps={'handled'}
                    messages={this.state.messages}
                    onSend={messages => this.onSend(messages)}
                    placeholder={"Post something..."}
                    isKeyboardInternallyHandled={false}
                    multiline={true}
                    extraData={this.state}
                    alwaysShowSend={true}
                    onLongPress={this.toggleEmojis}
                    user={{ _id: 1 }}
                    renderCustomView={this.displayEmojis}
                    renderMessage={this.renderMessage} />
                <KeyboardSpacer />
            </View>
        )
    }
}

const styles = StyleSheet.create({
    emojiContainer: {
        width: 55,
        height: 55,
        paddingHorizontal: '13%',
        right: '15%'
    },
    emoji: {
        width: 55,
        height: 55,
        borderRadius: 20,
    },
    emojiResize: {
        transform: [{ scale: 0.75 }],
    },
    emojiReacted: {
        transform: [{ scale: 0.4 }],
    },
})
//SlackMessage
import PropTypes from 'prop-types';
import React from 'react';
import {
  View,
  ViewPropTypes,
  StyleSheet,
  Image
} from 'react-native';

import { Avatar, Day, utils } from 'react-native-gifted-chat';
import Bubble from './SlackBubble';

const { isSameUser, isSameDay } = utils;

export default class Message extends React.Component {

  state = {
    images: [
      require("../assets/emojis/beer_photo.png"),
      require("../assets/emojis/party_photo.png"),
      require("../assets/emojis/laughing-emoji_photo.png"),
      require("../assets/emojis/happy_photo.png"),
      require("../assets/emojis/crying_photo.png"),
    ]
  }
  getInnerComponentProps() {
    const { containerStyle, ...props } = this.props;
    return {
      ...props,
      position: 'left',
      isSameUser,
      isSameDay,
    };
  }

  renderDay() {
    if (this.props.currentMessage.createdAt) {
      const dayProps = this.getInnerComponentProps();
      if (this.props.renderDay) {
        return this.props.renderDay(dayProps);
      }
      return <Day {...dayProps} />;
    }
    return null;
  }

  renderBubble() {
    const bubbleProps = this.getInnerComponentProps();
    if (this.props.renderBubble) {
      return this.props.renderBubble(bubbleProps);
    }
    return <Bubble {...bubbleProps} />;
  }

  renderAvatar() {
    let extraStyle;
    if (
      isSameUser(this.props.currentMessage, this.props.previousMessage)
      && isSameDay(this.props.currentMessage, this.props.previousMessage)
    ) {
      extraStyle = { height: 0 };
    }

    const avatarProps = this.getInnerComponentProps();
    return (
      <Avatar
        {...avatarProps}
        imageStyle={{ left: [styles.slackAvatar, avatarProps.imageStyle, extraStyle] }}
      />
    );
  }

  render() {
    const marginBottom = isSameUser(this.props.currentMessage, this.props.nextMessage) ? 2 : 10;

    const { images } = this.state
    const index = (this.props.extraData.reactedMessage);
    return (
      <View>
        {this.renderDay()}
        <View
          style={[
            styles.container,
            { marginBottom },
            this.props.containerStyle,
          ]}>
          {this.renderAvatar()}
          {this.renderBubble()}
          {<Image source={images[index]} style={{ width: 20, height: 20, right: '8%' }} />}
        </View>
      </View>
    );
  }

}

const styles = StyleSheet.create({
  container: {
    flexDirection: 'row',
    alignItems: 'flex-end',
    justifyContent: 'flex-start',
    marginLeft: 8,
    marginRight: 8,
    backgroundColor: 'white',
    borderWidth: 2,
    borderColor: '#BEBEBE',
    paddingBottom: '3%'
  },
  slackAvatar: {
    height: 40,
    width: 40,
    borderRadius: 3,
    left: '10%',
    bottom: '12%'
  },
});

Message.defaultProps = {
  renderAvatar: undefined,
  renderBubble: null,
  renderDay: null,
  currentMessage: {},
  nextMessage: {},
  previousMessage: {},
  user: {},
  containerStyle: {},
};

Message.propTypes = {
  renderAvatar: PropTypes.func,
  renderBubble: PropTypes.func,
  renderDay: PropTypes.func,
  currentMessage: PropTypes.object,
  nextMessage: PropTypes.object,
  previousMessage: PropTypes.object,
  user: PropTypes.object,
  containerStyle: PropTypes.shape({
    left: ViewPropTypes.style,
    right: ViewPropTypes.style,
  }),
};
//Bubble
import PropTypes from 'prop-types';
import React from 'react';
import {
  Text,
  Clipboard,
  StyleSheet,
  TouchableOpacity,
  View,
  ViewPropTypes,
  Platform,
} from 'react-native';

import { MessageText, MessageImage, Time, utils } from 'react-native-gifted-chat';

const { isSameUser, isSameDay } = utils;

export default class Bubble extends React.Component {

  constructor(props) {
    super(props);
    this.onLongPress = this.onLongPress.bind(this);
  }

  onLongPress() {
    if (this.props.onLongPress) {
      this.props.onLongPress(this.context, this.props.currentMessage);
    } else {
      if (this.props.currentMessage.text) {
        const options = [
          'Copy Text',
        ];
        const cancelButtonIndex = options.length - 1;
        this.context.actionSheet().showActionSheetWithOptions({
          options,
          cancelButtonIndex,
        },
        (buttonIndex) => {
          switch (buttonIndex) {
            case 0:
              Clipboard.setString(this.props.currentMessage.text);
              break;

          }
        });
      }
    }
  }

  renderMessageText() {
    if (this.props.currentMessage.text) {
      const { containerStyle, wrapperStyle, messageTextStyle, ...messageTextProps } = this.props;
      if (this.props.renderMessageText) {
        return this.props.renderMessageText(messageTextProps);
      }
      return (
        <MessageText
          {...messageTextProps}
          textStyle={{
            left: [styles.standardFont, styles.slackMessageText, messageTextProps.textStyle, messageTextStyle],
          }}
        />
      );
    }
    return null;
  }

  renderMessageImage() {
    if (this.props.currentMessage.image) {
      const { containerStyle, wrapperStyle, ...messageImageProps } = this.props;
      if (this.props.renderMessageImage) {
        return this.props.renderMessageImage(messageImageProps);
      }
      return <MessageImage {...messageImageProps} imageStyle={[styles.slackImage, messageImageProps.imageStyle]} />;
    }
    return null;
  }

  renderTicks() {
    const { currentMessage } = this.props;
    if (this.props.renderTicks) {
      return this.props.renderTicks(currentMessage);
    }
    if (currentMessage.user._id !== this.props.user._id) {
      return null;
    }
    if (currentMessage.sent || currentMessage.received) {
      return (
        <View style={[styles.headerItem, styles.tickView]}>
          {currentMessage.sent && <Text style={[styles.standardFont, styles.tick, this.props.tickStyle]}>✓</Text>}
          {currentMessage.received && <Text style={[styles.standardFont, styles.tick, this.props.tickStyle]}>✓</Text>}
        </View>
      );
    }
    return null;
  }

  renderUsername() {
    const username = this.props.currentMessage.user.name;
    if (username) {
      const { containerStyle, wrapperStyle, ...usernameProps } = this.props;
      if (this.props.renderUsername) {
        return this.props.renderUsername(usernameProps);
      }
      return (
        <Text style={[styles.standardFont, styles.headerItem, styles.username, this.props.usernameStyle]}>
          {username}
        </Text>
      );
    }
    return null;
  }

  renderTime() {
    if (this.props.currentMessage.createdAt) {
      const { containerStyle, wrapperStyle, ...timeProps } = this.props;
      if (this.props.renderTime) {
        return this.props.renderTime(timeProps);
      }
      return (
        <Time
          {...timeProps}
          containerStyle={{ left: [styles.timeContainer] }}
          textStyle={{ left: [styles.standardFont, styles.headerItem, styles.time, timeProps.textStyle] }}
        />
      );
    }
    return null;
  }

  renderCustomView() {
    if (this.props.renderCustomView) {
      return this.props.renderCustomView(this.props);
    }
    return null;
  }

  render() {
    const isSameThread = isSameUser(this.props.currentMessage, this.props.previousMessage)
      && isSameDay(this.props.currentMessage, this.props.previousMessage);

    const messageHeader = isSameThread ? null : (
      <View style={styles.headerView}>
        {this.renderUsername()}
        {this.renderTime()}
        {this.renderTicks()}
      </View>
    );

    return (
      <View style={[styles.container, this.props.containerStyle]}>
        <TouchableOpacity
          onLongPress={this.onLongPress}
          accessibilityTraits="text"
          {...this.props.touchableProps}
        >
          <View
            style={[
              styles.wrapper,
              this.props.wrapperStyle,
            ]}
          >
            <View>
              {this.renderCustomView()}
              {messageHeader}
              {this.renderMessageImage()}
              {this.renderMessageText()}
            </View>
          </View>
        </TouchableOpacity>
      </View>
    );
  }

}

// Note: Everything is forced to be "left" positioned with this component.
// The "right" position is only used in the default Bubble.
const styles = StyleSheet.create({
  standardFont: {
    fontSize: 15,
  },
  slackMessageText: {
    marginLeft: 0,
    marginRight: 0,
  },
  container: {
    flex: 1,
    alignItems: 'flex-start',
  },
  wrapper: {
    marginRight: 60,
    minHeight: 20,
    justifyContent: 'flex-end',
  },
  username: {
    fontWeight: 'bold',
  },
  time: {
    textAlign: 'left',
    fontSize: 12,
  },
  timeContainer: {
    marginLeft: 0,
    marginRight: 0,
    marginBottom: 0,
  },
  headerItem: {
    marginRight: 10,
  },
  headerView: {
    // Try to align it better with the avatar on Android.
    marginTop: Platform.OS === 'android' ? -2 : 0,
    flexDirection: 'row',
    alignItems: 'baseline',
  },
  /* eslint-disable react-native/no-color-literals */
  tick: {
    backgroundColor: 'transparent',
    color: 'white',
  },
  /* eslint-enable react-native/no-color-literals */
  tickView: {
    flexDirection: 'row',
  },
  slackImage: {
    borderRadius: 3,
    marginLeft: 0,
    marginRight: 0,
  },
});

Bubble.contextTypes = {
  actionSheet: PropTypes.func,
};

Bubble.defaultProps = {
  touchableProps: {},
  onLongPress: null,
  renderMessageImage: null,
  renderMessageText: null,
  renderCustomView: null,
  renderTime: null,
  currentMessage: {
    text: null,
    createdAt: null,
    image: null,
  },
  nextMessage: {},
  previousMessage: {},
  containerStyle: {},
  wrapperStyle: {},
  tickStyle: {},
  containerToNextStyle: {},
  containerToPreviousStyle: {},
};

Bubble.propTypes = {
  touchableProps: PropTypes.object,
  onLongPress: PropTypes.func,
  renderMessageImage: PropTypes.func,
  renderMessageText: PropTypes.func,
  renderCustomView: PropTypes.func,
  renderUsername: PropTypes.func,
  renderTime: PropTypes.func,
  renderTicks: PropTypes.func,
  currentMessage: PropTypes.object,
  nextMessage: PropTypes.object,
  previousMessage: PropTypes.object,
  user: PropTypes.object,
  containerStyle: PropTypes.shape({
    left: ViewPropTypes.style,
    right: ViewPropTypes.style,
  }),
  wrapperStyle: PropTypes.shape({
    left: ViewPropTypes.style,
    right: ViewPropTypes.style,
  }),
  messageTextStyle: Text.propTypes.style,
  usernameStyle: Text.propTypes.style,
  tickStyle: Text.propTypes.style,
  containerToNextStyle: PropTypes.shape({
    left: ViewPropTypes.style,
    right: ViewPropTypes.style,
  }),
  containerToPreviousStyle: PropTypes.shape({
    left: ViewPropTypes.style,
    right: ViewPropTypes.style,
  }),
};
...