From e23d4317eb2c8aa8a82ee32da9e3ff792bc7b302 Mon Sep 17 00:00:00 2001 From: zbettenbuk Date: Fri, 16 Feb 2018 10:06:03 -0600 Subject: [PATCH] Add hint box with dynamic join button --- lang/main.json | 1 + .../components/native/LoadingIndicator.js | 13 ++- .../components/AbstractRecentList.js | 9 +- .../components/RecentList.native.js | 16 ++- .../features/recent-list/components/styles.js | 7 ++ .../welcome/components/AbstractWelcomePage.js | 5 + .../welcome/components/WelcomePage.native.js | 99 ++++++++++++++++++- react/features/welcome/components/styles.js | 45 ++++++++- 8 files changed, 178 insertions(+), 17 deletions(-) diff --git a/lang/main.json b/lang/main.json index 43c02f833..2b884abed 100644 --- a/lang/main.json +++ b/lang/main.json @@ -49,6 +49,7 @@ "appDescription": "Go ahead, video chat with the whole team. In fact, invite everyone you know. __app__ is a fully encrypted, 100% open source video conferencing solution that you can use all day, every day, for free — with no account needed.", "audioOnlyLabel": "Voice", "go": "GO", + "hintText": "Enter a room name you want to join to, or simply create a new room name, eg. MeetingWithJohn", "join": "JOIN", "privacy": "Privacy", "roomname": "Enter room name", diff --git a/react/features/base/react/components/native/LoadingIndicator.js b/react/features/base/react/components/native/LoadingIndicator.js index ac2d6e8db..2cd2359e6 100644 --- a/react/features/base/react/components/native/LoadingIndicator.js +++ b/react/features/base/react/components/native/LoadingIndicator.js @@ -5,12 +5,21 @@ import { ActivityIndicator } from 'react-native'; import { ColorPalette } from '../../../styles'; +type Props = { + + /** + * Prop to set the size of the indicator. This is the same as the + * prop of the native component. + */ + size: 'large' | 'small' +}; + /** * An animated, large react-native {@link ActivityIndicator} which is considered * a suitable visualization of long-running processes with indeterminate amounts * of work to be done. */ -export default class LoadingIndicator extends Component<*> { +export default class LoadingIndicator extends Component { /** * Implements React's {@link Component#render()}. * @@ -22,7 +31,7 @@ export default class LoadingIndicator extends Component<*> { ); } diff --git a/react/features/recent-list/components/AbstractRecentList.js b/react/features/recent-list/components/AbstractRecentList.js index 2d7d46f5e..181e32dcb 100644 --- a/react/features/recent-list/components/AbstractRecentList.js +++ b/react/features/recent-list/components/AbstractRecentList.js @@ -9,6 +9,11 @@ import { appNavigate } from '../../app'; */ type Props = { + /** + * Indicates if the list is disabled or not. + */ + disabled: boolean, + /** * The redux store's {@code dispatch} function. */ @@ -31,7 +36,9 @@ export default class AbstractRecentList extends Component { * @returns {void} */ _onJoin(room) { - room && this.props.dispatch(appNavigate(room)); + const { disabled, dispatch } = this.props; + + !disabled && room && dispatch(appNavigate(room)); } /** diff --git a/react/features/recent-list/components/RecentList.native.js b/react/features/recent-list/components/RecentList.native.js index 11a442a35..627b9a83c 100644 --- a/react/features/recent-list/components/RecentList.native.js +++ b/react/features/recent-list/components/RecentList.native.js @@ -28,8 +28,8 @@ class RecentList extends AbstractRecentList { * * @inheritdoc */ - constructor() { - super(); + constructor(props) { + super(props); // Bind event handlers so they are only bound once per instance. this._getAvatarStyle = this._getAvatarStyle.bind(this); @@ -47,16 +47,22 @@ class RecentList extends AbstractRecentList { * @returns {ReactElement} */ render() { - if (!this.props || !this.props._recentList) { + const { _recentList, disabled } = this.props; + + if (!_recentList) { return null; } const listViewDataSource = this.dataSource.cloneWithRows( - getRecentRooms(this.props._recentList)); + getRecentRooms(_recentList)); return ( - + { - this._renderJoinButton() + this._renderHintBox() } - + @@ -144,6 +152,50 @@ class WelcomePage extends AbstractWelcomePage { ); } + /** + * Constructs a style array to handle the hint box animation. + * + * @private + * @returns {Array} + */ + _getHintBoxStyle() { + return [ + styles.hintContainer, + { + opacity: this.state.hintBoxAnimation + } + ]; + } + + /** + * Callback for when the room field's focus changes so the hint box + * must be rendered or removed. + * + * @private + * @param {boolean} focused - The focused state of the field. + * @returns {Function} + */ + _onFieldFocusChange(focused) { + return () => { + if (focused) { + this.setState({ + _fieldFocused: true + }); + } + + Animated.timing(this.state.hintBoxAnimation, { + duration: 300, + toValue: focused ? 1 : 0 + }).start(animationState => { + if (animationState.finished && !focused) { + this.setState({ + _fieldFocused: false + }); + } + }); + }; + } + /** * Toggles the side bar. * @@ -171,6 +223,36 @@ class WelcomePage extends AbstractWelcomePage { })); } + /** + * Renders the hint box if necessary. + * + * @private + * @returns {React$Node} + */ + _renderHintBox() { + if (this.state._fieldFocused) { + const { t } = this.props; + + return ( + + + + { t('welcomepage.hintText') } + + + + { + this._renderJoinButton() + } + + + ); + } + + return null; + } + /** * Renders the join button. * @@ -188,7 +270,9 @@ class WelcomePage extends AbstractWelcomePage { // modify non-native children. children = ( - + ); } else { @@ -201,12 +285,17 @@ class WelcomePage extends AbstractWelcomePage { /* eslint-enable no-extra-parens */ + const buttonDisabled = this._isJoinDisabled(); + return ( { children diff --git a/react/features/welcome/components/styles.js b/react/features/welcome/components/styles.js index 915e81830..c6f2c78dd 100644 --- a/react/features/welcome/components/styles.js +++ b/react/features/welcome/components/styles.js @@ -54,10 +54,17 @@ export default createStyleSheet({ borderColor: ColorPalette.blue, borderRadius: 4, borderWidth: 1, - height: 40, + height: 30, justifyContent: 'center', - marginBottom: BoxModel.margin, - marginTop: BoxModel.margin + paddingHorizontal: 20 + }, + + /** + * Renders the button visually disabled. + */ + buttonDisabled: { + backgroundColor: '#cccccc', + borderColor: '#999999' }, /** @@ -66,7 +73,7 @@ export default createStyleSheet({ buttonText: { alignSelf: 'center', color: ColorPalette.white, - fontSize: 18 + fontSize: 14 }, /** @@ -86,6 +93,36 @@ export default createStyleSheet({ justifyContent: 'space-between' }, + /** + * Container for the button on the hint box. + */ + hintButtonContainer: { + flexDirection: 'row', + justifyContent: 'flex-end' + }, + + /** + * Container for the text on the hint box. + */ + hintTextContainer: { + marginBottom: 2 * BoxModel.margin + }, + + /** + * Container for the hint box. + */ + hintContainer: { + backgroundColor: ColorPalette.white, + borderColor: ColorPalette.white, + borderRadius: 4, + borderWidth: 1, + flexDirection: 'column', + marginVertical: 5, + overflow: 'hidden', + paddingHorizontal: BoxModel.padding, + paddingVertical: 2 * BoxModel.padding + }, + /** * Container for the items in the side bar. */