2018-05-22 19:44:40 +00:00
|
|
|
// @flow
|
|
|
|
import React from 'react';
|
2018-09-11 10:16:01 +00:00
|
|
|
import { Animated, Text } from 'react-native';
|
2018-05-22 19:44:40 +00:00
|
|
|
|
2020-05-18 11:54:55 +00:00
|
|
|
import Icon from '../../icons/components/Icon';
|
2018-05-22 19:44:40 +00:00
|
|
|
import { combineStyles, type StyleType } from '../../styles';
|
|
|
|
|
|
|
|
import AbstractCircularLabel, {
|
|
|
|
type Props as AbstractProps
|
|
|
|
} from './AbstractCircularLabel';
|
|
|
|
import styles from './styles';
|
|
|
|
|
2018-09-11 10:16:01 +00:00
|
|
|
/**
|
|
|
|
* Const for status string 'in progress'.
|
|
|
|
*/
|
|
|
|
const STATUS_IN_PROGRESS = 'in_progress';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Const for status string 'off'.
|
|
|
|
*/
|
|
|
|
const STATUS_OFF = 'off';
|
|
|
|
|
2018-05-22 19:44:40 +00:00
|
|
|
type Props = AbstractProps & {
|
|
|
|
|
2018-09-11 10:16:01 +00:00
|
|
|
/**
|
|
|
|
* Status of the label. This prop adds some additional styles based on its
|
|
|
|
* value. E.g. if status = off, it will render the label symbolising that
|
|
|
|
* the thing it displays (e.g. recording) is off.
|
|
|
|
*/
|
|
|
|
status: ('in_progress' | 'off' | 'on'),
|
|
|
|
|
2018-05-22 19:44:40 +00:00
|
|
|
/**
|
|
|
|
* Style of the label.
|
|
|
|
*/
|
|
|
|
style?: ?StyleType
|
|
|
|
};
|
|
|
|
|
2018-09-11 10:16:01 +00:00
|
|
|
type State = {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* An animation object handling the opacity changes of the in progress
|
|
|
|
* label.
|
|
|
|
*/
|
|
|
|
pulseAnimation: Object
|
|
|
|
}
|
|
|
|
|
2018-05-22 19:44:40 +00:00
|
|
|
/**
|
|
|
|
* Renders a circular indicator to be used for status icons, such as recording
|
|
|
|
* on, audio-only conference, video quality and similar.
|
|
|
|
*/
|
2018-09-11 10:16:01 +00:00
|
|
|
export default class CircularLabel extends AbstractCircularLabel<Props, State> {
|
|
|
|
/**
|
|
|
|
* A reference to the started animation of this label.
|
|
|
|
*/
|
|
|
|
animationReference: Object;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Instantiates a new instance of {@code CircularLabel}.
|
|
|
|
*
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
constructor(props: Props) {
|
|
|
|
super(props);
|
|
|
|
|
|
|
|
this.state = {
|
|
|
|
pulseAnimation: new Animated.Value(0)
|
|
|
|
};
|
2018-11-02 21:48:03 +00:00
|
|
|
}
|
2018-09-11 10:16:01 +00:00
|
|
|
|
2018-11-02 21:48:03 +00:00
|
|
|
/**
|
|
|
|
* Implements {@code Component#componentDidMount}.
|
|
|
|
*
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
componentDidMount() {
|
|
|
|
this._maybeToggleAnimation({}, this.props);
|
2018-09-11 10:16:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2018-11-02 21:48:03 +00:00
|
|
|
* Implements {@code Component#componentDidUpdate}.
|
2018-09-11 10:16:01 +00:00
|
|
|
*
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
2018-11-02 21:48:03 +00:00
|
|
|
componentDidUpdate(prevProps: Props) {
|
|
|
|
this._maybeToggleAnimation(prevProps, this.props);
|
2018-09-11 10:16:01 +00:00
|
|
|
}
|
|
|
|
|
2018-05-22 19:44:40 +00:00
|
|
|
/**
|
|
|
|
* Implements React {@link Component}'s render.
|
|
|
|
*
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
render() {
|
2020-05-18 11:54:55 +00:00
|
|
|
const { icon, label, status, style } = this.props;
|
2018-09-11 10:16:01 +00:00
|
|
|
|
|
|
|
let extraStyle = null;
|
|
|
|
|
|
|
|
switch (status) {
|
|
|
|
case STATUS_IN_PROGRESS:
|
|
|
|
extraStyle = {
|
|
|
|
opacity: this.state.pulseAnimation
|
|
|
|
};
|
|
|
|
break;
|
|
|
|
case STATUS_OFF:
|
|
|
|
extraStyle = styles.labelOff;
|
|
|
|
break;
|
|
|
|
}
|
2018-05-22 19:44:40 +00:00
|
|
|
|
2020-05-18 11:54:55 +00:00
|
|
|
const labelComponent = icon
|
|
|
|
? (
|
|
|
|
<Icon
|
|
|
|
src = { icon }
|
|
|
|
style = { styles.indicatorIcon } />
|
|
|
|
) : (
|
|
|
|
<Text style = { styles.indicatorText }>
|
|
|
|
{ label }
|
|
|
|
</Text>
|
|
|
|
);
|
|
|
|
|
2018-05-22 19:44:40 +00:00
|
|
|
return (
|
2018-09-11 10:16:01 +00:00
|
|
|
<Animated.View
|
|
|
|
style = { [
|
|
|
|
combineStyles(styles.indicatorContainer, style),
|
|
|
|
extraStyle
|
|
|
|
] }>
|
2020-05-18 11:54:55 +00:00
|
|
|
{ labelComponent }
|
2018-09-11 10:16:01 +00:00
|
|
|
</Animated.View>
|
2018-05-22 19:44:40 +00:00
|
|
|
);
|
|
|
|
}
|
2018-09-11 10:16:01 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks if the animation has to be started or stopped and acts
|
|
|
|
* accordingly.
|
|
|
|
*
|
|
|
|
* @param {Props} oldProps - The previous values of the Props.
|
|
|
|
* @param {Props} newProps - The new values of the Props.
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
_maybeToggleAnimation(oldProps, newProps) {
|
|
|
|
const { status: oldStatus } = oldProps;
|
|
|
|
const { status: newStatus } = newProps;
|
|
|
|
const { pulseAnimation } = this.state;
|
|
|
|
|
|
|
|
if (newStatus === STATUS_IN_PROGRESS
|
|
|
|
&& oldStatus !== STATUS_IN_PROGRESS) {
|
|
|
|
// Animation must be started
|
|
|
|
this.animationReference = Animated.loop(Animated.sequence([
|
|
|
|
Animated.timing(pulseAnimation, {
|
|
|
|
delay: 500,
|
|
|
|
toValue: 1,
|
|
|
|
useNativeDriver: true
|
|
|
|
}),
|
|
|
|
Animated.timing(pulseAnimation, {
|
|
|
|
toValue: 0.3,
|
|
|
|
useNativeDriver: true
|
|
|
|
})
|
|
|
|
]));
|
|
|
|
|
|
|
|
this.animationReference.start();
|
|
|
|
} else if (this.animationReference
|
|
|
|
&& newStatus !== STATUS_IN_PROGRESS
|
|
|
|
&& oldStatus === STATUS_IN_PROGRESS) {
|
|
|
|
// Animation must be stopped
|
|
|
|
this.animationReference.stop();
|
|
|
|
}
|
|
|
|
}
|
2018-05-22 19:44:40 +00:00
|
|
|
}
|