feat(navigation) two actions screen header buttons ui updates

This commit is contained in:
Calin Chitu 2022-02-11 11:49:49 +02:00 committed by Calinteodor
parent 6ab46186e2
commit eb720d5ddc
10 changed files with 144 additions and 102 deletions

View File

@ -5,6 +5,7 @@ import BaseTheme from '../../../base/ui/components/BaseTheme.native';
export const INSECURE_ROOM_NAME_LABEL_COLOR = BaseTheme.palette.actionDanger; export const INSECURE_ROOM_NAME_LABEL_COLOR = BaseTheme.palette.actionDanger;
const TITLE_BAR_BUTTON_SIZE = 24; const TITLE_BAR_BUTTON_SIZE = 24;
const HEADER_ACTION_BUTTON_SIZE = 17;
/** /**
@ -36,7 +37,7 @@ export default {
}, },
headerNavigationIcon: { headerNavigationIcon: {
marginLeft: 12 marginLeft: 14
}, },
headerNavigationButton: { headerNavigationButton: {
@ -45,6 +46,19 @@ export default {
width: BaseTheme.spacing[6] width: BaseTheme.spacing[6]
}, },
headerNavigationText: {
color: BaseTheme.palette.text01,
fontSize: HEADER_ACTION_BUTTON_SIZE,
marginHorizontal: BaseTheme.spacing[3]
},
headerNavigationTextBold: {
...BaseTheme.typography.labelButton,
color: BaseTheme.palette.text01,
fontSize: HEADER_ACTION_BUTTON_SIZE,
marginHorizontal: BaseTheme.spacing[3]
},
/** /**
* View that contains the indicators. * View that contains the indicators.
*/ */

View File

@ -72,8 +72,7 @@ class SharedDocument extends PureComponent<Props> {
headerLeft: () => ( headerLeft: () => (
<HeaderNavigationButton <HeaderNavigationButton
onPress = { goBack } onPress = { goBack }
src = { IconArrowBack } src = { IconArrowBack } />
style = { styles.headerArrowBack } />
) )
}); });
} }

View File

@ -5,11 +5,6 @@ import { ColorPalette } from '../../../base/styles';
export const INDICATOR_COLOR = ColorPalette.lightGrey; export const INDICATOR_COLOR = ColorPalette.lightGrey;
export default { export default {
headerArrowBack: {
marginLeft: 12
},
indicatorWrapper: { indicatorWrapper: {
alignItems: 'center', alignItems: 'center',
backgroundColor: ColorPalette.white, backgroundColor: ColorPalette.white,

View File

@ -8,7 +8,7 @@ import {
TouchableOpacity, TouchableOpacity,
View View
} from 'react-native'; } from 'react-native';
import { Text, TouchableRipple, withTheme } from 'react-native-paper'; import { withTheme } from 'react-native-paper';
import { AlertDialog, openDialog } from '../../../../base/dialog'; import { AlertDialog, openDialog } from '../../../../base/dialog';
import { translate } from '../../../../base/i18n'; import { translate } from '../../../../base/i18n';
@ -26,6 +26,8 @@ import {
type Item type Item
} from '../../../../base/react'; } from '../../../../base/react';
import { connect } from '../../../../base/redux'; import { connect } from '../../../../base/redux';
import HeaderNavigationButton
from '../../../../mobile/navigation/components/HeaderNavigationButton';
import ClearableInput from '../../../../participants-pane/components/native/ClearableInput'; import ClearableInput from '../../../../participants-pane/components/native/ClearableInput';
import { beginShareRoom } from '../../../../share-room'; import { beginShareRoom } from '../../../../share-room';
import { INVITE_TYPES } from '../../../constants'; import { INVITE_TYPES } from '../../../constants';
@ -139,18 +141,14 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
* @returns {void} * @returns {void}
*/ */
componentDidMount() { componentDidMount() {
const { navigation, t, theme } = this.props; const { navigation, t } = this.props;
const { palette } = theme;
navigation.setOptions({ navigation.setOptions({
headerRight: () => ( headerRight: () => (
<TouchableRipple <HeaderNavigationButton
disabled = { this._isAddDisabled() } disabled = { this._isAddDisabled() }
rippleColor = { palette.screen01Header } > label = { t('inviteDialog.send') }
<Text style = { styles.headerSendInvite }> twoActions = { true } />
{ t('inviteDialog.send') }
</Text>
</TouchableRipple>
) )
}); });
} }
@ -161,20 +159,16 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
* @inheritdoc * @inheritdoc
*/ */
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
const { navigation, t, theme } = this.props; const { navigation, t } = this.props;
const { palette } = theme;
navigation.setOptions({ navigation.setOptions({
// eslint-disable-next-line react/no-multi-comp // eslint-disable-next-line react/no-multi-comp
headerRight: () => ( headerRight: () => (
<TouchableRipple <HeaderNavigationButton
disabled = { this._isAddDisabled() } disabled = { this._isAddDisabled() }
label = { t('inviteDialog.send') }
onPress = { this._onInvite } onPress = { this._onInvite }
rippleColor = { palette.screen01Header } > twoActions = { true } />
<Text style = { styles.headerSendInvite }>
{ t('inviteDialog.send') }
</Text>
</TouchableRipple>
) )
}); });

View File

@ -1,17 +1,19 @@
// @flow // @flow
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Linking, View } from 'react-native'; import { Linking, Platform, View } from 'react-native';
import { WebView } from 'react-native-webview'; import { WebView } from 'react-native-webview';
import { type Dispatch } from 'redux'; 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 { IconClose } from '../../../../base/icons';
import JitsiScreen from '../../../../base/modal/components/JitsiScreen'; 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 { renderArrowBackButton } import HeaderNavigationButton
from '../../../../mobile/navigation/components/welcome/functions'; from '../../../../mobile/navigation/components/HeaderNavigationButton';
import { navigateRoot } from '../../../../mobile/navigation/rootNavigationContainerRef';
import { screen } from '../../../../mobile/navigation/routes'; import { screen } from '../../../../mobile/navigation/routes';
import { getDialInfoPageURLForURIString } from '../../../functions'; import { getDialInfoPageURLForURIString } from '../../../functions';
@ -30,7 +32,12 @@ type Props = {
/** /**
* Default prop for navigating between screen components(React Navigation). * Default prop for navigating between screen components(React Navigation).
*/ */
route: Object route: Object,
/**
* Translation function.
*/
t: Function
}; };
/** /**
@ -46,6 +53,7 @@ class DialInSummary extends Component<Props> {
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
this._onNavigateToRoot = this._onNavigateToRoot.bind(this);
this._onError = this._onError.bind(this); this._onError = this._onError.bind(this);
this._onNavigate = this._onNavigate.bind(this); this._onNavigate = this._onNavigate.bind(this);
this._renderLoading = this._renderLoading.bind(this); this._renderLoading = this._renderLoading.bind(this);
@ -59,14 +67,24 @@ class DialInSummary extends Component<Props> {
* @returns {void} * @returns {void}
*/ */
componentDidMount() { componentDidMount() {
const { const { navigation, t } = this.props;
navigation
} = this.props;
navigation.setOptions({ navigation.setOptions({
headerLeft: () => headerLeft: () => {
renderArrowBackButton(() => if (Platform.OS === 'ios') {
navigation.navigate(screen.welcome.main)) return (
<HeaderNavigationButton
label = { t('dialog.close') }
onPress = { this._onNavigateToRoot } />
);
}
return (
<HeaderNavigationButton
onPress = { this._onNavigateToRoot }
src = { IconClose } />
);
}
}); });
} }
@ -94,6 +112,17 @@ class DialInSummary extends Component<Props> {
); );
} }
_onNavigateToRoot: () => void;
/**
* Callback to handle navigation back to root.
*
* @returns {void}
*/
_onNavigateToRoot() {
navigateRoot(screen.root);
}
_onError: () => void; _onError: () => void;
/** /**

View File

@ -2,38 +2,77 @@
import React from 'react'; import React from 'react';
import { TouchableOpacity } from 'react-native-gesture-handler'; import { TouchableOpacity } from 'react-native-gesture-handler';
import { Text, TouchableRipple } from 'react-native-paper';
import { Icon } from '../../../base/icons'; import { Icon } from '../../../base/icons';
import BaseTheme from '../../../base/ui/components/BaseTheme';
import styles from '../../../conference/components/native/styles'; import styles from '../../../conference/components/native/styles';
type Props = { type Props = {
/**
* Is the button disabled?
*/
disabled?: boolean,
/**
* Label of the button.
*/
label?: string,
/** /**
* Callback to invoke when the {@code HeaderNavigationButton} is clicked/pressed. * Callback to invoke when the {@code HeaderNavigationButton} is clicked/pressed.
*/ */
onPress: Function, onPress?: Function,
/** /**
* The ImageSource to be rendered as image. * The ImageSource to be rendered as image.
*/ */
src: Object, src?: Object,
/** /**
* The component's external style. * Header has two actions.
*/ */
style?: Object twoActions?: boolean
} }
const HeaderNavigationButton = ({ onPress, src, style }: Props) => ( const HeaderNavigationButton
= ({
disabled,
label,
onPress,
src,
twoActions
}: Props) =>
(
<>
{
src ? (
<TouchableOpacity <TouchableOpacity
onPress = { onPress } onPress = { onPress }
style = { styles.headerNavigationButton } > style = { styles.headerNavigationButton }>
<Icon <Icon
size = { 20 } size = { 20 }
src = { src } src = { src }
style = { [ styles.headerNavigationIcon, style ] } /> style = { styles.headerNavigationIcon } />
</TouchableOpacity> </TouchableOpacity>
); ) : (
<TouchableRipple
disabled = { disabled }
onPress = { onPress }
rippleColor = { BaseTheme.palette.screen01Header }>
<Text
style = {
twoActions
? styles.headerNavigationTextBold
: styles.headerNavigationText
}>
{ label }
</Text>
</TouchableRipple>
)}
</>
);
export default HeaderNavigationButton; export default HeaderNavigationButton;

View File

@ -4,7 +4,6 @@ import { TransitionPresets } from '@react-navigation/stack';
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Platform } from 'react-native'; import { Platform } from 'react-native';
import { Text, TouchableRipple } from 'react-native-paper';
import { import {
Icon, Icon,
@ -20,14 +19,6 @@ import HeaderNavigationButton from './components/HeaderNavigationButton';
import { goBack } from './components/conference/ConferenceNavigationContainerRef'; import { goBack } from './components/conference/ConferenceNavigationContainerRef';
/**
* Close button text color.
*/
export const closeTextColor = {
color: BaseTheme.palette.text01,
marginLeft: BaseTheme.spacing[3]
};
/** /**
* Navigation container theme. * Navigation container theme.
*/ */
@ -211,13 +202,9 @@ export const presentationScreenOptions = {
if (Platform.OS === 'ios') { if (Platform.OS === 'ios') {
return ( return (
<TouchableRipple <HeaderNavigationButton
onPress = { goBack } label = { t('dialog.close') }
rippleColor = { BaseTheme.palette.screen01Header }> onPress = { goBack } />
<Text style = { closeTextColor }>
{ t('dialog.close') }
</Text>
</TouchableRipple>
); );
} }
@ -226,7 +213,6 @@ export const presentationScreenOptions = {
onPress = { goBack } onPress = { goBack }
src = { IconClose } /> src = { IconClose } />
); );
}, },
headerStatusBarHeight: 0, headerStatusBarHeight: 0,
headerStyle: { headerStyle: {

View File

@ -1,13 +1,13 @@
// @flow // @flow
import React from 'react'; import React from 'react';
import { Text, TouchableRipple } from 'react-native-paper';
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 BaseTheme from '../../../../base/ui/components/BaseTheme';
import { googleApi } from '../../../../google-api'; import { googleApi } from '../../../../google-api';
import HeaderNavigationButton
from '../../../../mobile/navigation/components/HeaderNavigationButton';
import { goBack } import { goBack }
from '../../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef'; from '../../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
import { setLiveStreamKey } from '../../../actions'; import { setLiveStreamKey } from '../../../actions';
@ -33,7 +33,7 @@ class StartLiveStreamDialog extends AbstractStartLiveStreamDialog<Props> {
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.
this._onOkPress = this._onOkPress.bind(this); this._onStartPress = this._onStartPress.bind(this);
this._onStreamKeyChangeNative this._onStreamKeyChangeNative
= this._onStreamKeyChangeNative.bind(this); = this._onStreamKeyChangeNative.bind(this);
this._onStreamKeyPick = this._onStreamKeyPick.bind(this); this._onStreamKeyPick = this._onStreamKeyPick.bind(this);
@ -52,25 +52,22 @@ class StartLiveStreamDialog extends AbstractStartLiveStreamDialog<Props> {
navigation.setOptions({ navigation.setOptions({
headerRight: () => ( headerRight: () => (
<TouchableRipple <HeaderNavigationButton
onPress = { this._onOkPress } label = { t('dialog.start') }
rippleColor = { BaseTheme.palette.screen01Header } > onPress = { this._onStartPress }
<Text style = { styles.startLiveStreamLabel }> twoActions = { true } />
{ t('dialog.start') }
</Text>
</TouchableRipple>
) )
}); });
} }
_onOkPress: () => void; _onStartPress: () => void;
/** /**
* Starts live stream session and goes back to the previous screen. * Starts live stream session and goes back to the previous screen.
* *
* @returns {void} * @returns {void}
*/ */
_onOkPress() { _onStartPress() {
this._onSubmit() && goBack(); this._onSubmit() && goBack();
} }

View File

@ -57,14 +57,6 @@ export default createStyleSheet({
marginBottom: BoxModel.margin marginBottom: BoxModel.margin
}, },
/**
* Label for the button that starts live stream.
*/
startLiveStreamLabel: {
color: BaseTheme.palette.text01,
marginRight: 12
},
/** /**
* Container for the live stream screen. * Container for the live stream screen.
*/ */

View File

@ -1,12 +1,12 @@
// @flow // @flow
import React from 'react'; import React from 'react';
import { Text, TouchableRipple } from 'react-native-paper';
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 BaseTheme from '../../../../base/ui/components/BaseTheme'; import HeaderNavigationButton
from '../../../../mobile/navigation/components/HeaderNavigationButton';
import { goBack } from import { goBack } from
'../../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef'; '../../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
import AbstractStartRecordingDialog, { import AbstractStartRecordingDialog, {
@ -32,7 +32,7 @@ class StartRecordingDialog extends AbstractStartRecordingDialog<Props> {
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
this._onOkPress = this._onOkPress.bind(this); this._onStartPress = this._onStartPress.bind(this);
} }
/** /**
@ -55,36 +55,33 @@ class StartRecordingDialog extends AbstractStartRecordingDialog<Props> {
isValidating isValidating
} = this.state; } = this.state;
// disable ok button id recording service is shown only, when // disable start button id recording service is shown only, when
// validating dropbox token, if that is not enabled we either always // validating dropbox token, if that is not enabled we either always
// show the ok button or if just dropbox is enabled ok is available // show the start button or if just dropbox is enabled start is available
// when there is token // when there is token
const isOkDisabled const isStartDisabled
= _fileRecordingsServiceEnabled ? isValidating = _fileRecordingsServiceEnabled ? isValidating
: _isDropboxEnabled ? !isTokenValid : false; : _isDropboxEnabled ? !isTokenValid : false;
navigation.setOptions({ navigation.setOptions({
headerRight: () => ( headerRight: () => (
<TouchableRipple <HeaderNavigationButton
disabled = { isOkDisabled } disabled = { isStartDisabled }
onPress = { this._onOkPress } label = { t('dialog.start') }
rippleColor = { BaseTheme.palette.screen01Header } > onPress = { this._onStartPress }
<Text style = { styles.startRecordingLabel }> twoActions = { true } />
{ t('dialog.start') }
</Text>
</TouchableRipple>
) )
}); });
} }
_onOkPress: () => void; _onStartPress: () => void;
/** /**
* Starts recording session and goes back to the previous screen. * Starts recording session and goes back to the previous screen.
* *
* @returns {void} * @returns {void}
*/ */
_onOkPress() { _onStartPress() {
this._onSubmit() && goBack(); this._onSubmit() && goBack();
} }