Compare commits

..

8 Commits
2012 ... 2016

Author SHA1 Message Date
Lyubo Marinov
5f64ccb97d [RN] Naming 2017-06-09 14:51:31 -05:00
Saúl Ibarra Corretgé
4687c1f465 [RN] Add ability to skip the welcome page
Also expose this in the native SDKs.
2017-06-09 14:10:10 -05:00
Saúl Ibarra Corretgé
79d51bc379 feat(App): remove obsolete config prop
It's obsolete now, since config is handled in Redux. Also add a "defaultUrl"
prop so emdedding applications can select what the default base URL is.
2017-06-09 14:10:10 -05:00
hristoterezov
893d08d614 fix(device_selection_popup): URL 2017-06-09 13:23:32 -05:00
Lyubo Marinov
a5cd118550 [Android] Naming 2017-06-09 10:55:14 -05:00
Saúl Ibarra Corretgé
a266a71999 [RN] Add JitsiMeetViewAbstractListener to Android SDK 2017-06-09 09:57:06 -05:00
Saúl Ibarra Corretgé
be8694f93e [RN] Remove duplicated font on Android
Copy it from the main fonts directory instead.
2017-06-09 16:05:27 +02:00
Saúl Ibarra Corretgé
a1a394ad0b doc: update mobile building instructions for iOS 2017-06-09 09:55:40 +02:00
25 changed files with 425 additions and 159 deletions

View File

@@ -85,10 +85,17 @@ public class MainActivity extends AppCompatActivity {
This class encapsulates a high level API in the form of an Android `Activity`
which displays a single `JitsiMeetView`.
#### loadURL(url)
#### getWelcomePageEnabled()
See JitsiMeetView.getWelcomePageEnabled.
#### loadURL(URL)
See JitsiMeetView.loadURL.
#### setWelcomePageEnabled(boolean)
See JitsiMeetView.setWelcomePageEnabled.
### JitsiMeetView
@@ -97,18 +104,30 @@ display a Jitsi Meet conference (or a welcome page).
#### getListener()
Returns the `JitsiMeetView.Listener` instance attached to the view.
Returns the `JitsiMeetViewListener` instance attached to the view.
#### loadURL(url)
#### getWelcomePageEnabled()
Returns true if the Welcome page is enabled; otherwise, false. If false, a black
empty view will be rendered when not in a conference. Defaults to false.
#### loadURL(URL)
Loads the given URL and joins the room. If `null` is specified, the welcome page
is displayed instead.
#### setListener(listener)
Sets the given listener (class implementing the `JitsiMeetView.Listener`
Sets the given listener (class implementing the `JitsiMeetViewListener`
interface) on the view.
#### setWelcomePageEnabled(boolean)
Sets whether the Welcome page is enabled. See `getWelcomePageEnabled` for more
information.
NOTE: Must be called before `loadURL` for it to take effect.
#### onBackPressed()
Helper method which should be called from the activity's `onBackPressed` method.
@@ -144,10 +163,16 @@ activity's `onNewIntent` method.
This is a static method.
#### Listener
#### JitsiMeetViewListener
JitsiMeetView.Listener provides an interface apps can implement in order to get
notified about the state of the Jitsi Meet conference.
`JitsiMeetViewListener` provides an interface apps can implement to listen to
the state of the Jitsi Meet conference displayed in a `JitsiMeetView`.
### JitsiMeetViewAdapter
A default implementation of the `JitsiMeetViewListener` interface. Apps may
extend the class instead of implementing the interface in order to minimize
boilerplate.
##### onConferenceFailed

View File

@@ -16,6 +16,8 @@
package org.jitsi.meet;
import android.os.Bundle;
import org.jitsi.meet.sdk.JitsiMeetActivity;
/**
@@ -25,10 +27,23 @@ import org.jitsi.meet.sdk.JitsiMeetActivity;
* of it. Further attempts at launching the application once it was already
* launched will result in {@link Activity#onNewIntent(Intent)} being called.
*
* This {@code Activity} extends {@link JitsiMeetActivity} without adding
* anything to it. It exists to merely keep the React Native CLI working, since
* the latter always tries to launch an {@code Activity} named
* {@code MainActivity} when doing {@code react-native run-android}.
* This {@code Activity} extends {@link JitsiMeetActivity} to keep the React
* Native CLI working, since the latter always tries to launch an
* {@code Activity} named {@code MainActivity} when doing
* {@code react-native run-android}.
*/
public class MainActivity extends JitsiMeetActivity {
/**
* {@inheritDoc}
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
// As this is the Jitsi Meet app (i.e. not the Jitsi Meet SDK), we do
// want the Welcome page to be enabled. It defaults to disabled in the
// SDK at the time of this writing but it is clearer to be explicit
// about what we want anyway.
setWelcomePageEnabled(true);
super.onCreate(savedInstanceState);
}
}

View File

@@ -1 +0,0 @@
/build

View File

@@ -51,6 +51,7 @@ gradle.projectsEvaluated {
//
def currentFontTask = tasks.create(name: "${buildType.name}CopyFonts", type: Copy) {
from("${projectDir}/../../fonts/jitsi.ttf")
from("${projectDir}/../../node_modules/react-native-vector-icons/Fonts/")
into("${bundlePath}/assets/fonts")
}

View File

@@ -46,10 +46,24 @@ public class JitsiMeetActivity extends AppCompatActivity {
public static final int OVERLAY_PERMISSION_REQ_CODE = 4242;
/**
* Instance of the {@JitsiMeetView} which this activity will display.
* Instance of the {@link JitsiMeetView} which this activity will display.
*/
private JitsiMeetView view;
/**
* Whether the Welcome page is enabled. The value is used only while
* {@link #view} equals {@code null}.
*/
private boolean welcomePageEnabled;
/**
*
* @see JitsiMeetView#getWelcomePageEnabled
*/
public boolean getWelcomePageEnabled() {
return view == null ? welcomePageEnabled : view.getWelcomePageEnabled();
}
/**
* Loads the given URL and displays the conference. If the specified URL is
* null, the welcome page is displayed instead.
@@ -99,6 +113,11 @@ public class JitsiMeetActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
view = new JitsiMeetView(this);
// In order to have the desired effect
// JitsiMeetView#setWelcomePageEnabled(boolean) must be invoked before
// JitsiMeetView#loadURL(URL).
view.setWelcomePageEnabled(welcomePageEnabled);
view.loadURL(null);
// In debug mode React needs permission to write over other apps in
@@ -155,4 +174,16 @@ public class JitsiMeetActivity extends AppCompatActivity {
JitsiMeetView.onHostResume(this);
}
/**
*
* @see JitsiMeetView#setWelcomePageEnabled
*/
public void setWelcomePageEnabled(boolean welcomePageEnabled) {
if (view == null) {
this.welcomePageEnabled = welcomePageEnabled;
} else {
view.setWelcomePageEnabled(welcomePageEnabled);
}
}
}

View File

@@ -30,7 +30,6 @@ import com.facebook.react.ReactRootView;
import com.facebook.react.common.LifecycleState;
import java.net.URL;
import java.util.HashMap;
public class JitsiMeetView extends FrameLayout {
/**
@@ -43,7 +42,7 @@ public class JitsiMeetView extends FrameLayout {
* Reference to the single instance of this class we currently allow. It's
* currently used for fetching the instance from the listener's callbacks.
*
* TODO: lift this limitation.
* TODO: Lift this limitation.
*/
private static JitsiMeetView instance;
@@ -54,16 +53,21 @@ public class JitsiMeetView extends FrameLayout {
private static ReactInstanceManager reactInstanceManager;
/**
* {@JitsiMeetView.Listener} instance for reporting events occurring in
* {@link JitsiMeetViewListener} instance for reporting events occurring in
* Jitsi Meet.
*/
private JitsiMeetView.Listener listener;
private JitsiMeetViewListener listener;
/**
* React Native root view.
*/
private ReactRootView reactRootView;
/**
* Whether the Welcome page is enabled.
*/
private boolean welcomePageEnabled;
public JitsiMeetView(@NonNull Context context) {
super(context);
@@ -90,21 +94,33 @@ public class JitsiMeetView extends FrameLayout {
/**
* Returns the only instance of this class we currently allow creating.
*
* @returns The {@JitsiMeetView} instance.
* @return The {@code JitsiMeetView} instance.
*/
public static JitsiMeetView getInstance() {
return instance;
}
/**
* Getter for the {@JitsiMeetView.Listener} set on this view.
* Gets the {@link JitsiMeetViewListener} set on this {@code JitsiMeetView}.
*
* @returns The {@JitsiMeetView.Listener} instance.
* @return The {@code JitsiMeetViewListener} set on this
* {@code JitsiMeetView}.
*/
public Listener getListener() {
public JitsiMeetViewListener getListener() {
return listener;
}
/**
* Gets whether the Welcome page is enabled. If {@code true}, the Welcome
* page is rendered when this {@code JitsiMeetView} is not at a URL
* identifying a Jitsi Meet conference/room.
*
* @return {@true} if the Welcome page is enabled; otherwise, {@code false}.
*/
public boolean getWelcomePageEnabled() {
return welcomePageEnabled;
}
/**
* Internal method to initialize the React Native instance manager. We
* create a single instance in order to load the JavaScript bundle a single
@@ -141,9 +157,12 @@ public class JitsiMeetView extends FrameLayout {
public void loadURL(@Nullable URL url) {
Bundle props = new Bundle();
// url
if (url != null) {
props.putString("url", url.toString());
}
// welcomePageEnabled
props.putBoolean("welcomePageEnabled", welcomePageEnabled);
// TODO: ReactRootView#setAppProperties is only available on React
// Native 0.45, so destroy the current root view and create a new one.
@@ -160,14 +179,27 @@ public class JitsiMeetView extends FrameLayout {
}
/**
* Setter for the {@JitsiMeetView.Listener} set on this view.
* Sets a specific {@link JitsiMeetViewListener} on this
* {@code JitsiMeetView}.
*
* @param listener - Listener for this view.
* @param listener - The {@code JitsiMeetViewListener} to set on this
* {@code JitsiMeetView}.
*/
public void setListener(Listener listener) {
public void setListener(JitsiMeetViewListener listener) {
this.listener = listener;
}
/**
* Sets whether the Welcome page is enabled. Must be called before
* {@link #loadURL(URL)} for it to take effect.
*
* @param welcomePageEnabled {@code true} to enable the Welcome page;
* otherwise, {@code false}.
*/
public void setWelcomePageEnabled(boolean welcomePageEnabled) {
this.welcomePageEnabled = welcomePageEnabled;
}
/**
* Activity lifecycle method which should be called from
* <tt>Activity.onBackPressed</tt> so we can do the required internal
@@ -237,46 +269,4 @@ public class JitsiMeetView extends FrameLayout {
reactInstanceManager.onNewIntent(intent);
}
}
/**
* Interface for listening to events coming from Jitsi Meet.
*/
public interface Listener {
/**
* Called when joining a conference fails or an ongoing conference is
* interrupted due to a failure.
*
* @param data - HashMap with an "error" key describing the problem, and
* a "url" key with the conference URL.
*/
void onConferenceFailed(HashMap<String, Object> data);
/**
* Called when a conference was joined.
*
* @param data - HashMap with a "url" key with the conference URL.
*/
void onConferenceJoined(HashMap<String, Object> data);
/**
* Called when the conference was left, typically after hanging up.
*
* @param data - HashMap with a "url" key with the conference URL.
*/
void onConferenceLeft(HashMap<String, Object> data);
/**
* Called before the conference is joined.
*
* @param data - HashMap with a "url" key with the conference URL.
*/
void onConferenceWillJoin(HashMap<String, Object> data);
/**
* Called before the conference is left.
*
* @param data - HashMap with a "url" key with the conference URL.
*/
void onConferenceWillLeave(HashMap<String, Object> data);
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright @ 2017-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jitsi.meet.sdk;
import java.util.Map;
/**
* Implements {@link JitsiMeetViewListener} so apps don't have to add stubs for
* all methods in the interface if they are only interested in some.
*/
public abstract class JitsiMeetViewAdapter implements JitsiMeetViewListener {
/**
* {@inheritDoc}
*/
@Override
public void onConferenceFailed(Map<String, Object> data) {
}
/**
* {@inheritDoc}
*/
@Override
public void onConferenceJoined(Map<String, Object> data) {
}
/**
* {@inheritDoc}
*/
@Override
public void onConferenceLeft(Map<String, Object> data) {
}
/**
* {@inheritDoc}
*/
@Override
public void onConferenceWillJoin(Map<String, Object> data) {
}
/**
* {@inheritDoc}
*/
@Override
public void onConferenceWillLeave(Map<String, Object> data) {
}
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright @ 2017-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jitsi.meet.sdk;
import java.util.Map;
/**
* Interface for listening to events coming from Jitsi Meet.
*/
public interface JitsiMeetViewListener {
/**
* Called when joining a conference fails or an ongoing conference is
* interrupted due to a failure.
*
* @param data - Map with an "error" key describing the problem, and
* a "url" key with the conference URL.
*/
void onConferenceFailed(Map<String, Object> data);
/**
* Called when a conference was joined.
*
* @param data - Map with a "url" key with the conference URL.
*/
void onConferenceJoined(Map<String, Object> data);
/**
* Called when the conference was left, typically after hanging up.
*
* @param data - Map with a "url" key with the conference URL.
*/
void onConferenceLeft(Map<String, Object> data);
/**
* Called before the conference is joined.
*
* @param data - Map with a "url" key with the conference URL.
*/
void onConferenceWillJoin(Map<String, Object> data);
/**
* Called before the conference is left.
*
* @param data - Map with a "url" key with the conference URL.
*/
void onConferenceWillLeave(Map<String, Object> data);
}

View File

@@ -22,6 +22,7 @@ import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import org.jitsi.meet.sdk.JitsiMeetView;
import org.jitsi.meet.sdk.JitsiMeetViewListener;
import java.util.HashMap;
@@ -67,7 +68,7 @@ public class ExternalAPIModule extends ReactContextBaseJavaModule {
@ReactMethod
public void sendEvent(final String name, ReadableMap data) {
JitsiMeetView view = JitsiMeetView.getInstance();
JitsiMeetView.Listener listener
JitsiMeetViewListener listener
= view != null ? view.getListener() : null;
if (listener == null) {
@@ -78,32 +79,32 @@ public class ExternalAPIModule extends ReactContextBaseJavaModule {
// until React Native 0.46.
final HashMap<String, Object> dataMap = new HashMap<>();
try {
switch (name) {
case "CONFERENCE_FAILED":
dataMap.put("error", data.getString("error"));
dataMap.put("url", data.getString("url"));
listener.onConferenceFailed(dataMap);
break;
case "CONFERENCE_JOINED":
dataMap.put("url", data.getString("url"));
listener.onConferenceJoined(dataMap);
break;
case "CONFERENCE_LEFT":
dataMap.put("url", data.getString("url"));
listener.onConferenceLeft(dataMap);
break;
case "CONFERENCE_WILL_JOIN":
dataMap.put("url", data.getString("url"));
listener.onConferenceWillJoin(dataMap);
break;
case "CONFERENCE_WILL_LEAVE":
dataMap.put("url", data.getString("url"));
listener.onConferenceWillLeave(dataMap);
break;
}
} catch (UnsupportedOperationException e) {
// Allow partial interface implementations.
switch (name) {
case "CONFERENCE_FAILED":
dataMap.put("error", data.getString("error"));
dataMap.put("url", data.getString("url"));
listener.onConferenceFailed(dataMap);
break;
case "CONFERENCE_JOINED":
dataMap.put("url", data.getString("url"));
listener.onConferenceJoined(dataMap);
break;
case "CONFERENCE_LEFT":
dataMap.put("url", data.getString("url"));
listener.onConferenceLeft(dataMap);
break;
case "CONFERENCE_WILL_JOIN":
dataMap.put("url", data.getString("url"));
listener.onConferenceWillJoin(dataMap);
break;
case "CONFERENCE_WILL_LEAVE":
dataMap.put("url", data.getString("url"));
listener.onConferenceWillLeave(dataMap);
break;
}
}
}

View File

@@ -24,6 +24,15 @@ work properly with the native plugins we require.
You may need to add ```--unsafe-perm=true``` if you are running on [Mac OS 10.11 or greater](https://github.com/phonegap/ios-deploy#os-x-1011-el-capitan-or-greater).
- Install the required pods (CocoaPods must be installled first, it can
be done with Homebrew: `brew install cocoapods`)
```bash
cd ios
pod install
cd ..
```
2. Build the app
There are 2 ways to build the app: using the CLI or using Xcode.

View File

@@ -32,6 +32,19 @@ To get started:
The `JitsiMeetView` class is the entry point to the SDK. It a subclass of
`UIView` which renders a full conference in the designated area.
#### delegate
Property for getting / setting the `JitsiMeetViewDelegate` on `JitsiMeetView`.
#### welcomePageEnabled
Property for getting / setting whether the Welcome page is enabled. If NO, a
black empty view will be rendered when not in a conference. Defaults to NO.
NOTE: Must be set before calling `loadURL` for it to take effect.
#### loadURL(URL)
```objc
[meetView loadURL:[NSURL URLWithString:@"https://meet.jit.si/test123"]];
```

View File

@@ -32,6 +32,11 @@
JitsiMeetView *view = (JitsiMeetView *) self.view;
view.delegate = self;
// As this is the Jitsi Meet app (i.e. not the Jitsi Meet SDK), we do
// want the Welcome page to be enabled. It defaults to disabled in the
// SDK at the time of this writing but it is clearer to be explicit
// about what we want anyway.
view.welcomePageEnabled = YES;
[view loadURL:nil];
}

View File

@@ -23,6 +23,8 @@
@property (nonatomic, weak, nullable) id<JitsiMeetViewDelegate> delegate;
@property (nonatomic) BOOL welcomePageEnabled;
+ (BOOL)application:(UIApplication *)application
continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void (^)(NSArray *))restorationHandler;

View File

@@ -106,7 +106,14 @@ static JitsiMeetView *instance;
* is null, the welcome page is shown.
*/
- (void)loadURL:(NSURL *)url {
NSDictionary *props = url ? @{ url : url.absoluteString } : nil;
NSMutableDictionary *props = [[NSMutableDictionary alloc] init];
// url
if (url) {
[props setObject:url.absoluteString forKey:@"url"];
}
// welcomePageEnabled
[props setObject:@(self.welcomePageEnabled) forKey:@"welcomePageEnabled"];
if (rootView == nil) {
rootView

View File

@@ -1,4 +0,0 @@
/* global config */
// For legacy reasons, use jitsi-meet's global variable config.
export default typeof config === 'object' ? config : undefined;

View File

@@ -1,6 +1,6 @@
/**
* The type of the actions which signals that a specific App will mount (in the
* terms of React).
* The type of (redux) action which signals that a specific App will mount (in
* React terms).
*
* {
* type: APP_WILL_MOUNT,
@@ -10,8 +10,8 @@
export const APP_WILL_MOUNT = Symbol('APP_WILL_MOUNT');
/**
* The type of the actions which signals that a specific App will unmount (in
* the terms of React).
* The type of (redux) action which signals that a specific App will unmount (in
* React terms).
*
* {
* type: APP_WILL_UNMOUNT,

View File

@@ -20,6 +20,12 @@ import {
declare var APP: Object;
/**
* The default URL to open if no other was specified to {@code AbstractApp}
* via props.
*/
const DEFAULT_URL = 'https://meet.jit.si';
/**
* Base (abstract) class for main App component.
*
@@ -32,7 +38,15 @@ export class AbstractApp extends Component {
* @static
*/
static propTypes = {
config: React.PropTypes.object,
/**
* The default URL {@code AbstractApp} is to open when not in any
* conference/room.
*/
defaultURL: React.PropTypes.string,
/**
* (Optional) Redux store for this app.
*/
store: React.PropTypes.object,
/**
@@ -191,28 +205,31 @@ export class AbstractApp extends Component {
* @protected
*/
_createElement(component, props) {
/* eslint-disable no-unused-vars, lines-around-comment */
/* eslint-disable no-unused-vars */
const {
// Don't propagate the config prop(erty) because the config is
// stored inside the Redux state and, thus, is visible to the
// children anyway.
config,
// Don't propagate the dispatch and store props because they usually
// come from react-redux and programmers don't really expect them to
// be inherited but rather explicitly connected.
dispatch, // eslint-disable-line react/prop-types
store,
// The url property was introduced to be consumed entirely by
// AbstractApp.
// The following props were introduced to be consumed entirely by
// AbstractApp:
defaultURL,
url,
// The remaining props, if any, are considered suitable for
// propagation to the children of this Component.
...thisProps
} = this.props;
/* eslint-enable no-unused-vars, lines-around-comment */
// eslint-disable-next-line object-property-newline
return React.createElement(component, { ...thisProps, ...props });
/* eslint-enable no-unused-vars */
return React.createElement(component, {
...thisProps,
...props
});
}
/**
@@ -265,24 +282,7 @@ export class AbstractApp extends Component {
}
}
// By default, open the domain configured in the configuration file
// which may be the domain at which the whole server infrastructure is
// deployed.
const { config } = this.props;
if (typeof config === 'object') {
const { hosts } = config;
if (typeof hosts === 'object') {
const { domain } = hosts;
if (domain) {
return `https://${domain}`;
}
}
}
return 'https://meet.jit.si';
return this.props.defaultURL || DEFAULT_URL;
}
/**
@@ -356,7 +356,7 @@ export class AbstractApp extends Component {
// role of Router is now this AbstractApp, provide its nextState.
// (2) A replace function would be provided to the Route in case it
// chose to redirect to another path.
this._onRouteEnter(route, nextState, pathname => {
route && this._onRouteEnter(route, nextState, pathname => {
this._openURL(pathname);
// Do not proceed with the route because it chose to redirect to
@@ -376,11 +376,9 @@ export class AbstractApp extends Component {
*/
_onRouteEnter(route, ...args) {
// Notify the route that it is about to be entered.
const onEnter = route.onEnter;
const { onEnter } = route;
if (typeof onEnter === 'function') {
onEnter(...args);
}
typeof onEnter === 'function' && onEnter(...args);
}
/**

View File

@@ -1,5 +1,6 @@
/* global __DEV__ */
import React from 'react';
import { Linking } from 'react-native';
import { Platform } from '../../base/react';
@@ -23,7 +24,16 @@ export class App extends AbstractApp {
*
* @static
*/
static propTypes = AbstractApp.propTypes;
static propTypes = {
...AbstractApp.propTypes,
/**
* Whether the Welcome page is enabled. If {@code true}, the Welcome
* page is rendered when the {@link App} is not at a location (URL)
* identifying a Jitsi Meet conference/room.
*/
welcomePageEnabled: React.PropTypes.bool
};
/**
* Initializes a new App instance.

View File

@@ -14,7 +14,7 @@ export class App extends AbstractApp {
*
* @static
*/
static propTypes = AbstractApp.propTypes
static propTypes = AbstractApp.propTypes;
/**
* Initializes a new App instance.

View File

@@ -143,7 +143,19 @@ export function _getRouteToRender(stateOrGetState) {
? stateOrGetState()
: stateOrGetState;
const { room } = state['features/base/conference'];
const component = isRoomValid(room) ? Conference : WelcomePage;
let component;
if (isRoomValid(room)) {
component = Conference;
} else {
// The value of the App prop welcomePageEnabled was stored in redux in
// saghul's PR. But I removed the redux state, action, action type, etc.
// because I didn't like the name. We are not using the prop is a
// React-ive way anyway so it's all the same difference.
const { app } = state['features/app'];
component = app && app.props.welcomePageEnabled ? WelcomePage : null;
}
return RouteRegistry.getRouteByComponent(component);
}

View File

@@ -4,8 +4,10 @@ import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from './actionTypes';
ReducerRegistry.register('features/app', (state = {}, action) => {
switch (action.type) {
case APP_WILL_MOUNT:
if (state.app !== action.app) {
case APP_WILL_MOUNT: {
const { app } = action;
if (state.app !== app) {
return {
...state,
@@ -15,10 +17,11 @@ ReducerRegistry.register('features/app', (state = {}, action) => {
*
* @type {App}
*/
app: action.app
app
};
}
break;
}
case APP_WILL_UNMOUNT:
if (state.app === action.app) {

View File

@@ -79,8 +79,9 @@ function _openDeviceSelectionDialogInPopup() {
// API_ID will always be defined because the iframe api is enabled
const scope = `dialog_${API_ID}`;
const url = `static/deviceSelectionPopup.html#scope=${
encodeURIComponent(JSON.stringify(scope))}`;
const url = `${
window.location.origin}/static/deviceSelectionPopup.html#scope=${
encodeURIComponent(JSON.stringify(scope))}`;
const popup
= window.open(
url,

View File

@@ -2,7 +2,6 @@ import 'es6-symbol/implement';
import React, { Component } from 'react';
import { AppRegistry, Linking } from 'react-native';
import config from './config';
import { App } from './features/app';
/**
@@ -14,7 +13,26 @@ import { App } from './features/app';
*/
class Root extends Component {
/**
* Initializes a new Root instance.
* {@code Root} component's property types.
*
* @static
*/
static propTypes = {
/**
* The URL, if any, with which the app was launched.
*/
url: React.PropTypes.string,
/**
* Whether the Welcome page is enabled. If {@code true}, the Welcome
* page is rendered when the {@link App} is not at a location (URL)
* identifying a Jitsi Meet conference/room.
*/
welcomePageEnabled: React.PropTypes.bool
};
/**
* Initializes a new {@code Root} instance.
*
* @param {Object} props - The read-only properties with which the new
* instance is to be initialized.
@@ -25,7 +43,9 @@ class Root extends Component {
/**
* The initial state of this Component.
*
* @type {{url: string}}
* @type {{
* url: string
* }}
*/
this.state = {
/**
@@ -33,7 +53,7 @@ class Root extends Component {
*
* @type {string}
*/
url: undefined
url: this.props.url
};
// Handle the URL, if any, with which the app was launched.
@@ -57,19 +77,29 @@ class Root extends Component {
* @returns {ReactElement}
*/
render() {
// XXX We don't render the App component until we get the initial URL,
// either it's null or some other non-null defined value;
if (typeof this.state.url === 'undefined') {
const { url } = this.state;
// XXX We don't render the App component until we get the initial URL.
// Either it's null or some other non-null defined value.
if (typeof url === 'undefined') {
return null;
}
const {
// The following props are forked in state:
url: _, // eslint-disable-line no-unused-vars
// The remaining props are passed through to App.
...props
} = this.props;
return (
<App
config = { config }
url = { this.state.url } />
{ ...props }
url = { url } />
);
}
}
// Register the main Component.
// Register the main/root Component.
AppRegistry.registerComponent('App', () => Root);

View File

@@ -5,7 +5,6 @@ import ReactDOM from 'react-dom';
import { getJitsiMeetTransport } from '../modules/transport';
import config from './config';
import { App } from './features/app';
const logger = require('jitsi-meet-logger').getLogger(__filename);
@@ -19,10 +18,8 @@ document.addEventListener('DOMContentLoaded', () => {
APP.connectionTimes['document.ready'] = now;
logger.log('(TIME) document ready:\t', now);
// Render the main Component.
ReactDOM.render(
<App config = { config } />,
document.getElementById('react'));
// Render the main/root Component.
ReactDOM.render(<App />, document.getElementById('react'));
});
/**