Integrate Mobile landing in the Redux app
This commit is contained in:
parent
23ef0c8d9d
commit
8248b14555
|
@ -21,3 +21,14 @@ export const APP_WILL_MOUNT = Symbol('APP_WILL_MOUNT');
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
export const APP_WILL_UNMOUNT = Symbol('APP_WILL_UNMOUNT');
|
export const APP_WILL_UNMOUNT = Symbol('APP_WILL_UNMOUNT');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of this action sets the platform of user agent
|
||||||
|
* in order to decide to show the landing or not.
|
||||||
|
*
|
||||||
|
* {
|
||||||
|
* type: APP_SET_PLATFORM,
|
||||||
|
* platform: String
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
export const APP_SET_PLATFORM = Symbol('APP_SET_PLATFORM');
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
import { setRoom } from '../base/conference';
|
import { setRoom } from '../base/conference';
|
||||||
import { getDomain, setDomain } from '../base/connection';
|
import { getDomain, setDomain } from '../base/connection';
|
||||||
import { loadConfig, setConfig } from '../base/lib-jitsi-meet';
|
import { loadConfig, setConfig } from '../base/lib-jitsi-meet';
|
||||||
|
import {
|
||||||
|
detectAndroid,
|
||||||
|
detectIOS
|
||||||
|
} from '../base/util';
|
||||||
|
|
||||||
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from './actionTypes';
|
import {
|
||||||
|
APP_WILL_MOUNT,
|
||||||
|
APP_WILL_UNMOUNT,
|
||||||
|
APP_SET_PLATFORM
|
||||||
|
} from './actionTypes';
|
||||||
import {
|
import {
|
||||||
_getRoomAndDomainFromUrlString,
|
_getRoomAndDomainFromUrlString,
|
||||||
_getRouteToRender,
|
_getRouteToRender,
|
||||||
|
@ -31,7 +39,8 @@ export function appInit() {
|
||||||
*/
|
*/
|
||||||
export function appNavigate(urlOrRoom) {
|
export function appNavigate(urlOrRoom) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
const oldDomain = getDomain(getState());
|
const state = getState();
|
||||||
|
const oldDomain = getDomain(state);
|
||||||
|
|
||||||
const { domain, room } = _getRoomAndDomainFromUrlString(urlOrRoom);
|
const { domain, room } = _getRoomAndDomainFromUrlString(urlOrRoom);
|
||||||
|
|
||||||
|
@ -40,7 +49,9 @@ export function appNavigate(urlOrRoom) {
|
||||||
// current conference and start a new one with the new room name or
|
// current conference and start a new one with the new room name or
|
||||||
// domain.
|
// domain.
|
||||||
|
|
||||||
if (typeof domain === 'undefined' || oldDomain === domain) {
|
if (room === 'mobile-app') {
|
||||||
|
return;
|
||||||
|
} else if (typeof domain === 'undefined' || oldDomain === domain) {
|
||||||
// If both domain and room vars became undefined, that means we're
|
// If both domain and room vars became undefined, that means we're
|
||||||
// actually dealing with just room name and not with URL.
|
// actually dealing with just room name and not with URL.
|
||||||
dispatch(
|
dispatch(
|
||||||
|
@ -87,7 +98,6 @@ export function appNavigate(urlOrRoom) {
|
||||||
// start to not make app re-render conference page for two times.
|
// start to not make app re-render conference page for two times.
|
||||||
dispatch(setRoom(room));
|
dispatch(setRoom(room));
|
||||||
dispatch(setConfig(config));
|
dispatch(setConfig(config));
|
||||||
_navigate(getState());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -108,6 +118,37 @@ export function appWillMount(app) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detects the platform of user agent and
|
||||||
|
* signals that platform detected.
|
||||||
|
*
|
||||||
|
* @returns {Function}
|
||||||
|
*/
|
||||||
|
export function detectPlatform() {
|
||||||
|
return dispatch => {
|
||||||
|
if (detectAndroid()) {
|
||||||
|
dispatch(_setPlatform('android'));
|
||||||
|
} else if (detectIOS()) {
|
||||||
|
dispatch(_setPlatform('ios'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signals that user agent platform is mobile and it has
|
||||||
|
* been already detected.
|
||||||
|
*
|
||||||
|
* @param {string} platform - Mobile user agent platform.
|
||||||
|
* @returns {{type, platform: string}}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
export function _setPlatform(platform) {
|
||||||
|
return {
|
||||||
|
type: APP_SET_PLATFORM,
|
||||||
|
platform
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signals that a specific App will unmount (in the terms of React).
|
* Signals that a specific App will unmount (in the terms of React).
|
||||||
*
|
*
|
||||||
|
@ -152,9 +193,13 @@ function _setRoomAndNavigate(newRoom) {
|
||||||
dispatch(setRoom(newRoom));
|
dispatch(setRoom(newRoom));
|
||||||
|
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const room = state['features/base/conference'].room;
|
const { platform } = state['features/app'];
|
||||||
|
const { room } = state['features/base/conference'];
|
||||||
|
const { landingIsShown } = state['features/landing'];
|
||||||
|
|
||||||
if (room !== oldRoom) {
|
// If user agent is mobile browser and landing wasn't shown we
|
||||||
|
// should recheck which component to render.
|
||||||
|
if ((platform && !landingIsShown) || room !== oldRoom) {
|
||||||
_navigate(state);
|
_navigate(state);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { appInit } from '../actions';
|
import { appInit, detectPlatform } from '../actions';
|
||||||
import { AbstractApp } from './AbstractApp';
|
import { AbstractApp } from './AbstractApp';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -22,6 +22,7 @@ export class App extends AbstractApp {
|
||||||
componentWillMount(...args) {
|
componentWillMount(...args) {
|
||||||
super.componentWillMount(...args);
|
super.componentWillMount(...args);
|
||||||
|
|
||||||
|
this.props.store.dispatch(detectPlatform());
|
||||||
this.props.store.dispatch(appInit());
|
this.props.store.dispatch(appInit());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,10 +7,45 @@ import settings from '../../../modules/settings/Settings';
|
||||||
import getTokenData from '../../../modules/tokendata/TokenData';
|
import getTokenData from '../../../modules/tokendata/TokenData';
|
||||||
import JitsiMeetLogStorage from '../../../modules/util/JitsiMeetLogStorage';
|
import JitsiMeetLogStorage from '../../../modules/util/JitsiMeetLogStorage';
|
||||||
|
|
||||||
|
import { detectIOS, detectAndroid } from '../base/util';
|
||||||
|
|
||||||
|
// XXX We should import landing feature here in order to update router registry.
|
||||||
|
import { Landing } from '../landing';
|
||||||
|
import { Conference } from '../conference';
|
||||||
|
import { WelcomePage } from '../welcome';
|
||||||
|
|
||||||
const Logger = require('jitsi-meet-logger');
|
const Logger = require('jitsi-meet-logger');
|
||||||
|
|
||||||
export * from './functions.native';
|
export * from './functions.native';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines which route is to be rendered in order to depict a specific Redux
|
||||||
|
* store.
|
||||||
|
*
|
||||||
|
* @param {(Object|Function)} stateOrGetState - Redux state or Regux getState()
|
||||||
|
* method.
|
||||||
|
* @returns {Route}
|
||||||
|
*/
|
||||||
|
export function _getRouteToRender(stateOrGetState) {
|
||||||
|
const state
|
||||||
|
= typeof stateOrGetState === 'function'
|
||||||
|
? stateOrGetState()
|
||||||
|
: stateOrGetState;
|
||||||
|
|
||||||
|
const { platform } = state['features/app'];
|
||||||
|
const { room } = state['features/base/conference'];
|
||||||
|
const { landingIsShown } = state['features/landing'];
|
||||||
|
|
||||||
|
let component = isRoomValid(room) ? Conference : WelcomePage;
|
||||||
|
|
||||||
|
// If landing was shown there is no need to show it again.
|
||||||
|
if (platform && !landingIsShown) {
|
||||||
|
component = detectAndroid() || detectIOS() ? Landing : component;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RouteRegistry.getRouteByComponent(component);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Temporary solution. Later we'll get rid of global APP and set its properties
|
* Temporary solution. Later we'll get rid of global APP and set its properties
|
||||||
* in redux store.
|
* in redux store.
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
import { ReducerRegistry } from '../base/redux';
|
import { ReducerRegistry } from '../base/redux';
|
||||||
|
|
||||||
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from './actionTypes';
|
import {
|
||||||
|
APP_WILL_MOUNT,
|
||||||
|
APP_WILL_UNMOUNT,
|
||||||
|
APP_SET_PLATFORM
|
||||||
|
} from './actionTypes';
|
||||||
|
|
||||||
ReducerRegistry.register('features/app', (state = {}, action) => {
|
ReducerRegistry.register('features/app', (state = {}, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
@ -28,6 +32,13 @@ ReducerRegistry.register('features/app', (state = {}, action) => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case APP_SET_PLATFORM:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
platform: action.platform
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
|
|
|
@ -21,23 +21,3 @@ export function detectIOS() {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Transforms hash map with parameters to query string.
|
|
||||||
*
|
|
||||||
* @param {Object} params - Hash map to be processed into query string.
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
export function serializeQuery(params) {
|
|
||||||
return Object.keys(params).reduce((str, key, index) => {
|
|
||||||
const encodedKey = encodeURIComponent(key);
|
|
||||||
const encodedValue = encodeURIComponent(params[key]);
|
|
||||||
let separator = '&';
|
|
||||||
|
|
||||||
if (index === 0) {
|
|
||||||
separator = '?';
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${str}${separator}${encodedKey}=${encodedValue}`;
|
|
||||||
}, '');
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ import HttpConfigFetch from '../../../modules/config/HttpConfigFetch';
|
||||||
import ConferenceUrl from '../../../modules/URL/ConferenceUrl';
|
import ConferenceUrl from '../../../modules/URL/ConferenceUrl';
|
||||||
|
|
||||||
import { RouteRegistry } from '../base/navigator';
|
import { RouteRegistry } from '../base/navigator';
|
||||||
import { detectIOS, detectAndroid, serializeQuery } from '../base/util';
|
|
||||||
import { Conference } from './components';
|
import { Conference } from './components';
|
||||||
|
|
||||||
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { Link } from 'react-router';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import { Link } from 'react-router';
|
||||||
import { landingIsShown } from '../actions';
|
import { landingIsShown } from '../actions';
|
||||||
|
|
||||||
const links = {
|
const links = {
|
||||||
|
@ -14,6 +14,7 @@ const links = {
|
||||||
* @class Landing
|
* @class Landing
|
||||||
*/
|
*/
|
||||||
class Landing extends Component {
|
class Landing extends Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* React lifecycle method triggered after
|
* React lifecycle method triggered after
|
||||||
* component is mount.
|
* component is mount.
|
||||||
|
@ -26,7 +27,8 @@ class Landing extends Component {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
dispatch: React.PropTypes.func,
|
dispatch: React.PropTypes.func,
|
||||||
location: React.PropTypes.object
|
platform: React.PropTypes.string,
|
||||||
|
room: React.PropTypes.string
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,22 +38,20 @@ class Landing extends Component {
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
const { query } = this.props.location;
|
const { room } = this.props;
|
||||||
const { conferenceName, platform } = query;
|
|
||||||
let btnText;
|
let btnText;
|
||||||
let link = '/';
|
let link = '/';
|
||||||
|
|
||||||
if (conferenceName) {
|
if (room) {
|
||||||
btnText = 'Join the conversation';
|
btnText = 'Join the conversation';
|
||||||
link += conferenceName;
|
link += room;
|
||||||
} else {
|
} else {
|
||||||
btnText = 'Start a conference';
|
btnText = 'Start a conference';
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
btnText,
|
btnText,
|
||||||
link,
|
link
|
||||||
platform
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,8 @@ class Landing extends Component {
|
||||||
* @returns {ReactElement}
|
* @returns {ReactElement}
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
const { btnText, link, platform } = this.state;
|
const { platform } = this.props;
|
||||||
|
const { btnText, link } = this.state;
|
||||||
const primaryButtonClasses = 'landing__button landing__button_primary';
|
const primaryButtonClasses = 'landing__button landing__button_primary';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -94,4 +95,11 @@ class Landing extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect()(Landing);
|
const mapStateToProps = state => {
|
||||||
|
return {
|
||||||
|
platform: state['features/app'].platform,
|
||||||
|
room: state['features/base/conference'].room
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(mapStateToProps)(Landing);
|
||||||
|
|
|
@ -3,13 +3,5 @@ import { Landing } from './components';
|
||||||
|
|
||||||
RouteRegistry.register({
|
RouteRegistry.register({
|
||||||
component: Landing,
|
component: Landing,
|
||||||
path: '/mobile-app',
|
path: '/mobile-app'
|
||||||
onEnter: store => () => {
|
|
||||||
const state = store.getState();
|
|
||||||
const { landingIsShown } = state;
|
|
||||||
|
|
||||||
if (landingIsShown) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue