ref(RecentList): Improvements after review.
This commit is contained in:
parent
046b06e436
commit
fb75180632
|
@ -38,7 +38,6 @@ import {
|
||||||
conferenceWillLeave,
|
conferenceWillLeave,
|
||||||
dataChannelOpened,
|
dataChannelOpened,
|
||||||
EMAIL_COMMAND,
|
EMAIL_COMMAND,
|
||||||
getCurrentConference,
|
|
||||||
lockStateChanged,
|
lockStateChanged,
|
||||||
onStartMutedPolicyChanged,
|
onStartMutedPolicyChanged,
|
||||||
p2pStatusChanged,
|
p2pStatusChanged,
|
||||||
|
@ -307,10 +306,6 @@ class ConferenceConnector {
|
||||||
_onConferenceFailed(err, ...params) {
|
_onConferenceFailed(err, ...params) {
|
||||||
APP.store.dispatch(conferenceFailed(room, err, ...params));
|
APP.store.dispatch(conferenceFailed(room, err, ...params));
|
||||||
logger.error('CONFERENCE FAILED:', err, ...params);
|
logger.error('CONFERENCE FAILED:', err, ...params);
|
||||||
const state = APP.store.getState();
|
|
||||||
|
|
||||||
// The conference we have already joined or are joining.
|
|
||||||
const conference = getCurrentConference(state);
|
|
||||||
|
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case JitsiConferenceErrors.CONNECTION_ERROR: {
|
case JitsiConferenceErrors.CONNECTION_ERROR: {
|
||||||
|
@ -378,10 +373,11 @@ class ConferenceConnector {
|
||||||
|
|
||||||
case JitsiConferenceErrors.FOCUS_LEFT:
|
case JitsiConferenceErrors.FOCUS_LEFT:
|
||||||
case JitsiConferenceErrors.VIDEOBRIDGE_NOT_AVAILABLE:
|
case JitsiConferenceErrors.VIDEOBRIDGE_NOT_AVAILABLE:
|
||||||
|
APP.store.dispatch(conferenceWillLeave(room));
|
||||||
|
|
||||||
// FIXME the conference should be stopped by the library and not by
|
// FIXME the conference should be stopped by the library and not by
|
||||||
// the app. Both the errors above are unrecoverable from the library
|
// the app. Both the errors above are unrecoverable from the library
|
||||||
// perspective.
|
// perspective.
|
||||||
APP.store.dispatch(conferenceWillLeave(conference));
|
|
||||||
room.leave().then(() => connection.disconnect());
|
room.leave().then(() => connection.disconnect());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -475,12 +471,7 @@ function _connectionFailedHandler(error) {
|
||||||
JitsiConnectionEvents.CONNECTION_FAILED,
|
JitsiConnectionEvents.CONNECTION_FAILED,
|
||||||
_connectionFailedHandler);
|
_connectionFailedHandler);
|
||||||
if (room) {
|
if (room) {
|
||||||
const state = APP.store.getState();
|
APP.store.dispatch(conferenceWillLeave(room));
|
||||||
|
|
||||||
// The conference we have already joined or are joining.
|
|
||||||
const conference = getCurrentConference(state);
|
|
||||||
|
|
||||||
APP.store.dispatch(conferenceWillLeave(conference));
|
|
||||||
room.leave();
|
room.leave();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2478,12 +2469,6 @@ export default {
|
||||||
* requested
|
* requested
|
||||||
*/
|
*/
|
||||||
hangup(requestFeedback = false) {
|
hangup(requestFeedback = false) {
|
||||||
const state = APP.store.getState();
|
|
||||||
|
|
||||||
// The conference we have already joined or are joining.
|
|
||||||
const conference = getCurrentConference(state);
|
|
||||||
|
|
||||||
APP.store.dispatch(conferenceWillLeave(conference));
|
|
||||||
eventEmitter.emit(JitsiMeetConferenceEvents.BEFORE_HANGUP);
|
eventEmitter.emit(JitsiMeetConferenceEvents.BEFORE_HANGUP);
|
||||||
APP.UI.removeLocalMedia();
|
APP.UI.removeLocalMedia();
|
||||||
|
|
||||||
|
@ -2512,13 +2497,24 @@ export default {
|
||||||
// before all operations are done.
|
// before all operations are done.
|
||||||
Promise.all([
|
Promise.all([
|
||||||
requestFeedbackPromise,
|
requestFeedbackPromise,
|
||||||
room.leave().then(disconnect, disconnect)
|
this.leaveRoomAndDisconnect()
|
||||||
]).then(values => {
|
]).then(values => {
|
||||||
APP.API.notifyReadyToClose();
|
APP.API.notifyReadyToClose();
|
||||||
maybeRedirectToWelcomePage(values[0]);
|
maybeRedirectToWelcomePage(values[0]);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Leaves the room and calls JitsiConnection.disconnect.
|
||||||
|
*
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
leaveRoomAndDisconnect() {
|
||||||
|
APP.store.dispatch(conferenceWillLeave(room));
|
||||||
|
|
||||||
|
return room.leave().then(disconnect, disconnect);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the email for the local user
|
* Changes the email for the local user
|
||||||
* @param email {string} the new email
|
* @param email {string} the new email
|
||||||
|
|
|
@ -79,4 +79,4 @@
|
||||||
@import 'deep-linking/main';
|
@import 'deep-linking/main';
|
||||||
@import 'transcription-subtitles';
|
@import 'transcription-subtitles';
|
||||||
@import 'navigate_section_list';
|
@import 'navigate_section_list';
|
||||||
@import 'transcription-subtitles';
|
/* Modules END */
|
||||||
|
|
|
@ -10502,6 +10502,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.19.4.tgz",
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.19.4.tgz",
|
||||||
"integrity": "sha512-1xFTAknSLfc47DIxHDUbnJWC+UwgWxATmymaxIPQpmMh7LBm7ZbwVEsuushqwL2GYZU0jie4xO+TK44hJPjNSQ=="
|
"integrity": "sha512-1xFTAknSLfc47DIxHDUbnJWC+UwgWxATmymaxIPQpmMh7LBm7ZbwVEsuushqwL2GYZU0jie4xO+TK44hJPjNSQ=="
|
||||||
},
|
},
|
||||||
|
"moment-duration-format": {
|
||||||
|
"version": "2.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/moment-duration-format/-/moment-duration-format-2.2.2.tgz",
|
||||||
|
"integrity": "sha1-uVdhLeJgFsmtnrYIfAVFc+USd3k="
|
||||||
|
},
|
||||||
"morgan": {
|
"morgan": {
|
||||||
"version": "1.9.0",
|
"version": "1.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.0.tgz",
|
||||||
|
|
|
@ -24,12 +24,14 @@ import { TRACK_ADDED, TRACK_REMOVED } from '../tracks';
|
||||||
import {
|
import {
|
||||||
conferenceFailed,
|
conferenceFailed,
|
||||||
conferenceLeft,
|
conferenceLeft,
|
||||||
|
conferenceWillLeave,
|
||||||
createConference,
|
createConference,
|
||||||
setLastN
|
setLastN
|
||||||
} from './actions';
|
} from './actions';
|
||||||
import {
|
import {
|
||||||
CONFERENCE_FAILED,
|
CONFERENCE_FAILED,
|
||||||
CONFERENCE_JOINED,
|
CONFERENCE_JOINED,
|
||||||
|
CONFERENCE_WILL_LEAVE,
|
||||||
DATA_CHANNEL_OPENED,
|
DATA_CHANNEL_OPENED,
|
||||||
SET_AUDIO_ONLY,
|
SET_AUDIO_ONLY,
|
||||||
SET_LASTN,
|
SET_LASTN,
|
||||||
|
@ -46,6 +48,11 @@ const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
|
|
||||||
declare var APP: Object;
|
declare var APP: Object;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for before unload event.
|
||||||
|
*/
|
||||||
|
let beforeUnloadHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements the middleware of the feature base/conference.
|
* Implements the middleware of the feature base/conference.
|
||||||
*
|
*
|
||||||
|
@ -66,6 +73,10 @@ MiddlewareRegistry.register(store => next => action => {
|
||||||
case CONNECTION_FAILED:
|
case CONNECTION_FAILED:
|
||||||
return _connectionFailed(store, next, action);
|
return _connectionFailed(store, next, action);
|
||||||
|
|
||||||
|
case CONFERENCE_WILL_LEAVE:
|
||||||
|
_conferenceWillLeave();
|
||||||
|
break;
|
||||||
|
|
||||||
case DATA_CHANNEL_OPENED:
|
case DATA_CHANNEL_OPENED:
|
||||||
return _syncReceiveVideoQuality(store, next, action);
|
return _syncReceiveVideoQuality(store, next, action);
|
||||||
|
|
||||||
|
@ -135,6 +146,11 @@ function _conferenceFailed(store, next, action) {
|
||||||
// conference is handled by /conference.js and appropriate failure handlers
|
// conference is handled by /conference.js and appropriate failure handlers
|
||||||
// are set there.
|
// are set there.
|
||||||
if (typeof APP !== 'undefined') {
|
if (typeof APP !== 'undefined') {
|
||||||
|
if (typeof beforeUnloadHandler !== 'undefined') {
|
||||||
|
window.removeEventListener('beforeunload', beforeUnloadHandler);
|
||||||
|
beforeUnloadHandler = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,6 +191,16 @@ function _conferenceJoined({ dispatch, getState }, next, action) {
|
||||||
// and the LastN value needs to be synchronized here.
|
// and the LastN value needs to be synchronized here.
|
||||||
audioOnly && conference.getLastN() !== 0 && dispatch(setLastN(0));
|
audioOnly && conference.getLastN() !== 0 && dispatch(setLastN(0));
|
||||||
|
|
||||||
|
// FIXME: Very dirty solution. This will work on web only.
|
||||||
|
// When the user closes the window or quits the browser, lib-jitsi-meet
|
||||||
|
// handles the process of leaving the conference. This is temporary solution
|
||||||
|
// that should cover the described use case as part of the effort to
|
||||||
|
// implement the conferenceWillLeave action for web.
|
||||||
|
beforeUnloadHandler = () => {
|
||||||
|
dispatch(conferenceWillLeave(conference));
|
||||||
|
};
|
||||||
|
window.addEventListener('beforeunload', beforeUnloadHandler);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,6 +253,11 @@ function _connectionFailed({ dispatch, getState }, next, action) {
|
||||||
|
|
||||||
const result = next(action);
|
const result = next(action);
|
||||||
|
|
||||||
|
if (typeof beforeUnloadHandler !== 'undefined') {
|
||||||
|
window.removeEventListener('beforeunload', beforeUnloadHandler);
|
||||||
|
beforeUnloadHandler = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: Workaround for the web version. Currently, the creation of the
|
// FIXME: Workaround for the web version. Currently, the creation of the
|
||||||
// conference is handled by /conference.js and appropriate failure handlers
|
// conference is handled by /conference.js and appropriate failure handlers
|
||||||
// are set there.
|
// are set there.
|
||||||
|
@ -266,6 +297,21 @@ function _connectionFailed({ dispatch, getState }, next, action) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifies the feature base/conference that the action
|
||||||
|
* {@code CONFERENCE_WILL_LEAVE} is being dispatched within a specific redux
|
||||||
|
* store.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
function _conferenceWillLeave() {
|
||||||
|
if (typeof beforeUnloadHandler !== 'undefined') {
|
||||||
|
window.removeEventListener('beforeunload', beforeUnloadHandler);
|
||||||
|
beforeUnloadHandler = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether or not a CONNECTION_FAILED action is for a possible split
|
* Returns whether or not a CONNECTION_FAILED action is for a possible split
|
||||||
* brain error. A split brain error occurs when at least two users join a
|
* brain error. A split brain error occurs when at least two users join a
|
||||||
|
|
|
@ -114,6 +114,15 @@ function _visitNode(node, callback) {
|
||||||
global.addEventListener = () => {};
|
global.addEventListener = () => {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// removeEventListener
|
||||||
|
//
|
||||||
|
// Required by:
|
||||||
|
// - features/base/conference/middleware
|
||||||
|
if (typeof global.removeEventListener === 'undefined') {
|
||||||
|
// eslint-disable-next-line no-empty-function
|
||||||
|
global.removeEventListener = () => {};
|
||||||
|
}
|
||||||
|
|
||||||
// Array.prototype[@@iterator]
|
// Array.prototype[@@iterator]
|
||||||
//
|
//
|
||||||
// Required by:
|
// Required by:
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
// @flow
|
// @flow
|
||||||
/**
|
|
||||||
* item data for NavigateSectionList
|
|
||||||
*/
|
|
||||||
import type {
|
|
||||||
ComponentType,
|
|
||||||
Element
|
|
||||||
} from 'react';
|
|
||||||
|
|
||||||
|
import type { ComponentType, Element } from 'react';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Item data for <tt>NavigateSectionList</tt>.
|
||||||
|
*/
|
||||||
export type Item = {
|
export type Item = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
import { translate } from '../../i18n';
|
// TODO: Maybe try to make all NavigateSectionList components to work for both
|
||||||
|
// mobile and web, and move them to NavigateSectionList component.
|
||||||
import {
|
import {
|
||||||
NavigateSectionListEmptyComponent,
|
NavigateSectionListEmptyComponent,
|
||||||
NavigateSectionListItem,
|
NavigateSectionListItem,
|
||||||
|
@ -19,11 +19,6 @@ type Props = {
|
||||||
*/
|
*/
|
||||||
disabled: boolean,
|
disabled: boolean,
|
||||||
|
|
||||||
/**
|
|
||||||
* The translate function.
|
|
||||||
*/
|
|
||||||
t: Function,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function to be invoked when an item is pressed. The item's URL is passed.
|
* Function to be invoked when an item is pressed. The item's URL is passed.
|
||||||
*/
|
*/
|
||||||
|
@ -59,7 +54,7 @@ class NavigateSectionList extends Component<Props> {
|
||||||
* @private
|
* @private
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
static createSection(title, key) {
|
static createSection(title: string, key: string) {
|
||||||
return {
|
return {
|
||||||
data: [],
|
data: [],
|
||||||
key,
|
key,
|
||||||
|
@ -166,7 +161,7 @@ class NavigateSectionList extends Component<Props> {
|
||||||
* @private
|
* @private
|
||||||
* @returns {Component}
|
* @returns {Component}
|
||||||
*/
|
*/
|
||||||
_renderItem(listItem, key = '') {
|
_renderItem(listItem, key: string = '') {
|
||||||
const { item } = listItem;
|
const { item } = listItem;
|
||||||
const { url } = item;
|
const { url } = item;
|
||||||
|
|
||||||
|
@ -197,12 +192,11 @@ class NavigateSectionList extends Component<Props> {
|
||||||
* @returns {React$Node}
|
* @returns {React$Node}
|
||||||
*/
|
*/
|
||||||
_renderListEmptyComponent() {
|
_renderListEmptyComponent() {
|
||||||
const { t, onRefresh } = this.props;
|
const { onRefresh } = this.props;
|
||||||
|
|
||||||
if (typeof onRefresh === 'function') {
|
if (typeof onRefresh === 'function') {
|
||||||
return (
|
return (
|
||||||
<NavigateSectionListEmptyComponent
|
<NavigateSectionListEmptyComponent />
|
||||||
t = { t } />
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,4 +220,4 @@ class NavigateSectionList extends Component<Props> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default translate(NavigateSectionList);
|
export default NavigateSectionList;
|
||||||
|
|
|
@ -34,6 +34,7 @@ export default class Container extends AbstractContainer {
|
||||||
accessible,
|
accessible,
|
||||||
onClick,
|
onClick,
|
||||||
touchFeedback = onClick,
|
touchFeedback = onClick,
|
||||||
|
underlayColor,
|
||||||
visible = true,
|
visible = true,
|
||||||
...props
|
...props
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
@ -62,7 +63,8 @@ export default class Container extends AbstractContainer {
|
||||||
{
|
{
|
||||||
accessibilityLabel,
|
accessibilityLabel,
|
||||||
accessible,
|
accessible,
|
||||||
onPress: onClick
|
onPress: onClick,
|
||||||
|
underlayColor
|
||||||
},
|
},
|
||||||
element);
|
element);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import {
|
import { Text, View } from 'react-native';
|
||||||
Text,
|
|
||||||
View
|
|
||||||
} from 'react-native';
|
|
||||||
|
|
||||||
import { Icon } from '../../../font-icons/index';
|
import { Icon } from '../../../font-icons';
|
||||||
import { translate } from '../../../i18n/index';
|
import { translate } from '../../../i18n';
|
||||||
|
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { TouchableHighlight } from 'react-native';
|
|
||||||
|
|
||||||
import {
|
import Container from './Container';
|
||||||
Text,
|
import Text from './Text';
|
||||||
Container
|
|
||||||
} from './index';
|
|
||||||
import styles, { UNDERLAY_COLOR } from './styles';
|
import styles, { UNDERLAY_COLOR } from './styles';
|
||||||
import type { Item } from '../../Types';
|
import type { Item } from '../../Types';
|
||||||
|
|
||||||
|
@ -110,36 +107,35 @@ export default class NavigateSectionListItem extends Component<Props> {
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
const { colorBase, lines, title } = this.props.item;
|
const { colorBase, lines, title } = this.props.item;
|
||||||
|
const avatarStyles = {
|
||||||
|
...styles.avatar,
|
||||||
|
...this._getAvatarColor(colorBase)
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TouchableHighlight
|
<Container
|
||||||
onPress = { this.props.onPress }
|
onClick = { this.props.onPress }
|
||||||
|
style = { styles.listItem }
|
||||||
underlayColor = { UNDERLAY_COLOR }>
|
underlayColor = { UNDERLAY_COLOR }>
|
||||||
<Container style = { styles.listItem }>
|
<Container style = { styles.avatarContainer }>
|
||||||
<Container style = { styles.avatarContainer }>
|
<Container style = { avatarStyles }>
|
||||||
<Container
|
<Text style = { styles.avatarContent }>
|
||||||
style = { [
|
{title.substr(0, 1).toUpperCase()}
|
||||||
styles.avatar,
|
|
||||||
this._getAvatarColor(colorBase)
|
|
||||||
] }>
|
|
||||||
<Text style = { styles.avatarContent }>
|
|
||||||
{title.substr(0, 1).toUpperCase()}
|
|
||||||
</Text>
|
|
||||||
</Container>
|
|
||||||
</Container>
|
|
||||||
<Container style = { styles.listItemDetails }>
|
|
||||||
<Text
|
|
||||||
numberOfLines = { 1 }
|
|
||||||
style = { [
|
|
||||||
styles.listItemText,
|
|
||||||
styles.listItemTitle
|
|
||||||
] }>
|
|
||||||
{title}
|
|
||||||
</Text>
|
</Text>
|
||||||
{this._renderItemLines(lines)}
|
|
||||||
</Container>
|
</Container>
|
||||||
</Container>
|
</Container>
|
||||||
</TouchableHighlight>
|
<Container style = { styles.listItemDetails }>
|
||||||
|
<Text
|
||||||
|
numberOfLines = { 1 }
|
||||||
|
style = {{
|
||||||
|
...styles.listItemText,
|
||||||
|
...styles.listItemTitle
|
||||||
|
}}>
|
||||||
|
{title}
|
||||||
|
</Text>
|
||||||
|
{this._renderItemLines(lines)}
|
||||||
|
</Container>
|
||||||
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
import { Text, Container } from './index';
|
import Container from './Container';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
import Text from './Text';
|
||||||
import type { SetionListSection } from '../../Types';
|
import type { SetionListSection } from '../../Types';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
import { Text, Container } from './index';
|
import Container from './Container';
|
||||||
|
import Text from './Text';
|
||||||
import type { Item } from '../../Types';
|
import type { Item } from '../../Types';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
import { Text } from './index';
|
import Text from './Text';
|
||||||
import type { Section } from '../../Types';
|
import type { Section } from '../../Types';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
import { Container } from './index';
|
import Container from './Container';
|
||||||
import type { Section } from '../../Types';
|
import type { Section } from '../../Types';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
export * from './components';
|
export * from './components';
|
||||||
export { default as Platform } from './Platform';
|
export { default as Platform } from './Platform';
|
||||||
|
export * from './Types';
|
||||||
|
|
|
@ -20,6 +20,15 @@ const throttledPersistState
|
||||||
state => PersistenceRegistry.persistState(state),
|
state => PersistenceRegistry.persistState(state),
|
||||||
PERSIST_STATE_DELAY);
|
PERSIST_STATE_DELAY);
|
||||||
|
|
||||||
|
// Web only code.
|
||||||
|
// We need the <tt>if</tt> beacuse it appears that on mobile the polyfill is not
|
||||||
|
// executed yet.
|
||||||
|
if (typeof window.addEventListener === 'function') {
|
||||||
|
window.addEventListener('unload', () => {
|
||||||
|
throttledPersistState.flush();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A master MiddleWare to selectively persist state. Please use the
|
* A master MiddleWare to selectively persist state. Please use the
|
||||||
* {@link persisterconfig.json} to set which subtrees of the redux state should
|
* {@link persisterconfig.json} to set which subtrees of the redux state should
|
||||||
|
@ -37,8 +46,3 @@ MiddlewareRegistry.register(store => next => action => {
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|
||||||
window.addEventListener('beforeunload', () => {
|
|
||||||
// Stop the LogCollector
|
|
||||||
throttledPersistState.flush();
|
|
||||||
});
|
|
||||||
|
|
|
@ -4,10 +4,10 @@ import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { appNavigate, getDefaultURL } from '../../app';
|
import { appNavigate, getDefaultURL } from '../../app';
|
||||||
import { translate } from '../../base/i18n';
|
import { translate } from '../../base/i18n';
|
||||||
import type { Section } from '../../base/react/Types';
|
|
||||||
import { NavigateSectionList } from '../../base/react';
|
import { NavigateSectionList } from '../../base/react';
|
||||||
|
import type { Section } from '../../base/react';
|
||||||
|
|
||||||
import { toDisplayableList } from '../functions';
|
import { isRecentListEnabled, toDisplayableList } from '../functions';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the React {@code Component} props of {@link RecentList}
|
* The type of the React {@code Component} props of {@link RecentList}
|
||||||
|
@ -62,6 +62,9 @@ class RecentList extends Component<Props> {
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
|
if (!isRecentListEnabled()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
const { disabled, t, _defaultServerURL, _recentList } = this.props;
|
const { disabled, t, _defaultServerURL, _recentList } = this.props;
|
||||||
const recentList = toDisplayableList(_recentList, t, _defaultServerURL);
|
const recentList = toDisplayableList(_recentList, t, _defaultServerURL);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
/**
|
|
||||||
* Everything about recent list on web should be behind a feature flag and in
|
|
||||||
* order to share code, this alias for the feature flag on mobile is always true
|
|
||||||
* because we dont need a feature flag for recent list on mobile
|
|
||||||
* @type {boolean}
|
|
||||||
*/
|
|
||||||
export const RECENT_LIST_ENABLED = true;
|
|
|
@ -1,10 +0,0 @@
|
||||||
// @flow
|
|
||||||
declare var interfaceConfig: Object;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Everything about recent list on web should be behind a feature flag and in
|
|
||||||
* order to share code, this alias for the feature flag on mobile is set to the
|
|
||||||
* value defined in interface_config
|
|
||||||
* @type {boolean}
|
|
||||||
*/
|
|
||||||
export const { RECENT_LIST_ENABLED } = interfaceConfig;
|
|
|
@ -1,6 +1,8 @@
|
||||||
import { getLocalizedDateFormatter, getLocalizedDurationFormatter }
|
import {
|
||||||
from '../base/i18n/index';
|
getLocalizedDateFormatter,
|
||||||
import { parseURIString } from '../base/util/index';
|
getLocalizedDurationFormatter
|
||||||
|
} from '../base/i18n';
|
||||||
|
import { parseURIString } from '../base/util';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a displayable list item of a recent list entry.
|
* Creates a displayable list item of a recent list entry.
|
||||||
|
@ -12,7 +14,6 @@ import { parseURIString } from '../base/util/index';
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
export function toDisplayableItem(item, defaultServerURL, t) {
|
export function toDisplayableItem(item, defaultServerURL, t) {
|
||||||
// const { _defaultServerURL } = this.props;
|
|
||||||
const location = parseURIString(item.conference);
|
const location = parseURIString(item.conference);
|
||||||
const baseURL = `${location.protocol}//${location.host}`;
|
const baseURL = `${location.protocol}//${location.host}`;
|
||||||
const serverName = baseURL === defaultServerURL ? null : location.host;
|
const serverName = baseURL === defaultServerURL ? null : location.host;
|
||||||
|
@ -54,26 +55,20 @@ export function _toDurationString(duration) {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function _toDateString(itemDate, t) {
|
export function _toDateString(itemDate, t) {
|
||||||
const date = new Date(itemDate);
|
|
||||||
const dateString = date.toDateString();
|
|
||||||
const m = getLocalizedDateFormatter(itemDate);
|
const m = getLocalizedDateFormatter(itemDate);
|
||||||
const yesterday = new Date();
|
const date = new Date(itemDate);
|
||||||
|
const dateInMs = date.getTime();
|
||||||
|
const now = new Date();
|
||||||
|
const todayInMs = (new Date()).setHours(0, 0, 0, 0);
|
||||||
|
const yesterdayInMs = todayInMs - 86400000; // 1 day = 86400000ms
|
||||||
|
|
||||||
yesterday.setDate(yesterday.getDate() - 1);
|
if (dateInMs >= todayInMs) {
|
||||||
const yesterdayString = yesterday.toDateString();
|
|
||||||
const today = new Date();
|
|
||||||
const todayString = today.toDateString();
|
|
||||||
const currentYear = today.getFullYear();
|
|
||||||
const year = date.getFullYear();
|
|
||||||
|
|
||||||
if (dateString === todayString) {
|
|
||||||
// The date is today, we use fromNow format.
|
|
||||||
return m.fromNow();
|
return m.fromNow();
|
||||||
} else if (dateString === yesterdayString) {
|
} else if (dateInMs >= yesterdayInMs) {
|
||||||
return t('dateUtils.yesterday');
|
return t('dateUtils.yesterday');
|
||||||
} else if (year !== currentYear) {
|
} else if (date.getFullYear() !== now.getFullYear()) {
|
||||||
// we only want to include the year in the date if its not the current
|
// We only want to include the year in the date if its not the current
|
||||||
// year
|
// year.
|
||||||
return m.format('ddd, MMMM DD h:mm A, gggg');
|
return m.format('ddd, MMMM DD h:mm A, gggg');
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { NavigateSectionList } from '../base/react/index';
|
import { NavigateSectionList } from '../base/react';
|
||||||
|
|
||||||
import { toDisplayableItem } from './functions.all';
|
import { toDisplayableItem } from './functions.any';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms the history list to a displayable list
|
* Transforms the history list to a displayable list
|
||||||
|
@ -60,3 +60,12 @@ export function toDisplayableList(recentList, t, defaultServerURL) {
|
||||||
return displayableList;
|
return displayableList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns <tt>true</tt> if recent list is enabled and <tt>false</tt> otherwise.
|
||||||
|
*
|
||||||
|
* @returns {boolean} <tt>true</tt> if recent list is enabled and <tt>false</tt>
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
export function isRecentListEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import { NavigateSectionList } from '../base/react/index';
|
/* global interfaceConfig */
|
||||||
|
|
||||||
|
import { NavigateSectionList } from '../base/react';
|
||||||
|
|
||||||
|
import { toDisplayableItem } from './functions.any';
|
||||||
|
|
||||||
import { toDisplayableItem } from './functions.all';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms the history list to a displayable list
|
* Transforms the history list to a displayable list
|
||||||
|
@ -14,10 +17,11 @@ import { toDisplayableItem } from './functions.all';
|
||||||
*/
|
*/
|
||||||
export function toDisplayableList(recentList, t, defaultServerURL) {
|
export function toDisplayableList(recentList, t, defaultServerURL) {
|
||||||
const { createSection } = NavigateSectionList;
|
const { createSection } = NavigateSectionList;
|
||||||
const section = createSection(t('recentList.joinPastMeeting'), 'all');
|
const section
|
||||||
|
= createSection(t('recentList.joinPastMeeting'), 'joinPastMeeting');
|
||||||
|
|
||||||
// we only want the last three conferences we were in for web
|
// We only want the last three conferences we were in for web.
|
||||||
for (const item of recentList.slice(1).slice(-3)) {
|
for (const item of recentList.slice(-3)) {
|
||||||
const displayableItem = toDisplayableItem(item, defaultServerURL, t);
|
const displayableItem = toDisplayableItem(item, defaultServerURL, t);
|
||||||
|
|
||||||
section.data.push(displayableItem);
|
section.data.push(displayableItem);
|
||||||
|
@ -32,3 +36,12 @@ export function toDisplayableList(recentList, t, defaultServerURL) {
|
||||||
return displayableList;
|
return displayableList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns <tt>true</tt> if recent list is enabled and <tt>false</tt> otherwise.
|
||||||
|
*
|
||||||
|
* @returns {boolean} <tt>true</tt> if recent list is enabled and <tt>false</tt>
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
export function isRecentListEnabled() {
|
||||||
|
return interfaceConfig.RECENT_LIST_ENABLED;
|
||||||
|
}
|
||||||
|
|
|
@ -1,19 +1,18 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import { APP_WILL_MOUNT } from '../base/app';
|
import { APP_WILL_MOUNT } from '../base/app';
|
||||||
import { CONFERENCE_WILL_LEAVE, SET_ROOM } from '../base/conference';
|
import {
|
||||||
import { JITSI_CONFERENCE_URL_KEY } from '../base/conference/constants';
|
CONFERENCE_WILL_LEAVE,
|
||||||
|
SET_ROOM,
|
||||||
|
JITSI_CONFERENCE_URL_KEY
|
||||||
|
} from '../base/conference';
|
||||||
import { addKnownDomains } from '../base/known-domains';
|
import { addKnownDomains } from '../base/known-domains';
|
||||||
import { MiddlewareRegistry } from '../base/redux';
|
import { MiddlewareRegistry } from '../base/redux';
|
||||||
import { parseURIString } from '../base/util';
|
import { parseURIString } from '../base/util';
|
||||||
import { RECENT_LIST_ENABLED } from './featureFlag';
|
|
||||||
|
|
||||||
import { _storeCurrentConference, _updateConferenceDuration } from './actions';
|
import { _storeCurrentConference, _updateConferenceDuration } from './actions';
|
||||||
|
import { isRecentListEnabled } from './functions';
|
||||||
|
|
||||||
/**
|
|
||||||
* used in order to get the device because there is a different way to get the
|
|
||||||
* location URL on web and on native
|
|
||||||
*/
|
|
||||||
declare var APP: Object;
|
declare var APP: Object;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,7 +23,7 @@ declare var APP: Object;
|
||||||
* @returns {Function}
|
* @returns {Function}
|
||||||
*/
|
*/
|
||||||
MiddlewareRegistry.register(store => next => action => {
|
MiddlewareRegistry.register(store => next => action => {
|
||||||
if (RECENT_LIST_ENABLED) {
|
if (isRecentListEnabled()) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case APP_WILL_MOUNT:
|
case APP_WILL_MOUNT:
|
||||||
return _appWillMount(store, next, action);
|
return _appWillMount(store, next, action);
|
||||||
|
@ -89,7 +88,8 @@ function _appWillMount({ dispatch, getState }, next, action) {
|
||||||
function _conferenceWillLeave({ dispatch, getState }, next, action) {
|
function _conferenceWillLeave({ dispatch, getState }, next, action) {
|
||||||
let locationURL;
|
let locationURL;
|
||||||
|
|
||||||
/** FIXME
|
/**
|
||||||
|
* FIXME:
|
||||||
* It is better to use action.conference[JITSI_CONFERENCE_URL_KEY]
|
* It is better to use action.conference[JITSI_CONFERENCE_URL_KEY]
|
||||||
* in order to make sure we get the url the conference is leaving
|
* in order to make sure we get the url the conference is leaving
|
||||||
* from (i.e. the room we are leaving from) because if the order of events
|
* from (i.e. the room we are leaving from) because if the order of events
|
||||||
|
|
|
@ -8,7 +8,7 @@ import {
|
||||||
_STORE_CURRENT_CONFERENCE,
|
_STORE_CURRENT_CONFERENCE,
|
||||||
_UPDATE_CONFERENCE_DURATION
|
_UPDATE_CONFERENCE_DURATION
|
||||||
} from './actionTypes';
|
} from './actionTypes';
|
||||||
import { RECENT_LIST_ENABLED } from './featureFlag';
|
import { isRecentListEnabled } from './functions';
|
||||||
|
|
||||||
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ PersistenceRegistry.register(STORE_NAME);
|
||||||
ReducerRegistry.register(
|
ReducerRegistry.register(
|
||||||
STORE_NAME,
|
STORE_NAME,
|
||||||
(state = _getLegacyRecentRoomList(), action) => {
|
(state = _getLegacyRecentRoomList(), action) => {
|
||||||
if (RECENT_LIST_ENABLED) {
|
if (isRecentListEnabled()) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case APP_WILL_MOUNT:
|
case APP_WILL_MOUNT:
|
||||||
return _appWillMount(state);
|
return _appWillMount(state);
|
||||||
|
@ -62,9 +62,9 @@ ReducerRegistry.register(
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -100,7 +100,7 @@ class WelcomePage extends AbstractWelcomePage {
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
const { t } = this.props;
|
const { t } = this.props;
|
||||||
const { APP_NAME, RECENT_LIST_ENABLED } = interfaceConfig;
|
const { APP_NAME } = interfaceConfig;
|
||||||
const showAdditionalContent = this._shouldShowAdditionalContent();
|
const showAdditionalContent = this._shouldShowAdditionalContent();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -147,7 +147,7 @@ class WelcomePage extends AbstractWelcomePage {
|
||||||
{ t('welcomepage.go') }
|
{ t('welcomepage.go') }
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
{ RECENT_LIST_ENABLED ? <RecentList /> : null }
|
<RecentList />
|
||||||
</div>
|
</div>
|
||||||
{ showAdditionalContent
|
{ showAdditionalContent
|
||||||
? <div
|
? <div
|
||||||
|
|
Loading…
Reference in New Issue