feat(rn,welcome) React Navigation drawer
This commit is contained in:
parent
f5cdd5fca1
commit
4e2fea1e12
|
@ -1140,6 +1140,12 @@
|
||||||
"button": "Invite others",
|
"button": "Invite others",
|
||||||
"youAreAlone": "You are the only one in the meeting"
|
"youAreAlone": "You are the only one in the meeting"
|
||||||
},
|
},
|
||||||
|
"termsView": {
|
||||||
|
"header": "Terms"
|
||||||
|
},
|
||||||
|
"privacyView": {
|
||||||
|
"header": "Privacy"
|
||||||
|
},
|
||||||
"helpView": {
|
"helpView": {
|
||||||
"header": "Help center"
|
"header": "Help center"
|
||||||
},
|
},
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
"@react-native-community/netinfo": "4.1.5",
|
"@react-native-community/netinfo": "4.1.5",
|
||||||
"@react-native-community/slider": "3.0.3",
|
"@react-native-community/slider": "3.0.3",
|
||||||
"@react-native-masked-view/masked-view": "0.2.6",
|
"@react-native-masked-view/masked-view": "0.2.6",
|
||||||
|
"@react-navigation/drawer": "5.12.9",
|
||||||
"@react-navigation/material-top-tabs": "5.3.19",
|
"@react-navigation/material-top-tabs": "5.3.19",
|
||||||
"@react-navigation/native": "5.9.8",
|
"@react-navigation/native": "5.9.8",
|
||||||
"@react-navigation/stack": "5.14.9",
|
"@react-navigation/stack": "5.14.9",
|
||||||
|
@ -4255,6 +4256,24 @@
|
||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@react-navigation/drawer": {
|
||||||
|
"version": "5.12.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-navigation/drawer/-/drawer-5.12.9.tgz",
|
||||||
|
"integrity": "sha512-SYb2BCEAn+BiEwC6WBfCzs1VlWD+ZdQbxmsim6vo1o+ndPW2e+kiq7FXKRs0vUXhQRZVl2oOB3vBn0c3YCllQg==",
|
||||||
|
"dependencies": {
|
||||||
|
"color": "^3.1.3",
|
||||||
|
"react-native-iphone-x-helper": "^1.3.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@react-navigation/native": "^5.0.5",
|
||||||
|
"react": "*",
|
||||||
|
"react-native": "*",
|
||||||
|
"react-native-gesture-handler": ">= 1.0.0",
|
||||||
|
"react-native-reanimated": ">= 1.0.0",
|
||||||
|
"react-native-safe-area-context": ">= 0.6.0",
|
||||||
|
"react-native-screens": ">= 2.0.0-alpha.0 || >= 2.0.0-beta.0 || >= 2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@react-navigation/material-top-tabs": {
|
"node_modules/@react-navigation/material-top-tabs": {
|
||||||
"version": "5.3.19",
|
"version": "5.3.19",
|
||||||
"resolved": "https://registry.npmjs.org/@react-navigation/material-top-tabs/-/material-top-tabs-5.3.19.tgz",
|
"resolved": "https://registry.npmjs.org/@react-navigation/material-top-tabs/-/material-top-tabs-5.3.19.tgz",
|
||||||
|
@ -23379,6 +23398,15 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@react-navigation/drawer": {
|
||||||
|
"version": "5.12.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-navigation/drawer/-/drawer-5.12.9.tgz",
|
||||||
|
"integrity": "sha512-SYb2BCEAn+BiEwC6WBfCzs1VlWD+ZdQbxmsim6vo1o+ndPW2e+kiq7FXKRs0vUXhQRZVl2oOB3vBn0c3YCllQg==",
|
||||||
|
"requires": {
|
||||||
|
"color": "^3.1.3",
|
||||||
|
"react-native-iphone-x-helper": "^1.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@react-navigation/material-top-tabs": {
|
"@react-navigation/material-top-tabs": {
|
||||||
"version": "5.3.19",
|
"version": "5.3.19",
|
||||||
"resolved": "https://registry.npmjs.org/@react-navigation/material-top-tabs/-/material-top-tabs-5.3.19.tgz",
|
"resolved": "https://registry.npmjs.org/@react-navigation/material-top-tabs/-/material-top-tabs-5.3.19.tgz",
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
"@react-native-community/netinfo": "4.1.5",
|
"@react-native-community/netinfo": "4.1.5",
|
||||||
"@react-native-community/slider": "3.0.3",
|
"@react-native-community/slider": "3.0.3",
|
||||||
"@react-native-masked-view/masked-view": "0.2.6",
|
"@react-native-masked-view/masked-view": "0.2.6",
|
||||||
|
"@react-navigation/drawer": "5.12.9",
|
||||||
"@react-navigation/material-top-tabs": "5.3.19",
|
"@react-navigation/material-top-tabs": "5.3.19",
|
||||||
"@react-navigation/native": "5.9.8",
|
"@react-navigation/native": "5.9.8",
|
||||||
"@react-navigation/stack": "5.14.9",
|
"@react-navigation/stack": "5.14.9",
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
import { isRoomValid } from '../base/conference';
|
import { isRoomValid } from '../base/conference';
|
||||||
import { toState } from '../base/redux';
|
import { toState } from '../base/redux';
|
||||||
import { ConferenceNavigationContainer } from '../conference';
|
import { ConferenceNavigationContainer } from '../conference';
|
||||||
import { isWelcomePageAppEnabled } from '../welcome';
|
import RootNavigationContainer from '../welcome/components/RootNavigationContainer';
|
||||||
import { BlankPage, WelcomePage } from '../welcome/components';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines which route is to be rendered in order to depict a specific Redux
|
* Determines which route is to be rendered in order to depict a specific Redux
|
||||||
|
@ -26,27 +25,17 @@ export function _getRouteToRender(stateful) {
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
function _getMobileRoute(state) {
|
function _getMobileRoute(state) {
|
||||||
const route = _getEmptyRoute();
|
const route = {
|
||||||
|
component: null,
|
||||||
|
href: undefined
|
||||||
|
};
|
||||||
|
|
||||||
if (isRoomValid(state['features/base/conference'].room)) {
|
if (isRoomValid(state['features/base/conference'].room)) {
|
||||||
route.component = ConferenceNavigationContainer;
|
route.component = ConferenceNavigationContainer;
|
||||||
} else if (isWelcomePageAppEnabled(state)) {
|
|
||||||
route.component = WelcomePage;
|
|
||||||
} else {
|
} else {
|
||||||
route.component = BlankPage;
|
route.component = RootNavigationContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.resolve(route);
|
return Promise.resolve(route);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the default {@code Route}.
|
|
||||||
*
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
function _getEmptyRoute() {
|
|
||||||
return {
|
|
||||||
component: BlankPage,
|
|
||||||
href: undefined
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,9 +7,7 @@ import { toState } from '../base/redux';
|
||||||
import { Conference } from '../conference';
|
import { Conference } from '../conference';
|
||||||
import { getDeepLinkingPage } from '../deep-linking';
|
import { getDeepLinkingPage } from '../deep-linking';
|
||||||
import { UnsupportedDesktopBrowser } from '../unsupported-browser';
|
import { UnsupportedDesktopBrowser } from '../unsupported-browser';
|
||||||
import { isWelcomePageUserEnabled } from '../welcome';
|
import { BlankPage, isWelcomePageUserEnabled, WelcomePage } from '../welcome';
|
||||||
import { BlankPage, WelcomePage } from '../welcome/components';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines which route is to be rendered in order to depict a specific Redux
|
* Determines which route is to be rendered in order to depict a specific Redux
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30" width="30px" height="30px">
|
||||||
|
<path d="M 15 2 A 1 1 0 0 0 14.300781 2.2851562 L 3.3925781 11.207031 A 1 1 0 0 0 3.3554688 11.236328 L 3.3183594 11.267578 L 3.3183594 11.269531 A 1 1 0 0 0 3 12 A 1 1 0 0 0 4 13 L 5 13 L 5 24 C 5 25.105 5.895 26 7 26 L 23 26 C 24.105 26 25 25.105 25 24 L 25 13 L 26 13 A 1 1 0 0 0 27 12 A 1 1 0 0 0 26.681641 11.267578 L 26.666016 11.255859 A 1 1 0 0 0 26.597656 11.199219 L 25 9.8925781 L 25 6 C 25 5.448 24.552 5 24 5 L 23 5 C 22.448 5 22 5.448 22 6 L 22 7.4394531 L 15.677734 2.2675781 A 1 1 0 0 0 15 2 z M 18 15 L 22 15 L 22 23 L 18 23 L 18 15 z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 677 B |
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<svg fill="#000000" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30" width="30px" height="30px">
|
||||||
|
<path d="M 15 2 A 1 1 0 0 0 14.300781 2.2851562 L 3.3925781 11.207031 A 1 1 0 0 0 3.3554688 11.236328 L 3.3183594 11.267578 L 3.3183594 11.269531 A 1 1 0 0 0 3 12 A 1 1 0 0 0 4 13 L 5 13 L 5 24 C 5 25.105 5.895 26 7 26 L 23 26 C 24.105 26 25 25.105 25 24 L 25 13 L 26 13 A 1 1 0 0 0 27 12 A 1 1 0 0 0 26.681641 11.267578 L 26.666016 11.255859 A 1 1 0 0 0 26.597656 11.199219 L 25 9.8925781 L 25 6 C 25 5.448 24.552 5 24 5 L 23 5 C 22.448 5 22 5.448 22 6 L 22 7.4394531 L 15.677734 2.2675781 A 1 1 0 0 0 15 2 z M 18 15 L 22 15 L 22 23 L 18 23 L 18 15 z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 692 B |
|
@ -60,6 +60,7 @@ export { default as IconFullScreen } from './full-screen.svg';
|
||||||
export { default as IconGoogle } from './google.svg';
|
export { default as IconGoogle } from './google.svg';
|
||||||
export { default as IconHangup } from './hangup.svg';
|
export { default as IconHangup } from './hangup.svg';
|
||||||
export { default as IconHelp } from './help.svg';
|
export { default as IconHelp } from './help.svg';
|
||||||
|
export { default as IconHome } from './home.svg';
|
||||||
export { default as IconHorizontalPoints } from './horizontal-points.svg';
|
export { default as IconHorizontalPoints } from './horizontal-points.svg';
|
||||||
export { default as IconInfo } from './info.svg';
|
export { default as IconInfo } from './info.svg';
|
||||||
export { default as IconInviteMore } from './user-plus.svg';
|
export { default as IconInviteMore } from './user-plus.svg';
|
||||||
|
|
|
@ -1,188 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import React, { PureComponent } from 'react';
|
|
||||||
import { KeyboardAvoidingView, Platform, SafeAreaView } from 'react-native';
|
|
||||||
|
|
||||||
import { ColorSchemeRegistry } from '../../color-scheme';
|
|
||||||
import { HeaderWithNavigation, SlidingView } from '../../react';
|
|
||||||
import { connect } from '../../redux';
|
|
||||||
import { StyleType } from '../../styles';
|
|
||||||
import { setActiveModalId } from '../actions';
|
|
||||||
|
|
||||||
import styles from './styles';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The color schemed style of the common header component.
|
|
||||||
*/
|
|
||||||
_headerStyles: StyleType,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* True if the modal should be shown, false otherwise.
|
|
||||||
*/
|
|
||||||
_show: boolean,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The color schemed style of the modal.
|
|
||||||
*/
|
|
||||||
_styles: StyleType,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The children component(s) of the Modal, to be rendered.
|
|
||||||
*/
|
|
||||||
children: React$Node,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Redux Dispatch function.
|
|
||||||
*/
|
|
||||||
dispatch: Function,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Optional function that renders a footer component, if needed.
|
|
||||||
*/
|
|
||||||
footerComponent?: Function,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Props to be passed over to the header.
|
|
||||||
*
|
|
||||||
* See {@code HeaderWithNavigation} for more details.
|
|
||||||
*/
|
|
||||||
headerProps: Object,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* True if the header with navigation should be hidden, false otherwise.
|
|
||||||
*/
|
|
||||||
hideHeaderWithNavigation?: boolean,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The ID of the modal that is being rendered. This is used to show/hide the modal.
|
|
||||||
*/
|
|
||||||
modalId: string,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback to be invoked when the modal closes.
|
|
||||||
*/
|
|
||||||
onClose?: Function,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The position from where the modal should be opened. This is derived from the
|
|
||||||
* props of the {@code SlidingView} with the same name.
|
|
||||||
*/
|
|
||||||
position?: string,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Additional style to be appended to the View containing the content of the modal.
|
|
||||||
*/
|
|
||||||
style?: StyleType
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements a custom Jitsi Modal that doesn't use the built in native
|
|
||||||
* Modal component of React Native.
|
|
||||||
*/
|
|
||||||
class JitsiModal extends PureComponent<Props> {
|
|
||||||
static defaultProps = {
|
|
||||||
position: 'bottom',
|
|
||||||
hideHeaderWithNavigation: false
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiates a new component.
|
|
||||||
*
|
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this._onRequestClose = this._onRequestClose.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements {@code PureComponent#render}.
|
|
||||||
*
|
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
_headerStyles,
|
|
||||||
_show,
|
|
||||||
_styles,
|
|
||||||
children,
|
|
||||||
footerComponent,
|
|
||||||
headerProps,
|
|
||||||
position,
|
|
||||||
hideHeaderWithNavigation,
|
|
||||||
style
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SlidingView
|
|
||||||
onHide = { this._onRequestClose }
|
|
||||||
position = { position }
|
|
||||||
show = { _show }>
|
|
||||||
<KeyboardAvoidingView
|
|
||||||
behavior =
|
|
||||||
{
|
|
||||||
Platform.OS === 'ios'
|
|
||||||
? 'padding' : 'height'
|
|
||||||
}
|
|
||||||
enabled = { true }
|
|
||||||
style = { [
|
|
||||||
_headerStyles.page,
|
|
||||||
_styles.page,
|
|
||||||
style
|
|
||||||
] }>
|
|
||||||
<HeaderWithNavigation
|
|
||||||
{ ...headerProps }
|
|
||||||
hideHeaderWithNavigation = { hideHeaderWithNavigation }
|
|
||||||
onPressBack = { this._onRequestClose } />
|
|
||||||
<SafeAreaView style = { styles.safeArea }>
|
|
||||||
{ children }
|
|
||||||
</SafeAreaView>
|
|
||||||
{ footerComponent && footerComponent() }
|
|
||||||
</KeyboardAvoidingView>
|
|
||||||
</SlidingView>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_onRequestClose: () => boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback to be invoked when the SlidingView requests closing.
|
|
||||||
*
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
_onRequestClose() {
|
|
||||||
const { _show, dispatch, onClose } = this.props;
|
|
||||||
let shouldCloseModal = true;
|
|
||||||
|
|
||||||
if (_show) {
|
|
||||||
if (typeof onClose === 'function') {
|
|
||||||
shouldCloseModal = onClose();
|
|
||||||
}
|
|
||||||
shouldCloseModal && dispatch(setActiveModalId());
|
|
||||||
|
|
||||||
return shouldCloseModal;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maps part of the Redix state to the props of this component.
|
|
||||||
*
|
|
||||||
* @param {Object} state - The Redux state.
|
|
||||||
* @param {Props} ownProps - The own props of the component.
|
|
||||||
* @returns {Props}
|
|
||||||
*/
|
|
||||||
function _mapStateToProps(state, ownProps): $Shape<Props> {
|
|
||||||
return {
|
|
||||||
_headerStyles: ColorSchemeRegistry.get(state, 'Header'),
|
|
||||||
_show: state['features/base/modal'].activeModalId === ownProps.modalId,
|
|
||||||
_styles: ColorSchemeRegistry.get(state, 'Modal')
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(_mapStateToProps)(JitsiModal);
|
|
|
@ -30,7 +30,7 @@ type Props = {
|
||||||
/**
|
/**
|
||||||
* Is the screen rendering a tab navigator?
|
* Is the screen rendering a tab navigator?
|
||||||
*/
|
*/
|
||||||
hasTabNavigator: boolean,
|
hasTabNavigator?: boolean,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Additional style to be appended to the KeyboardAvoidingView containing the content of the modal.
|
* Additional style to be appended to the KeyboardAvoidingView containing the content of the modal.
|
||||||
|
@ -42,7 +42,7 @@ const JitsiScreen = ({
|
||||||
contentContainerStyle,
|
contentContainerStyle,
|
||||||
children,
|
children,
|
||||||
footerComponent,
|
footerComponent,
|
||||||
hasTabNavigator,
|
hasTabNavigator = false,
|
||||||
style
|
style
|
||||||
}: Props) => (
|
}: Props) => (
|
||||||
<View
|
<View
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import WebView from 'react-native-webview';
|
||||||
|
|
||||||
|
import JitsiScreen from './JitsiScreen';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL to display.
|
||||||
|
*/
|
||||||
|
source: string,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The component's external style.
|
||||||
|
*/
|
||||||
|
style: Object
|
||||||
|
}
|
||||||
|
|
||||||
|
const JitsiScreenWebView = ({ source, style }: Props) => (
|
||||||
|
<JitsiScreen
|
||||||
|
style = { style }>
|
||||||
|
<WebView source = {{ uri: source }} />
|
||||||
|
</JitsiScreen>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default JitsiScreenWebView;
|
|
@ -0,0 +1,79 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import React, { useCallback } from 'react';
|
||||||
|
import { StatusBar } from 'react-native';
|
||||||
|
|
||||||
|
import { ColorSchemeRegistry } from '../../color-scheme';
|
||||||
|
import { connect } from '../../redux';
|
||||||
|
import { isDarkColor } from '../../styles';
|
||||||
|
|
||||||
|
// Register style
|
||||||
|
import '../../react/components/native/headerstyles';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constants for the (currently) supported statusbar colors.
|
||||||
|
*/
|
||||||
|
const STATUSBAR_DARK = 'dark-content';
|
||||||
|
const STATUSBAR_LIGHT = 'light-content';
|
||||||
|
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color schemed style of the component.
|
||||||
|
*/
|
||||||
|
_styles: Object
|
||||||
|
}
|
||||||
|
|
||||||
|
const JitsiStatusBar = ({ _styles }: Props) => {
|
||||||
|
|
||||||
|
const getStatusBarContentColor = useCallback(() => {
|
||||||
|
const { statusBarContent } = _styles;
|
||||||
|
|
||||||
|
if (statusBarContent) {
|
||||||
|
// We have the possibility to define the statusbar color in the
|
||||||
|
// color scheme feature, but since mobile devices (at the moment)
|
||||||
|
// only support two colors (light and dark) we need to normalize
|
||||||
|
// the value.
|
||||||
|
|
||||||
|
if (isDarkColor(statusBarContent)) {
|
||||||
|
return STATUSBAR_DARK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUSBAR_LIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The statusbar color is not defined, so we need to base our choice
|
||||||
|
// on the header colors
|
||||||
|
const { statusBar, screenHeader } = _styles;
|
||||||
|
|
||||||
|
if (isDarkColor(statusBar || screenHeader.backgroundColor)) {
|
||||||
|
return STATUSBAR_LIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUSBAR_DARK;
|
||||||
|
}, [ _styles ]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StatusBar
|
||||||
|
backgroundColor = { _styles.statusBar }
|
||||||
|
barStyle = { getStatusBarContentColor() }
|
||||||
|
translucent = { false } />
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps part of the Redux state to the props of the component.
|
||||||
|
*
|
||||||
|
* @param {Object} state - The Redux state.
|
||||||
|
* @returns {{
|
||||||
|
* _styles: Object
|
||||||
|
* }}
|
||||||
|
*/
|
||||||
|
function _mapStateToProps(state) {
|
||||||
|
return {
|
||||||
|
_styles: ColorSchemeRegistry.get(state, 'Header')
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(_mapStateToProps)(JitsiStatusBar);
|
|
@ -1,34 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
import { Keyboard } from 'react-native';
|
|
||||||
|
|
||||||
import { toState } from '../../redux';
|
import { toState } from '../../redux';
|
||||||
|
|
||||||
export const useKeyboardHeight = () => {
|
|
||||||
const [ keyboardHeight, setKeyboardHeight ] = useState(0);
|
|
||||||
|
|
||||||
const onKeyboardDidShow = e => {
|
|
||||||
setKeyboardHeight(e.endCoordinates.height);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onKeyboardDidHide = () => {
|
|
||||||
setKeyboardHeight(0);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const keyboardShow = Keyboard.addListener('keyboardDidShow', onKeyboardDidShow);
|
|
||||||
const keyboardHide = Keyboard.addListener('keyboardDidHide', onKeyboardDidHide);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
keyboardShow.remove();
|
|
||||||
keyboardHide.remove();
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return keyboardHeight;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Returns the client width.
|
* Returns the client width.
|
||||||
|
@ -39,7 +12,7 @@ export const useKeyboardHeight = () => {
|
||||||
* @returns {number}.
|
* @returns {number}.
|
||||||
*/
|
*/
|
||||||
export function getClientWidth(stateful: Object) {
|
export function getClientWidth(stateful: Object) {
|
||||||
const state = toState(stateful['features/base/responsive-ui']);
|
const state = toState(stateful)['features/base/responsive-ui'];
|
||||||
|
|
||||||
return state.clientWidth;
|
return state.clientWidth;
|
||||||
}
|
}
|
||||||
|
@ -54,7 +27,7 @@ export function getClientWidth(stateful: Object) {
|
||||||
* @returns {number}.
|
* @returns {number}.
|
||||||
*/
|
*/
|
||||||
export function getClientHeight(stateful: Object) {
|
export function getClientHeight(stateful: Object) {
|
||||||
const state = toState(stateful['features/base/responsive-ui']);
|
const state = toState(stateful)['features/base/responsive-ui'];
|
||||||
|
|
||||||
return state.clientHeight;
|
return state.clientHeight;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
export { default as JitsiModal } from './JitsiModal';
|
|
|
@ -1,6 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { Component } from 'react';
|
|
||||||
|
|
||||||
export const JitsiModal = Component;
|
|
||||||
|
|
|
@ -2,4 +2,3 @@
|
||||||
|
|
||||||
export * from './actions';
|
export * from './actions';
|
||||||
export * from './actionTypes';
|
export * from './actionTypes';
|
||||||
export * from './components';
|
|
||||||
|
|
|
@ -1,122 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import React, { PureComponent, type Node } from 'react';
|
|
||||||
import { SafeAreaView, StatusBar, View } from 'react-native';
|
|
||||||
|
|
||||||
import { ColorSchemeRegistry } from '../../../color-scheme';
|
|
||||||
import { connect } from '../../../redux';
|
|
||||||
import { isDarkColor } from '../../../styles';
|
|
||||||
|
|
||||||
// Register style
|
|
||||||
import './headerstyles';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constanst for the (currently) supported statusbar colors.
|
|
||||||
*/
|
|
||||||
const STATUSBAR_DARK = 'dark-content';
|
|
||||||
const STATUSBAR_LIGHT = 'light-content';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The type of the React {@code Component} props of {@link Header}.
|
|
||||||
*/
|
|
||||||
type Props = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Children component(s).
|
|
||||||
*/
|
|
||||||
children: Node,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The component's external style.
|
|
||||||
*/
|
|
||||||
style: Object,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The color schemed style of the component.
|
|
||||||
*/
|
|
||||||
_styles: Object
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A generic screen header component.
|
|
||||||
*/
|
|
||||||
class Header extends PureComponent<Props> {
|
|
||||||
/**
|
|
||||||
* Implements React's {@link Component#render()}.
|
|
||||||
*
|
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
render() {
|
|
||||||
const { _styles } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style = { _styles.headerOverlay }>
|
|
||||||
<StatusBar
|
|
||||||
backgroundColor = { _styles.statusBar }
|
|
||||||
barStyle = { this._getStatusBarContentColor() }
|
|
||||||
translucent = { false } />
|
|
||||||
<SafeAreaView>
|
|
||||||
<View
|
|
||||||
style = { [
|
|
||||||
_styles.screenHeader,
|
|
||||||
this.props.style
|
|
||||||
] }>
|
|
||||||
{
|
|
||||||
this.props.children
|
|
||||||
}
|
|
||||||
</View>
|
|
||||||
</SafeAreaView>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the color of the statusbar content (light or dark) based on
|
|
||||||
* certain criteria.
|
|
||||||
*
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
_getStatusBarContentColor() {
|
|
||||||
const { _styles } = this.props;
|
|
||||||
const { statusBarContent } = _styles;
|
|
||||||
|
|
||||||
if (statusBarContent) {
|
|
||||||
// We have the possibility to define the statusbar color in the
|
|
||||||
// color scheme feature, but since mobile devices (at the moment)
|
|
||||||
// only support two colors (light and dark) we need to normalize
|
|
||||||
// the value.
|
|
||||||
|
|
||||||
if (isDarkColor(statusBarContent)) {
|
|
||||||
return STATUSBAR_DARK;
|
|
||||||
}
|
|
||||||
|
|
||||||
return STATUSBAR_LIGHT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The statusbar color is not defined, so we need to base our choice
|
|
||||||
// on the header colors
|
|
||||||
const { statusBar, screenHeader } = _styles;
|
|
||||||
|
|
||||||
if (isDarkColor(statusBar || screenHeader.backgroundColor)) {
|
|
||||||
return STATUSBAR_LIGHT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return STATUSBAR_DARK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maps part of the Redux state to the props of the component.
|
|
||||||
*
|
|
||||||
* @param {Object} state - The Redux state.
|
|
||||||
* @returns {{
|
|
||||||
* _styles: Object
|
|
||||||
* }}
|
|
||||||
*/
|
|
||||||
function _mapStateToProps(state) {
|
|
||||||
return {
|
|
||||||
_styles: ColorSchemeRegistry.get(state, 'Header')
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(_mapStateToProps)(Header);
|
|
|
@ -1,72 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
|
|
||||||
import { translate } from '../../../i18n';
|
|
||||||
|
|
||||||
import BackButton from './BackButton';
|
|
||||||
import ForwardButton from './ForwardButton';
|
|
||||||
import Header from './Header';
|
|
||||||
import HeaderLabel from './HeaderLabel';
|
|
||||||
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Boolean to set the forward button disabled.
|
|
||||||
*/
|
|
||||||
forwardDisabled: boolean,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The i18n key of the the forward button label.
|
|
||||||
*/
|
|
||||||
forwardLabelKey: ?string,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The i18n key of the header label (title).
|
|
||||||
*/
|
|
||||||
headerLabelKey: ?string,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* True if the header with navigation should be hidden, false otherwise.
|
|
||||||
*/
|
|
||||||
hideHeaderWithNavigation?: boolean,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback to be invoked on pressing the back button.
|
|
||||||
*/
|
|
||||||
onPressBack: ?Function,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback to be invoked on pressing the forward button.
|
|
||||||
*/
|
|
||||||
onPressForward: ?Function,
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements a header with the standard navigation content.
|
|
||||||
*/
|
|
||||||
class HeaderWithNavigation extends Component<Props> {
|
|
||||||
/**
|
|
||||||
* Implements {@code Component#render}.
|
|
||||||
*
|
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
render() {
|
|
||||||
const { hideHeaderWithNavigation, onPressBack, onPressForward } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
!hideHeaderWithNavigation
|
|
||||||
&& <Header>
|
|
||||||
{ onPressBack && <BackButton onPress = { onPressBack } /> }
|
|
||||||
<HeaderLabel labelKey = { this.props.headerLabelKey } />
|
|
||||||
{ onPressForward && <ForwardButton
|
|
||||||
disabled = { this.props.forwardDisabled }
|
|
||||||
labelKey = { this.props.forwardLabelKey }
|
|
||||||
onPress = { onPressForward } /> }
|
|
||||||
</Header>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default translate(HeaderWithNavigation);
|
|
|
@ -6,9 +6,7 @@ export { default as BaseIndicator } from './BaseIndicator';
|
||||||
export { default as Button } from './Button';
|
export { default as Button } from './Button';
|
||||||
export { default as Container } from './Container';
|
export { default as Container } from './Container';
|
||||||
export { default as ForwardButton } from './ForwardButton';
|
export { default as ForwardButton } from './ForwardButton';
|
||||||
export { default as Header } from './Header';
|
|
||||||
export { default as HeaderLabel } from './HeaderLabel';
|
export { default as HeaderLabel } from './HeaderLabel';
|
||||||
export { default as HeaderWithNavigation } from './HeaderWithNavigation';
|
|
||||||
export { default as Image } from './Image';
|
export { default as Image } from './Image';
|
||||||
export { default as Link } from './Link';
|
export { default as Link } from './Link';
|
||||||
export { default as Linkify } from './Linkify';
|
export { default as Linkify } from './Linkify';
|
||||||
|
|
|
@ -18,6 +18,7 @@ export const colors = {
|
||||||
primary08: '#99BBF3',
|
primary08: '#99BBF3',
|
||||||
primary09: '#CCDDF9',
|
primary09: '#CCDDF9',
|
||||||
primary10: '#17A0DB',
|
primary10: '#17A0DB',
|
||||||
|
primary11: '#1081B2',
|
||||||
|
|
||||||
surface00: '#111111',
|
surface00: '#111111',
|
||||||
surface01: '#040404',
|
surface01: '#040404',
|
||||||
|
@ -32,12 +33,14 @@ export const colors = {
|
||||||
surface10: '#E0E0E0',
|
surface10: '#E0E0E0',
|
||||||
surface11: '#FFF',
|
surface11: '#FFF',
|
||||||
surface12: '#AAAAAA',
|
surface12: '#AAAAAA',
|
||||||
|
surface13: '#495258',
|
||||||
|
|
||||||
success04: '#189B55',
|
success04: '#189B55',
|
||||||
success05: '#1EC26A',
|
success05: '#1EC26A',
|
||||||
|
|
||||||
warning05: '#F8AE1A',
|
warning05: '#F8AE1A',
|
||||||
warning06: '#ED9E1B'
|
warning06: '#ED9E1B',
|
||||||
|
warning07: '#D77976'
|
||||||
};
|
};
|
||||||
|
|
||||||
// Mapping between the token used and the color
|
// Mapping between the token used and the color
|
||||||
|
@ -51,13 +54,18 @@ export const colorMap = {
|
||||||
ui03: 'surface04',
|
ui03: 'surface04',
|
||||||
ui04: 'surface05',
|
ui04: 'surface05',
|
||||||
ui05: 'surface06',
|
ui05: 'surface06',
|
||||||
|
ui12: 'surface11',
|
||||||
|
|
||||||
// Primary buttons
|
// Primary buttons
|
||||||
action01: 'primary05',
|
action01: 'primary05',
|
||||||
|
action04: 'primary11',
|
||||||
|
|
||||||
// Screen header
|
// Screen header
|
||||||
screen01Header: 'primary10',
|
screen01Header: 'primary10',
|
||||||
|
|
||||||
|
// Status bar
|
||||||
|
status01Bar: 'primary11',
|
||||||
|
|
||||||
// Hover state for primary buttons
|
// Hover state for primary buttons
|
||||||
action01Hover: 'primary06',
|
action01Hover: 'primary06',
|
||||||
|
|
||||||
|
@ -115,6 +123,9 @@ export const colorMap = {
|
||||||
// Disabled state for danger buttons
|
// Disabled state for danger buttons
|
||||||
actionDangerDisabled: 'error03',
|
actionDangerDisabled: 'error03',
|
||||||
|
|
||||||
|
// Underlay color for buttons
|
||||||
|
underlay01: 'surface13',
|
||||||
|
|
||||||
// Bottom sheet background
|
// Bottom sheet background
|
||||||
bottomSheet: 'surface00',
|
bottomSheet: 'surface00',
|
||||||
|
|
||||||
|
@ -130,6 +141,9 @@ export const colorMap = {
|
||||||
// Text for bottom sheet items
|
// Text for bottom sheet items
|
||||||
text04: 'surface12',
|
text04: 'surface12',
|
||||||
|
|
||||||
|
// Text for drawer menu displayed name
|
||||||
|
text05: 'surface06',
|
||||||
|
|
||||||
// error messages
|
// error messages
|
||||||
textError: 'error06',
|
textError: 'error06',
|
||||||
|
|
||||||
|
@ -216,7 +230,10 @@ export const colorMap = {
|
||||||
warning01: 'warning05',
|
warning01: 'warning05',
|
||||||
|
|
||||||
// Color for indicating a raised hand
|
// Color for indicating a raised hand
|
||||||
warning02: 'warning06'
|
warning02: 'warning06',
|
||||||
|
|
||||||
|
// Color for insecure room
|
||||||
|
warning03: 'warning07'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ import React, { useEffect } from 'react';
|
||||||
import { translate } from '../../../base/i18n';
|
import { translate } from '../../../base/i18n';
|
||||||
import JitsiScreen from '../../../base/modal/components/JitsiScreen';
|
import JitsiScreen from '../../../base/modal/components/JitsiScreen';
|
||||||
import { connect } from '../../../base/redux';
|
import { connect } from '../../../base/redux';
|
||||||
import { screen } from '../../../conference/components/native/routes';
|
|
||||||
import { closeChat, openChat } from '../../actions.native';
|
import { closeChat, openChat } from '../../actions.native';
|
||||||
import AbstractChat, {
|
import AbstractChat, {
|
||||||
_mapStateToProps,
|
_mapStateToProps,
|
||||||
|
@ -71,7 +70,8 @@ export default translate(connect(_mapStateToProps)(props => {
|
||||||
_nbUnreadMessages,
|
_nbUnreadMessages,
|
||||||
dispatch,
|
dispatch,
|
||||||
navigation,
|
navigation,
|
||||||
route
|
route,
|
||||||
|
t
|
||||||
} = props;
|
} = props;
|
||||||
const isChatScreenFocused = useIsFocused();
|
const isChatScreenFocused = useIsFocused();
|
||||||
const privateMessageRecipient = route.params?.privateMessageRecipient;
|
const privateMessageRecipient = route.params?.privateMessageRecipient;
|
||||||
|
@ -84,7 +84,7 @@ export default translate(connect(_mapStateToProps)(props => {
|
||||||
dispatch(openChat(privateMessageRecipient));
|
dispatch(openChat(privateMessageRecipient));
|
||||||
|
|
||||||
navigation.setOptions({
|
navigation.setOptions({
|
||||||
tabBarLabel: `${screen.conference.chatandpolls.tab.chat} ${nrUnreadMessages}`
|
tabBarLabel: `${t('chat.tabs.chat')} ${nrUnreadMessages}`
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => dispatch(closeChat());
|
return () => dispatch(closeChat());
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import { NavigationContainer } from '@react-navigation/native';
|
import { NavigationContainer } from '@react-navigation/native';
|
||||||
import { createStackNavigator } from '@react-navigation/stack';
|
import { createStackNavigator } from '@react-navigation/stack';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
|
@ -23,6 +24,7 @@ import {
|
||||||
conferenceScreenOptions,
|
conferenceScreenOptions,
|
||||||
inviteScreenOptions,
|
inviteScreenOptions,
|
||||||
lobbyScreenOptions,
|
lobbyScreenOptions,
|
||||||
|
navigationContainerTheme,
|
||||||
participantsScreenOptions,
|
participantsScreenOptions,
|
||||||
sharedDocumentScreenOptions
|
sharedDocumentScreenOptions
|
||||||
} from './ConferenceNavigatorScreenOptions';
|
} from './ConferenceNavigatorScreenOptions';
|
||||||
|
@ -30,6 +32,7 @@ import { screen } from './routes';
|
||||||
|
|
||||||
const ConferenceStack = createStackNavigator();
|
const ConferenceStack = createStackNavigator();
|
||||||
|
|
||||||
|
|
||||||
const ConferenceNavigationContainer = () => {
|
const ConferenceNavigationContainer = () => {
|
||||||
const isPollsDisabled = useSelector(getDisablePolls);
|
const isPollsDisabled = useSelector(getDisablePolls);
|
||||||
const ChatScreen
|
const ChatScreen
|
||||||
|
@ -40,56 +43,52 @@ const ConferenceNavigationContainer = () => {
|
||||||
= isPollsDisabled
|
= isPollsDisabled
|
||||||
? screen.conference.chat
|
? screen.conference.chat
|
||||||
: screen.conference.chatandpolls.main;
|
: screen.conference.chatandpolls.main;
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SafeAreaProvider>
|
<SafeAreaProvider>
|
||||||
<NavigationContainer
|
<NavigationContainer
|
||||||
independent = { true }
|
independent = { true }
|
||||||
ref = { conferenceNavigationRef }
|
ref = { conferenceNavigationRef }
|
||||||
theme = {{
|
theme = { navigationContainerTheme }>
|
||||||
colors: {
|
|
||||||
background: '#fff'
|
|
||||||
}
|
|
||||||
}}>
|
|
||||||
<ConferenceStack.Navigator
|
<ConferenceStack.Navigator
|
||||||
initialRouteName = { screen.conference.main }
|
initialRouteName = { screen.conference.main }
|
||||||
mode = 'modal'>
|
mode = 'modal'>
|
||||||
<ConferenceStack.Screen
|
<ConferenceStack.Screen
|
||||||
component = { Conference }
|
component = { Conference }
|
||||||
name = { screen.conference.main }
|
name = { screen.conference.main }
|
||||||
options = {{
|
options = { conferenceScreenOptions } />
|
||||||
...conferenceScreenOptions
|
|
||||||
}} />
|
|
||||||
<ConferenceStack.Screen
|
<ConferenceStack.Screen
|
||||||
/* eslint-disable-next-line react/jsx-no-bind */
|
|
||||||
component = { ChatScreen }
|
component = { ChatScreen }
|
||||||
name = { chatScreenName }
|
name = { chatScreenName }
|
||||||
options = {{
|
options = {{
|
||||||
...chatScreenOptions
|
...chatScreenOptions,
|
||||||
|
title: t('chat.title')
|
||||||
}} />
|
}} />
|
||||||
<ConferenceStack.Screen
|
<ConferenceStack.Screen
|
||||||
component = { ParticipantsPane }
|
component = { ParticipantsPane }
|
||||||
name = { screen.conference.participants }
|
name = { screen.conference.participants }
|
||||||
options = {{
|
options = {{
|
||||||
...participantsScreenOptions
|
...participantsScreenOptions,
|
||||||
|
title: t('participantsPane.header')
|
||||||
}} />
|
}} />
|
||||||
<ConferenceStack.Screen
|
<ConferenceStack.Screen
|
||||||
component = { LobbyScreen }
|
component = { LobbyScreen }
|
||||||
name = { screen.lobby }
|
name = { screen.lobby }
|
||||||
options = {{
|
options = { lobbyScreenOptions } />
|
||||||
...lobbyScreenOptions
|
|
||||||
}} />
|
|
||||||
<ConferenceStack.Screen
|
<ConferenceStack.Screen
|
||||||
component = { AddPeopleDialog }
|
component = { AddPeopleDialog }
|
||||||
name = { screen.conference.invite }
|
name = { screen.conference.invite }
|
||||||
options = {{
|
options = {{
|
||||||
...inviteScreenOptions
|
...inviteScreenOptions,
|
||||||
|
title: t('addPeople.add')
|
||||||
}} />
|
}} />
|
||||||
<ConferenceStack.Screen
|
<ConferenceStack.Screen
|
||||||
component = { SharedDocument }
|
component = { SharedDocument }
|
||||||
name = { screen.conference.sharedDocument }
|
name = { screen.conference.sharedDocument }
|
||||||
options = {{
|
options = {{
|
||||||
...sharedDocumentScreenOptions
|
...sharedDocumentScreenOptions,
|
||||||
|
title: t('documentSharing.title')
|
||||||
}} />
|
}} />
|
||||||
</ConferenceStack.Navigator>
|
</ConferenceStack.Navigator>
|
||||||
</NavigationContainer>
|
</NavigationContainer>
|
||||||
|
|
|
@ -1,13 +1,31 @@
|
||||||
|
// @flow
|
||||||
|
/* eslint-disable react/no-multi-comp */
|
||||||
|
|
||||||
import { TransitionPresets } from '@react-navigation/stack';
|
import { TransitionPresets } from '@react-navigation/stack';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Platform } from 'react-native';
|
import { Platform } from 'react-native';
|
||||||
|
|
||||||
import { IconClose } from '../../../base/icons';
|
import {
|
||||||
|
Icon,
|
||||||
|
IconClose,
|
||||||
|
IconHelp,
|
||||||
|
IconHome,
|
||||||
|
IconInfo,
|
||||||
|
IconSettings
|
||||||
|
} from '../../../base/icons';
|
||||||
import BaseTheme from '../../../base/ui/components/BaseTheme';
|
import BaseTheme from '../../../base/ui/components/BaseTheme';
|
||||||
|
|
||||||
import { goBack } from './ConferenceNavigationContainerRef';
|
import { goBack } from './ConferenceNavigationContainerRef';
|
||||||
import HeaderNavigationButton from './HeaderNavigationButton';
|
import HeaderNavigationButton from './HeaderNavigationButton';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigation container theme.
|
||||||
|
*/
|
||||||
|
export const navigationContainerTheme = {
|
||||||
|
colors: {
|
||||||
|
background: BaseTheme.palette.ui12
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default modal transition for the current platform.
|
* Default modal transition for the current platform.
|
||||||
|
@ -20,24 +38,126 @@ export const conferenceModalPresentation = Platform.select({
|
||||||
/**
|
/**
|
||||||
* Screen options and transition types.
|
* Screen options and transition types.
|
||||||
*/
|
*/
|
||||||
export const screenOptions = {
|
export const fullScreenOptions = {
|
||||||
...TransitionPresets.ModalTransition,
|
...TransitionPresets.ModalTransition,
|
||||||
gestureEnabled: false,
|
gestureEnabled: false,
|
||||||
headerShown: false
|
headerShown: false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dial-IN Info screen options and transition types.
|
||||||
|
*/
|
||||||
|
export const dialInSummaryScreenOptions = {
|
||||||
|
...TransitionPresets.ModalTransition,
|
||||||
|
gestureEnabled: true,
|
||||||
|
headerShown: true,
|
||||||
|
headerStyle: {
|
||||||
|
backgroundColor: BaseTheme.palette.screen01Header
|
||||||
|
},
|
||||||
|
headerTitleStyle: {
|
||||||
|
color: BaseTheme.palette.text01
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drawer navigator screens options and transition types.
|
||||||
|
*/
|
||||||
|
export const drawerNavigatorScreenOptions = {
|
||||||
|
...TransitionPresets.ModalTransition,
|
||||||
|
gestureEnabled: true,
|
||||||
|
headerShown: false
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drawer screen options and transition types.
|
||||||
|
*/
|
||||||
|
export const drawerScreenOptions = {
|
||||||
|
...TransitionPresets.ModalTransition,
|
||||||
|
gestureEnabled: true,
|
||||||
|
headerShown: true,
|
||||||
|
headerStyle: {
|
||||||
|
backgroundColor: BaseTheme.palette.screen01Header
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Screen options for welcome page.
|
||||||
|
*/
|
||||||
|
export const welcomeScreenOptions = {
|
||||||
|
...drawerScreenOptions,
|
||||||
|
drawerIcon: ({ focused }) => (
|
||||||
|
<Icon
|
||||||
|
color = { focused ? BaseTheme.palette.screen01Header : BaseTheme.palette.field01Disabled }
|
||||||
|
size = { 20 }
|
||||||
|
src = { IconHome } />
|
||||||
|
),
|
||||||
|
headerTitleStyle: {
|
||||||
|
color: BaseTheme.palette.screen01Header
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Screen options for settings screen.
|
||||||
|
*/
|
||||||
|
export const settingsScreenOptions = {
|
||||||
|
...drawerScreenOptions,
|
||||||
|
drawerIcon: ({ focused }) => (
|
||||||
|
<Icon
|
||||||
|
color = { focused ? BaseTheme.palette.screen01Header : BaseTheme.palette.field01Disabled }
|
||||||
|
size = { 20 }
|
||||||
|
src = { IconSettings } />
|
||||||
|
),
|
||||||
|
headerTitleStyle: {
|
||||||
|
color: BaseTheme.palette.text01
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Screen options for terms/privacy screens.
|
||||||
|
*/
|
||||||
|
export const termsAndPrivacyScreenOptions = {
|
||||||
|
...drawerScreenOptions,
|
||||||
|
drawerIcon: ({ focused }) => (
|
||||||
|
<Icon
|
||||||
|
color = { focused ? BaseTheme.palette.screen01Header : BaseTheme.palette.field01Disabled }
|
||||||
|
size = { 20 }
|
||||||
|
src = { IconInfo } />
|
||||||
|
),
|
||||||
|
headerTitleStyle: {
|
||||||
|
color: BaseTheme.palette.text01
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Screen options for help screen.
|
||||||
|
*/
|
||||||
|
export const helpScreenOptions = {
|
||||||
|
...drawerScreenOptions,
|
||||||
|
drawerIcon: ({ focused }) => (
|
||||||
|
<Icon
|
||||||
|
color = { focused ? BaseTheme.palette.screen01Header : BaseTheme.palette.field01Disabled }
|
||||||
|
size = { 20 }
|
||||||
|
src = { IconHelp } />
|
||||||
|
),
|
||||||
|
headerTitleStyle: {
|
||||||
|
color: BaseTheme.palette.text01
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Screen options for conference.
|
* Screen options for conference.
|
||||||
*/
|
*/
|
||||||
export const conferenceScreenOptions = {
|
export const conferenceScreenOptions = {
|
||||||
...screenOptions
|
...fullScreenOptions
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Screen options for lobby modal.
|
* Screen options for lobby modal.
|
||||||
*/
|
*/
|
||||||
export const lobbyScreenOptions = {
|
export const lobbyScreenOptions = {
|
||||||
...screenOptions
|
...fullScreenOptions
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { TouchableWithoutFeedback } from 'react-native';
|
import { TouchableOpacity } from 'react-native-gesture-handler';
|
||||||
|
|
||||||
import { Icon } from '../../../base/icons';
|
import { Icon } from '../../../base/icons';
|
||||||
|
|
||||||
|
@ -22,17 +22,18 @@ type Props = {
|
||||||
/**
|
/**
|
||||||
* The component's external style.
|
* The component's external style.
|
||||||
*/
|
*/
|
||||||
style: Object
|
style?: Object
|
||||||
}
|
}
|
||||||
|
|
||||||
const HeaderNavigationButton = ({ onPress, src, style }: Props) => (
|
const HeaderNavigationButton = ({ onPress, src, style }: Props) => (
|
||||||
<TouchableWithoutFeedback
|
<TouchableOpacity
|
||||||
onPress = { onPress } >
|
onPress = { onPress }
|
||||||
|
style = { styles.headerNavigationButton } >
|
||||||
<Icon
|
<Icon
|
||||||
size = { 20 }
|
size = { 20 }
|
||||||
src = { src }
|
src = { src }
|
||||||
style = { [ styles.headerNavigationButton, style ] } />
|
style = { [ styles.headerNavigationIcon, style ] } />
|
||||||
</TouchableWithoutFeedback>
|
</TouchableOpacity>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,12 @@
|
||||||
export const screen = {
|
export const screen = {
|
||||||
|
welcome: {
|
||||||
|
main: 'Home',
|
||||||
|
settings: 'Settings',
|
||||||
|
terms: 'Terms',
|
||||||
|
privacy: 'Privacy',
|
||||||
|
help: 'Help'
|
||||||
|
},
|
||||||
|
dialInSummary: 'Dial-In Info',
|
||||||
conference: {
|
conference: {
|
||||||
main: 'Conference',
|
main: 'Conference',
|
||||||
chat: 'Chat',
|
chat: 'Chat',
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { ColorSchemeRegistry, schemeColor } from '../../../base/color-scheme';
|
import { ColorSchemeRegistry, schemeColor } from '../../../base/color-scheme';
|
||||||
import { BoxModel, ColorPalette, fixAndroidViewClipping } from '../../../base/styles';
|
import { BoxModel, fixAndroidViewClipping } from '../../../base/styles';
|
||||||
|
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
|
||||||
|
|
||||||
export const INSECURE_ROOM_NAME_LABEL_COLOR = ColorPalette.warning;
|
export const INSECURE_ROOM_NAME_LABEL_COLOR = BaseTheme.palette.warning03;
|
||||||
|
|
||||||
const NAVBAR_BUTTON_SIZE = 24;
|
const NAVBAR_BUTTON_SIZE = 24;
|
||||||
|
|
||||||
|
@ -15,7 +16,7 @@ export default {
|
||||||
*/
|
*/
|
||||||
conference: fixAndroidViewClipping({
|
conference: fixAndroidViewClipping({
|
||||||
alignSelf: 'stretch',
|
alignSelf: 'stretch',
|
||||||
backgroundColor: '#040404',
|
backgroundColor: BaseTheme.palette.uiBackground,
|
||||||
flex: 1
|
flex: 1
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
@ -23,10 +24,16 @@ export default {
|
||||||
margin: 10
|
margin: 10
|
||||||
},
|
},
|
||||||
|
|
||||||
headerNavigationButton: {
|
headerNavigationIcon: {
|
||||||
marginLeft: 12
|
marginLeft: 12
|
||||||
},
|
},
|
||||||
|
|
||||||
|
headerNavigationButton: {
|
||||||
|
height: BaseTheme.spacing[6],
|
||||||
|
marginTop: BaseTheme.spacing[3],
|
||||||
|
width: BaseTheme.spacing[6]
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View that contains the indicators.
|
* View that contains the indicators.
|
||||||
*/
|
*/
|
||||||
|
@ -45,17 +52,17 @@ export default {
|
||||||
inviteButton: {
|
inviteButton: {
|
||||||
iconStyle: {
|
iconStyle: {
|
||||||
padding: 10,
|
padding: 10,
|
||||||
color: ColorPalette.white,
|
color: BaseTheme.palette.icon01,
|
||||||
fontSize: NAVBAR_BUTTON_SIZE
|
fontSize: NAVBAR_BUTTON_SIZE
|
||||||
},
|
},
|
||||||
underlayColor: ColorPalette.buttonUnderlay
|
underlayColor: BaseTheme.spacing.underlay01
|
||||||
},
|
},
|
||||||
|
|
||||||
lonelyButton: {
|
lonelyButton: {
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
borderRadius: 24,
|
borderRadius: 24,
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
height: 48,
|
height: BaseTheme.spacing[6],
|
||||||
justifyContent: 'space-around',
|
justifyContent: 'space-around',
|
||||||
paddingHorizontal: 12
|
paddingHorizontal: 12
|
||||||
},
|
},
|
||||||
|
@ -84,10 +91,10 @@ export default {
|
||||||
pipButton: {
|
pipButton: {
|
||||||
iconStyle: {
|
iconStyle: {
|
||||||
padding: 10,
|
padding: 10,
|
||||||
color: ColorPalette.white,
|
color: BaseTheme.palette.icon01,
|
||||||
fontSize: NAVBAR_BUTTON_SIZE
|
fontSize: NAVBAR_BUTTON_SIZE
|
||||||
},
|
},
|
||||||
underlayColor: ColorPalette.buttonUnderlay
|
underlayColor: BaseTheme.palette.underlay01
|
||||||
},
|
},
|
||||||
|
|
||||||
navBarSafeView: {
|
navBarSafeView: {
|
||||||
|
@ -107,7 +114,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
roomTimer: {
|
roomTimer: {
|
||||||
color: ColorPalette.white,
|
color: BaseTheme.palette.text01,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: '400',
|
fontWeight: '400',
|
||||||
paddingHorizontal: 8
|
paddingHorizontal: 8
|
||||||
|
@ -123,7 +130,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
roomName: {
|
roomName: {
|
||||||
color: ColorPalette.white,
|
color: BaseTheme.palette.text01,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: '400'
|
fontWeight: '400'
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,7 +15,8 @@ export * from './functions.any';
|
||||||
* @returns {boolean}.
|
* @returns {boolean}.
|
||||||
*/
|
*/
|
||||||
export function getDisablePolls(stateful: Object) {
|
export function getDisablePolls(stateful: Object) {
|
||||||
const state = toState(stateful['features/base/config']);
|
const state = toState(stateful)['features/base/config'];
|
||||||
|
|
||||||
return state.disablePolls;
|
return state.disablePolls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,6 @@ class SharedDocument extends PureComponent<Props> {
|
||||||
return (
|
return (
|
||||||
<JitsiScreen
|
<JitsiScreen
|
||||||
addHeaderHeightValue = { true }
|
addHeaderHeightValue = { true }
|
||||||
hasTabNavigator = { false }
|
|
||||||
style = { styles.sharedDocContainer }>
|
style = { styles.sharedDocContainer }>
|
||||||
<WebView
|
<WebView
|
||||||
renderLoading = { this._renderLoading }
|
renderLoading = { this._renderLoading }
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import React, { PureComponent } from 'react';
|
|
||||||
import WebView from 'react-native-webview';
|
|
||||||
|
|
||||||
import { JitsiModal } from '../../base/modal';
|
|
||||||
import { connect } from '../../base/redux';
|
|
||||||
import { HELP_VIEW_MODAL_ID } from '../constants';
|
|
||||||
|
|
||||||
const DEFAULT_HELP_CENTRE_URL = 'https://web-cdn.jitsi.net/faq/meet-faq.html';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The URL to display in the Help Centre.
|
|
||||||
*/
|
|
||||||
_url: string
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements a page that renders the help content for the app.
|
|
||||||
*/
|
|
||||||
class HelpView extends PureComponent<Props> {
|
|
||||||
/**
|
|
||||||
* Implements {@code PureComponent#render()}.
|
|
||||||
*
|
|
||||||
* @inheritdoc
|
|
||||||
* @returns {ReactElement}
|
|
||||||
*/
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<JitsiModal
|
|
||||||
headerProps = {{
|
|
||||||
headerLabelKey: 'helpView.header'
|
|
||||||
}}
|
|
||||||
modalId = { HELP_VIEW_MODAL_ID }>
|
|
||||||
<WebView source = {{ uri: this.props._url }} />
|
|
||||||
</JitsiModal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maps part of the Redux state to the props of this component.
|
|
||||||
*
|
|
||||||
* @param {Object} state - The Redux state.
|
|
||||||
* @returns {Props}
|
|
||||||
*/
|
|
||||||
function _mapStateToProps(state) {
|
|
||||||
return {
|
|
||||||
_url: state['features/base/config'].helpCentreURL || DEFAULT_HELP_CENTRE_URL
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(_mapStateToProps)(HelpView);
|
|
|
@ -1,3 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
export { default as HelpView } from './HelpView';
|
|
|
@ -1,3 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
export const HELP_VIEW_MODAL_ID = 'helpView';
|
|
|
@ -1,4 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
export * from './components';
|
|
||||||
export * from './constants';
|
|
|
@ -210,7 +210,6 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
|
||||||
return (
|
return (
|
||||||
<JitsiScreen
|
<JitsiScreen
|
||||||
footerComponent = { this._renderShareMeetingButton }
|
footerComponent = { this._renderShareMeetingButton }
|
||||||
hasTabNavigator = { false }
|
|
||||||
style = { styles.addPeopleContainer }>
|
style = { styles.addPeopleContainer }>
|
||||||
<ClearableInput
|
<ClearableInput
|
||||||
autoFocus = { false }
|
autoFocus = { false }
|
||||||
|
|
|
@ -7,10 +7,11 @@ import { type Dispatch } from 'redux';
|
||||||
|
|
||||||
import { openDialog } from '../../../../base/dialog';
|
import { openDialog } from '../../../../base/dialog';
|
||||||
import { translate } from '../../../../base/i18n';
|
import { translate } from '../../../../base/i18n';
|
||||||
import { JitsiModal, setActiveModalId } from '../../../../base/modal';
|
import JitsiScreen from '../../../../base/modal/components/JitsiScreen';
|
||||||
import { LoadingIndicator } from '../../../../base/react';
|
import { LoadingIndicator } from '../../../../base/react';
|
||||||
import { connect } from '../../../../base/redux';
|
import { connect } from '../../../../base/redux';
|
||||||
import { DIAL_IN_SUMMARY_VIEW_ID } from '../../../constants';
|
import { screen } from '../../../../conference/components/native/routes';
|
||||||
|
import { renderArrowBackButton } from '../../../../welcome/functions.native';
|
||||||
import { getDialInfoPageURLForURIString } from '../../../functions';
|
import { getDialInfoPageURLForURIString } from '../../../functions';
|
||||||
|
|
||||||
import DialInSummaryErrorDialog from './DialInSummaryErrorDialog';
|
import DialInSummaryErrorDialog from './DialInSummaryErrorDialog';
|
||||||
|
@ -18,12 +19,17 @@ import styles, { INDICATOR_COLOR } from './styles';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
||||||
/**
|
dispatch: Dispatch<any>,
|
||||||
* The URL to display the summary for.
|
|
||||||
*/
|
|
||||||
_summaryUrl: ?string,
|
|
||||||
|
|
||||||
dispatch: Dispatch<any>
|
/**
|
||||||
|
* Default prop for navigating between screen components(React Navigation).
|
||||||
|
*/
|
||||||
|
navigation: Object,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default prop for navigating between screen components(React Navigation).
|
||||||
|
*/
|
||||||
|
route: Object
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,29 +50,46 @@ class DialInSummary extends Component<Props> {
|
||||||
this._renderLoading = this._renderLoading.bind(this);
|
this._renderLoading = this._renderLoading.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements React's {@link Component#componentDidMount()}. Invoked
|
||||||
|
* immediately after mounting occurs.
|
||||||
|
*
|
||||||
|
* @inheritdoc
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
componentDidMount() {
|
||||||
|
const {
|
||||||
|
navigation
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
navigation.setOptions({
|
||||||
|
headerLeft: () =>
|
||||||
|
renderArrowBackButton(() =>
|
||||||
|
navigation.navigate(screen.welcome.main))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements React's {@link Component#render()}.
|
* Implements React's {@link Component#render()}.
|
||||||
*
|
*
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
const { _summaryUrl } = this.props;
|
const { route } = this.props;
|
||||||
|
const summaryUrl = route.params?.summaryUrl;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<JitsiModal
|
<JitsiScreen
|
||||||
headerProps = {{
|
|
||||||
headerLabelKey: 'info.label'
|
|
||||||
}}
|
|
||||||
modalId = { DIAL_IN_SUMMARY_VIEW_ID }
|
|
||||||
style = { styles.backDrop }>
|
style = { styles.backDrop }>
|
||||||
<WebView
|
<WebView
|
||||||
onError = { this._onError }
|
onError = { this._onError }
|
||||||
onShouldStartLoadWithRequest = { this._onNavigate }
|
onShouldStartLoadWithRequest = { this._onNavigate }
|
||||||
renderLoading = { this._renderLoading }
|
renderLoading = { this._renderLoading }
|
||||||
source = {{ uri: getDialInfoPageURLForURIString(_summaryUrl) }}
|
setSupportMultipleWindows = { false }
|
||||||
|
source = {{ uri: getDialInfoPageURLForURIString(summaryUrl) }}
|
||||||
startInLoadingState = { true }
|
startInLoadingState = { true }
|
||||||
style = { styles.webView } />
|
style = { styles.webView } />
|
||||||
</JitsiModal>
|
</JitsiScreen>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +101,6 @@ class DialInSummary extends Component<Props> {
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
_onError() {
|
_onError() {
|
||||||
this.props.dispatch(setActiveModalId());
|
|
||||||
this.props.dispatch(openDialog(DialInSummaryErrorDialog));
|
this.props.dispatch(openDialog(DialInSummaryErrorDialog));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,14 +116,14 @@ class DialInSummary extends Component<Props> {
|
||||||
*/
|
*/
|
||||||
_onNavigate(request) {
|
_onNavigate(request) {
|
||||||
const { url } = request;
|
const { url } = request;
|
||||||
|
const { route } = this.props;
|
||||||
|
const summaryUrl = route.params?.summaryUrl;
|
||||||
|
|
||||||
if (url.startsWith('tel:')) {
|
if (url.startsWith('tel:')) {
|
||||||
Linking.openURL(url);
|
Linking.openURL(url);
|
||||||
|
|
||||||
this.props.dispatch(setActiveModalId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return url === getDialInfoPageURLForURIString(this.props._summaryUrl);
|
return url === getDialInfoPageURLForURIString(summaryUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderLoading: () => React$Component<any>;
|
_renderLoading: () => React$Component<any>;
|
||||||
|
@ -122,18 +144,4 @@ class DialInSummary extends Component<Props> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export default translate(connect()(DialInSummary));
|
||||||
* Maps part of the Redux state to the props of this component.
|
|
||||||
*
|
|
||||||
* @param {Object} state - The Redux state.
|
|
||||||
* @returns {{
|
|
||||||
* _summaryUrl: ?string
|
|
||||||
* }}
|
|
||||||
*/
|
|
||||||
function _mapStateToProps(state) {
|
|
||||||
return {
|
|
||||||
_summaryUrl: (state['features/base/modal'].modalProps || {}).summaryUrl
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default translate(connect(_mapStateToProps)(DialInSummary));
|
|
||||||
|
|
|
@ -9,7 +9,8 @@ const WV_BACKGROUND = 'rgb(71, 71, 71)';
|
||||||
export default {
|
export default {
|
||||||
|
|
||||||
backDrop: {
|
backDrop: {
|
||||||
backgroundColor: WV_BACKGROUND
|
backgroundColor: WV_BACKGROUND,
|
||||||
|
flex: 1
|
||||||
},
|
},
|
||||||
|
|
||||||
indicatorWrapper: {
|
indicatorWrapper: {
|
||||||
|
|
|
@ -28,7 +28,6 @@ class LobbyScreen extends AbstractLobbyScreen {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<JitsiScreen
|
<JitsiScreen
|
||||||
hasTabNavigator = { false }
|
|
||||||
style = { styles.contentWrapper }>
|
style = { styles.contentWrapper }>
|
||||||
<SafeAreaView>
|
<SafeAreaView>
|
||||||
<Text style = { styles.dialogTitle }>
|
<Text style = { styles.dialogTitle }>
|
||||||
|
|
|
@ -35,7 +35,6 @@ const ParticipantsPane = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<JitsiScreen
|
<JitsiScreen
|
||||||
hasTabNavigator = { false }
|
|
||||||
style = { styles.participantsPane }>
|
style = { styles.participantsPane }>
|
||||||
<ScrollView bounces = { false }>
|
<ScrollView bounces = { false }>
|
||||||
<LobbyParticipantList />
|
<LobbyParticipantList />
|
||||||
|
|
|
@ -8,7 +8,6 @@ import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
import JitsiScreen from '../../../base/modal/components/JitsiScreen';
|
import JitsiScreen from '../../../base/modal/components/JitsiScreen';
|
||||||
import { BUTTON_MODES } from '../../../chat/constants';
|
import { BUTTON_MODES } from '../../../chat/constants';
|
||||||
import { screen } from '../../../conference/components/native/routes';
|
|
||||||
import { getUnreadPollCount } from '../../functions';
|
import { getUnreadPollCount } from '../../functions';
|
||||||
import AbstractPollsPane from '../AbstractPollsPane';
|
import AbstractPollsPane from '../AbstractPollsPane';
|
||||||
import type { AbstractProps } from '../AbstractPollsPane';
|
import type { AbstractProps } from '../AbstractPollsPane';
|
||||||
|
@ -31,7 +30,7 @@ const PollsPane = (props: AbstractProps) => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
navigation.setOptions({
|
navigation.setOptions({
|
||||||
tabBarLabel: `${screen.conference.chatandpolls.tab.polls} ${nrUnreadPolls}`
|
tabBarLabel: `${t('chat.tabs.polls')} ${nrUnreadPolls}`
|
||||||
});
|
});
|
||||||
}, [ nrUnreadPolls ]);
|
}, [ nrUnreadPolls ]);
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
import { translate } from '../../base/i18n';
|
import { translate } from '../../base/i18n';
|
||||||
import { IconInfo } from '../../base/icons';
|
import { IconInfo } from '../../base/icons';
|
||||||
import { setActiveModalId } from '../../base/modal';
|
|
||||||
import { connect } from '../../base/redux';
|
import { connect } from '../../base/redux';
|
||||||
import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox/components';
|
import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox/components';
|
||||||
import { DIAL_IN_SUMMARY_VIEW_ID } from '../../invite/constants';
|
import { screen } from '../../conference/components/native/routes';
|
||||||
|
import { navigate } from '../../welcome/components/RootNavigationContainerRef';
|
||||||
|
|
||||||
export type Props = AbstractButtonProps & {
|
export type Props = AbstractButtonProps & {
|
||||||
|
|
||||||
|
@ -40,9 +40,11 @@ class ShowDialInInfoButton extends AbstractButton<Props, *> {
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
_handleClick() {
|
_handleClick() {
|
||||||
const { dispatch, itemId } = this.props;
|
const { itemId } = this.props;
|
||||||
|
|
||||||
dispatch(setActiveModalId(DIAL_IN_SUMMARY_VIEW_ID, { summaryUrl: itemId.url }));
|
navigate(screen.dialInSummary, {
|
||||||
|
summaryUrl: itemId.url
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
export * from './native';
|
|
|
@ -13,7 +13,7 @@ import { isRecentListEnabled } from '../../recent-list/functions';
|
||||||
/**
|
/**
|
||||||
* {@code AbstractWelcomePage}'s React {@code Component} prop types.
|
* {@code AbstractWelcomePage}'s React {@code Component} prop types.
|
||||||
*/
|
*/
|
||||||
type Props = {
|
export type Props = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the calendar functionality is enabled or not.
|
* Whether the calendar functionality is enabled or not.
|
||||||
|
@ -56,7 +56,7 @@ type Props = {
|
||||||
*
|
*
|
||||||
* @abstract
|
* @abstract
|
||||||
*/
|
*/
|
||||||
export class AbstractWelcomePage extends Component<Props, *> {
|
export class AbstractWelcomePage<P: Props> extends Component<P, *> {
|
||||||
_mounted: ?boolean;
|
_mounted: ?boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -64,7 +64,7 @@ export class AbstractWelcomePage extends Component<Props, *> {
|
||||||
*
|
*
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
static getDerivedStateFromProps(props: Props, state: Object) {
|
static getDerivedStateFromProps(props: P, state: Object) {
|
||||||
return {
|
return {
|
||||||
room: props._room || state.room
|
room: props._room || state.room
|
||||||
};
|
};
|
||||||
|
@ -99,7 +99,7 @@ export class AbstractWelcomePage extends Component<Props, *> {
|
||||||
* @param {Props} props - The React {@code Component} props to initialize
|
* @param {Props} props - The React {@code Component} props to initialize
|
||||||
* the new {@code AbstractWelcomePage} instance with.
|
* the new {@code AbstractWelcomePage} instance with.
|
||||||
*/
|
*/
|
||||||
constructor(props: Props) {
|
constructor(props: P) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
// Bind event handlers so they are only bound once per instance.
|
// Bind event handlers so they are only bound once per instance.
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import { DrawerItemList } from '@react-navigation/drawer';
|
||||||
|
import React from 'react';
|
||||||
|
import { ScrollView, Text, View } from 'react-native';
|
||||||
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||||
|
|
||||||
|
import { Avatar } from '../../base/avatar';
|
||||||
|
import {
|
||||||
|
getLocalParticipant, getParticipantDisplayName
|
||||||
|
} from '../../base/participants';
|
||||||
|
import { connect } from '../../base/redux';
|
||||||
|
|
||||||
|
import styles, { DRAWER_AVATAR_SIZE } from './styles';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local participant name to be displayed.
|
||||||
|
*/
|
||||||
|
displayName: string,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ID of the local participant.
|
||||||
|
*/
|
||||||
|
localParticipantId: string
|
||||||
|
};
|
||||||
|
|
||||||
|
const CustomDrawerContent = (props: Props) => (
|
||||||
|
<ScrollView bounces = { false }>
|
||||||
|
<View style = { styles.drawerHeader }>
|
||||||
|
<Avatar
|
||||||
|
participantId = { props.localParticipantId }
|
||||||
|
size = { DRAWER_AVATAR_SIZE } />
|
||||||
|
<Text style = { styles.displayName }>
|
||||||
|
{ props.displayName }
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<SafeAreaView
|
||||||
|
edges = { [
|
||||||
|
'left',
|
||||||
|
'right'
|
||||||
|
] }>
|
||||||
|
<DrawerItemList { ...props } />
|
||||||
|
</SafeAreaView>
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps (parts of) the redux state to the React {@code Component} props.
|
||||||
|
*
|
||||||
|
* @param {Object} state - The redux state.
|
||||||
|
* @protected
|
||||||
|
* @returns {Props}
|
||||||
|
*/
|
||||||
|
function mapStateToProps(state: Object) {
|
||||||
|
const localParticipant = getLocalParticipant(state);
|
||||||
|
const localParticipantId = localParticipant?.id;
|
||||||
|
const displayName = localParticipant && getParticipantDisplayName(state, localParticipantId);
|
||||||
|
|
||||||
|
return {
|
||||||
|
displayName,
|
||||||
|
localParticipantId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps)(CustomDrawerContent);
|
|
@ -0,0 +1,74 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import { NavigationContainer } from '@react-navigation/native';
|
||||||
|
import { createStackNavigator } from '@react-navigation/stack';
|
||||||
|
import React from 'react';
|
||||||
|
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||||
|
|
||||||
|
import { connect } from '../../base/redux';
|
||||||
|
import {
|
||||||
|
dialInSummaryScreenOptions,
|
||||||
|
drawerNavigatorScreenOptions,
|
||||||
|
navigationContainerTheme
|
||||||
|
} from '../../conference/components/native/ConferenceNavigatorScreenOptions';
|
||||||
|
import { screen } from '../../conference/components/native/routes';
|
||||||
|
import { DialInSummary } from '../../invite';
|
||||||
|
import { isWelcomePageAppEnabled } from '../functions.native';
|
||||||
|
|
||||||
|
import BlankPage from './BlankPage';
|
||||||
|
import { rootNavigationRef } from './RootNavigationContainerRef';
|
||||||
|
import WelcomePageNavigationContainer from './WelcomePageNavigationContainer';
|
||||||
|
|
||||||
|
const RootStack = createStackNavigator();
|
||||||
|
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is welcome page available?
|
||||||
|
*/
|
||||||
|
isWelcomePageAvailable: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const RootNavigationContainer = ({ isWelcomePageAvailable }: Props) => (
|
||||||
|
<SafeAreaProvider>
|
||||||
|
<NavigationContainer
|
||||||
|
independent = { true }
|
||||||
|
ref = { rootNavigationRef }
|
||||||
|
theme = { navigationContainerTheme }>
|
||||||
|
<RootStack.Navigator
|
||||||
|
initialRouteName = { screen.welcome.main }>
|
||||||
|
{
|
||||||
|
isWelcomePageAvailable
|
||||||
|
? <RootStack.Screen
|
||||||
|
component = { WelcomePageNavigationContainer }
|
||||||
|
name = { screen.welcome.main }
|
||||||
|
options = { drawerNavigatorScreenOptions } />
|
||||||
|
: <RootStack.Screen
|
||||||
|
component = { BlankPage }
|
||||||
|
name = { screen.welcome.main } />
|
||||||
|
}
|
||||||
|
<RootStack.Screen
|
||||||
|
component = { DialInSummary }
|
||||||
|
name = { screen.dialInSummary }
|
||||||
|
options = { dialInSummaryScreenOptions } />
|
||||||
|
</RootStack.Navigator>
|
||||||
|
</NavigationContainer>
|
||||||
|
</SafeAreaProvider>
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps part of the Redux store to the props of this component.
|
||||||
|
*
|
||||||
|
* @param {Object} state - The Redux state.
|
||||||
|
* @returns {Props}
|
||||||
|
*/
|
||||||
|
function mapStateToProps(state: Object) {
|
||||||
|
return {
|
||||||
|
isWelcomePageAvailable: isWelcomePageAppEnabled(state)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps)(RootNavigationContainer);
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
// $FlowExpectedError
|
||||||
|
export const rootNavigationRef = React.createRef();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User defined navigation action included inside the reference to the container.
|
||||||
|
*
|
||||||
|
* @param {string} name - Destination name of the route that has been defined somewhere.
|
||||||
|
* @param {Object} params - Params to pass to the destination route.
|
||||||
|
* @returns {Function}
|
||||||
|
*/
|
||||||
|
export function navigate(name: string, params: Object) {
|
||||||
|
// $FlowExpectedError
|
||||||
|
return rootNavigationRef.current?.navigate(name, params);
|
||||||
|
}
|
||||||
|
|
|
@ -1,101 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { Linking, Text, TouchableOpacity, View } from 'react-native';
|
|
||||||
|
|
||||||
import { translate } from '../../base/i18n';
|
|
||||||
import { Icon } from '../../base/icons';
|
|
||||||
|
|
||||||
import styles from './styles';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The icon of the item.
|
|
||||||
*/
|
|
||||||
icon: Object,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The i18n label of the item.
|
|
||||||
*/
|
|
||||||
label: string,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The function to be invoked when the item is pressed
|
|
||||||
* if the item is a button.
|
|
||||||
*/
|
|
||||||
onPress: Function,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The translate function.
|
|
||||||
*/
|
|
||||||
t: Function,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The URL of the link, if this item is a link.
|
|
||||||
*/
|
|
||||||
url: string
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A component rendering an item in the system sidebar.
|
|
||||||
*/
|
|
||||||
class SideBarItem extends Component<Props> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes a new {@code SideBarItem} instance.
|
|
||||||
*
|
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
// Bind event handlers so they are only bound once per instance.
|
|
||||||
this._onOpenURL = this._onOpenURL.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements React's {@link Component#render()}, renders the sidebar item.
|
|
||||||
*
|
|
||||||
* @inheritdoc
|
|
||||||
* @returns {ReactElement}
|
|
||||||
*/
|
|
||||||
render() {
|
|
||||||
const { label, onPress, t } = this.props;
|
|
||||||
const onPressCalculated
|
|
||||||
= typeof onPress === 'function' ? onPress : this._onOpenURL;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TouchableOpacity
|
|
||||||
onPress = { onPressCalculated }
|
|
||||||
style = { styles.sideBarItem }>
|
|
||||||
<View style = { styles.sideBarItemButtonContainer }>
|
|
||||||
<Icon
|
|
||||||
src = { this.props.icon }
|
|
||||||
style = { styles.sideBarItemIcon } />
|
|
||||||
<Text style = { styles.sideBarItemText }>
|
|
||||||
{ t(label) }
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
</TouchableOpacity>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_onOpenURL: () => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens the URL if one is provided.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
_onOpenURL() {
|
|
||||||
const { url } = this.props;
|
|
||||||
|
|
||||||
if (typeof url === 'string') {
|
|
||||||
Linking.openURL(url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default translate(SideBarItem);
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import { DrawerActions } from '@react-navigation/native';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {
|
import {
|
||||||
Animated,
|
Animated,
|
||||||
Keyboard,
|
|
||||||
SafeAreaView,
|
SafeAreaView,
|
||||||
TextInput,
|
TextInput,
|
||||||
TouchableHighlight,
|
TouchableHighlight,
|
||||||
|
@ -14,7 +16,8 @@ import { ColorSchemeRegistry } from '../../base/color-scheme';
|
||||||
import { translate } from '../../base/i18n';
|
import { translate } from '../../base/i18n';
|
||||||
import { Icon, IconMenu, IconWarning } from '../../base/icons';
|
import { Icon, IconMenu, IconWarning } from '../../base/icons';
|
||||||
import { MEDIA_TYPE } from '../../base/media';
|
import { MEDIA_TYPE } from '../../base/media';
|
||||||
import { Header, LoadingIndicator, Text } from '../../base/react';
|
import JitsiStatusBar from '../../base/modal/components/JitsiStatusBar';
|
||||||
|
import { LoadingIndicator, Text } from '../../base/react';
|
||||||
import { connect } from '../../base/redux';
|
import { connect } from '../../base/redux';
|
||||||
import { ColorPalette } from '../../base/styles';
|
import { ColorPalette } from '../../base/styles';
|
||||||
import {
|
import {
|
||||||
|
@ -22,41 +25,63 @@ import {
|
||||||
destroyLocalDesktopTrackIfExists,
|
destroyLocalDesktopTrackIfExists,
|
||||||
destroyLocalTracks
|
destroyLocalTracks
|
||||||
} from '../../base/tracks';
|
} from '../../base/tracks';
|
||||||
import { HelpView } from '../../help';
|
|
||||||
import { DialInSummary } from '../../invite';
|
|
||||||
import { SettingsView } from '../../settings/components';
|
|
||||||
import { setSideBarVisible } from '../actions';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AbstractWelcomePage,
|
AbstractWelcomePage,
|
||||||
_mapStateToProps as _abstractMapStateToProps
|
_mapStateToProps as _abstractMapStateToProps,
|
||||||
|
type Props as AbstractProps
|
||||||
} from './AbstractWelcomePage';
|
} from './AbstractWelcomePage';
|
||||||
import LocalVideoTrackUnderlay from './LocalVideoTrackUnderlay';
|
import LocalVideoTrackUnderlay from './LocalVideoTrackUnderlay';
|
||||||
import VideoSwitch from './VideoSwitch';
|
import VideoSwitch from './VideoSwitch';
|
||||||
import WelcomePageLists from './WelcomePageLists';
|
import WelcomePageLists from './WelcomePageLists';
|
||||||
import WelcomePageSideBar from './WelcomePageSideBar';
|
|
||||||
import styles, { PLACEHOLDER_TEXT_COLOR } from './styles';
|
import styles, { PLACEHOLDER_TEXT_COLOR } from './styles';
|
||||||
|
|
||||||
|
|
||||||
|
type Props = AbstractProps & {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color schemed style of the Header component.
|
||||||
|
*/
|
||||||
|
_headerStyles: Object,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default prop for navigating between screen components(React Navigation).
|
||||||
|
*/
|
||||||
|
navigation: Object,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default prop for navigating between screen components(React Navigation).
|
||||||
|
*/
|
||||||
|
route: Object,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The translate function.
|
||||||
|
*/
|
||||||
|
t: Function
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The native container rendering the welcome page.
|
* The native container rendering the welcome page.
|
||||||
*
|
*
|
||||||
* @augments AbstractWelcomePage
|
* @augments AbstractWelcomePage
|
||||||
*/
|
*/
|
||||||
class WelcomePage extends AbstractWelcomePage {
|
class WelcomePage extends AbstractWelcomePage<*> {
|
||||||
/**
|
/**
|
||||||
* Constructor of the Component.
|
* Constructor of the Component.
|
||||||
*
|
*
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
constructor(props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
|
// $FlowExpectedError
|
||||||
this.state._fieldFocused = false;
|
this.state._fieldFocused = false;
|
||||||
|
|
||||||
|
// $FlowExpectedError
|
||||||
this.state.hintBoxAnimation = new Animated.Value(0);
|
this.state.hintBoxAnimation = new Animated.Value(0);
|
||||||
|
|
||||||
// Bind event handlers so they are only bound once per instance.
|
// Bind event handlers so they are only bound once per instance.
|
||||||
this._onFieldFocusChange = this._onFieldFocusChange.bind(this);
|
this._onFieldFocusChange = this._onFieldFocusChange.bind(this);
|
||||||
this._onShowSideBar = this._onShowSideBar.bind(this);
|
|
||||||
this._renderHintBox = this._renderHintBox.bind(this);
|
this._renderHintBox = this._renderHintBox.bind(this);
|
||||||
|
|
||||||
// Specially bind functions to avoid function definition on render.
|
// Specially bind functions to avoid function definition on render.
|
||||||
|
@ -64,6 +89,16 @@ class WelcomePage extends AbstractWelcomePage {
|
||||||
this._onFieldFocus = this._onFieldFocusChange.bind(this, true);
|
this._onFieldFocus = this._onFieldFocusChange.bind(this, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onFieldBlur: () => void;
|
||||||
|
|
||||||
|
_onFieldFocus: () => void;
|
||||||
|
|
||||||
|
_onJoin: () => void;
|
||||||
|
|
||||||
|
_onRoomChange: (string) => void;
|
||||||
|
|
||||||
|
_updateRoomname: () => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements React's {@link Component#componentDidMount()}. Invoked
|
* Implements React's {@link Component#componentDidMount()}. Invoked
|
||||||
* immediately after mounting occurs. Creates a local video track if none
|
* immediately after mounting occurs. Creates a local video track if none
|
||||||
|
@ -77,7 +112,29 @@ class WelcomePage extends AbstractWelcomePage {
|
||||||
|
|
||||||
this._updateRoomname();
|
this._updateRoomname();
|
||||||
|
|
||||||
const { dispatch } = this.props;
|
const {
|
||||||
|
_headerStyles,
|
||||||
|
dispatch,
|
||||||
|
navigation
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
navigation.setOptions({
|
||||||
|
headerLeft: () => (
|
||||||
|
<TouchableOpacity
|
||||||
|
/* eslint-disable-next-line react/jsx-no-bind */
|
||||||
|
onPress = { () =>
|
||||||
|
navigation.dispatch(DrawerActions.openDrawer()) }
|
||||||
|
style = { styles.drawerNavigationIcon }>
|
||||||
|
<Icon
|
||||||
|
size = { 20 }
|
||||||
|
src = { IconMenu }
|
||||||
|
style = { _headerStyles.headerButtonIcon } />
|
||||||
|
</TouchableOpacity>
|
||||||
|
),
|
||||||
|
// eslint-disable-next-line react/no-multi-comp
|
||||||
|
headerRight: () =>
|
||||||
|
<VideoSwitch />
|
||||||
|
});
|
||||||
|
|
||||||
if (this.props._settings.startAudioOnly) {
|
if (this.props._settings.startAudioOnly) {
|
||||||
dispatch(destroyLocalTracks());
|
dispatch(destroyLocalTracks());
|
||||||
|
@ -153,11 +210,14 @@ class WelcomePage extends AbstractWelcomePage {
|
||||||
styles.messageContainer,
|
styles.messageContainer,
|
||||||
styles.hintContainer,
|
styles.hintContainer,
|
||||||
{
|
{
|
||||||
|
// $FlowExpectedError
|
||||||
opacity: this.state.hintBoxAnimation
|
opacity: this.state.hintBoxAnimation
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onFieldFocusChange: (boolean) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback for when the room field's focus changes so the hint box
|
* Callback for when the room field's focus changes so the hint box
|
||||||
* must be rendered or removed.
|
* must be rendered or removed.
|
||||||
|
@ -169,6 +229,7 @@ class WelcomePage extends AbstractWelcomePage {
|
||||||
_onFieldFocusChange(focused) {
|
_onFieldFocusChange(focused) {
|
||||||
if (focused) {
|
if (focused) {
|
||||||
// Stop placeholder animation.
|
// Stop placeholder animation.
|
||||||
|
// $FlowExpectedError
|
||||||
this._clearTimeouts();
|
this._clearTimeouts();
|
||||||
this.setState({
|
this.setState({
|
||||||
_fieldFocused: true,
|
_fieldFocused: true,
|
||||||
|
@ -180,29 +241,28 @@ class WelcomePage extends AbstractWelcomePage {
|
||||||
}
|
}
|
||||||
|
|
||||||
Animated.timing(
|
Animated.timing(
|
||||||
|
|
||||||
|
// $FlowExpectedError
|
||||||
this.state.hintBoxAnimation,
|
this.state.hintBoxAnimation,
|
||||||
|
|
||||||
|
// $FlowExpectedError
|
||||||
{
|
{
|
||||||
duration: 300,
|
duration: 300,
|
||||||
toValue: focused ? 1 : 0
|
toValue: focused ? 1 : 0
|
||||||
})
|
})
|
||||||
.start(animationState =>
|
.start(animationState =>
|
||||||
|
|
||||||
|
// $FlowExpectedError
|
||||||
animationState.finished
|
animationState.finished
|
||||||
|
|
||||||
|
// $FlowExpectedError
|
||||||
&& !focused
|
&& !focused
|
||||||
&& this.setState({
|
&& this.setState({
|
||||||
_fieldFocused: false
|
_fieldFocused: false
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
_renderHintBox: () => React$Element<any>;
|
||||||
* Toggles the side bar.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
_onShowSideBar() {
|
|
||||||
Keyboard.dismiss();
|
|
||||||
this.props.dispatch(setSideBarVisible(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the hint box if necessary.
|
* Renders the hint box if necessary.
|
||||||
|
@ -211,9 +271,10 @@ class WelcomePage extends AbstractWelcomePage {
|
||||||
* @returns {React$Node}
|
* @returns {React$Node}
|
||||||
*/
|
*/
|
||||||
_renderHintBox() {
|
_renderHintBox() {
|
||||||
if (this.state._fieldFocused) {
|
|
||||||
const { t } = this.props;
|
const { t } = this.props;
|
||||||
|
|
||||||
|
// $FlowExpectedError
|
||||||
|
if (this.state._fieldFocused) {
|
||||||
return (
|
return (
|
||||||
<Animated.View style = { this._getHintBoxStyle() }>
|
<Animated.View style = { this._getHintBoxStyle() }>
|
||||||
<View style = { styles.hintTextContainer } >
|
<View style = { styles.hintTextContainer } >
|
||||||
|
@ -283,25 +344,20 @@ class WelcomePage extends AbstractWelcomePage {
|
||||||
const { _headerStyles, t } = this.props;
|
const { _headerStyles, t } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<JitsiStatusBar />
|
||||||
<LocalVideoTrackUnderlay style = { styles.welcomePage }>
|
<LocalVideoTrackUnderlay style = { styles.welcomePage }>
|
||||||
<View style = { _headerStyles.page }>
|
<View style = { _headerStyles.page }>
|
||||||
<Header style = { styles.header }>
|
|
||||||
<TouchableOpacity onPress = { this._onShowSideBar } >
|
|
||||||
<Icon
|
|
||||||
src = { IconMenu }
|
|
||||||
style = { _headerStyles.headerButtonIcon } />
|
|
||||||
</TouchableOpacity>
|
|
||||||
<VideoSwitch />
|
|
||||||
</Header>
|
|
||||||
<SafeAreaView style = { styles.roomContainer } >
|
<SafeAreaView style = { styles.roomContainer } >
|
||||||
<View style = { styles.joinControls } >
|
<View style = { styles.joinControls } >
|
||||||
<Text style = { styles.enterRoomText }>
|
<Text style = { styles.enterRoomText }>
|
||||||
{ t('welcomepage.roomname') }
|
{ t('welcomepage.roomname') }
|
||||||
</Text>
|
</Text>
|
||||||
|
{/* // $FlowExpectedError*/}
|
||||||
<TextInput
|
<TextInput
|
||||||
accessibilityLabel = { t(roomnameAccLabel) }
|
accessibilityLabel = { t(roomnameAccLabel) }
|
||||||
autoCapitalize = 'none'
|
autoCapitalize = { 'none' }
|
||||||
autoComplete = 'off'
|
autoComplete = { 'off' }
|
||||||
autoCorrect = { false }
|
autoCorrect = { false }
|
||||||
autoFocus = { false }
|
autoFocus = { false }
|
||||||
onBlur = { this._onFieldBlur }
|
onBlur = { this._onFieldBlur }
|
||||||
|
@ -316,6 +372,8 @@ class WelcomePage extends AbstractWelcomePage {
|
||||||
underlineColorAndroid = 'transparent'
|
underlineColorAndroid = 'transparent'
|
||||||
value = { this.state.room } />
|
value = { this.state.room } />
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// $FlowExpectedError
|
||||||
this._renderInsecureRoomNameWarning()
|
this._renderInsecureRoomNameWarning()
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
@ -323,11 +381,11 @@ class WelcomePage extends AbstractWelcomePage {
|
||||||
}
|
}
|
||||||
</View>
|
</View>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
|
{/* $FlowExpectedError*/}
|
||||||
<WelcomePageLists disabled = { this.state._fieldFocused } />
|
<WelcomePageLists disabled = { this.state._fieldFocused } />
|
||||||
</View>
|
</View>
|
||||||
<WelcomePageSideBar />
|
|
||||||
{ this._renderWelcomePageModals() }
|
|
||||||
</LocalVideoTrackUnderlay>
|
</LocalVideoTrackUnderlay>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,19 +405,6 @@ class WelcomePage extends AbstractWelcomePage {
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders JitsiModals that are supposed to be on the welcome page.
|
|
||||||
*
|
|
||||||
* @returns {Array<ReactElement>}
|
|
||||||
*/
|
|
||||||
_renderWelcomePageModals() {
|
|
||||||
return [
|
|
||||||
<HelpView key = 'helpView' />,
|
|
||||||
<DialInSummary key = 'dialInSummary' />,
|
|
||||||
<SettingsView key = 'settings' />
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import { createDrawerNavigator } from '@react-navigation/drawer';
|
||||||
|
import React from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import {
|
||||||
|
helpScreenOptions,
|
||||||
|
settingsScreenOptions,
|
||||||
|
termsAndPrivacyScreenOptions,
|
||||||
|
welcomeScreenOptions
|
||||||
|
} from '../../conference/components/native/ConferenceNavigatorScreenOptions';
|
||||||
|
import { screen } from '../../conference/components/native/routes';
|
||||||
|
import HelpView from '../components/help/components/HelpView';
|
||||||
|
import PrivacyView from '../components/privacy/components/PrivacyView';
|
||||||
|
import SettingsView from '../components/settings/components/SettingsView';
|
||||||
|
import TermsView from '../components/terms/components/TermsView';
|
||||||
|
|
||||||
|
import CustomDrawerContent from './CustomDrawerContent';
|
||||||
|
import WelcomePage from './WelcomePage.native';
|
||||||
|
import { drawerContentOptions } from './constants';
|
||||||
|
import styles from './styles';
|
||||||
|
|
||||||
|
const DrawerStack = createDrawerNavigator();
|
||||||
|
|
||||||
|
|
||||||
|
const WelcomePageNavigationContainer = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DrawerStack.Navigator
|
||||||
|
/* eslint-disable-next-line react/jsx-no-bind */
|
||||||
|
drawerContent = { props => <CustomDrawerContent { ...props } /> }
|
||||||
|
drawerContentOptions = { drawerContentOptions }
|
||||||
|
drawerStyle = { styles.drawerStyle }>
|
||||||
|
<DrawerStack.Screen
|
||||||
|
component = { WelcomePage }
|
||||||
|
name = { screen.welcome.main }
|
||||||
|
options = { welcomeScreenOptions } />
|
||||||
|
<DrawerStack.Screen
|
||||||
|
component = { SettingsView }
|
||||||
|
name = { screen.welcome.settings }
|
||||||
|
options = {{
|
||||||
|
...settingsScreenOptions,
|
||||||
|
title: t('settingsView.header')
|
||||||
|
}} />
|
||||||
|
<DrawerStack.Screen
|
||||||
|
component = { TermsView }
|
||||||
|
name = { screen.welcome.terms }
|
||||||
|
options = {{
|
||||||
|
...termsAndPrivacyScreenOptions,
|
||||||
|
title: t('termsView.header')
|
||||||
|
}} />
|
||||||
|
<DrawerStack.Screen
|
||||||
|
component = { PrivacyView }
|
||||||
|
name = { screen.welcome.privacy }
|
||||||
|
options = {{
|
||||||
|
...termsAndPrivacyScreenOptions,
|
||||||
|
title: t('privacyView.header')
|
||||||
|
}} />
|
||||||
|
<DrawerStack.Screen
|
||||||
|
component = { HelpView }
|
||||||
|
name = { screen.welcome.help }
|
||||||
|
options = {{
|
||||||
|
...helpScreenOptions,
|
||||||
|
title: t('helpView.header')
|
||||||
|
}} />
|
||||||
|
</DrawerStack.Navigator>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WelcomePageNavigationContainer;
|
||||||
|
|
|
@ -1,182 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { SafeAreaView, ScrollView, Text } from 'react-native';
|
|
||||||
|
|
||||||
import { Avatar } from '../../base/avatar';
|
|
||||||
import { IconInfo, IconSettings, IconHelp } from '../../base/icons';
|
|
||||||
import { setActiveModalId } from '../../base/modal';
|
|
||||||
import {
|
|
||||||
getLocalParticipant,
|
|
||||||
getParticipantDisplayName
|
|
||||||
} from '../../base/participants';
|
|
||||||
import {
|
|
||||||
Header,
|
|
||||||
SlidingView
|
|
||||||
} from '../../base/react';
|
|
||||||
import { connect } from '../../base/redux';
|
|
||||||
import { HELP_VIEW_MODAL_ID } from '../../help';
|
|
||||||
import { SETTINGS_VIEW_ID } from '../../settings/constants';
|
|
||||||
import { setSideBarVisible } from '../actions';
|
|
||||||
|
|
||||||
import SideBarItem from './SideBarItem';
|
|
||||||
import styles, { SIDEBAR_AVATAR_SIZE } from './styles';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The URL at which the privacy policy is available to the user.
|
|
||||||
*/
|
|
||||||
const PRIVACY_URL = 'https://jitsi.org/meet/privacy';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The URL at which the terms (of service/use) are available to the user.
|
|
||||||
*/
|
|
||||||
const TERMS_URL = 'https://jitsi.org/meet/terms';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redux dispatch action.
|
|
||||||
*/
|
|
||||||
dispatch: Function,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display name of the local participant.
|
|
||||||
*/
|
|
||||||
_displayName: ?string,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ID of the local participant.
|
|
||||||
*/
|
|
||||||
_localParticipantId: ?string,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the side bar visible or hidden.
|
|
||||||
*/
|
|
||||||
_visible: boolean
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A component rendering a welcome page sidebar.
|
|
||||||
*/
|
|
||||||
class WelcomePageSideBar extends Component<Props> {
|
|
||||||
/**
|
|
||||||
* Constructs a new SideBar instance.
|
|
||||||
*
|
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
// Bind event handlers so they are only bound once per instance.
|
|
||||||
this._onHideSideBar = this._onHideSideBar.bind(this);
|
|
||||||
this._onOpenHelpPage = this._onOpenHelpPage.bind(this);
|
|
||||||
this._onOpenSettings = this._onOpenSettings.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements React's {@link Component#render()}, renders the sidebar.
|
|
||||||
*
|
|
||||||
* @inheritdoc
|
|
||||||
* @returns {ReactElement}
|
|
||||||
*/
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<SlidingView
|
|
||||||
onHide = { this._onHideSideBar }
|
|
||||||
show = { this.props._visible }
|
|
||||||
style = { styles.sideBar } >
|
|
||||||
<Header style = { styles.sideBarHeader }>
|
|
||||||
<Avatar
|
|
||||||
participantId = { this.props._localParticipantId }
|
|
||||||
size = { SIDEBAR_AVATAR_SIZE } />
|
|
||||||
<Text style = { styles.displayName }>
|
|
||||||
{ this.props._displayName }
|
|
||||||
</Text>
|
|
||||||
</Header>
|
|
||||||
<SafeAreaView style = { styles.sideBarBody }>
|
|
||||||
<ScrollView
|
|
||||||
style = { styles.itemContainer }>
|
|
||||||
<SideBarItem
|
|
||||||
icon = { IconSettings }
|
|
||||||
label = 'settings.title'
|
|
||||||
onPress = { this._onOpenSettings } />
|
|
||||||
<SideBarItem
|
|
||||||
icon = { IconInfo }
|
|
||||||
label = 'welcomepage.terms'
|
|
||||||
url = { TERMS_URL } />
|
|
||||||
<SideBarItem
|
|
||||||
icon = { IconInfo }
|
|
||||||
label = 'welcomepage.privacy'
|
|
||||||
url = { PRIVACY_URL } />
|
|
||||||
<SideBarItem
|
|
||||||
icon = { IconHelp }
|
|
||||||
label = 'welcomepage.getHelp'
|
|
||||||
onPress = { this._onOpenHelpPage } />
|
|
||||||
</ScrollView>
|
|
||||||
</SafeAreaView>
|
|
||||||
</SlidingView>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_onHideSideBar: () => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoked when the sidebar has closed itself (e.g. Overlay pressed).
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
_onHideSideBar() {
|
|
||||||
this.props.dispatch(setSideBarVisible(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
_onOpenHelpPage: () => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows the {@link HelpView}.
|
|
||||||
*
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
_onOpenHelpPage() {
|
|
||||||
const { dispatch } = this.props;
|
|
||||||
|
|
||||||
dispatch(setSideBarVisible(false));
|
|
||||||
dispatch(setActiveModalId(HELP_VIEW_MODAL_ID));
|
|
||||||
}
|
|
||||||
|
|
||||||
_onOpenSettings: () => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows the {@link SettingsView}.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
_onOpenSettings() {
|
|
||||||
const { dispatch } = this.props;
|
|
||||||
|
|
||||||
dispatch(setSideBarVisible(false));
|
|
||||||
dispatch(setActiveModalId(SETTINGS_VIEW_ID));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maps (parts of) the redux state to the React {@code Component} props.
|
|
||||||
*
|
|
||||||
* @param {Object} state - The redux state.
|
|
||||||
* @protected
|
|
||||||
* @returns {Props}
|
|
||||||
*/
|
|
||||||
function _mapStateToProps(state: Object) {
|
|
||||||
const _localParticipant = getLocalParticipant(state);
|
|
||||||
const _localParticipantId = _localParticipant?.id;
|
|
||||||
const _displayName = _localParticipant && getParticipantDisplayName(state, _localParticipantId);
|
|
||||||
|
|
||||||
return {
|
|
||||||
_displayName,
|
|
||||||
_localParticipantId,
|
|
||||||
_visible: state['features/welcome'].sideBarVisible
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(_mapStateToProps)(WelcomePageSideBar);
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import BaseTheme from '../../base/ui/components/BaseTheme';
|
||||||
|
|
||||||
|
|
||||||
|
export const drawerContentOptions = {
|
||||||
|
activeBackgroundColor: BaseTheme.palette.ui12,
|
||||||
|
activeTintColor: BaseTheme.palette.screen01Header,
|
||||||
|
labelStyle: {
|
||||||
|
marginLeft: BaseTheme.spacing[2]
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,83 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import React, { PureComponent } from 'react';
|
||||||
|
|
||||||
|
import JitsiScreenWebView from '../../../../base/modal/components/JitsiScreenWebView';
|
||||||
|
import JitsiStatusBar from '../../../../base/modal/components/JitsiStatusBar';
|
||||||
|
import { connect } from '../../../../base/redux';
|
||||||
|
import { screen } from '../../../../conference/components/native/routes';
|
||||||
|
import { renderArrowBackButton } from '../../../../welcome/functions.native';
|
||||||
|
|
||||||
|
|
||||||
|
import styles from './styles';
|
||||||
|
|
||||||
|
|
||||||
|
const DEFAULT_HELP_CENTRE_URL = 'https://web-cdn.jitsi.net/faq/meet-faq.html';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL to display in the Help Centre.
|
||||||
|
*/
|
||||||
|
_url: string,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default prop for navigating between screen components(React Navigation).
|
||||||
|
*/
|
||||||
|
navigation: Object
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements a page that renders the help content for the app.
|
||||||
|
*/
|
||||||
|
class HelpView extends PureComponent<Props> {
|
||||||
|
/**
|
||||||
|
* Implements React's {@link Component#componentDidMount()}. Invoked
|
||||||
|
* immediately after mounting occurs.
|
||||||
|
*
|
||||||
|
* @inheritdoc
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
componentDidMount() {
|
||||||
|
const {
|
||||||
|
navigation
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
navigation.setOptions({
|
||||||
|
headerLeft: () =>
|
||||||
|
renderArrowBackButton(() =>
|
||||||
|
navigation.jumpTo(screen.welcome.main))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements {@code PureComponent#render()}.
|
||||||
|
*
|
||||||
|
* @inheritdoc
|
||||||
|
* @returns {ReactElement}
|
||||||
|
*/
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<JitsiStatusBar />
|
||||||
|
<JitsiScreenWebView
|
||||||
|
source = { this.props._url }
|
||||||
|
style = { styles.helpViewContainer } />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps part of the Redux state to the props of this component.
|
||||||
|
*
|
||||||
|
* @param {Object} state - The Redux state.
|
||||||
|
* @returns {Props}
|
||||||
|
*/
|
||||||
|
function _mapStateToProps(state) {
|
||||||
|
return {
|
||||||
|
_url: state['features/base/config'].helpCentreURL || DEFAULT_HELP_CENTRE_URL
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(_mapStateToProps)(HelpView);
|
|
@ -0,0 +1,12 @@
|
||||||
|
/**
|
||||||
|
* The styles of the native components of the feature {@code settings}.
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Style for screen container.
|
||||||
|
*/
|
||||||
|
helpViewContainer: {
|
||||||
|
flex: 1
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,46 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import React, { useEffect } from 'react';
|
||||||
|
|
||||||
|
import JitsiScreenWebView from '../../../../base/modal/components/JitsiScreenWebView';
|
||||||
|
import JitsiStatusBar from '../../../../base/modal/components/JitsiStatusBar';
|
||||||
|
import { screen } from '../../../../conference/components/native/routes';
|
||||||
|
import { renderArrowBackButton } from '../../../../welcome/functions.native';
|
||||||
|
|
||||||
|
import styles from './styles';
|
||||||
|
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default prop for navigating between screen components(React Navigation).
|
||||||
|
*/
|
||||||
|
navigation: Object
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL at which the privacy policy is available to the user.
|
||||||
|
*/
|
||||||
|
const PRIVACY_URL = 'https://jitsi.org/meet/privacy';
|
||||||
|
|
||||||
|
const PrivacyView = ({ navigation }: Props) => {
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
navigation.setOptions({
|
||||||
|
headerLeft: () =>
|
||||||
|
renderArrowBackButton(() =>
|
||||||
|
navigation.jumpTo(screen.welcome.main))
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<JitsiStatusBar />
|
||||||
|
<JitsiScreenWebView
|
||||||
|
source = { PRIVACY_URL }
|
||||||
|
style = { styles.privacyViewContainer } />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PrivacyView;
|
|
@ -0,0 +1,12 @@
|
||||||
|
/**
|
||||||
|
* The styles of the native components of the feature {@code privacy}.
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Style for screen container.
|
||||||
|
*/
|
||||||
|
privacyViewContainer: {
|
||||||
|
flex: 1
|
||||||
|
}
|
||||||
|
};
|
|
@ -3,7 +3,7 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { Text, View } from 'react-native';
|
import { Text, View } from 'react-native';
|
||||||
|
|
||||||
import { translate } from '../../../base/i18n';
|
import { translate } from '../../../../base/i18n';
|
||||||
|
|
||||||
import styles, { ANDROID_UNDERLINE_COLOR, PLACEHOLDER_COLOR } from './styles';
|
import styles, { ANDROID_UNDERLINE_COLOR, PLACEHOLDER_COLOR } from './styles';
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
import React, { useCallback, useState } from 'react';
|
import React, { useCallback, useState } from 'react';
|
||||||
import { List } from 'react-native-paper';
|
import { List } from 'react-native-paper';
|
||||||
|
|
||||||
import { translate } from '../../../base/i18n';
|
import { translate } from '../../../../base/i18n';
|
||||||
import { Icon, IconArrowDown, IconArrowUp } from '../../../base/icons';
|
import { Icon, IconArrowDown, IconArrowUp } from '../../../../base/icons';
|
||||||
|
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
|
|
@ -1,19 +1,25 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Alert, NativeModules, ScrollView, Text } from 'react-native';
|
import {
|
||||||
|
Alert,
|
||||||
|
NativeModules,
|
||||||
|
ScrollView,
|
||||||
|
Text
|
||||||
|
} from 'react-native';
|
||||||
import { Divider, Switch, TextInput, withTheme } from 'react-native-paper';
|
import { Divider, Switch, TextInput, withTheme } from 'react-native-paper';
|
||||||
|
|
||||||
import { translate } from '../../../base/i18n';
|
import { translate } from '../../../../base/i18n';
|
||||||
import { JitsiModal } from '../../../base/modal';
|
import JitsiScreen from '../../../../base/modal/components/JitsiScreen';
|
||||||
import { connect } from '../../../base/redux';
|
import { connect } from '../../../../base/redux';
|
||||||
import { SETTINGS_VIEW_ID } from '../../constants';
|
import { screen } from '../../../../conference/components/native/routes';
|
||||||
import { normalizeUserInputURL, isServerURLChangeEnabled } from '../../functions';
|
|
||||||
import {
|
import {
|
||||||
AbstractSettingsView,
|
AbstractSettingsView,
|
||||||
_mapStateToProps as _abstractMapStateToProps,
|
_mapStateToProps as _abstractMapStateToProps,
|
||||||
type Props as AbstractProps
|
type Props as AbstractProps
|
||||||
} from '../AbstractSettingsView';
|
} from '../../../../settings/components/AbstractSettingsView';
|
||||||
|
import { normalizeUserInputURL, isServerURLChangeEnabled } from '../../../../settings/functions';
|
||||||
|
import { renderArrowBackButton } from '../../../../welcome/functions.native';
|
||||||
|
|
||||||
import FormRow from './FormRow';
|
import FormRow from './FormRow';
|
||||||
import FormSectionAccordion from './FormSectionAccordion';
|
import FormSectionAccordion from './FormSectionAccordion';
|
||||||
|
@ -80,6 +86,11 @@ type Props = AbstractProps & {
|
||||||
*/
|
*/
|
||||||
_serverURLChangeEnabled: boolean,
|
_serverURLChangeEnabled: boolean,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default prop for navigating between screen components(React Navigation).
|
||||||
|
*/
|
||||||
|
navigation: Object,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Theme used for styles.
|
* Theme used for styles.
|
||||||
*/
|
*/
|
||||||
|
@ -133,6 +144,25 @@ class SettingsView extends AbstractSettingsView<Props, State> {
|
||||||
this._showURLAlert = this._showURLAlert.bind(this);
|
this._showURLAlert = this._showURLAlert.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements React's {@link Component#componentDidMount()}. Invoked
|
||||||
|
* immediately after mounting occurs.
|
||||||
|
*
|
||||||
|
* @inheritdoc
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
componentDidMount() {
|
||||||
|
const {
|
||||||
|
navigation
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
navigation.setOptions({
|
||||||
|
headerLeft: () =>
|
||||||
|
renderArrowBackButton(() =>
|
||||||
|
navigation.jumpTo(screen.welcome.main))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements React's {@link Component#render()}, renders the settings page.
|
* Implements React's {@link Component#render()}, renders the settings page.
|
||||||
*
|
*
|
||||||
|
@ -153,12 +183,8 @@ class SettingsView extends AbstractSettingsView<Props, State> {
|
||||||
const { palette } = this.props.theme;
|
const { palette } = this.props.theme;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<JitsiModal
|
<JitsiScreen
|
||||||
headerProps = {{
|
style = { styles.settingsViewContainer }>
|
||||||
headerLabelKey: 'settingsView.header'
|
|
||||||
}}
|
|
||||||
modalId = { SETTINGS_VIEW_ID }
|
|
||||||
onClose = { this._onClose }>
|
|
||||||
<ScrollView>
|
<ScrollView>
|
||||||
<FormSectionAccordion
|
<FormSectionAccordion
|
||||||
accordion = { false }
|
accordion = { false }
|
||||||
|
@ -175,7 +201,7 @@ class SettingsView extends AbstractSettingsView<Props, State> {
|
||||||
textContentType = { 'name' } // iOS only
|
textContentType = { 'name' } // iOS only
|
||||||
theme = {{
|
theme = {{
|
||||||
colors: {
|
colors: {
|
||||||
primary: palette.action01Active,
|
primary: palette.screen01Header,
|
||||||
underlineColor: 'transparent'
|
underlineColor: 'transparent'
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
@ -194,7 +220,7 @@ class SettingsView extends AbstractSettingsView<Props, State> {
|
||||||
textContentType = { 'emailAddress' } // iOS only
|
textContentType = { 'emailAddress' } // iOS only
|
||||||
theme = {{
|
theme = {{
|
||||||
colors: {
|
colors: {
|
||||||
primary: palette.action01Active,
|
primary: palette.screen01Header,
|
||||||
underlineColor: 'transparent'
|
underlineColor: 'transparent'
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
@ -219,7 +245,7 @@ class SettingsView extends AbstractSettingsView<Props, State> {
|
||||||
textContentType = { 'URL' } // iOS only
|
textContentType = { 'URL' } // iOS only
|
||||||
theme = {{
|
theme = {{
|
||||||
colors: {
|
colors: {
|
||||||
primary: palette.action01Active,
|
primary: palette.screen01Header,
|
||||||
underlineColor: 'transparent'
|
underlineColor: 'transparent'
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
@ -230,7 +256,7 @@ class SettingsView extends AbstractSettingsView<Props, State> {
|
||||||
<Switch
|
<Switch
|
||||||
onValueChange = { this._onStartAudioMutedChange }
|
onValueChange = { this._onStartAudioMutedChange }
|
||||||
thumbColor = { THUMB_COLOR }
|
thumbColor = { THUMB_COLOR }
|
||||||
trackColor = {{ true: palette.action01Active }}
|
trackColor = {{ true: palette.screen01Header }}
|
||||||
value = { startWithAudioMuted } />
|
value = { startWithAudioMuted } />
|
||||||
</FormRow>
|
</FormRow>
|
||||||
<Divider style = { styles.fieldSeparator } />
|
<Divider style = { styles.fieldSeparator } />
|
||||||
|
@ -238,7 +264,7 @@ class SettingsView extends AbstractSettingsView<Props, State> {
|
||||||
<Switch
|
<Switch
|
||||||
onValueChange = { this._onStartVideoMutedChange }
|
onValueChange = { this._onStartVideoMutedChange }
|
||||||
thumbColor = { THUMB_COLOR }
|
thumbColor = { THUMB_COLOR }
|
||||||
trackColor = {{ true: palette.action01Active }}
|
trackColor = {{ true: palette.screen01Header }}
|
||||||
value = { startWithVideoMuted } />
|
value = { startWithVideoMuted } />
|
||||||
</FormRow>
|
</FormRow>
|
||||||
</FormSectionAccordion>
|
</FormSectionAccordion>
|
||||||
|
@ -262,7 +288,7 @@ class SettingsView extends AbstractSettingsView<Props, State> {
|
||||||
<Switch
|
<Switch
|
||||||
onValueChange = { this._onDisableCallIntegration }
|
onValueChange = { this._onDisableCallIntegration }
|
||||||
thumbColor = { THUMB_COLOR }
|
thumbColor = { THUMB_COLOR }
|
||||||
trackColor = {{ true: palette.action01Active }}
|
trackColor = {{ true: palette.screen01Header }}
|
||||||
value = { disableCallIntegration } />
|
value = { disableCallIntegration } />
|
||||||
</FormRow>
|
</FormRow>
|
||||||
<Divider style = { styles.fieldSeparator } />
|
<Divider style = { styles.fieldSeparator } />
|
||||||
|
@ -271,7 +297,7 @@ class SettingsView extends AbstractSettingsView<Props, State> {
|
||||||
<Switch
|
<Switch
|
||||||
onValueChange = { this._onDisableP2P }
|
onValueChange = { this._onDisableP2P }
|
||||||
thumbColor = { THUMB_COLOR }
|
thumbColor = { THUMB_COLOR }
|
||||||
trackColor = {{ true: palette.action01Active }}
|
trackColor = {{ true: palette.screen01Header }}
|
||||||
value = { disableP2P } />
|
value = { disableP2P } />
|
||||||
</FormRow>
|
</FormRow>
|
||||||
<Divider style = { styles.fieldSeparator } />
|
<Divider style = { styles.fieldSeparator } />
|
||||||
|
@ -282,13 +308,13 @@ class SettingsView extends AbstractSettingsView<Props, State> {
|
||||||
<Switch
|
<Switch
|
||||||
onValueChange = { this._onDisableCrashReporting }
|
onValueChange = { this._onDisableCrashReporting }
|
||||||
thumbColor = { THUMB_COLOR }
|
thumbColor = { THUMB_COLOR }
|
||||||
trackColor = {{ true: palette.action01Active }}
|
trackColor = {{ true: palette.screen01Header }}
|
||||||
value = { disableCrashReporting } />
|
value = { disableCrashReporting } />
|
||||||
</FormRow>
|
</FormRow>
|
||||||
)}
|
)}
|
||||||
</FormSectionAccordion>
|
</FormSectionAccordion>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</JitsiModal>
|
</JitsiScreen>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
|
import BaseTheme from '../../../../base/ui/components/BaseTheme.native';
|
||||||
export const ANDROID_UNDERLINE_COLOR = 'transparent';
|
export const ANDROID_UNDERLINE_COLOR = 'transparent';
|
||||||
export const PLACEHOLDER_COLOR = BaseTheme.palette.action02Focus;
|
export const PLACEHOLDER_COLOR = BaseTheme.palette.action02Focus;
|
||||||
export const THUMB_COLOR = BaseTheme.palette.field02;
|
export const THUMB_COLOR = BaseTheme.palette.field02;
|
||||||
|
@ -9,6 +9,14 @@ const TEXT_SIZE = 14;
|
||||||
* The styles of the native components of the feature {@code settings}.
|
* The styles of the native components of the feature {@code settings}.
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Style for screen container.
|
||||||
|
*/
|
||||||
|
settingsViewContainer: {
|
||||||
|
flex: 1
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standardized style for a field container {@code View}.
|
* Standardized style for a field container {@code View}.
|
||||||
*/
|
*/
|
||||||
|
@ -80,7 +88,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
formSectionTitleActive: {
|
formSectionTitleActive: {
|
||||||
color: BaseTheme.palette.section01Active
|
color: BaseTheme.palette.screen01Header
|
||||||
},
|
},
|
||||||
|
|
||||||
formSectionTitleInActive: {
|
formSectionTitleInActive: {
|
||||||
|
@ -93,7 +101,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
sectionOpen: {
|
sectionOpen: {
|
||||||
color: BaseTheme.palette.section01Active,
|
color: BaseTheme.palette.screen01Header,
|
||||||
fontSize: 14
|
fontSize: 14
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,23 +1,25 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import { Dimensions, StyleSheet } from 'react-native';
|
import { StyleSheet } from 'react-native';
|
||||||
|
|
||||||
import { BoxModel, ColorPalette } from '../../base/styles';
|
import { BoxModel } from '../../base/styles';
|
||||||
|
import BaseTheme from '../../base/ui/components/BaseTheme.native';
|
||||||
|
|
||||||
export const PLACEHOLDER_TEXT_COLOR = 'rgba(255, 255, 255, 0.5)';
|
|
||||||
|
|
||||||
export const SIDEBAR_AVATAR_SIZE = 100;
|
export const PLACEHOLDER_TEXT_COLOR = BaseTheme.palette.text01;
|
||||||
|
|
||||||
const SIDEBAR_HEADER_HEIGHT = 150;
|
export const DRAWER_AVATAR_SIZE = 104;
|
||||||
|
|
||||||
export const SWITCH_THUMB_COLOR = ColorPalette.blueHighlight;
|
const DRAWER_HEADER_HEIGHT = 220;
|
||||||
|
|
||||||
|
export const SWITCH_THUMB_COLOR = BaseTheme.palette.action04;
|
||||||
|
|
||||||
export const SWITCH_UNDER_COLOR = 'rgba(0, 0, 0, 0.4)';
|
export const SWITCH_UNDER_COLOR = 'rgba(0, 0, 0, 0.4)';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default color of text on the WelcomePage.
|
* The default color of text on the WelcomePage.
|
||||||
*/
|
*/
|
||||||
const TEXT_COLOR = ColorPalette.white;
|
const TEXT_COLOR = BaseTheme.palette.text01;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The styles of the React {@code Components} of the feature welcome including
|
* The styles of the React {@code Components} of the feature welcome including
|
||||||
|
@ -37,7 +39,8 @@ export default {
|
||||||
*/
|
*/
|
||||||
audioVideoSwitchContainer: {
|
audioVideoSwitchContainer: {
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
flexDirection: 'row'
|
flexDirection: 'row',
|
||||||
|
marginRight: BaseTheme.spacing[2]
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -55,8 +58,8 @@ export default {
|
||||||
* Join button style.
|
* Join button style.
|
||||||
*/
|
*/
|
||||||
button: {
|
button: {
|
||||||
backgroundColor: ColorPalette.blue,
|
backgroundColor: BaseTheme.palette.screen01Header,
|
||||||
borderColor: ColorPalette.blue,
|
borderColor: BaseTheme.palette.screen01Header,
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
height: 30,
|
height: 30,
|
||||||
|
@ -69,15 +72,23 @@ export default {
|
||||||
*/
|
*/
|
||||||
buttonText: {
|
buttonText: {
|
||||||
alignSelf: 'center',
|
alignSelf: 'center',
|
||||||
color: ColorPalette.white,
|
color: BaseTheme.palette.text01,
|
||||||
fontSize: 14
|
fontSize: 14
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drawer style.
|
||||||
|
*/
|
||||||
|
drawerStyle: {
|
||||||
|
backgroundColor: BaseTheme.palette.ui12,
|
||||||
|
width: '54%'
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The style of the display name label in the side bar.
|
* The style of the display name label in the side bar.
|
||||||
*/
|
*/
|
||||||
displayName: {
|
displayName: {
|
||||||
color: ColorPalette.white,
|
color: BaseTheme.palette.text01,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
marginTop: BoxModel.margin,
|
marginTop: BoxModel.margin,
|
||||||
textAlign: 'center'
|
textAlign: 'center'
|
||||||
|
@ -89,13 +100,6 @@ export default {
|
||||||
marginBottom: BoxModel.margin
|
marginBottom: BoxModel.margin
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* The welcome screen header style.
|
|
||||||
*/
|
|
||||||
header: {
|
|
||||||
justifyContent: 'space-between'
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Container for the button on the hint box.
|
* Container for the button on the hint box.
|
||||||
*/
|
*/
|
||||||
|
@ -142,8 +146,8 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
messageContainer: {
|
messageContainer: {
|
||||||
backgroundColor: ColorPalette.white,
|
backgroundColor: BaseTheme.palette.ui12,
|
||||||
borderColor: ColorPalette.white,
|
borderColor: BaseTheme.palette.field02,
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
marginVertical: 5,
|
marginVertical: 5,
|
||||||
|
@ -174,7 +178,7 @@ export default {
|
||||||
*/
|
*/
|
||||||
reducedUIContainer: {
|
reducedUIContainer: {
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
backgroundColor: ColorPalette.blue,
|
backgroundColor: BaseTheme.palette.screen01Header,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
justifyContent: 'center'
|
justifyContent: 'center'
|
||||||
},
|
},
|
||||||
|
@ -192,64 +196,22 @@ export default {
|
||||||
flexDirection: 'column'
|
flexDirection: 'column'
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Container of the side bar.
|
|
||||||
*/
|
|
||||||
sideBar: {
|
|
||||||
width: 250,
|
|
||||||
height: Dimensions.get('window').height
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The body of the side bar where the items are.
|
|
||||||
*/
|
|
||||||
sideBarBody: {
|
|
||||||
backgroundColor: ColorPalette.white,
|
|
||||||
flex: 1
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The style of the side bar header.
|
* The style of the side bar header.
|
||||||
*/
|
*/
|
||||||
sideBarHeader: {
|
drawerHeader: {
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
backgroundColor: BaseTheme.palette.screen01Header,
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
height: SIDEBAR_HEADER_HEIGHT,
|
height: DRAWER_HEADER_HEIGHT,
|
||||||
justifyContent: 'center',
|
justifyContent: 'center'
|
||||||
padding: BoxModel.padding
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
drawerNavigationIcon: {
|
||||||
* Style of the menu items in the side bar.
|
height: BaseTheme.spacing[6],
|
||||||
*/
|
marginLeft: BaseTheme.spacing[1],
|
||||||
sideBarItem: {
|
marginTop: BaseTheme.spacing[1],
|
||||||
padding: 13
|
width: BaseTheme.spacing[6]
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The View inside the side bar buttons (icon + text).
|
|
||||||
*/
|
|
||||||
sideBarItemButtonContainer: {
|
|
||||||
alignItems: 'center',
|
|
||||||
flexDirection: 'row',
|
|
||||||
justifyContent: 'flex-start'
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The icon in the side bar item touchables.
|
|
||||||
*/
|
|
||||||
sideBarItemIcon: {
|
|
||||||
color: ColorPalette.blueHighlight,
|
|
||||||
fontSize: 20,
|
|
||||||
marginRight: 15
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The label of the side bar item touchables.
|
|
||||||
*/
|
|
||||||
sideBarItemText: {
|
|
||||||
color: ColorPalette.black,
|
|
||||||
fontWeight: 'bold'
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -264,7 +226,7 @@ export default {
|
||||||
*/
|
*/
|
||||||
textInput: {
|
textInput: {
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: 'transparent',
|
||||||
borderColor: ColorPalette.white,
|
borderColor: BaseTheme.palette.field02,
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
color: TEXT_COLOR,
|
color: TEXT_COLOR,
|
||||||
|
@ -291,13 +253,13 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
insecureRoomNameWarningIcon: {
|
insecureRoomNameWarningIcon: {
|
||||||
color: ColorPalette.warning,
|
color: BaseTheme.palette.warning03,
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
marginRight: 10
|
marginRight: 10
|
||||||
},
|
},
|
||||||
|
|
||||||
insecureRoomNameWarningText: {
|
insecureRoomNameWarningText: {
|
||||||
color: ColorPalette.warning,
|
color: BaseTheme.palette.warning03,
|
||||||
flex: 1
|
flex: 1
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -305,7 +267,7 @@ export default {
|
||||||
* The style of the top-level container of {@code WelcomePage}.
|
* The style of the top-level container of {@code WelcomePage}.
|
||||||
*/
|
*/
|
||||||
welcomePage: {
|
welcomePage: {
|
||||||
backgroundColor: ColorPalette.blue,
|
backgroundColor: BaseTheme.palette.screen01Header,
|
||||||
overflow: 'hidden'
|
overflow: 'hidden'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import React, { useEffect } from 'react';
|
||||||
|
|
||||||
|
import JitsiScreenWebView from '../../../../base/modal/components/JitsiScreenWebView';
|
||||||
|
import JitsiStatusBar from '../../../../base/modal/components/JitsiStatusBar';
|
||||||
|
import { screen } from '../../../../conference/components/native/routes';
|
||||||
|
import { renderArrowBackButton } from '../../../../welcome/functions.native';
|
||||||
|
|
||||||
|
import styles from './styles';
|
||||||
|
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default prop for navigating between screen components(React Navigation).
|
||||||
|
*/
|
||||||
|
navigation: Object
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL at which the terms (of service/use) are available to the user.
|
||||||
|
*/
|
||||||
|
const TERMS_URL = 'https://jitsi.org/meet/terms';
|
||||||
|
|
||||||
|
const TermsView = ({ navigation }: Props) => {
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
navigation.setOptions({
|
||||||
|
headerLeft: () =>
|
||||||
|
renderArrowBackButton(() =>
|
||||||
|
navigation.jumpTo(screen.welcome.main))
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<JitsiStatusBar />
|
||||||
|
<JitsiScreenWebView
|
||||||
|
source = { TERMS_URL }
|
||||||
|
style = { styles.termsViewContainer } />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TermsView;
|
|
@ -0,0 +1,12 @@
|
||||||
|
/**
|
||||||
|
* The styles of the native components of the feature {@code terms}.
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Style for screen container.
|
||||||
|
*/
|
||||||
|
termsViewContainer: {
|
||||||
|
flex: 1
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,35 +1,9 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import { WELCOME_PAGE_ENABLED, getFeatureFlag } from '../base/flags';
|
|
||||||
import { toState } from '../base/redux';
|
import { toState } from '../base/redux';
|
||||||
|
|
||||||
declare var APP: Object;
|
declare var APP: Object;
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines whether the {@code WelcomePage} is enabled by the app itself
|
|
||||||
* (e.g. Programmatically via the Jitsi Meet SDK for Android and iOS). Not to be
|
|
||||||
* confused with {@link isWelcomePageUserEnabled}.
|
|
||||||
*
|
|
||||||
* @param {Function|Object} stateful - The redux state or {@link getState}
|
|
||||||
* function.
|
|
||||||
* @returns {boolean} If the {@code WelcomePage} is enabled by the app, then
|
|
||||||
* {@code true}; otherwise, {@code false}.
|
|
||||||
*/
|
|
||||||
export function isWelcomePageAppEnabled(stateful: Function | Object) {
|
|
||||||
if (navigator.product === 'ReactNative') {
|
|
||||||
// We introduced the welcomePageEnabled prop on App in Jitsi Meet SDK
|
|
||||||
// for Android and iOS. There isn't a strong reason not to introduce it
|
|
||||||
// on Web but there're a few considerations to be taken before I go
|
|
||||||
// there among which:
|
|
||||||
// - Enabling/disabling the Welcome page on Web historically
|
|
||||||
// automatically redirects to a random room and that does not make sense
|
|
||||||
// on mobile (right now).
|
|
||||||
return Boolean(getFeatureFlag(stateful, WELCOME_PAGE_ENABLED));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether the {@code WelcomePage} is enabled by the user either
|
* Determines whether the {@code WelcomePage} is enabled by the user either
|
||||||
* herself or through her deployment config(uration). Not to be confused with
|
* herself or through her deployment config(uration). Not to be confused with
|
||||||
|
@ -46,3 +20,5 @@ export function isWelcomePageUserEnabled(stateful: Function | Object) {
|
||||||
? true
|
? true
|
||||||
: toState(stateful)['features/base/config'].enableWelcomePage);
|
: toState(stateful)['features/base/config'].enableWelcomePage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { getFeatureFlag, WELCOME_PAGE_ENABLED } from '../base/flags';
|
||||||
|
import { IconArrowBack } from '../base/icons';
|
||||||
|
import HeaderNavigationButton
|
||||||
|
from '../conference/components/native/HeaderNavigationButton';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the {@code WelcomePage} is enabled by the app itself
|
||||||
|
* (e.g. Programmatically via the Jitsi Meet SDK for Android and iOS). Not to be
|
||||||
|
* confused with {@link isWelcomePageUserEnabled}.
|
||||||
|
*
|
||||||
|
* @param {Function|Object} stateful - The redux state or {@link getState}
|
||||||
|
* function.
|
||||||
|
* @returns {boolean} If the {@code WelcomePage} is enabled by the app, then
|
||||||
|
* {@code true}; otherwise, {@code false}.
|
||||||
|
*/
|
||||||
|
export function isWelcomePageAppEnabled(stateful: Function | Object) {
|
||||||
|
return Boolean(getFeatureFlag(stateful, WELCOME_PAGE_ENABLED));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render header arrow back button for navigation.
|
||||||
|
*
|
||||||
|
* @param {Function} onPress - Callback for when the button is pressed
|
||||||
|
* function.
|
||||||
|
* @returns {ReactElement}
|
||||||
|
*/
|
||||||
|
export function renderArrowBackButton(onPress: Function) {
|
||||||
|
return (
|
||||||
|
<HeaderNavigationButton
|
||||||
|
onPress = { onPress }
|
||||||
|
src = { IconArrowBack } />
|
||||||
|
);
|
||||||
|
}
|
Loading…
Reference in New Issue