mirror of https://github.com/jitsi/jitsi-meet
parent
612586ed1f
commit
19d1e3829d
@ -0,0 +1,81 @@ |
|||||||
|
// @flow
|
||||||
|
|
||||||
|
import type { Dispatch } from 'redux'; |
||||||
|
|
||||||
|
import { createToolbarEvent, sendAnalytics } from '../../analytics'; |
||||||
|
import { translate } from '../../base/i18n'; |
||||||
|
import { IconShareDoc } from '../../base/icons'; |
||||||
|
import { connect } from '../../base/redux'; |
||||||
|
import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox'; |
||||||
|
|
||||||
|
import { toggleDocument } from '../actions'; |
||||||
|
|
||||||
|
|
||||||
|
type Props = AbstractButtonProps & { |
||||||
|
|
||||||
|
/** |
||||||
|
* Whether the shared document is being edited or not. |
||||||
|
*/ |
||||||
|
_editing: boolean, |
||||||
|
|
||||||
|
/** |
||||||
|
* Redux dispatch function. |
||||||
|
*/ |
||||||
|
dispatch: Dispatch<any>, |
||||||
|
}; |
||||||
|
|
||||||
|
/** |
||||||
|
* Implements an {@link AbstractButton} to open the chat screen on mobile. |
||||||
|
*/ |
||||||
|
class SharedDocumentButton extends AbstractButton<Props, *> { |
||||||
|
accessibilityLabel = 'toolbar.accessibilityLabel.document'; |
||||||
|
icon = IconShareDoc; |
||||||
|
label = 'toolbar.documentOpen'; |
||||||
|
toggledLabel = 'toolbar.documentClose'; |
||||||
|
|
||||||
|
/** |
||||||
|
* Handles clicking / pressing the button, and opens / closes the appropriate dialog. |
||||||
|
* |
||||||
|
* @private |
||||||
|
* @returns {void} |
||||||
|
*/ |
||||||
|
_handleClick() { |
||||||
|
sendAnalytics(createToolbarEvent( |
||||||
|
'toggle.etherpad', |
||||||
|
{ |
||||||
|
enable: !this.props._editing |
||||||
|
})); |
||||||
|
this.props.dispatch(toggleDocument()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Indicates whether this button is in toggled state or not. |
||||||
|
* |
||||||
|
* @override |
||||||
|
* @protected |
||||||
|
* @returns {boolean} |
||||||
|
*/ |
||||||
|
_isToggled() { |
||||||
|
return this.props._editing; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Maps part of the redux state to the component's props. |
||||||
|
* |
||||||
|
* @param {Object} state - The redux store/state. |
||||||
|
* @param {Object} ownProps - The properties explicitly passed to the component |
||||||
|
* instance. |
||||||
|
* @returns {Object} |
||||||
|
*/ |
||||||
|
function _mapStateToProps(state: Object, ownProps: Object) { |
||||||
|
const { documentUrl, editing } = state['features/etherpad']; |
||||||
|
const { visible = Boolean(documentUrl) } = ownProps; |
||||||
|
|
||||||
|
return { |
||||||
|
_editing: editing, |
||||||
|
visible |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
export default translate(connect(_mapStateToProps)(SharedDocumentButton)); |
||||||
@ -0,0 +1,2 @@ |
|||||||
|
export { default as SharedDocument } from './native/SharedDocument'; |
||||||
|
export { default as SharedDocumentButton } from './SharedDocumentButton'; |
||||||
@ -0,0 +1 @@ |
|||||||
|
export { default as SharedDocumentButton } from './SharedDocumentButton'; |
||||||
@ -0,0 +1,178 @@ |
|||||||
|
// @flow
|
||||||
|
|
||||||
|
import React, { PureComponent } from 'react'; |
||||||
|
import { SafeAreaView, View } from 'react-native'; |
||||||
|
import { WebView } from 'react-native-webview'; |
||||||
|
import type { Dispatch } from 'redux'; |
||||||
|
|
||||||
|
import { ColorSchemeRegistry } from '../../../base/color-scheme'; |
||||||
|
import { translate } from '../../../base/i18n'; |
||||||
|
import { HeaderWithNavigation, LoadingIndicator, SlidingView } from '../../../base/react'; |
||||||
|
import { connect } from '../../../base/redux'; |
||||||
|
|
||||||
|
import { toggleDocument } from '../../actions'; |
||||||
|
import { getSharedDocumentUrl } from '../../functions'; |
||||||
|
|
||||||
|
import styles, { INDICATOR_COLOR } from './styles'; |
||||||
|
|
||||||
|
/** |
||||||
|
* The type of the React {@code Component} props of {@code ShareDocument}. |
||||||
|
*/ |
||||||
|
type Props = { |
||||||
|
|
||||||
|
/** |
||||||
|
* URL for the shared document. |
||||||
|
*/ |
||||||
|
_documentUrl: string, |
||||||
|
|
||||||
|
/** |
||||||
|
* Color schemed style of the header component. |
||||||
|
*/ |
||||||
|
_headerStyles: Object, |
||||||
|
|
||||||
|
/** |
||||||
|
* True if the chat window should be rendered. |
||||||
|
*/ |
||||||
|
_isOpen: boolean, |
||||||
|
|
||||||
|
/** |
||||||
|
* The Redux dispatch function. |
||||||
|
*/ |
||||||
|
dispatch: Dispatch<any>, |
||||||
|
|
||||||
|
/** |
||||||
|
* Function to be used to translate i18n labels. |
||||||
|
*/ |
||||||
|
t: Function |
||||||
|
}; |
||||||
|
|
||||||
|
/** |
||||||
|
* Implements a React native component that renders the shared document window. |
||||||
|
*/ |
||||||
|
class SharedDocument extends PureComponent<Props> { |
||||||
|
/** |
||||||
|
* Instantiates a new instance. |
||||||
|
* |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
constructor(props: Props) { |
||||||
|
super(props); |
||||||
|
|
||||||
|
this._onClose = this._onClose.bind(this); |
||||||
|
this._onError = this._onError.bind(this); |
||||||
|
this._renderLoading = this._renderLoading.bind(this); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Implements React's {@link Component#render()}. |
||||||
|
* |
||||||
|
* @inheritdoc |
||||||
|
*/ |
||||||
|
render() { |
||||||
|
const { _documentUrl, _isOpen } = this.props; |
||||||
|
const webViewStyles = this._getWebViewStyles(); |
||||||
|
|
||||||
|
return ( |
||||||
|
<SlidingView |
||||||
|
onHide = { this._onClose } |
||||||
|
position = 'bottom' |
||||||
|
show = { _isOpen } > |
||||||
|
<View style = { styles.webViewWrapper }> |
||||||
|
<HeaderWithNavigation |
||||||
|
headerLabelKey = 'documentSharing.title' |
||||||
|
onPressBack = { this._onClose } /> |
||||||
|
<SafeAreaView style = { webViewStyles }> |
||||||
|
<WebView |
||||||
|
onError = { this._onError } |
||||||
|
renderLoading = { this._renderLoading } |
||||||
|
source = {{ uri: _documentUrl }} |
||||||
|
startInLoadingState = { true } /> |
||||||
|
</SafeAreaView> |
||||||
|
</View> |
||||||
|
</SlidingView> |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Computes the styles required for the WebView component. |
||||||
|
* |
||||||
|
* @returns {Object} |
||||||
|
*/ |
||||||
|
_getWebViewStyles() { |
||||||
|
return { |
||||||
|
...styles.webView, |
||||||
|
backgroundColor: this.props._headerStyles.screenHeader.backgroundColor |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
_onClose: () => boolean |
||||||
|
|
||||||
|
/** |
||||||
|
* Closes the window. |
||||||
|
* |
||||||
|
* @returns {boolean} |
||||||
|
*/ |
||||||
|
_onClose() { |
||||||
|
const { _isOpen, dispatch } = this.props; |
||||||
|
|
||||||
|
if (_isOpen) { |
||||||
|
dispatch(toggleDocument()); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
_onError: () => void; |
||||||
|
|
||||||
|
/** |
||||||
|
* Callback to handle the error if the page fails to load. |
||||||
|
* |
||||||
|
* @returns {void} |
||||||
|
*/ |
||||||
|
_onError() { |
||||||
|
const { _isOpen, dispatch } = this.props; |
||||||
|
|
||||||
|
if (_isOpen) { |
||||||
|
dispatch(toggleDocument()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
_renderLoading: () => React$Component<any>; |
||||||
|
|
||||||
|
/** |
||||||
|
* Renders the loading indicator. |
||||||
|
* |
||||||
|
* @returns {React$Component<any>} |
||||||
|
*/ |
||||||
|
_renderLoading() { |
||||||
|
return ( |
||||||
|
<View style = { styles.indicatorWrapper }> |
||||||
|
<LoadingIndicator |
||||||
|
color = { INDICATOR_COLOR } |
||||||
|
size = 'large' /> |
||||||
|
</View> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Maps (parts of) the redux state to {@link SharedDocument} React {@code Component} props. |
||||||
|
* |
||||||
|
* @param {Object} state - The redux store/state. |
||||||
|
* @private |
||||||
|
* @returns {Object} |
||||||
|
*/ |
||||||
|
export function _mapStateToProps(state: Object) { |
||||||
|
const { editing } = state['features/etherpad']; |
||||||
|
const documentUrl = getSharedDocumentUrl(state); |
||||||
|
|
||||||
|
return { |
||||||
|
_documentUrl: documentUrl, |
||||||
|
_headerStyles: ColorSchemeRegistry.get(state, 'Header'), |
||||||
|
_isOpen: editing |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
export default translate(connect(_mapStateToProps)(SharedDocument)); |
||||||
@ -0,0 +1,24 @@ |
|||||||
|
// @flow
|
||||||
|
|
||||||
|
import { ColorPalette } from '../../../base/styles'; |
||||||
|
|
||||||
|
export const INDICATOR_COLOR = ColorPalette.lightGrey; |
||||||
|
|
||||||
|
export default { |
||||||
|
|
||||||
|
indicatorWrapper: { |
||||||
|
alignItems: 'center', |
||||||
|
backgroundColor: ColorPalette.white, |
||||||
|
height: '100%', |
||||||
|
justifyContent: 'center' |
||||||
|
}, |
||||||
|
|
||||||
|
webView: { |
||||||
|
flex: 1 |
||||||
|
}, |
||||||
|
|
||||||
|
webViewWrapper: { |
||||||
|
flex: 1, |
||||||
|
flexDirection: 'column' |
||||||
|
} |
||||||
|
}; |
||||||
@ -0,0 +1,34 @@ |
|||||||
|
// @flow
|
||||||
|
|
||||||
|
import { toState } from '../base/redux'; |
||||||
|
|
||||||
|
const ETHERPAD_OPTIONS = { |
||||||
|
showControls: 'true', |
||||||
|
showChat: 'false', |
||||||
|
showLineNumbers: 'true', |
||||||
|
useMonospaceFont: 'false' |
||||||
|
}; |
||||||
|
|
||||||
|
/** |
||||||
|
* Retrieves the current sahred document URL. |
||||||
|
* |
||||||
|
* @param {Function|Object} stateful - The redux store or {@code getState} function. |
||||||
|
* @returns {?string} - Current shared document URL or undefined. |
||||||
|
*/ |
||||||
|
export function getSharedDocumentUrl(stateful: Function | Object) { |
||||||
|
const state = toState(stateful); |
||||||
|
const { documentUrl } = state['features/etherpad']; |
||||||
|
const { displayName } = state['features/base/settings']; |
||||||
|
|
||||||
|
if (!documentUrl) { |
||||||
|
return undefined; |
||||||
|
} |
||||||
|
|
||||||
|
const params = new URLSearchParams(ETHERPAD_OPTIONS); |
||||||
|
|
||||||
|
if (displayName) { |
||||||
|
params.append('userName', displayName); |
||||||
|
} |
||||||
|
|
||||||
|
return `${documentUrl}?${params.toString()}`; |
||||||
|
} |
||||||
@ -1,5 +1,7 @@ |
|||||||
export * from './actions'; |
export * from './actions'; |
||||||
export * from './actionTypes'; |
export * from './actionTypes'; |
||||||
|
export * from './components'; |
||||||
|
export * from './functions'; |
||||||
|
|
||||||
import './middleware'; |
import './middleware'; |
||||||
import './reducer'; |
import './reducer'; |
||||||
|
|||||||
Loading…
Reference in new issue