Add conference timer (#4958)
This commit is contained in:
committed by
Дамян Минков
parent
c73ba37202
commit
c2cf09a2ca
@@ -52,6 +52,16 @@ export const CONFERENCE_LEFT = 'CONFERENCE_LEFT';
|
||||
*/
|
||||
export const CONFERENCE_SUBJECT_CHANGED = 'CONFERENCE_SUBJECT_CHANGED';
|
||||
|
||||
/**
|
||||
* The type of (redux) action, which indicates conference UTC timestamp changes.
|
||||
*
|
||||
* {
|
||||
* type: CONFERENCE_TIMESTAMP_CHANGED
|
||||
* timestamp: number
|
||||
* }
|
||||
*/
|
||||
export const CONFERENCE_TIMESTAMP_CHANGED = 'CONFERENCE_TIMESTAMP_CHANGED';
|
||||
|
||||
/**
|
||||
* The type of (redux) action which signals that a specific conference will be
|
||||
* joined.
|
||||
|
||||
@@ -35,6 +35,7 @@ import {
|
||||
CONFERENCE_JOINED,
|
||||
CONFERENCE_LEFT,
|
||||
CONFERENCE_SUBJECT_CHANGED,
|
||||
CONFERENCE_TIMESTAMP_CHANGED,
|
||||
CONFERENCE_WILL_JOIN,
|
||||
CONFERENCE_WILL_LEAVE,
|
||||
DATA_CHANNEL_OPENED,
|
||||
@@ -93,10 +94,16 @@ function _addConferenceListeners(conference, dispatch) {
|
||||
(...args) => dispatch(conferenceJoined(conference, ...args)));
|
||||
conference.on(
|
||||
JitsiConferenceEvents.CONFERENCE_LEFT,
|
||||
(...args) => dispatch(conferenceLeft(conference, ...args)));
|
||||
(...args) => {
|
||||
dispatch(conferenceTimestampChanged(0));
|
||||
dispatch(conferenceLeft(conference, ...args));
|
||||
});
|
||||
conference.on(JitsiConferenceEvents.SUBJECT_CHANGED,
|
||||
(...args) => dispatch(conferenceSubjectChanged(...args)));
|
||||
|
||||
conference.on(JitsiConferenceEvents.CONFERENCE_CREATED_TIMESTAMP,
|
||||
(...args) => dispatch(conferenceTimestampChanged(...args)));
|
||||
|
||||
conference.on(
|
||||
JitsiConferenceEvents.KICKED,
|
||||
(...args) => dispatch(kickedOut(conference, ...args)));
|
||||
@@ -313,6 +320,22 @@ export function conferenceSubjectChanged(subject: string) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals that the conference timestamp has been changed.
|
||||
*
|
||||
* @param {number} conferenceTimestamp - The UTC timestamp.
|
||||
* @returns {{
|
||||
* type: CONFERENCE_TIMESTAMP_CHANGED,
|
||||
* conferenceTimestamp
|
||||
* }}
|
||||
*/
|
||||
export function conferenceTimestampChanged(conferenceTimestamp: number) {
|
||||
return {
|
||||
type: CONFERENCE_TIMESTAMP_CHANGED,
|
||||
conferenceTimestamp
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds any existing local tracks to a specific conference before the conference
|
||||
* is joined. Then signals the intention of the application to have the local
|
||||
|
||||
@@ -167,6 +167,20 @@ export function getConferenceName(stateful: Function | Object): string {
|
||||
|| _.startCase(safeDecodeURIComponent(room));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the UTC timestamp when the first participant joined the conference.
|
||||
*
|
||||
* @param {Function | Object} stateful - Reference that can be resolved to Redux
|
||||
* state with the {@code toState} function.
|
||||
* @returns {number}
|
||||
*/
|
||||
export function getConferenceTimestamp(stateful: Function | Object): number {
|
||||
const state = toState(stateful);
|
||||
const { conferenceTimestamp } = state['features/base/conference'];
|
||||
|
||||
return conferenceTimestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current {@code JitsiConference} which is joining or joined and is
|
||||
* not leaving. Please note the contrast with merely reading the
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
CONFERENCE_JOINED,
|
||||
CONFERENCE_LEFT,
|
||||
CONFERENCE_SUBJECT_CHANGED,
|
||||
CONFERENCE_TIMESTAMP_CHANGED,
|
||||
CONFERENCE_WILL_JOIN,
|
||||
CONFERENCE_WILL_LEAVE,
|
||||
LOCK_STATE_CHANGED,
|
||||
@@ -59,6 +60,9 @@ ReducerRegistry.register(
|
||||
case CONFERENCE_SUBJECT_CHANGED:
|
||||
return set(state, 'subject', action.subject);
|
||||
|
||||
case CONFERENCE_TIMESTAMP_CHANGED:
|
||||
return set(state, 'conferenceTimestamp', action.conferenceTimestamp);
|
||||
|
||||
case CONFERENCE_LEFT:
|
||||
case CONFERENCE_WILL_LEAVE:
|
||||
return _conferenceLeftOrWillLeave(state, action);
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
// @flow
|
||||
|
||||
import { Component } from 'react';
|
||||
|
||||
import { connect } from '../../base/redux';
|
||||
import { getLocalizedDurationFormatter } from '../../base/i18n';
|
||||
import { getConferenceTimestamp } from '../../base/conference/functions';
|
||||
import { renderConferenceTimer } from '../';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link ConferenceTimer}.
|
||||
*/
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The UTC timestamp representing the time when first participant joined.
|
||||
*/
|
||||
_startTimestamp: ?number,
|
||||
|
||||
/**
|
||||
* The redux {@code dispatch} function.
|
||||
*/
|
||||
dispatch: Function
|
||||
};
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} state of {@link ConferenceTimer}.
|
||||
*/
|
||||
type State = {
|
||||
|
||||
/**
|
||||
* Value of current conference time.
|
||||
*/
|
||||
timerValue: string
|
||||
};
|
||||
|
||||
/**
|
||||
* ConferenceTimer react component.
|
||||
*
|
||||
* @class ConferenceTimer
|
||||
* @extends Component
|
||||
*/
|
||||
class ConferenceTimer extends Component<Props, State> {
|
||||
|
||||
/**
|
||||
* Handle for setInterval timer.
|
||||
*/
|
||||
_interval;
|
||||
|
||||
/**
|
||||
* Initializes a new {@code ConferenceTimer} instance.
|
||||
*
|
||||
* @param {Props} props - The read-only properties with which the new
|
||||
* instance is to be initialized.
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
timerValue: getLocalizedDurationFormatter(0)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the conference timer when component will be
|
||||
* mounted.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentDidMount() {
|
||||
this._startTimer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the conference timer when component will be
|
||||
* unmounted.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
this._stopTimer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { timerValue } = this.state;
|
||||
const { _startTimestamp } = this.props;
|
||||
|
||||
if (!_startTimestamp) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return renderConferenceTimer(timerValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current state values that will be used to render the timer.
|
||||
*
|
||||
* @param {number} refValueUTC - The initial UTC timestamp value.
|
||||
* @param {number} currentValueUTC - The current UTC timestamp value.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_setStateFromUTC(refValueUTC, currentValueUTC) {
|
||||
|
||||
if (!refValueUTC || !currentValueUTC) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentValueUTC < refValueUTC) {
|
||||
return;
|
||||
}
|
||||
|
||||
const timerMsValue = currentValueUTC - refValueUTC;
|
||||
|
||||
const localizedTime = getLocalizedDurationFormatter(timerMsValue);
|
||||
|
||||
this.setState({
|
||||
timerValue: localizedTime
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Start conference timer.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_startTimer() {
|
||||
if (!this._interval) {
|
||||
this._setStateFromUTC(this.props._startTimestamp, (new Date()).getTime());
|
||||
|
||||
this._interval = setInterval(() => {
|
||||
this._setStateFromUTC(this.props._startTimestamp, (new Date()).getTime());
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop conference timer.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_stopTimer() {
|
||||
if (this._interval) {
|
||||
clearInterval(this._interval);
|
||||
}
|
||||
|
||||
this.setState({
|
||||
timerValue: getLocalizedDurationFormatter(0)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps (parts of) the Redux state to the associated
|
||||
* {@code ConferenceTimer}'s props.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @private
|
||||
* @returns {{
|
||||
* _startTimestamp: number
|
||||
* }}
|
||||
*/
|
||||
export function _mapStateToProps(state: Object) {
|
||||
|
||||
return {
|
||||
_startTimestamp: getConferenceTimestamp(state)
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(_mapStateToProps)(ConferenceTimer);
|
||||
@@ -0,0 +1,23 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { Text } from 'react-native';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
/**
|
||||
* Returns native element to be rendered.
|
||||
*
|
||||
* @param {string} timerValue - String to display as time.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
export default function renderConferenceTimer(timerValue: string) {
|
||||
return (
|
||||
<Text
|
||||
numberOfLines = { 4 }
|
||||
style = { styles.roomTimer }>
|
||||
{ timerValue }
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import { connect } from '../../../base/redux';
|
||||
import { PictureInPictureButton } from '../../../mobile/picture-in-picture';
|
||||
import { isToolboxVisible } from '../../../toolbox';
|
||||
|
||||
import ConferenceTimer from '../ConferenceTimer';
|
||||
import styles, { NAVBAR_GRADIENT_COLORS } from './styles';
|
||||
|
||||
type Props = {
|
||||
@@ -63,6 +64,7 @@ class NavigationBar extends Component<Props> {
|
||||
style = { styles.roomName }>
|
||||
{ this.props._meetingName }
|
||||
</Text>
|
||||
<ConferenceTimer />
|
||||
</View>
|
||||
</View>
|
||||
];
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// @flow
|
||||
|
||||
export { default as Conference } from './Conference';
|
||||
export { default as renderConferenceTimer } from './ConferenceTimerDisplay';
|
||||
|
||||
@@ -105,6 +105,12 @@ export default {
|
||||
paddingHorizontal: 14
|
||||
},
|
||||
|
||||
roomTimer: {
|
||||
color: ColorPalette.white,
|
||||
fontSize: 15,
|
||||
opacity: 0.6
|
||||
},
|
||||
|
||||
roomName: {
|
||||
color: ColorPalette.white,
|
||||
fontSize: 17,
|
||||
@@ -112,8 +118,8 @@ export default {
|
||||
},
|
||||
|
||||
roomNameWrapper: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
left: 0,
|
||||
paddingHorizontal: 48,
|
||||
position: 'absolute',
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
|
||||
/**
|
||||
* Returns web element to be rendered.
|
||||
*
|
||||
* @param {string} timerValue - String to display as time.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
export default function renderConferenceTimer(timerValue: string) {
|
||||
return (
|
||||
<span className = 'subject-conference-timer' >{ timerValue }</span>
|
||||
);
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import { getParticipantCount } from '../../../base/participants/functions';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { isToolboxVisible } from '../../../toolbox';
|
||||
|
||||
import ConferenceTimer from '../ConferenceTimer';
|
||||
import ParticipantsCount from './ParticipantsCount';
|
||||
|
||||
/**
|
||||
@@ -51,6 +52,7 @@ class Subject extends Component<Props> {
|
||||
<div className = { `subject ${_visible ? 'visible' : ''}` }>
|
||||
<span className = 'subject-text'>{ _subject }</span>
|
||||
{ _showParticipantCount && <ParticipantsCount /> }
|
||||
<ConferenceTimer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// @flow
|
||||
|
||||
export { default as Conference } from './Conference';
|
||||
export { default as renderConferenceTimer } from './ConferenceTimerDisplay';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user