mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-01-29 01:50:18 +00:00
Compare commits
37 Commits
node_10_bu
...
3095
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e207ad609a | ||
|
|
35da17f5a6 | ||
|
|
fb6949f7ba | ||
|
|
9013c0db39 | ||
|
|
99542e29e6 | ||
|
|
1ba66e4b65 | ||
|
|
80afe30e9e | ||
|
|
957606b3f8 | ||
|
|
769a2c7c94 | ||
|
|
f349357d3c | ||
|
|
9c2f816c29 | ||
|
|
b844a9f06b | ||
|
|
d4e18e78fa | ||
|
|
f13cfe70f3 | ||
|
|
5cb4bec633 | ||
|
|
4409bbabb7 | ||
|
|
d6216f21d5 | ||
|
|
3a32f7f3f0 | ||
|
|
d5fb2c2717 | ||
|
|
c4f1588bb0 | ||
|
|
609f3887f2 | ||
|
|
77f8f85b96 | ||
|
|
14adc0b887 | ||
|
|
c288d0e18c | ||
|
|
eaafc21133 | ||
|
|
72c1fa38be | ||
|
|
45068f68db | ||
|
|
e0cbb838be | ||
|
|
c28c70fb2f | ||
|
|
280178f5d1 | ||
|
|
e9b2518f8a | ||
|
|
1e3e71c2ff | ||
|
|
007d60eb6c | ||
|
|
85f487cca5 | ||
|
|
b24e7ec5f0 | ||
|
|
a045353e6e | ||
|
|
420c466f80 |
@@ -33,80 +33,72 @@ dependencies {
|
||||
|
||||
### Build and use your own SDK artifacts/binaries
|
||||
|
||||
1. Install all required [dependencies](https://github.com/jitsi/jitsi-meet/blob/master/doc/mobile.md).
|
||||
Start by making sure that your development environment [is set up correctly](https://github.com/jitsi/jitsi-meet/blob/master/doc/mobile.md).
|
||||
|
||||
2. Create the SDK-release assembly, by invoking the following in the jitsi-meet
|
||||
project source:
|
||||
A note on dependencies: Apart from the SDK, Jitsi also publishes a binary Maven artifact for some of the SDK dependencies (that are not otherwise publicly available) to the Jitsi Maven repository. When you're planning to use a SDK that is built from source, you'll likely use a version of the source code that is newer (or at least _different_) than the version of the source that was used to create the binary SDK artifact. As a consequence, the dependencies that your project will need, might also be different from those that are published in the Jitsi Maven repository. This might lead to build problems, caused by dependencies that are unavailable.
|
||||
|
||||
```bash
|
||||
cd android/
|
||||
./gradlew :sdk:assembleRelease
|
||||
```
|
||||
When this successfully executes, artifacts/binaries are ready to be published
|
||||
into a Maven repository of your choice.
|
||||
If you want to use a SDK that is built from source, you will likely benefit from composing a local Maven repository that contains these dependencies. The text below describes how you create a repository that includes both the SDK as well as these dependencies. For illustration purposes, we'll define the location of this local Maven repository as `/tmp/repo`
|
||||
|
||||
3. Configure the Maven repositories in which you are going to publish the
|
||||
artifacts/binaries during step 4.
|
||||
In source code form, the Android SDK dependencies are locked/pinned by package.json and package-lock.json of the Jitsi Meet project. To obtain the data, execute NPM in the parent directory:
|
||||
|
||||
In the file `android/sdk/build.gradle` modify the line that contains
|
||||
`"file:${rootProject.projectDir}/../../../jitsi/jitsi-maven-repository/releases"`
|
||||
$ (cd ..; npm install)
|
||||
|
||||
Change this value (which represents the Maven repository location used internally
|
||||
by the Jitsi Developers) to the location of the repository that you'd like to use.
|
||||
This will pull in the dependencies in either binary format, or in source code format, somewhere under /node_modules/
|
||||
|
||||
4. Publish the Maven artifact/binary of Jitsi Meet SDK for Android in the Maven
|
||||
repository configured in step 3:
|
||||
At the time of writing, the React Native dependency is the only one pulled in in binary format. To copy it to your local Maven repository, you can simply copy part of the directory structure that was pulled in by NPM:
|
||||
|
||||
```bash
|
||||
./gradlew :sdk:publish
|
||||
cd ../
|
||||
```
|
||||
5. In _your_ project, add the Maven repository that you configured in step 3, as well
|
||||
as the dependency `org.jitsi.react:jitsi-meet-sdk` into your `build.gradle`
|
||||
file. Note that it's needed to pull in the transitive dependencies:
|
||||
$ cp -r ../node_modules/react-native/android/com /tmp/repo/
|
||||
|
||||
```gradle
|
||||
implementation ('org.jitsi.react:jitsi-meet-sdk:+') { transitive = true }
|
||||
```
|
||||
In the same way, copy the JavaScriptCore dependency:
|
||||
|
||||
Generally, if you are modifying the JavaScript code of Jitsi Meet SDK for Android only,
|
||||
the above will suffice. If you would like to publish a third-party react-native module
|
||||
which Jitsi Meet SDK for Android depends on (and is not publicly available in Maven
|
||||
repositories) continue below.
|
||||
$ cp -r ../node_modules/jsc-android/dist/org /tmp/repo/
|
||||
|
||||
6. Create the release assembly for _each_ third-party react-native module that you
|
||||
need, replacing it's name in the example below.
|
||||
Third-party React Native _modules_, which Jitsi Meet SDK for Android depends on, are download by NPM in source code form. These need to be assembled into Maven artifacts, and then published to your local Maven repository. The SDK project facilitates this.
|
||||
|
||||
```bash
|
||||
./gradlew :react-native-webrtc:assembleRelease
|
||||
```
|
||||
To prepare, Configure the Maven repositories in which you are going to publish the SDK artifacts/binaries. In `android/sdk/build.gradle` as well as in `android/build.gradle` modify the lines that contain:
|
||||
|
||||
7. Configure the Maven repositories in which you are going to publish the
|
||||
artifacts/binaries during step 8.
|
||||
"file:${rootProject.projectDir}/../../../jitsi/jitsi-maven-repository/releases"
|
||||
|
||||
In the file `android/build.gradle` (note that this is a different file than the file
|
||||
that was modified in step 3) modify the line that contains
|
||||
`"file:${rootProject.projectDir}/../../../jitsi/jitsi-maven-repository/releases"`
|
||||
Change this value (which represents the Maven repository location used internally by the Jitsi Developers) to the location of the repository that you'd like to use:
|
||||
|
||||
Change this value (which represents the Maven repository location used internally
|
||||
by the Jitsi Developers) to the location of the repository that you'd like to use.
|
||||
You can use the same repository as the one you configured in step 3 if you want.
|
||||
"file:/tmp/repo"
|
||||
|
||||
8. Publish the Maven artifact/binary of _each_ third-party react-native module that
|
||||
you need, replacing it's name in the example below. For example, to publish
|
||||
react-native-webrtc:
|
||||
Make sure to do this in both files! Each file should require one line to be changed.
|
||||
|
||||
```bash
|
||||
./gradlew :react-native-webrtc:publish
|
||||
```
|
||||
To create the release assembly for any _specific_ third-party React Native module that you need, you can execture the following commands, replace the module name in the examples below.
|
||||
|
||||
Note that there should not be a need to explicitly add these dependencies in
|
||||
_your_ project, as they will be pulled in as transitive dependencies of
|
||||
`jitsi-meet-sdk`.
|
||||
$ ./gradlew :react-native-webrtc:assembleRelease
|
||||
$ ./gradlew :react-native-webrtc:publish
|
||||
|
||||
You build and publish the SDK itself in the same way:
|
||||
|
||||
$ ./gradlew :sdk:assembleRelease
|
||||
$ ./gradlew :sdk:publish
|
||||
|
||||
Alternatively, you can assemble and publish _all_ subprojects, which include the react-native modules, but also the SDK itself, with a single command:
|
||||
|
||||
$ ./gradlew assembleRelease publish
|
||||
|
||||
You're now ready to use the artifacts. In _your_ project, add the Maven repository that you used above (`/tmp/repo`) into your top-level `build.gradle` file:
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
maven { url "file:/tmp/repo" }
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
You can use your local repository to replace the Jitsi repository (`maven { url "https://github.com/jitsi/jitsi-maven-repository/raw/master/releases" }`) when you published _all_ subprojects. If you didn't do that, you'll have to add both repositories. Make sure your local repository is listed first!
|
||||
|
||||
Then, define the dependency `org.jitsi.react:jitsi-meet-sdk` into the `build.gradle` file of your module:
|
||||
|
||||
implementation ('org.jitsi.react:jitsi-meet-sdk:+') { transitive = true }
|
||||
|
||||
Note that there should not be a need to explicitly add the other dependencies, as they will be pulled in as transitive dependencies of `jitsi-meet-sdk`.
|
||||
|
||||
|
||||
## Using the API
|
||||
=======
|
||||
|
||||
Jitsi Meet SDK is an Android library which embodies the whole Jitsi Meet
|
||||
experience and makes it reusable by third-party apps.
|
||||
|
||||
@@ -24,6 +24,7 @@ dependencies {
|
||||
implementation "com.android.support:support-v4:${rootProject.ext.supportLibVersion}"
|
||||
implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
|
||||
|
||||
implementation 'org.webkit:android-jsc:+'
|
||||
implementation 'com.dropbox.core:dropbox-core-sdk:3.0.8'
|
||||
api 'com.facebook.react:react-native:+'
|
||||
|
||||
|
||||
@@ -262,7 +262,7 @@ public class JitsiMeetView
|
||||
// the respective conference again if the first invocation was followed
|
||||
// by leaving the conference. However, React and, respectively,
|
||||
// appProperties/initialProperties are declarative expressions i.e. one
|
||||
// and the same URL will not trigger componentWillReceiveProps in the
|
||||
// and the same URL will not trigger an automatic re-render in the
|
||||
// JavaScript source code. The workaround implemented bellow introduces
|
||||
// imperativeness in React Component props by defining a unique value
|
||||
// per loadURLObject: invocation.
|
||||
|
||||
@@ -44,4 +44,15 @@
|
||||
#largeVideoContainer {
|
||||
background-color: $defaultBackground !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Thumbnail popover menus can overlap other thumbnails. Setting an auto
|
||||
* z-index will allow AtlasKit InlineDialog's large z-index to be
|
||||
* respected and thereby display over elements in other thumbnails,
|
||||
* specifically the various status icons.
|
||||
*/
|
||||
.remotevideomenu,
|
||||
.videocontainer__toptoolbar {
|
||||
z-index: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,17 +22,17 @@ PODS:
|
||||
- "GoogleToolboxForMac/NSString+URLArguments (2.1.4)"
|
||||
- GTMOAuth2 (1.1.6):
|
||||
- GTMSessionFetcher (~> 1.1)
|
||||
- GTMSessionFetcher (1.2.0):
|
||||
- GTMSessionFetcher/Full (= 1.2.0)
|
||||
- GTMSessionFetcher/Core (1.2.0)
|
||||
- GTMSessionFetcher/Full (1.2.0):
|
||||
- GTMSessionFetcher/Core (= 1.2.0)
|
||||
- GTMSessionFetcher (1.2.1):
|
||||
- GTMSessionFetcher/Full (= 1.2.1)
|
||||
- GTMSessionFetcher/Core (1.2.1)
|
||||
- GTMSessionFetcher/Full (1.2.1):
|
||||
- GTMSessionFetcher/Core (= 1.2.1)
|
||||
- ObjectiveDropboxOfficial (3.9.2)
|
||||
- React (0.57.1):
|
||||
- React/Core (= 0.57.1)
|
||||
- React (0.57.6):
|
||||
- React/Core (= 0.57.6)
|
||||
- react-native-background-timer (2.0.0):
|
||||
- React
|
||||
- react-native-calendar-events (1.6.2):
|
||||
- react-native-calendar-events (1.6.3):
|
||||
- React
|
||||
- react-native-fast-image (4.0.14):
|
||||
- FLAnimatedImage
|
||||
@@ -45,42 +45,42 @@ PODS:
|
||||
- React
|
||||
- react-native-webrtc (1.67.1):
|
||||
- React
|
||||
- React/Core (0.57.1):
|
||||
- yoga (= 0.57.1.React)
|
||||
- React/CxxBridge (0.57.1):
|
||||
- React/Core (0.57.6):
|
||||
- yoga (= 0.57.6.React)
|
||||
- React/CxxBridge (0.57.6):
|
||||
- Folly (= 2016.10.31.00)
|
||||
- React/Core
|
||||
- React/cxxreact
|
||||
- React/cxxreact (0.57.1):
|
||||
- React/cxxreact (0.57.6):
|
||||
- boost-for-react-native (= 1.63.0)
|
||||
- Folly (= 2016.10.31.00)
|
||||
- React/jschelpers
|
||||
- React/jsinspector
|
||||
- React/DevSupport (0.57.1):
|
||||
- React/DevSupport (0.57.6):
|
||||
- React/Core
|
||||
- React/RCTWebSocket
|
||||
- React/fishhook (0.57.1)
|
||||
- React/jschelpers (0.57.1):
|
||||
- React/fishhook (0.57.6)
|
||||
- React/jschelpers (0.57.6):
|
||||
- Folly (= 2016.10.31.00)
|
||||
- React/PrivateDatabase
|
||||
- React/jsinspector (0.57.1)
|
||||
- React/PrivateDatabase (0.57.1)
|
||||
- React/RCTActionSheet (0.57.1):
|
||||
- React/jsinspector (0.57.6)
|
||||
- React/PrivateDatabase (0.57.6)
|
||||
- React/RCTActionSheet (0.57.6):
|
||||
- React/Core
|
||||
- React/RCTAnimation (0.57.1):
|
||||
- React/RCTAnimation (0.57.6):
|
||||
- React/Core
|
||||
- React/RCTBlob (0.57.1):
|
||||
- React/RCTBlob (0.57.6):
|
||||
- React/Core
|
||||
- React/RCTImage (0.57.1):
|
||||
- React/RCTImage (0.57.6):
|
||||
- React/Core
|
||||
- React/RCTNetwork
|
||||
- React/RCTLinkingIOS (0.57.1):
|
||||
- React/RCTLinkingIOS (0.57.6):
|
||||
- React/Core
|
||||
- React/RCTNetwork (0.57.1):
|
||||
- React/RCTNetwork (0.57.6):
|
||||
- React/Core
|
||||
- React/RCTText (0.57.1):
|
||||
- React/RCTText (0.57.6):
|
||||
- React/Core
|
||||
- React/RCTWebSocket (0.57.1):
|
||||
- React/RCTWebSocket (0.57.6):
|
||||
- React/Core
|
||||
- React/fishhook
|
||||
- React/RCTBlob
|
||||
@@ -98,7 +98,7 @@ PODS:
|
||||
- SDWebImage/GIF (4.4.2):
|
||||
- FLAnimatedImage (~> 1.0)
|
||||
- SDWebImage/Core
|
||||
- yoga (0.57.1.React)
|
||||
- yoga (0.57.6.React)
|
||||
|
||||
DEPENDENCIES:
|
||||
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
|
||||
@@ -176,7 +176,7 @@ SPEC CHECKSUMS:
|
||||
GoogleSignIn: 11183592dc63e105475c7305a325045ff95e02b7
|
||||
GoogleToolboxForMac: 91c824d21e85b31c2aae9bb011c5027c9b4e738f
|
||||
GTMOAuth2: c77fe325e4acd453837e72d91e3b5f13116857b2
|
||||
GTMSessionFetcher: 0c4baf0a73acd0041bf9f71ea018deedab5ea84e
|
||||
GTMSessionFetcher: 32aeca0aa144acea523e1c8e053089dec2cb98ca
|
||||
ObjectiveDropboxOfficial: aa792e0556ceb7b72955fa29a2709072f6e35fd9
|
||||
React: 1fe0eb13d90b625d94c3b117c274dcfd2e760e11
|
||||
react-native-background-timer: 63dcbf37dbcf294b5c6c071afcdc661fa06a7594
|
||||
|
||||
@@ -268,7 +268,7 @@ static NSMapTable<NSString *, JitsiMeetView *> *views;
|
||||
// conference again if the first invocation was followed by leaving the
|
||||
// conference. However, React and, respectively,
|
||||
// appProperties/initialProperties are declarative expressions i.e. one and
|
||||
// the same URL will not trigger componentWillReceiveProps in the JavaScript
|
||||
// the same URL will not trigger an automatic re-render in the JavaScript
|
||||
// source code. The workaround implemented bellow introduces imperativeness
|
||||
// in React Component props by defining a unique value per loadURLObject:
|
||||
// invocation.
|
||||
|
||||
1072
package-lock.json
generated
1072
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -58,10 +58,10 @@
|
||||
"moment-duration-format": "2.2.2",
|
||||
"postis": "2.2.0",
|
||||
"prop-types": "15.6.0",
|
||||
"react": "16.5.0",
|
||||
"react": "16.6.1",
|
||||
"react-dom": "16.5.0",
|
||||
"react-i18next": "7.13.0",
|
||||
"react-native": "0.57.1",
|
||||
"react-native": "0.57.6",
|
||||
"react-native-background-timer": "2.0.0",
|
||||
"react-native-calendar-events": "github:wmcmahan/react-native-calendar-events#056807286da610d884fb6b4c8ca187a767b261f7",
|
||||
"react-native-callstats": "3.53.4",
|
||||
@@ -109,7 +109,7 @@
|
||||
"file-loader": "1.1.5",
|
||||
"flow-bin": "0.78.0",
|
||||
"imports-loader": "0.7.1",
|
||||
"metro-react-native-babel-preset": "0.47.0",
|
||||
"metro-react-native-babel-preset": "0.49.2",
|
||||
"node-sass": "4.10.0",
|
||||
"precommit-hook": "3.0.0",
|
||||
"string-replace-loader": "1.3.0",
|
||||
|
||||
@@ -205,6 +205,18 @@ export default class AlwaysOnTop extends Component<*, State> {
|
||||
this._hideToolbarAfterTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a timeout to hide the toolbar when the toolbar is shown.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {void}
|
||||
*/
|
||||
componentDidUpdate(prevProps: *, prevState: State) {
|
||||
if (!prevState.visible && this.state.visible) {
|
||||
this._hideToolbarAfterTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all listeners.
|
||||
*
|
||||
@@ -223,18 +235,6 @@ export default class AlwaysOnTop extends Component<*, State> {
|
||||
window.removeEventListener('mousemove', this._mouseMove);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a timeout to hide the toolbar when the toolbar is shown.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {void}
|
||||
*/
|
||||
componentWillUpdate(nextProps: *, nextState: State) {
|
||||
if (!this.state.visible && nextState.visible) {
|
||||
this._hideToolbarAfterTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
|
||||
@@ -49,12 +49,12 @@ export default class AbstractDialog<P : Props, S : State>
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#componentWillMount()}. Invoked
|
||||
* Implements React's {@link Component#componentDidMount()}. Invoked
|
||||
* immediately before mounting occurs.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentWillMount() {
|
||||
componentDidMount() {
|
||||
this._mounted = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,11 @@ export type Props = {
|
||||
*/
|
||||
closeDialog: Function,
|
||||
|
||||
/**
|
||||
* Css class name that will be added to the dialog.
|
||||
*/
|
||||
cssClassName: string,
|
||||
|
||||
/**
|
||||
* Which settings tab should be initially displayed. If not defined then
|
||||
* the first tab will be displayed.
|
||||
@@ -44,7 +49,12 @@ export type Props = {
|
||||
/**
|
||||
* Information about the tabs that will be rendered.
|
||||
*/
|
||||
tabs: Array<Object>
|
||||
tabs: Array<Object>,
|
||||
|
||||
/**
|
||||
* Key to use for showing a title.
|
||||
*/
|
||||
titleKey: string
|
||||
|
||||
};
|
||||
|
||||
@@ -102,8 +112,8 @@ class DialogWithTabs extends Component<Props, State> {
|
||||
= { this.props.disableBlanketClickDismiss }
|
||||
onCancel = { onCancel }
|
||||
onSubmit = { this._onSubmit }
|
||||
titleKey = 'settings.title'>
|
||||
<div className = 'settings-dialog'>
|
||||
titleKey = { this.props.titleKey } >
|
||||
<div className = { this.props.cssClassName } >
|
||||
{ this._renderTabs() }
|
||||
</div>
|
||||
</StatelessDialog>
|
||||
|
||||
@@ -102,26 +102,8 @@ class StatelessDialog extends Component<Props> {
|
||||
this._onDialogDismissed = this._onDialogDismissed.bind(this);
|
||||
this._onKeyDown = this._onKeyDown.bind(this);
|
||||
this._onSubmit = this._onSubmit.bind(this);
|
||||
this._renderFooter = this._renderFooter.bind(this);
|
||||
this._setDialogElement = this._setDialogElement.bind(this);
|
||||
|
||||
this._Footer = this._createFooterConstructor(props);
|
||||
}
|
||||
|
||||
/**
|
||||
* React Component method that executes before the component is updated.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @param {Object} nextProps - The next properties, before the update.
|
||||
* @returns {void}
|
||||
*/
|
||||
componentWillUpdate(nextProps) {
|
||||
// If button states have changed, update the Footer constructor function
|
||||
// so buttons of the proper state are rendered.
|
||||
if (nextProps.okDisabled !== this.props.okDisabled
|
||||
|| nextProps.cancelDisabled !== this.props.cancelDisabled
|
||||
|| nextProps.submitDisabled !== this.props.submitDisabled) {
|
||||
this._Footer = this._createFooterConstructor(nextProps);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,7 +124,7 @@ class StatelessDialog extends Component<Props> {
|
||||
return (
|
||||
<Modal
|
||||
autoFocus = { true }
|
||||
footer = { this._Footer }
|
||||
footer = { this._renderFooter }
|
||||
heading = { titleString || t(titleKey) }
|
||||
i18n = { this.props.i18n }
|
||||
onClose = { this._onDialogDismissed }
|
||||
@@ -174,41 +156,38 @@ class StatelessDialog extends Component<Props> {
|
||||
);
|
||||
}
|
||||
|
||||
_onCancel: () => Function;
|
||||
_renderFooter: () => React$Node;
|
||||
|
||||
/**
|
||||
* Returns a functional component to be used for the modal footer.
|
||||
* Returns a ReactElement to display buttons for closing the modal.
|
||||
*
|
||||
* @param {Object} options - The configuration for how the buttons in the
|
||||
* footer should display. Essentially {@code StatelessDialog} props should
|
||||
* be passed in.
|
||||
* @param {Object} propsFromModalFooter - The props passed in from the
|
||||
* {@link ModalFooter} component.
|
||||
* @private
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_createFooterConstructor(options) {
|
||||
_renderFooter(propsFromModalFooter) {
|
||||
// Filter out falsy (null) values because {@code ButtonGroup} will error
|
||||
// if passed in anything but buttons with valid type props.
|
||||
const buttons = [
|
||||
this._renderOKButton(options),
|
||||
this._renderCancelButton(options)
|
||||
this._renderOKButton(),
|
||||
this._renderCancelButton()
|
||||
].filter(Boolean);
|
||||
|
||||
return function Footer(modalFooterProps) {
|
||||
return (
|
||||
<ModalFooter showKeyline = { modalFooterProps.showKeyline } >
|
||||
{
|
||||
return (
|
||||
<ModalFooter showKeyline = { propsFromModalFooter.showKeyline } >
|
||||
{
|
||||
|
||||
/**
|
||||
* Atlaskit has this empty span (JustifySim) so...
|
||||
*/
|
||||
}
|
||||
<span />
|
||||
<ButtonGroup>
|
||||
{ buttons }
|
||||
</ButtonGroup>
|
||||
</ModalFooter>
|
||||
);
|
||||
};
|
||||
/**
|
||||
* Atlaskit has this empty span (JustifySim) so...
|
||||
*/
|
||||
}
|
||||
<span />
|
||||
<ButtonGroup>
|
||||
{ buttons }
|
||||
</ButtonGroup>
|
||||
</ModalFooter>
|
||||
);
|
||||
}
|
||||
|
||||
_onCancel: () => void;
|
||||
@@ -257,21 +236,14 @@ class StatelessDialog extends Component<Props> {
|
||||
/**
|
||||
* Renders Cancel button.
|
||||
*
|
||||
* @param {Object} options - The configuration for the Cancel button.
|
||||
* @param {boolean} options.cancelDisabled - True if the cancel button
|
||||
* should not be rendered.
|
||||
* @param {string} options.cancelTitleKey - The translation key to use as
|
||||
* text on the button.
|
||||
* @param {boolean} options.isModal - True if the cancel button should not
|
||||
* be rendered.
|
||||
* @private
|
||||
* @returns {ReactElement|null} The Cancel button if enabled and dialog is
|
||||
* not modal.
|
||||
*/
|
||||
_renderCancelButton(options = {}) {
|
||||
if (options.cancelDisabled
|
||||
|| options.isModal
|
||||
|| options.hideCancelButton) {
|
||||
_renderCancelButton() {
|
||||
if (this.props.cancelDisabled
|
||||
|| this.props.isModal
|
||||
|| this.props.hideCancelButton) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -286,7 +258,7 @@ class StatelessDialog extends Component<Props> {
|
||||
key = 'cancel'
|
||||
onClick = { this._onCancel }
|
||||
type = 'button'>
|
||||
{ t(options.cancelTitleKey || 'dialog.Cancel') }
|
||||
{ t(this.props.cancelTitleKey || 'dialog.Cancel') }
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@@ -294,18 +266,11 @@ class StatelessDialog extends Component<Props> {
|
||||
/**
|
||||
* Renders OK button.
|
||||
*
|
||||
* @param {Object} options - The configuration for the OK button.
|
||||
* @param {boolean} options.okDisabled - True if the button should display
|
||||
* as disabled and clicking should have no effect.
|
||||
* @param {string} options.okTitleKey - The translation key to use as text
|
||||
* on the button.
|
||||
* @param {boolean} options.submitDisabled - True if the button should not
|
||||
* be rendered.
|
||||
* @private
|
||||
* @returns {ReactElement|null} The OK button if enabled.
|
||||
*/
|
||||
_renderOKButton(options = {}) {
|
||||
if (options.submitDisabled) {
|
||||
_renderOKButton() {
|
||||
if (this.props.submitDisabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -318,11 +283,11 @@ class StatelessDialog extends Component<Props> {
|
||||
appearance = 'primary'
|
||||
form = 'modal-dialog-form'
|
||||
id = { OK_BUTTON_ID }
|
||||
isDisabled = { options.okDisabled }
|
||||
isDisabled = { this.props.okDisabled }
|
||||
key = 'submit'
|
||||
onClick = { this._onSubmit }
|
||||
type = 'button'>
|
||||
{ t(options.okTitleKey || 'dialog.Ok') }
|
||||
{ t(this.props.okTitleKey || 'dialog.Ok') }
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -64,17 +64,24 @@ export default class CircularLabel extends AbstractCircularLabel<Props, State> {
|
||||
this.state = {
|
||||
pulseAnimation: new Animated.Value(0)
|
||||
};
|
||||
|
||||
this._maybeToggleAnimation({}, props);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@code Component#componentWillReceiveProps}.
|
||||
* Implements {@code Component#componentDidMount}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentWillReceiveProps(newProps: Props) {
|
||||
this._maybeToggleAnimation(this.props, newProps);
|
||||
componentDidMount() {
|
||||
this._maybeToggleAnimation({}, this.props);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@code Component#componentDidUpdate}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
this._maybeToggleAnimation(prevProps, this.props);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -125,6 +125,20 @@ export function getParticipantCount(stateful: Object | Function) {
|
||||
return getParticipants(stateful).length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a count of the known participants in the passed in redux state,
|
||||
* including fake participants.
|
||||
*
|
||||
* @param {(Function|Object|Participant[])} stateful - The redux state
|
||||
* features/base/participants, the (whole) redux state, or redux's
|
||||
* {@code getState} function to be used to retrieve the state
|
||||
* features/base/participants.
|
||||
* @returns {number}
|
||||
*/
|
||||
export function getParticipantCountWithFake(stateful: Object | Function) {
|
||||
return _getAllParticipants(stateful).length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns participant's display name.
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import React, { Component, type Node } from 'react';
|
||||
import React, { PureComponent, type Node } from 'react';
|
||||
import { Animated, TouchableWithoutFeedback, View } from 'react-native';
|
||||
|
||||
import styles, { SIDEBAR_WIDTH } from './styles';
|
||||
@@ -46,7 +46,18 @@ type State = {
|
||||
/**
|
||||
* A generic animated side bar to be used for left-side, hamburger-style menus.
|
||||
*/
|
||||
export default class SideBar extends Component<Props, State> {
|
||||
export default class SideBar extends PureComponent<Props, State> {
|
||||
/**
|
||||
* Implements React's {@link Component#getDerivedStateFromProps()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
static getDerivedStateFromProps(props: Props, prevState: State) {
|
||||
return {
|
||||
showOverlay: props.show || prevState.showOverlay
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new {@code SideBar} instance.
|
||||
*
|
||||
@@ -74,12 +85,12 @@ export default class SideBar extends Component<Props, State> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#componentWillReceiveProps()}.
|
||||
* Implements React's {@link Component#componentDidUpdate()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentWillReceiveProps({ show }: Props) {
|
||||
(show === this.props.show) || this._setShow(show);
|
||||
componentDidUpdate() {
|
||||
this._setShow(this.props.show);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,8 +159,6 @@ export default class SideBar extends Component<Props, State> {
|
||||
* @returns {void}
|
||||
*/
|
||||
_setShow(show) {
|
||||
show && this.setState({ showOverlay: true });
|
||||
|
||||
Animated
|
||||
.timing(
|
||||
/* value */ this.state.sliderAnimation,
|
||||
|
||||
@@ -206,6 +206,16 @@ export default class AbstractButton<P: Props, S: *> extends Component<P, S> {
|
||||
return buttonStyles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tooltip to display when hovering over the button.
|
||||
*
|
||||
* @private
|
||||
* @returns {string}
|
||||
*/
|
||||
_getTooltip() {
|
||||
return this.tooltip || '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to be implemented by subclasses, which must return a
|
||||
* boolean value indicating if this button is disabled or not.
|
||||
@@ -258,7 +268,7 @@ export default class AbstractButton<P: Props, S: *> extends Component<P, S> {
|
||||
iconName: this._getIconName(),
|
||||
label: this._getLabel(),
|
||||
styles: this._getStyles(),
|
||||
tooltip: this.tooltip
|
||||
tooltip: this._getTooltip()
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -81,23 +81,15 @@ class DeepLinkingMobilePage extends Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
joinURL: generateDeepLinkingURL()
|
||||
};
|
||||
|
||||
// Bind event handlers so they are only bound once per instance.
|
||||
this._onDownloadApp = this._onDownloadApp.bind(this);
|
||||
this._onOpenApp = this._onOpenApp.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the text and URL of the `Start a conference` / `Join the
|
||||
* conversation` button which takes the user to the mobile app.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentWillMount() {
|
||||
this.setState({
|
||||
joinURL: generateDeepLinkingURL()
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the Component's componentDidMount method.
|
||||
*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// @flow
|
||||
|
||||
import Tabs from '@atlaskit/tabs';
|
||||
import React, { Component } from 'react';
|
||||
import React, { PureComponent } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { Dialog, hideDialog } from '../../base/dialog';
|
||||
@@ -94,12 +94,36 @@ type State = {
|
||||
types: Array<string>
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* React component for DesktopPicker.
|
||||
*
|
||||
* @extends Component
|
||||
*/
|
||||
class DesktopPicker extends Component<Props, State> {
|
||||
class DesktopPicker extends PureComponent<Props, State> {
|
||||
/**
|
||||
* Implements React's {@link Component#getDerivedStateFromProps()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
static getDerivedStateFromProps(props) {
|
||||
return {
|
||||
types: DesktopPicker._getValidTypes(props.desktopSharingSources)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts only the valid types from the passed {@code types}.
|
||||
*
|
||||
* @param {Array<string>} types - The types to filter.
|
||||
* @private
|
||||
* @returns {Array<string>} The filtered types.
|
||||
*/
|
||||
static _getValidTypes(types = []) {
|
||||
return types.filter(
|
||||
type => VALID_TYPES.includes(type));
|
||||
}
|
||||
|
||||
_poller = null;
|
||||
|
||||
state = {
|
||||
@@ -133,7 +157,7 @@ class DesktopPicker extends Component<Props, State> {
|
||||
this._updateSources = this._updateSources.bind(this);
|
||||
|
||||
this.state.types
|
||||
= this._getValidTypes(this.props.desktopSharingSources);
|
||||
= DesktopPicker._getValidTypes(this.props.desktopSharingSources);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,31 +170,6 @@ class DesktopPicker extends Component<Props, State> {
|
||||
this._startPolling();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies this mounted React Component that it will receive new props.
|
||||
* Sets a default selected source if one is not already set.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @param {Object} nextProps - The read-only React Component props that this
|
||||
* instance will receive.
|
||||
* @returns {void}
|
||||
*/
|
||||
componentWillReceiveProps(nextProps: Props) {
|
||||
const { desktopSharingSources } = nextProps;
|
||||
|
||||
/**
|
||||
* Do only reference check in order to not calculate the types on every
|
||||
* update. This is enough for our use case and we don't need value
|
||||
* checking because if the value is the same we won't change the
|
||||
* reference for the desktopSharingSources array.
|
||||
*/
|
||||
if (desktopSharingSources !== this.props.desktopSharingSources) {
|
||||
this.setState({
|
||||
types: this._getValidTypes(desktopSharingSources)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up component and DesktopCapturerSource store state.
|
||||
*
|
||||
@@ -241,17 +240,6 @@ class DesktopPicker extends Component<Props, State> {
|
||||
return selectedSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts only the valid types from the passed {@code types}.
|
||||
*
|
||||
* @param {Array<string>} types - The types to filter.
|
||||
* @returns {Array<string>} The filtered types.
|
||||
*/
|
||||
_getValidTypes(types = []) {
|
||||
return types.filter(
|
||||
type => VALID_TYPES.includes(type));
|
||||
}
|
||||
|
||||
_onCloseModal: (?string, string) => void;
|
||||
|
||||
/**
|
||||
|
||||
@@ -63,9 +63,9 @@ class AudioInputPreview extends Component<Props, State> {
|
||||
* @inheritdoc
|
||||
* @returns {void}
|
||||
*/
|
||||
componentWillReceiveProps(nextProps: Props) {
|
||||
if (nextProps.track !== this.props.track) {
|
||||
this._listenForAudioUpdates(nextProps.track);
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
if (prevProps.track !== this.props.track) {
|
||||
this._listenForAudioUpdates(this.props.track);
|
||||
this._updateAudioLevel(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,7 +151,8 @@ class DeviceSelection extends AbstractDialogTab<Props, State> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if audio / video permissions were granted.
|
||||
* Checks if audio / video permissions were granted. Updates audio input and
|
||||
* video input previews.
|
||||
*
|
||||
* @param {Object} prevProps - Previous props this component received.
|
||||
* @param {Object} prevState - Previous state this component had.
|
||||
@@ -174,25 +175,15 @@ class DeviceSelection extends AbstractDialogTab<Props, State> {
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates audio input and video input previews.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @param {Object} nextProps - The read-only props which this Component will
|
||||
* receive.
|
||||
* @returns {void}
|
||||
*/
|
||||
componentWillReceiveProps(nextProps: Object) {
|
||||
const { selectedAudioInputId, selectedVideoInputId } = this.props;
|
||||
|
||||
if (selectedAudioInputId !== nextProps.selectedAudioInputId) {
|
||||
this._createAudioInputTrack(nextProps.selectedAudioInputId);
|
||||
if (prevProps.selectedAudioInputId
|
||||
!== this.props.selectedAudioInputId) {
|
||||
this._createAudioInputTrack(this.props.selectedAudioInputId);
|
||||
}
|
||||
|
||||
if (selectedVideoInputId !== nextProps.selectedVideoInputId) {
|
||||
this._createVideoInputTrack(nextProps.selectedVideoInputId);
|
||||
if (prevProps.selectedVideoInputId
|
||||
!== this.props.selectedVideoInputId) {
|
||||
this._createVideoInputTrack(this.props.selectedVideoInputId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// @flow
|
||||
|
||||
import {
|
||||
getParticipantCount,
|
||||
getParticipantCountWithFake,
|
||||
getPinnedParticipant
|
||||
} from '../base/participants';
|
||||
import { toState } from '../base/redux';
|
||||
@@ -36,7 +36,10 @@ export function shouldRemoteVideosBeVisible(state: Object) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const participantCount = getParticipantCount(state);
|
||||
// Include fake participants to derive how many thumbnails are dispalyed,
|
||||
// as it is assumed all participants, including fake, will be displayed
|
||||
// in the filmstrip.
|
||||
const participantCount = getParticipantCountWithFake(state);
|
||||
let pinnedParticipant;
|
||||
|
||||
return Boolean(
|
||||
|
||||
@@ -70,6 +70,12 @@ type Props = {
|
||||
*/
|
||||
type State = {
|
||||
|
||||
/**
|
||||
* Cache the conference connection state to derive when transitioning from
|
||||
* not joined to join, in order to auto-show the InfoDialog.
|
||||
*/
|
||||
hasConnectedToConference: boolean,
|
||||
|
||||
/**
|
||||
* Whether or not {@code InfoDialog} should be visible.
|
||||
*/
|
||||
@@ -83,6 +89,23 @@ type State = {
|
||||
* @extends Component
|
||||
*/
|
||||
class InfoDialogButton extends Component<Props, State> {
|
||||
/**
|
||||
* Implements React's {@link Component#getDerivedStateFromProps()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
static getDerivedStateFromProps(props, state) {
|
||||
return {
|
||||
hasConnectedToConference: props._isConferenceJoined,
|
||||
showDialog: (props._toolboxVisible && state.showDialog)
|
||||
|| (!state.hasConnectedToConference
|
||||
&& props._isConferenceJoined
|
||||
&& props._participantCount < 2
|
||||
&& props._toolboxVisible
|
||||
&& !props._disableAutoShow)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes new {@code InfoDialogButton} instance.
|
||||
*
|
||||
@@ -92,6 +115,7 @@ class InfoDialogButton extends Component<Props, State> {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
hasConnectedToConference: props._isConferenceJoined,
|
||||
showDialog: false
|
||||
};
|
||||
|
||||
@@ -111,22 +135,6 @@ class InfoDialogButton extends Component<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the visibility of the {@code InfoDialog}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentWillReceiveProps(nextProps) {
|
||||
// Ensure the dialog is closed when the toolbox becomes hidden.
|
||||
if (this.state.showDialog && !nextProps._toolboxVisible) {
|
||||
this._onDialogClose();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this._maybeAutoShowDialog(nextProps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
@@ -159,24 +167,6 @@ class InfoDialogButton extends Component<Props, State> {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked to trigger display of the {@code InfoDialog} if certain
|
||||
* conditions are met.
|
||||
*
|
||||
* @param {Object} nextProps - The future properties of this component.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_maybeAutoShowDialog(nextProps) {
|
||||
if (!this.props._isConferenceJoined
|
||||
&& nextProps._isConferenceJoined
|
||||
&& nextProps._participantCount < 2
|
||||
&& nextProps._toolboxVisible
|
||||
&& !nextProps._disableAutoShow) {
|
||||
this.setState({ showDialog: true });
|
||||
}
|
||||
}
|
||||
|
||||
_onDialogClose: () => void;
|
||||
|
||||
/**
|
||||
|
||||
@@ -112,6 +112,28 @@ type State = {
|
||||
class InfoDialog extends Component<Props, State> {
|
||||
_copyElement: ?Object;
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#getDerivedStateFromProps()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
static getDerivedStateFromProps(props, state) {
|
||||
let phoneNumber = state.phoneNumber;
|
||||
|
||||
if (!state.phoneNumber && props.dialIn.numbers) {
|
||||
const { defaultCountry, numbers } = props.dialIn;
|
||||
|
||||
phoneNumber = _getDefaultPhoneNumber(numbers, defaultCountry);
|
||||
}
|
||||
|
||||
return {
|
||||
// Exit edit mode when a password is set locally or remotely.
|
||||
passwordEditEnabled: state.passwordEditEnabled && props._password
|
||||
? false : state.passwordEditEnabled,
|
||||
phoneNumber
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code InfoDialog} component's local state.
|
||||
*
|
||||
@@ -162,28 +184,6 @@ class InfoDialog extends Component<Props, State> {
|
||||
this._setCopyElement = this._setCopyElement.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#componentWillReceiveProps()}. Invoked
|
||||
* before this mounted component receives new props.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @param {Props} nextProps - New props component will receive.
|
||||
*/
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (!this.props._password && nextProps._password) {
|
||||
this.setState({ passwordEditEnabled: false });
|
||||
}
|
||||
|
||||
if (!this.state.phoneNumber && nextProps.dialIn.numbers) {
|
||||
const { defaultCountry, numbers } = nextProps.dialIn;
|
||||
|
||||
this.setState({
|
||||
phoneNumber:
|
||||
_getDefaultPhoneNumber(numbers, defaultCountry)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
|
||||
@@ -55,6 +55,17 @@ type State = {
|
||||
* @extends Component
|
||||
*/
|
||||
class PasswordForm extends Component<Props, State> {
|
||||
/**
|
||||
* Implements React's {@link Component#getDerivedStateFromProps()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
static getDerivedStateFromProps(props, state) {
|
||||
return {
|
||||
enteredPassword: props.editEnabled ? state.enteredPassword : ''
|
||||
};
|
||||
}
|
||||
|
||||
state = {
|
||||
enteredPassword: ''
|
||||
};
|
||||
@@ -74,19 +85,6 @@ class PasswordForm extends Component<Props, State> {
|
||||
this._onPasswordSubmit = this._onPasswordSubmit.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#componentWillReceiveProps()}. Invoked
|
||||
* before this mounted component receives new props.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @param {Props} nextProps - New props component will receive.
|
||||
*/
|
||||
componentWillReceiveProps(nextProps: Props) {
|
||||
if (this.props.editEnabled && !nextProps.editEnabled) {
|
||||
this.setState({ enteredPassword: '' });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
@@ -182,5 +180,4 @@ class PasswordForm extends Component<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default translate(PasswordForm);
|
||||
|
||||
@@ -32,6 +32,19 @@ type State = {
|
||||
* @extends Component
|
||||
*/
|
||||
class Labels extends AbstractLabels<Props, State> {
|
||||
/**
|
||||
* Updates the state for whether or not the filmstrip is transitioning to
|
||||
* a displayed state.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
static getDerivedStateFromProps(props, prevState) {
|
||||
return {
|
||||
filmstripBecomingVisible: !prevState.filmstripBecomingVisible
|
||||
&& props._filmstripVisible
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new {@code Labels} instance.
|
||||
*
|
||||
@@ -46,22 +59,6 @@ class Labels extends AbstractLabels<Props, State> {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the state for whether or not the filmstrip is being toggled to
|
||||
* display after having being hidden.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @param {Object} nextProps - The read-only props which this Component will
|
||||
* receive.
|
||||
* @returns {void}
|
||||
*/
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.setState({
|
||||
filmstripBecomingVisible: nextProps._filmstripVisible
|
||||
&& !this.props._filmstripVisible
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
|
||||
@@ -117,17 +117,15 @@ export class LargeVideoBackground extends Component<Props> {
|
||||
* Starts or stops the interval to update the image displayed in the canvas.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @param {Object} nextProps - The read-only React {@code Component} props
|
||||
* with which the new instance is to be initialized.
|
||||
*/
|
||||
componentWillReceiveProps(nextProps: Props) {
|
||||
if (this.props.hidden && !nextProps.hidden) {
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
if (prevProps.hidden && !this.props.hidden) {
|
||||
this._clearCanvas();
|
||||
this._setUpdateCanvasInterval();
|
||||
}
|
||||
|
||||
if ((!this.props.hidden && nextProps.hidden)
|
||||
|| !nextProps.videoElement) {
|
||||
if ((!prevProps.hidden && this.props.hidden)
|
||||
|| !this.props.videoElement) {
|
||||
this._clearCanvas();
|
||||
this._clearUpdateCanvasInterval();
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ class AudioRoutePickerDialog extends Component<Props, State> {
|
||||
state = {
|
||||
/**
|
||||
* Available audio devices, it will be set in
|
||||
* {@link #componentWillMount()}.
|
||||
* {@link #componentDidMount()}.
|
||||
*/
|
||||
devices: []
|
||||
};
|
||||
@@ -132,7 +132,7 @@ class AudioRoutePickerDialog extends Component<Props, State> {
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentWillMount() {
|
||||
componentDidMount() {
|
||||
AudioMode.getAudioDevices().then(({ devices, selected }) => {
|
||||
const audioDevices = [];
|
||||
|
||||
|
||||
@@ -54,6 +54,18 @@ const STALE_TIMEOUT = 10 * 1000;
|
||||
*/
|
||||
export default class AbstractRecordingLabel
|
||||
extends Component<Props, State> {
|
||||
/**
|
||||
* Implements {@code Component#getDerivedStateFromProps}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
static getDerivedStateFromProps(props: Props, prevState: State) {
|
||||
return {
|
||||
staleLabel: props._status !== JitsiRecordingConstants.status.OFF
|
||||
&& prevState.staleLabel ? false : prevState.staleLabel
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new {@code AbstractRecordingLabel} component.
|
||||
*
|
||||
@@ -70,12 +82,12 @@ export default class AbstractRecordingLabel
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@code Component#componentWillReceiveProps}.
|
||||
* Implements {@code Component#componentDidUpdate}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentWillReceiveProps(newProps: Props) {
|
||||
this._updateStaleStatus(this.props, newProps);
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
this._updateStaleStatus(prevProps, this.props);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,13 +149,8 @@ export default class AbstractRecordingLabel
|
||||
}
|
||||
}, STALE_TIMEOUT);
|
||||
}
|
||||
} else if (this.state.staleLabel) {
|
||||
this.setState({
|
||||
staleLabel: false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,24 +33,13 @@ export type Props = {
|
||||
value: string
|
||||
};
|
||||
|
||||
/**
|
||||
* The state of the component.
|
||||
*/
|
||||
type State = {
|
||||
|
||||
/**
|
||||
* The value entered in the field.
|
||||
*/
|
||||
value: string
|
||||
}
|
||||
|
||||
/**
|
||||
* An abstract React Component for entering a key for starting a YouTube live
|
||||
* stream.
|
||||
*
|
||||
* @extends Component
|
||||
*/
|
||||
export default class AbstractStreamKeyForm extends Component<Props, State> {
|
||||
export default class AbstractStreamKeyForm extends Component<Props> {
|
||||
helpURL: string;
|
||||
|
||||
/**
|
||||
@@ -61,10 +50,6 @@ export default class AbstractStreamKeyForm extends Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
value: props.value
|
||||
};
|
||||
|
||||
this.helpURL = (typeof interfaceConfig !== 'undefined'
|
||||
&& interfaceConfig.LIVE_STREAMING_HELP_LINK)
|
||||
|| LIVE_STREAMING_HELP_LINK;
|
||||
@@ -73,17 +58,6 @@ export default class AbstractStreamKeyForm extends Component<Props, State> {
|
||||
this._onInputChange = this._onInputChange.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@code Component}'s componentWillReceiveProps.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentWillReceiveProps(newProps: Props) {
|
||||
this.setState({
|
||||
value: newProps.value
|
||||
});
|
||||
}
|
||||
|
||||
_onInputChange: Object => void
|
||||
|
||||
/**
|
||||
@@ -99,9 +73,6 @@ export default class AbstractStreamKeyForm extends Component<Props, State> {
|
||||
_onInputChange(change) {
|
||||
const value = typeof change === 'object' ? change.target.value : change;
|
||||
|
||||
this.setState({
|
||||
value
|
||||
});
|
||||
this.props.onChange(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ class StreamKeyForm extends AbstractStreamKeyForm {
|
||||
onChangeText = { this._onInputChange }
|
||||
placeholder = { t('liveStreaming.enterStreamKey') }
|
||||
style = { styles.streamKeyInput }
|
||||
value = { this.state.value } />
|
||||
value = { this.props.value } />
|
||||
<TouchableOpacity
|
||||
onPress = { this._onOpenHelp }
|
||||
style = { styles.streamKeyHelp } >
|
||||
|
||||
@@ -37,26 +37,6 @@ class LiveStreamButton extends AbstractLiveStreamButton<Props> {
|
||||
iconName = 'icon-public';
|
||||
toggledIconName = 'icon-public';
|
||||
|
||||
/**
|
||||
* Constructor of the component.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.tooltip = props._liveStreamDisabledTooltipKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@code Component}'s componentWillReceiveProps.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentWillReceiveProps(newProps: Props) {
|
||||
this.tooltip = newProps._liveStreamDisabledTooltipKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to be implemented by subclasses, which returns
|
||||
* a React Element to display (a beta tag) at the end of the button.
|
||||
@@ -76,6 +56,16 @@ class LiveStreamButton extends AbstractLiveStreamButton<Props> {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tooltip that should be displayed when the button is disabled.
|
||||
*
|
||||
* @private
|
||||
* @returns {string}
|
||||
*/
|
||||
_getTooltip() {
|
||||
return this.props._liveStreamDisabledTooltipKey || '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to be implemented by subclasses, which must return a
|
||||
* boolean value indicating if this button is disabled or not.
|
||||
|
||||
@@ -51,7 +51,7 @@ class StreamKeyForm extends AbstractStreamKeyForm {
|
||||
placeholder = { t('liveStreaming.enterStreamKey') }
|
||||
shouldFitContainer = { true }
|
||||
type = 'text'
|
||||
value = { this.state.value } />
|
||||
value = { this.props.value } />
|
||||
{ this.helpURL
|
||||
? <div className = 'form-footer'>
|
||||
<a
|
||||
|
||||
@@ -36,23 +36,13 @@ class RecordButton extends AbstractRecordButton<Props> {
|
||||
toggledIconName = 'icon-camera-take-picture';
|
||||
|
||||
/**
|
||||
* Constructor of the component.
|
||||
* Returns the tooltip that should be displayed when the button is disabled.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @private
|
||||
* @returns {string}
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.tooltip = props._fileRecordingsDisabledTooltipKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@code Component}'s componentWillReceiveProps.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentWillReceiveProps(newProps: Props) {
|
||||
this.tooltip = newProps._fileRecordingsDisabledTooltipKey;
|
||||
_getTooltip() {
|
||||
return this.tooltip || '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -262,13 +262,15 @@ export default class DeviceSelectionPopup {
|
||||
<AtlasKitThemeProvider mode = 'dark'>
|
||||
<DialogWithTabs
|
||||
closeDialog = { this.close }
|
||||
cssClassName = 'settings-dialog'
|
||||
onSubmit = { onSubmit }
|
||||
tabs = { [ {
|
||||
component: DeviceSelection,
|
||||
label: 'settings.devices',
|
||||
props: this._dialogProps,
|
||||
submit: this._onSubmit
|
||||
} ] } />
|
||||
} ] }
|
||||
titleKey = 'settings.title' />
|
||||
</AtlasKitThemeProvider>
|
||||
</I18nextProvider>,
|
||||
document.getElementById('react'));
|
||||
|
||||
@@ -91,11 +91,13 @@ class SettingsDialog extends Component<Props> {
|
||||
return (
|
||||
<DialogWithTabs
|
||||
closeDialog = { this._closeDialog }
|
||||
cssClassName = 'settings-dialog'
|
||||
defaultTab = {
|
||||
defaultTabIdx === -1 ? undefined : defaultTabIdx
|
||||
}
|
||||
onSubmit = { onSubmit }
|
||||
tabs = { tabs } />
|
||||
tabs = { tabs }
|
||||
titleKey = 'settings.title' />
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import SpeakerStatsLabels from './SpeakerStatsLabels';
|
||||
declare var interfaceConfig: Object;
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link SpeakerStats}
|
||||
* The type of the React {@code Component} props of {@link SpeakerStats}.
|
||||
*/
|
||||
type Props = {
|
||||
|
||||
@@ -33,7 +33,7 @@ type Props = {
|
||||
};
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} state of {@link SpeakerStats}
|
||||
* The type of the React {@code Component} state of {@link SpeakerStats}.
|
||||
*/
|
||||
type State = {
|
||||
|
||||
@@ -49,10 +49,6 @@ type State = {
|
||||
* @extends Component
|
||||
*/
|
||||
class SpeakerStats extends Component<Props, State> {
|
||||
state = {
|
||||
stats: {}
|
||||
};
|
||||
|
||||
_updateInterval: IntervalID;
|
||||
|
||||
/**
|
||||
@@ -64,19 +60,20 @@ class SpeakerStats extends Component<Props, State> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
stats: this.props.conference.getSpeakerStats()
|
||||
};
|
||||
|
||||
// Bind event handlers so they are only bound once per instance.
|
||||
this._updateStats = this._updateStats.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Immediately request for updated speaker stats and begin
|
||||
* polling for speaker stats updates.
|
||||
* Begin polling for speaker stats updates.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {void}
|
||||
*/
|
||||
componentWillMount() {
|
||||
this._updateStats();
|
||||
componentDidMount() {
|
||||
this._updateInterval = setInterval(this._updateStats, 1000);
|
||||
}
|
||||
|
||||
|
||||
@@ -280,15 +280,15 @@ class Toolbox extends Component<Props> {
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentWillReceiveProps(nextProps) {
|
||||
componentDidUpdate(prevProps) {
|
||||
// Ensure the dialog is closed when the toolbox becomes hidden.
|
||||
if (this.props._overflowMenuVisible && !nextProps._visible) {
|
||||
if (prevProps._overflowMenuVisible && !this.props._visible) {
|
||||
this._onSetOverflowVisible(false);
|
||||
}
|
||||
|
||||
if (this.props._overflowMenuVisible
|
||||
&& !this.props._dialog
|
||||
&& nextProps._dialog) {
|
||||
if (prevProps._overflowMenuVisible
|
||||
&& !prevProps._dialog
|
||||
&& this.props._dialog) {
|
||||
this._onSetOverflowVisible(false);
|
||||
this.props.dispatch(setToolbarHovered(false));
|
||||
}
|
||||
|
||||
@@ -37,6 +37,17 @@ type Props = {
|
||||
export class AbstractWelcomePage extends Component<Props, *> {
|
||||
_mounted: ?boolean;
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#getDerivedStateFromProps()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
static getDerivedStateFromProps(props: Props, state: Object) {
|
||||
return {
|
||||
room: props._room || state.room
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Save room name into component's local state.
|
||||
*
|
||||
@@ -77,26 +88,15 @@ export class AbstractWelcomePage extends Component<Props, *> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#componentWillMount()}. Invoked
|
||||
* immediately before mounting occurs.
|
||||
* Implements React's {@link Component#componentDidMount()}. Invoked
|
||||
* immediately after mounting occurs.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentWillMount() {
|
||||
componentDidMount() {
|
||||
this._mounted = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#componentWillReceiveProps()}. Invoked
|
||||
* before this mounted component receives new props.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @param {Props} nextProps - New props component will receive.
|
||||
*/
|
||||
componentWillReceiveProps(nextProps: Props) {
|
||||
this.setState({ room: nextProps._room });
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#componentWillUnmount()}. Invoked
|
||||
* immediately before this component is unmounted and destroyed.
|
||||
|
||||
@@ -29,7 +29,7 @@ class BlankPage extends Component<Props> {
|
||||
* @inheritdoc
|
||||
* @returns {void}
|
||||
*/
|
||||
componentWillMount() {
|
||||
componentDidMount() {
|
||||
this.props.dispatch(destroyLocalTracks());
|
||||
}
|
||||
|
||||
|
||||
@@ -33,69 +33,11 @@ type Props = {
|
||||
style: Object
|
||||
};
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} state of
|
||||
* {@link LocalVideoTrackUnderlay}.
|
||||
*/
|
||||
type State = {
|
||||
|
||||
/**
|
||||
* The style of {@code LocalVideoTrackUnderlay} which is a combination
|
||||
* of its default style and the consumer-specified style.
|
||||
*/
|
||||
style: Object
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements a React {@code Component} which underlays the local video track,
|
||||
* if any, underneath its children.
|
||||
*/
|
||||
class LocalVideoTrackUnderlay extends Component<Props, State> {
|
||||
/**
|
||||
* Initializes a new {@code LocalVideoTrackUnderlay} instance.
|
||||
*
|
||||
* @param {Object} props - The read-only React {@code Component} props with
|
||||
* which the new instance is to be initialized.
|
||||
*/
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.componentWillReceiveProps(props);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies this mounted React {@code Component} that it will receive new
|
||||
* props. Forks (in Facebook/React speak) the prop {@code style} because its
|
||||
* value is to be combined with the default style.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @param {Object} nextProps - The read-only React {@code Component} props
|
||||
* that this instance will receive.
|
||||
* @returns {void}
|
||||
*/
|
||||
componentWillReceiveProps(nextProps) {
|
||||
// style
|
||||
const prevStyle = this.props && this.props.style;
|
||||
const nextStyle = nextProps && nextProps.style;
|
||||
const assignState = !this.state;
|
||||
|
||||
if (prevStyle !== nextStyle || assignState) {
|
||||
const nextState = {
|
||||
style: {
|
||||
...styles.localVideoTrackUnderlay,
|
||||
...nextStyle
|
||||
}
|
||||
};
|
||||
|
||||
if (assignState) {
|
||||
// eslint-disable-next-line react/no-direct-mutation-state
|
||||
this.state = nextState;
|
||||
} else {
|
||||
this.setState(nextState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class LocalVideoTrackUnderlay extends Component<Props> {
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
@@ -105,7 +47,11 @@ class LocalVideoTrackUnderlay extends Component<Props, State> {
|
||||
*/
|
||||
render() {
|
||||
return (
|
||||
<View style = { this.state.style }>
|
||||
<View
|
||||
style = { [
|
||||
styles.localVideoTrackUnderlay,
|
||||
this.props.style
|
||||
] }>
|
||||
<VideoTrack videoTrack = { this.props._localVideoTrack } />
|
||||
<TintedView>
|
||||
{ this.props.children }
|
||||
|
||||
@@ -57,15 +57,15 @@ class WelcomePage extends AbstractWelcomePage {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#componentWillMount()}. Invoked
|
||||
* immediately before mounting occurs. Creates a local video track if none
|
||||
* Implements React's {@link Component#componentDidMount()}. Invoked
|
||||
* immediately after mounting occurs. Creates a local video track if none
|
||||
* is available and the camera permission was already granted.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {void}
|
||||
*/
|
||||
componentWillMount() {
|
||||
super.componentWillMount();
|
||||
componentDidMount() {
|
||||
super.componentDidMount();
|
||||
|
||||
const { dispatch } = this.props;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user