init
Some checks failed
Close stale issues and PRs / stale (push) Has been cancelled

This commit is contained in:
2025-09-02 14:49:16 +08:00
commit 38ba663466
2885 changed files with 391107 additions and 0 deletions

View File

@@ -0,0 +1,168 @@
import { Component } from 'react';
import { IStore } from '../../../../app/types';
import { hideDialog } from '../../actions';
import { DialogProps } from '../../constants';
/**
* The type of the React {@code Component} props of {@link AbstractDialog}.
*/
export interface IProps extends DialogProps {
/**
* Used to show/hide the dialog on cancel.
*/
dispatch: IStore['dispatch'];
}
/**
* The type of the React {@code Component} state of {@link AbstractDialog}.
*/
export interface IState {
submitting?: boolean;
}
/**
* An abstract implementation of a dialog on Web/React and mobile/react-native.
*/
export default class AbstractDialog<P extends IProps, S extends IState = IState>
extends Component<P, S> {
_mounted: boolean;
/**
* Initializes a new {@code AbstractDialog} instance.
*
* @param {Object} props - The read-only React {@code Component} props with
* which the new instance is to be initialized.
*/
constructor(props: P) {
super(props);
// Bind event handlers so they are only bound once per instance.
this._onBack = this._onBack.bind(this);
this._onCancel = this._onCancel.bind(this);
this._onSubmit = this._onSubmit.bind(this);
this._onSubmitFulfilled = this._onSubmitFulfilled.bind(this);
this._onSubmitRejected = this._onSubmitRejected.bind(this);
}
/**
* Implements React's {@link Component#componentDidMount()}. Invoked
* immediately before mounting occurs.
*
* @inheritdoc
*/
override componentDidMount() {
this._mounted = true;
}
/**
* Implements React's {@link Component#componentWillUnmount()}. Invoked
* immediately before this component is unmounted and destroyed.
*
* @inheritdoc
*/
override componentWillUnmount() {
this._mounted = false;
}
/**
* Dispatches a redux action to hide this dialog.
*
* @returns {*} The return value of {@link hideDialog}.
*/
_hide() {
return this.props.dispatch(hideDialog());
}
_onBack() {
const { backDisabled = false, onBack } = this.props;
if (!backDisabled && (!onBack || onBack())) {
this._hide();
}
}
/**
* Dispatches a redux action to hide this dialog when it's canceled.
*
* @protected
* @returns {void}
*/
_onCancel() {
const { cancelDisabled = false, onCancel } = this.props;
if (!cancelDisabled && (!onCancel || onCancel())) {
this._hide();
}
}
/**
* Submits this {@code Dialog}. If the React {@code Component} prop
* {@code onSubmit} is defined, the function that is the value of the prop
* is invoked. If the function returns a {@code thenable}, then the
* resolution of the {@code thenable} is awaited. If the submission
* completes successfully, a redux action will be dispatched to hide this
* dialog.
*
* @protected
* @param {string} [value] - The submitted value if any.
* @returns {void}
*/
_onSubmit(value?: string) {
const { okDisabled = false, onSubmit } = this.props;
if (!okDisabled) {
this.setState({ submitting: true });
// Invoke the React Component prop onSubmit if any.
const r = !onSubmit || onSubmit(value);
// If the invocation returns a thenable, await its resolution;
// otherwise, treat the return value as a boolean indicating whether
// the submission has completed successfully.
let then;
if (r) {
switch (typeof r) {
case 'function':
case 'object':
then = r.then;
break;
}
}
if (typeof then === 'function' && then.length === 2) {
then.call(r, this._onSubmitFulfilled, this._onSubmitRejected);
} else if (r) {
this._onSubmitFulfilled();
} else {
this._onSubmitRejected();
}
}
}
/**
* Notifies this {@code AbstractDialog} that it has been submitted
* successfully. Dispatches a redux action to hide this dialog after it has
* been submitted.
*
* @private
* @returns {void}
*/
_onSubmitFulfilled() {
this._mounted && this.setState({ submitting: false });
this._hide();
}
/**
* Notifies this {@code AbstractDialog} that its submission has failed.
*
* @private
* @returns {void}
*/
_onSubmitRejected() {
this._mounted && this.setState({ submitting: false });
}
}

View File

@@ -0,0 +1,56 @@
import React from 'react';
import { WithTranslation } from 'react-i18next';
import Dialog from 'react-native-dialog';
import { connect } from 'react-redux';
import { translate } from '../../../i18n/functions';
import { _abstractMapStateToProps } from '../../functions';
import { renderHTML } from '../functions.native';
import AbstractDialog, { IProps as AbstractProps } from './AbstractDialog';
interface IProps extends AbstractProps, WithTranslation {
/**
* Untranslated i18n key of the content to be displayed.
*
* NOTE: This dialog also adds support to Object type keys that will be
* translated using the provided params. See i18n function
* {@code translate(string, Object)} for more details.
*/
contentKey: string | { key: string; params: Object; };
}
/**
* Implements an alert dialog, to simply show an error or a message,
* then disappear on dismiss.
*/
class AlertDialog extends AbstractDialog<IProps> {
/**
* Implements React's {@link Component#render}.
*
* @inheritdoc
*/
override render() {
const { contentKey, t } = this.props;
const content
= typeof contentKey === 'string'
? t(contentKey)
: renderHTML(t(contentKey.key, contentKey.params));
return (
<Dialog.Container
coverScreen = { false }
visible = { true }>
<Dialog.Description>
{ content }
</Dialog.Description>
<Dialog.Button
label = { t('dialog.Ok') }
onPress = { this._onSubmit } />
</Dialog.Container>
);
}
}
export default translate(connect(_abstractMapStateToProps)(AlertDialog));

View File

@@ -0,0 +1,150 @@
import React, { PureComponent, ReactNode } from 'react';
import { SafeAreaView, ScrollView, View, ViewStyle } from 'react-native';
import { connect } from 'react-redux';
import { IStore } from '../../../../app/types';
import SlidingView from '../../../react/components/native/SlidingView';
import { hideSheet } from '../../actions';
import { bottomSheetStyles as styles } from './styles';
/**
* The type of {@code BottomSheet}'s React {@code Component} prop types.
*/
type Props = {
/**
* Whether to add padding to scroll view.
*/
addScrollViewPadding?: boolean;
/**
* The children to be displayed within this component.
*/
children: ReactNode;
/**
* Redux Dispatch function.
*/
dispatch: IStore['dispatch'];
/**
* Handler for the cancel event, which happens when the user dismisses
* the sheet.
*/
onCancel?: Function;
/**
* Function to render a bottom sheet footer element, if necessary.
*/
renderFooter?: () => React.ReactNode;
/**
* Function to render a bottom sheet header element, if necessary.
*/
renderHeader?: Function;
/**
* Whether to show sliding view or not.
*/
showSlidingView?: boolean;
/**
* The component's external style.
*/
style?: Object;
};
/**
* A component emulating Android's BottomSheet.
*/
class BottomSheet extends PureComponent<Props> {
/**
* Default values for {@code BottomSheet} component's properties.
*
* @static
*/
static defaultProps = {
addScrollViewPadding: true,
showSlidingView: true
};
/**
* Initializes a new instance.
*
* @param {Props} props - The React {@code Component} props to initialize
* the new instance with.
*/
constructor(props: Props) {
super(props);
this._onCancel = this._onCancel.bind(this);
}
/**
* Handles the cancel event, when the user dismissed the sheet. By default we close it.
*
* @returns {void}
*/
_onCancel() {
if (this.props.onCancel) {
this.props.onCancel();
} else {
this.props.dispatch(hideSheet());
}
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
override render() {
const {
addScrollViewPadding,
renderHeader,
renderFooter,
showSlidingView,
style
} = this.props;
return (
<SlidingView
onHide = { this._onCancel }
position = 'bottom'
show = { Boolean(showSlidingView) }>
<View
pointerEvents = 'box-none'
style = { styles.sheetContainer as ViewStyle }>
<View
pointerEvents = 'box-none'
style = { styles.sheetAreaCover } />
{ renderHeader?.() }
<SafeAreaView
style = { [
styles.sheetItemContainer,
renderHeader
? styles.sheetHeader
: styles.sheet,
renderFooter && styles.sheetFooter,
style
] }>
<ScrollView
bounces = { false }
showsVerticalScrollIndicator = { false }
style = { [
renderFooter && styles.sheet,
addScrollViewPadding && styles.scrollView
] } >
{ this.props.children }
</ScrollView>
{ renderFooter?.() }
</SafeAreaView>
</View>
</SlidingView>
);
}
}
export default connect()(BottomSheet);

View File

@@ -0,0 +1,22 @@
import React, { Fragment } from 'react';
import { useSelector } from 'react-redux';
import { IReduxState } from '../../../../app/types';
const BottomSheetContainer: () => JSX.Element | null = (): JSX.Element | null => {
const { sheet, sheetProps } = useSelector((state: IReduxState) => state['features/base/dialog']);
const { reducedUI } = useSelector((state: IReduxState) => state['features/base/responsive-ui']);
if (!sheet || reducedUI) {
return null;
}
return (
<Fragment>
{ React.createElement(sheet, sheetProps) }
</Fragment>
);
};
export default BottomSheetContainer;

View File

@@ -0,0 +1,172 @@
import React from 'react';
import { WithTranslation } from 'react-i18next';
import Dialog from 'react-native-dialog';
import { connect } from 'react-redux';
import { translate } from '../../../i18n/functions';
import { renderHTML } from '../functions.native';
import AbstractDialog, { IProps as AbstractProps } from './AbstractDialog';
import styles from './styles';
/**
* The type of the React {@code Component} props of
* {@link ConfirmDialog}.
*/
interface IProps extends AbstractProps, WithTranslation {
/**
* The i18n key of the text label for the back button.
*/
backLabel?: string;
/**
* The i18n key of the text label for the cancel button.
*/
cancelLabel?: string;
/**
* The React {@code Component} children.
*/
children?: React.ReactNode;
/**
* The i18n key of the text label for the confirm button.
*/
confirmLabel?: string;
/**
* Dialog description key for translations.
*/
descriptionKey?: string | { key: string; params: string; };
/**
* Whether the back button is hidden.
*/
isBackHidden?: Boolean;
/**
* Whether the cancel button is hidden.
*/
isCancelHidden?: Boolean;
/**
* Whether or not the nature of the confirm button is destructive.
*/
isConfirmDestructive?: Boolean;
/**
* Whether or not the confirm button is hidden.
*/
isConfirmHidden?: Boolean;
/**
* Dialog title.
*/
title?: string;
/**
* Renders buttons vertically.
*/
verticalButtons?: boolean;
}
/**
* React Component for getting confirmation to stop a file recording session in
* progress.
*
* @augments Component
*/
class ConfirmDialog extends AbstractDialog<IProps> {
/**
* Default values for {@code ConfirmDialog} component's properties.
*
* @static
*/
static defaultProps = {
isConfirmDestructive: false,
isConfirmHidden: false
};
/**
* Renders the dialog description.
*
* @returns {React$Component}
*/
_renderDescription() {
const { descriptionKey, t } = this.props;
const description
= typeof descriptionKey === 'string'
? t(descriptionKey)
: renderHTML(
t(descriptionKey?.key ?? '', descriptionKey?.params)
);
return (
<Dialog.Description>
{ description }
</Dialog.Description>
);
}
/**
* Implements {@code Component#render}.
*
* @inheritdoc
*/
override render() {
const {
backLabel,
cancelLabel,
children,
confirmLabel,
isBackHidden = true,
isCancelHidden,
isConfirmDestructive,
isConfirmHidden,
t,
title,
verticalButtons
} = this.props;
const dialogButtonStyle
= isConfirmDestructive
? styles.destructiveDialogButton : styles.dialogButton;
return (
<Dialog.Container
coverScreen = { false }
verticalButtons = { verticalButtons }
visible = { true }>
{
title && <Dialog.Title>
{ t(title) }
</Dialog.Title>
}
{ this._renderDescription() }
{ children }
{
!isBackHidden && <Dialog.Button
label = { t(backLabel || 'dialog.confirmBack') }
onPress = { this._onBack }
style = { styles.dialogButton } />
}
{
!isCancelHidden && <Dialog.Button
label = { t(cancelLabel || 'dialog.confirmNo') }
onPress = { this._onCancel }
style = { styles.dialogButton } />
}
{
!isConfirmHidden && <Dialog.Button
label = { t(confirmLabel || 'dialog.confirmYes') }
onPress = { this._onSubmit }
style = { dialogButtonStyle } />
}
</Dialog.Container>
);
}
}
export default translate(connect()(ConfirmDialog));

View File

@@ -0,0 +1,58 @@
import React, { Fragment } from 'react';
import { connect } from 'react-redux';
import { IReduxState } from '../../../../app/types';
import ReactionEmoji from '../../../../reactions/components/native/ReactionEmoji';
import { getReactionsQueue } from '../../../../reactions/functions.native';
import AbstractDialogContainer, {
abstractMapStateToProps
} from '../AbstractDialogContainer';
/**
* Implements a DialogContainer responsible for showing all dialogs. We will
* need a separate container so we can handle multiple dialogs by showing them
* simultaneously or queueing them.
*
* @augments AbstractDialogContainer
*/
class DialogContainer extends AbstractDialogContainer {
/**
* Returns the reactions to be displayed.
*
* @returns {Array<React$Element>}
*/
_renderReactions() {
const { _reactionsQueue } = this.props;
return _reactionsQueue.map(({ reaction, uid }, index) => (<ReactionEmoji
index = { index }
key = { uid }
reaction = { reaction }
uid = { uid } />));
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
override render() {
return (
<Fragment>
{this._renderReactions()}
{this._renderDialogContent()}
</Fragment>
);
}
}
const mapStateToProps = (state: IReduxState) => {
return {
...abstractMapStateToProps(state),
_reactionsQueue: getReactionsQueue(state)
};
};
export default connect(mapStateToProps)(DialogContainer);

View File

@@ -0,0 +1,170 @@
import React from 'react';
import { WithTranslation } from 'react-i18next';
import { TextStyle } from 'react-native';
import Dialog from 'react-native-dialog';
import { connect } from 'react-redux';
import { translate } from '../../../i18n/functions';
import { _abstractMapStateToProps } from '../../functions';
import AbstractDialog, {
IProps as AbstractProps,
IState as AbstractState
} from './AbstractDialog';
import { inputDialog as styles } from './styles';
interface IProps extends AbstractProps, WithTranslation {
/**
* The dialog descriptionKey.
*/
descriptionKey?: string;
/**
* Whether to display the cancel button.
*/
disableCancel?: boolean;
/**
* An optional initial value to initiate the field with.
*/
initialValue?: string;
/**
* A message key to be shown for the user (e.g. An error that is defined after submitting the form).
*/
messageKey?: string;
/**
* Props for the text input.
*/
textInputProps?: Object;
/**
* The untranslated i18n key for the dialog title.
*/
titleKey?: string;
/**
* Validating of the input.
*/
validateInput?: Function;
}
interface IState extends AbstractState {
/**
* The current value of the field.
*/
fieldValue?: string;
/**
* The result of the input validation.
*/
isValid: boolean;
}
/**
* Implements a single field input dialog component.
*/
class InputDialog extends AbstractDialog<IProps, IState> {
/**
* Instantiates a new {@code InputDialog}.
*
* @inheritdoc
*/
constructor(props: IProps) {
super(props);
this.state = {
fieldValue: props.initialValue,
isValid: props.validateInput ? props.validateInput(props.initialValue) : true,
submitting: false
};
this._onChangeText = this._onChangeText.bind(this);
this._onSubmitValue = this._onSubmitValue.bind(this);
}
/**
* Implements {@code Component#render}.
*
* @inheritdoc
*/
override render() {
const {
descriptionKey,
messageKey,
t,
titleKey
} = this.props;
return (
<Dialog.Container
coverScreen = { false }
visible = { true }>
<Dialog.Title>
{ t(titleKey ?? '') }
</Dialog.Title>
{
descriptionKey && (
<Dialog.Description>
{ t(descriptionKey) }
</Dialog.Description>
)
}
<Dialog.Input
autoFocus = { true }
onChangeText = { this._onChangeText }
value = { this.state.fieldValue }
{ ...this.props.textInputProps } />
{
messageKey && (
<Dialog.Description
style = { styles.formMessage as TextStyle }>
{ t(messageKey) }
</Dialog.Description>
)
}
{!this.props.disableCancel && <Dialog.Button
label = { t('dialog.Cancel') }
onPress = { this._onCancel } />}
<Dialog.Button
disabled = { !this.state.isValid }
label = { t('dialog.Ok') }
onPress = { this._onSubmitValue } />
</Dialog.Container>
);
}
/**
* Callback to be invoked when the text in the field changes.
*
* @param {string} fieldValue - The updated field value.
* @returns {void}
*/
_onChangeText(fieldValue: string) {
if (this.props.validateInput) {
this.setState({
isValid: this.props.validateInput(fieldValue),
fieldValue
});
return;
}
this.setState({
fieldValue
});
}
/**
* Callback to be invoked when the value of this dialog is submitted.
*
* @returns {boolean}
*/
_onSubmitValue() {
return this._onSubmit(this.state.fieldValue);
}
}
export default translate(connect(_abstractMapStateToProps)(InputDialog));

View File

@@ -0,0 +1,221 @@
// @ts-expect-error
import { randomInt } from '@jitsi/js-utils/random';
import React, { Component } from 'react';
import { WithTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import { appNavigate, reloadNow } from '../../../../app/actions.native';
import { IReduxState, IStore } from '../../../../app/types';
import { translate } from '../../../i18n/functions';
import { isFatalJitsiConnectionError } from '../../../lib-jitsi-meet/functions.native';
import { hideDialog } from '../../actions';
import logger from '../../logger';
import ConfirmDialog from './ConfirmDialog';
/**
* The type of the React {@code Component} props of
* {@link PageReloadDialog}.
*/
interface IProps extends WithTranslation {
conferenceError?: Error;
configError?: Error;
connectionError?: Error;
dispatch: IStore['dispatch'];
isNetworkFailure: boolean;
reason?: string;
}
/**
* The type of the React {@code Component} state of
* {@link PageReloadDialog}.
*/
interface IPageReloadDialogState {
timeLeft: number;
}
/**
* Implements a React Component that is shown before the
* conference is reloaded.
* Shows a warning message and counts down towards the re-load.
*/
class PageReloadDialog extends Component<IProps, IPageReloadDialogState> {
_interval?: number;
_timeoutSeconds: number;
/**
* Initializes a new PageReloadOverlay instance.
*
* @param {Object} props - The read-only properties with which the new
* instance is to be initialized.
* @public
*/
constructor(props: IProps) {
super(props);
this._timeoutSeconds = 10 + randomInt(0, 20);
this.state = {
timeLeft: this._timeoutSeconds
};
this._onCancel = this._onCancel.bind(this);
this._onReloadNow = this._onReloadNow.bind(this);
this._onReconnecting = this._onReconnecting.bind(this);
}
/**
* React Component method that executes once component is mounted.
*
* @inheritdoc
* @returns {void}
*/
override componentDidMount() {
const { timeLeft } = this.state;
logger.info(
`The conference will be reloaded after ${timeLeft} seconds.`
);
this._interval = setInterval(() =>
this._onReconnecting(), 1000);
}
/**
* Clears the timer interval.
*
* @inheritdoc
* @returns {void}
*/
override componentWillUnmount() {
if (this._interval) {
clearInterval(this._interval);
this._interval = undefined;
}
}
/**
* Handle clicking of the "Cancel" button. It will navigate back to the
* welcome page.
*
* @private
* @returns {boolean}
*/
_onCancel() {
const { dispatch } = this.props;
clearInterval(this._interval ?? 0);
dispatch(appNavigate(undefined));
return true;
}
/**
* Handles automatic reconnection.
*
* @private
* @returns {void}
*/
_onReconnecting() {
const { dispatch } = this.props;
const { timeLeft } = this.state;
if (timeLeft === 0) {
if (this._interval) {
dispatch(hideDialog());
this._onReloadNow();
this._interval = undefined;
}
}
this.setState({
timeLeft: timeLeft - 1
});
}
/**
* Handle clicking on the "Reload Now" button. It will navigate to the same
* conference URL as before immediately, without waiting for the timer to
* kick in.
*
* @private
* @returns {boolean}
*/
_onReloadNow() {
const { dispatch } = this.props;
clearInterval(this._interval ?? 0);
dispatch(reloadNow());
return true;
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
override render() {
const { isNetworkFailure, t } = this.props;
const { timeLeft } = this.state;
let message, title;
if (isNetworkFailure) {
title = 'dialog.conferenceDisconnectTitle';
message = 'dialog.conferenceDisconnectMsg';
} else {
title = 'dialog.conferenceReloadTitle';
message = 'dialog.conferenceReloadMsg';
}
return (
<ConfirmDialog
cancelLabel = 'dialog.Cancel'
confirmLabel = 'dialog.rejoinNow'
descriptionKey = { `${t(message, { seconds: timeLeft })}` }
onCancel = { this._onCancel }
onSubmit = { this._onReloadNow }
title = { title } />
);
}
}
/**
* Maps (parts of) the redux state to the associated component's props.
*
* @param {Object} state - The redux state.
* @param {IProps} ownProps - The own props of the component.
* @protected
* @returns {{
* isNetworkFailure: boolean,
* reason: string
* }}
*/
function mapStateToProps(state: IReduxState, ownProps: IProps) {
const { conferenceError, configError, connectionError } = ownProps;
const fatalConnectionError
= connectionError && isFatalJitsiConnectionError(connectionError);
const isNetworkFailure = Boolean(configError || fatalConnectionError);
let reason;
if (conferenceError) {
reason = `error.conference.${conferenceError.name}`;
} else if (connectionError) {
reason = `error.conference.${connectionError.name}`;
} else if (configError) {
reason = `error.config.${configError.name}`;
} else {
logger.error('No reload reason defined!');
}
return {
isNetworkFailure,
reason
};
}
export default translate(connect(mapStateToProps)(PageReloadDialog));

View File

@@ -0,0 +1,265 @@
import { StyleSheet } from 'react-native';
import ColorSchemeRegistry from '../../../color-scheme/ColorSchemeRegistry';
import { schemeColor } from '../../../color-scheme/functions';
import { BoxModel } from '../../../styles/components/styles/BoxModel';
import BaseTheme from '../../../ui/components/BaseTheme.native';
import { PREFERRED_DIALOG_SIZE } from '../../constants';
const BORDER_RADIUS = 5;
/**
* NOTE: These Material guidelines based values are currently only used in
* dialogs (and related) but later on it would be nice to export it into a base
* Material feature.
*/
export const MD_FONT_SIZE = 16;
export const MD_ITEM_HEIGHT = 48;
export const MD_ITEM_MARGIN_PADDING = BaseTheme.spacing[3];
/**
* Reusable (colored) style for text in any branded dialogs.
*/
const brandedDialogText = {
color: schemeColor('text'),
fontSize: MD_FONT_SIZE,
textAlign: 'center'
};
const brandedDialogLabelStyle = {
color: BaseTheme.palette.text01,
flexShrink: 1,
fontSize: MD_FONT_SIZE,
opacity: 0.90
};
const brandedDialogItemContainerStyle = {
alignItems: 'center',
flexDirection: 'row',
height: MD_ITEM_HEIGHT
};
const brandedDialogIconStyle = {
color: BaseTheme.palette.icon01,
fontSize: 24
};
export const inputDialog = {
formMessage: {
alignSelf: 'flex-start',
fontStyle: 'italic',
fontWeight: 'bold',
marginTop: BaseTheme.spacing[3]
}
};
/**
* The React {@code Component} styles of {@code BottomSheet}. These have
* been implemented as per the Material Design guidelines:
* {@link https://material.io/guidelines/components/bottom-sheets.html}.
*/
export const bottomSheetStyles = {
sheetAreaCover: {
backgroundColor: 'transparent',
flex: 1
},
scrollView: {
paddingHorizontal: 0
},
/**
* Style for the container of the sheet.
*/
sheetContainer: {
alignItems: 'stretch',
flex: 1,
flexDirection: 'column',
justifyContent: 'flex-end',
maxWidth: 500,
marginLeft: 'auto',
marginRight: 'auto',
width: '100%'
},
sheetItemContainer: {
flex: -1,
maxHeight: '75%'
},
buttons: {
/**
* Style for the {@code Icon} element in a generic item of the menu.
*/
iconStyle: {
...brandedDialogIconStyle
},
/**
* Style for the label in a generic item rendered in the menu.
*/
labelStyle: {
...brandedDialogLabelStyle,
marginLeft: 16
},
/**
* Container style for a generic item rendered in the menu.
*/
style: {
...brandedDialogItemContainerStyle,
paddingHorizontal: MD_ITEM_MARGIN_PADDING
},
/**
* Additional style that is not directly used as a style object.
*/
underlayColor: BaseTheme.palette.ui04
},
/**
* Bottom sheet's base style.
*/
sheet: {
backgroundColor: BaseTheme.palette.ui02,
borderTopLeftRadius: 16,
borderTopRightRadius: 16
},
/**
* Bottom sheet's base style with header.
*/
sheetHeader: {
backgroundColor: BaseTheme.palette.ui02
},
/**
* Bottom sheet's background color with footer.
*/
sheetFooter: {
backgroundColor: BaseTheme.palette.ui01
}
};
export default {
dialogButton: {
...BaseTheme.typography.bodyLongBold
},
destructiveDialogButton: {
...BaseTheme.typography.bodyLongBold,
color: BaseTheme.palette.actionDanger
}
};
export const brandedDialog = {
/**
* The style of bold {@code Text} rendered by the {@code Dialog}s of the
* feature authentication.
*/
boldDialogText: {
fontWeight: 'bold'
},
buttonFarRight: {
borderBottomRightRadius: BORDER_RADIUS
},
buttonWrapper: {
alignItems: 'stretch',
borderRadius: BORDER_RADIUS,
flexDirection: 'row'
},
mainWrapper: {
alignSelf: 'stretch',
padding: BoxModel.padding * 2,
// The added bottom padding is to compensate the empty space around the
// close icon.
paddingBottom: BoxModel.padding * 3
},
overlayTouchable: {
...StyleSheet.absoluteFillObject
}
};
/**
* Color schemed styles for all the component based on the abstract dialog.
*/
ColorSchemeRegistry.register('Dialog', {
button: {
backgroundColor: '#44A5FF',
flex: 1,
padding: BoxModel.padding * 1.5
},
/**
* Separator line for the buttons in a dialog.
*/
buttonSeparator: {
borderRightColor: schemeColor('border'),
borderRightWidth: 1
},
buttonLabel: {
color: schemeColor('buttonLabel'),
fontSize: MD_FONT_SIZE,
textAlign: 'center'
},
/**
* Style of the close icon on a dialog.
*/
closeStyle: {
color: schemeColor('icon'),
fontSize: MD_FONT_SIZE
},
/**
* Base style of the dialogs.
*/
dialog: {
alignItems: 'stretch',
backgroundColor: schemeColor('background'),
borderColor: schemeColor('border'),
borderRadius: BORDER_RADIUS,
borderWidth: 1,
flex: 1,
flexDirection: 'column',
maxWidth: PREFERRED_DIALOG_SIZE
},
/**
* Field on an input dialog.
*/
field: {
...brandedDialogText,
borderBottomWidth: 1,
borderColor: schemeColor('border'),
margin: BoxModel.margin,
textAlign: 'left'
},
/**
* Style for the field label on an input dialog.
*/
fieldLabel: {
...brandedDialogText,
margin: BoxModel.margin,
textAlign: 'left'
},
text: {
...brandedDialogText,
color: BaseTheme.palette.text01
},
topBorderContainer: {
borderTopColor: BaseTheme.palette.ui07,
borderTopWidth: 1
}
});