You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Label.js 4.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // @flow
  2. import React from 'react';
  3. import { Animated, Text } from 'react-native';
  4. import Icon from '../../../icons/components/Icon';
  5. import { type StyleType, combineStyles } from '../../../styles';
  6. import AbstractLabel, {
  7. type Props as AbstractProps
  8. } from '../AbstractLabel';
  9. import styles from './styles';
  10. /**
  11. * Const for status string 'in progress'.
  12. */
  13. const STATUS_IN_PROGRESS = 'in_progress';
  14. /**
  15. * Const for status string 'off'.
  16. */
  17. const STATUS_OFF = 'off';
  18. type Props = AbstractProps & {
  19. /**
  20. * Color for the icon.
  21. */
  22. iconColor?: ?string,
  23. /**
  24. * Status of the label. This prop adds some additional styles based on its
  25. * value. E.g. If status = off, it will render the label symbolising that
  26. * the thing it displays (e.g. Recording) is off.
  27. */
  28. status: ('in_progress' | 'off' | 'on'),
  29. /**
  30. * Style of the label.
  31. */
  32. style?: ?StyleType,
  33. /**
  34. * Custom styles for the text.
  35. */
  36. textStyle?: ?StyleType
  37. };
  38. type State = {
  39. /**
  40. * An animation object handling the opacity changes of the in progress
  41. * label.
  42. */
  43. pulseAnimation: Object
  44. }
  45. /**
  46. * Renders a circular indicator to be used for status icons, such as recording
  47. * on, audio-only conference, video quality and similar.
  48. */
  49. export default class Label extends AbstractLabel<Props, State> {
  50. /**
  51. * A reference to the started animation of this label.
  52. */
  53. animationReference: Object;
  54. /**
  55. * Instantiates a new instance of {@code Label}.
  56. *
  57. * @inheritdoc
  58. */
  59. constructor(props: Props) {
  60. super(props);
  61. this.state = {
  62. pulseAnimation: new Animated.Value(0)
  63. };
  64. }
  65. /**
  66. * Implements {@code Component#componentDidMount}.
  67. *
  68. * @inheritdoc
  69. */
  70. componentDidMount() {
  71. this._maybeToggleAnimation({}, this.props);
  72. }
  73. /**
  74. * Implements {@code Component#componentDidUpdate}.
  75. *
  76. * @inheritdoc
  77. */
  78. componentDidUpdate(prevProps: Props) {
  79. this._maybeToggleAnimation(prevProps, this.props);
  80. }
  81. /**
  82. * Implements React {@link Component}'s render.
  83. *
  84. * @inheritdoc
  85. */
  86. render() {
  87. const { icon, text, status, style, iconColor, textStyle } = this.props;
  88. let extraStyle = null;
  89. switch (status) {
  90. case STATUS_IN_PROGRESS:
  91. extraStyle = {
  92. opacity: this.state.pulseAnimation
  93. };
  94. break;
  95. case STATUS_OFF:
  96. extraStyle = styles.labelOff;
  97. break;
  98. }
  99. return (
  100. <Animated.View
  101. style = { [
  102. combineStyles(styles.labelContainer, style),
  103. extraStyle
  104. ] }>
  105. { icon && <Icon
  106. color = { iconColor }
  107. size = '18'
  108. src = { icon } /> }
  109. { text && <Text style = { [ styles.labelText, textStyle ] }>
  110. { text }
  111. </Text>}
  112. </Animated.View>
  113. );
  114. }
  115. /**
  116. * Checks if the animation has to be started or stopped and acts
  117. * accordingly.
  118. *
  119. * @param {Props} oldProps - The previous values of the Props.
  120. * @param {Props} newProps - The new values of the Props.
  121. * @returns {void}
  122. */
  123. _maybeToggleAnimation(oldProps, newProps) {
  124. const { status: oldStatus } = oldProps;
  125. const { status: newStatus } = newProps;
  126. const { pulseAnimation } = this.state;
  127. if (newStatus === STATUS_IN_PROGRESS
  128. && oldStatus !== STATUS_IN_PROGRESS) {
  129. // Animation must be started
  130. this.animationReference = Animated.loop(Animated.sequence([
  131. Animated.timing(pulseAnimation, {
  132. delay: 500,
  133. toValue: 1,
  134. useNativeDriver: true
  135. }),
  136. Animated.timing(pulseAnimation, {
  137. toValue: 0.3,
  138. useNativeDriver: true
  139. })
  140. ]));
  141. this.animationReference.start();
  142. } else if (this.animationReference
  143. && newStatus !== STATUS_IN_PROGRESS
  144. && oldStatus === STATUS_IN_PROGRESS) {
  145. // Animation must be stopped
  146. this.animationReference.stop();
  147. }
  148. }
  149. }