feat(base/ui/native): Use new Input component (#12526)
feat(base/ui/native): replaced react native TextInput component with our native Input component
This commit is contained in:
parent
74cd486232
commit
2c7dc5e40e
|
@ -89,7 +89,7 @@
|
|||
"chat": {
|
||||
"enter": "Enter room",
|
||||
"error": "Error: your message was not sent. Reason: {{error}}",
|
||||
"fieldPlaceHolder": "Type your message here",
|
||||
"fieldPlaceHolder": "Aa",
|
||||
"lobbyChatMessageTo": "Lobby chat message to {{recipient}}",
|
||||
"message": "Message",
|
||||
"messageAccessibleTitle": "{{user}} says:",
|
||||
|
@ -266,7 +266,7 @@
|
|||
"e2eeWarning": "WARNING: Not all participants in this meeting seem to have support for End-to-End encryption. If you enable it they won't be able to see nor hear you.",
|
||||
"e2eeWillDisableDueToMaxModeDescription": "WARNING: End-to-End Encryption will be automatically disabled if more participants join the conference.",
|
||||
"embedMeeting": "Embed meeting",
|
||||
"enterDisplayName": "Enter your name here",
|
||||
"enterDisplayName": "Enter your name",
|
||||
"error": "Error",
|
||||
"gracefulShutdown": "Our service is currently down for maintenance. Please try again later.",
|
||||
"grantModeratorDialog": "Are you sure you want to grant moderator rights to {{participantName}}?",
|
||||
|
@ -1003,6 +1003,7 @@
|
|||
"displayName": "Display name",
|
||||
"displayNamePlaceholderText": "Eg: John Doe",
|
||||
"email": "Email",
|
||||
"emailPlaceholderText": "email@example.com",
|
||||
"goTo": "Go to",
|
||||
"header": "Settings",
|
||||
"help": "Help",
|
||||
|
|
|
@ -73,11 +73,11 @@ const SECTION_LIST_STYLES = {
|
|||
|
||||
listSection: {
|
||||
alignItems: 'center',
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.2)',
|
||||
backgroundColor: BaseTheme.palette.ui02,
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
paddingVertical: 5,
|
||||
paddingHorizontal: 10
|
||||
paddingVertical: BaseTheme.spacing[1],
|
||||
paddingHorizontal: BaseTheme.spacing[2]
|
||||
},
|
||||
|
||||
listSectionText: {
|
||||
|
@ -164,5 +164,10 @@ export default {
|
|||
iconButtonContainerSecondary: {
|
||||
...iconButtonContainer,
|
||||
backgroundColor: BaseTheme.palette.action02
|
||||
},
|
||||
|
||||
iconButtonContainerDisabled: {
|
||||
...iconButtonContainer,
|
||||
backgroundColor: BaseTheme.palette.disabled01
|
||||
}
|
||||
};
|
||||
|
|
|
@ -44,6 +44,11 @@ const IconButton: React.FC<IIconButtonProps> = ({
|
|||
rippleColor = tapColor;
|
||||
}
|
||||
|
||||
if (disabled) {
|
||||
color = BaseTheme.palette.icon03;
|
||||
iconButtonContainerStyles = styles.iconButtonContainerDisabled;
|
||||
rippleColor = 'transparent';
|
||||
}
|
||||
|
||||
return (
|
||||
<TouchableRipple
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
import React, { useCallback, useState } from 'react';
|
||||
/* eslint-disable lines-around-comment */
|
||||
|
||||
import React, { forwardRef, useCallback, useState } from 'react';
|
||||
import {
|
||||
NativeSyntheticEvent,
|
||||
KeyboardTypeOptions,
|
||||
NativeSyntheticEvent, ReturnKeyTypeOptions,
|
||||
StyleProp,
|
||||
Text,
|
||||
TextInput,
|
||||
TextInputChangeEventData,
|
||||
TextInputFocusEventData, TextInputKeyPressEventData,
|
||||
TextInputSubmitEditingEventData,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
ViewStyle
|
||||
|
@ -18,11 +23,24 @@ import { IInputProps } from '../types';
|
|||
import styles from './inputStyles';
|
||||
|
||||
interface IProps extends IInputProps {
|
||||
|
||||
/**
|
||||
* Custom styles to be applied to the component.
|
||||
*/
|
||||
accessibilityLabel?: any;
|
||||
autoCapitalize?: string | undefined;
|
||||
autoFocus?: boolean;
|
||||
blurOnSubmit?: boolean | undefined;
|
||||
customStyles?: ICustomStyles;
|
||||
editable?: boolean | undefined;
|
||||
keyboardType?: KeyboardTypeOptions;
|
||||
maxLength?: number | undefined;
|
||||
minHeight?: number | string | undefined;
|
||||
multiline?: boolean | undefined;
|
||||
numberOfLines?: number | undefined;
|
||||
onBlur?: ((e: NativeSyntheticEvent<TextInputFocusEventData>) => void) | undefined;
|
||||
onFocus?: ((e: NativeSyntheticEvent<TextInputFocusEventData>) => void) | undefined;
|
||||
onKeyPress?: ((e: NativeSyntheticEvent<TextInputKeyPressEventData>) => void) | undefined;
|
||||
onSubmitEditing?: (value: string) => void;
|
||||
returnKeyType?: ReturnKeyTypeOptions | undefined;
|
||||
secureTextEntry?: boolean | undefined;
|
||||
textContentType?: any;
|
||||
}
|
||||
|
||||
interface ICustomStyles {
|
||||
|
@ -30,17 +48,33 @@ interface ICustomStyles {
|
|||
input?: Object;
|
||||
}
|
||||
|
||||
const Input = ({
|
||||
const Input = forwardRef<TextInput, IInputProps>(({
|
||||
accessibilityLabel,
|
||||
autoCapitalize,
|
||||
autoFocus,
|
||||
blurOnSubmit,
|
||||
clearable,
|
||||
customStyles,
|
||||
disabled,
|
||||
error,
|
||||
icon,
|
||||
keyboardType,
|
||||
label,
|
||||
maxLength,
|
||||
minHeight,
|
||||
multiline,
|
||||
numberOfLines,
|
||||
onBlur,
|
||||
onChange,
|
||||
onFocus,
|
||||
onKeyPress,
|
||||
onSubmitEditing,
|
||||
placeholder,
|
||||
returnKeyType,
|
||||
secureTextEntry,
|
||||
textContentType,
|
||||
value
|
||||
}: IProps) => {
|
||||
}: IProps, ref) => {
|
||||
const [ focused, setFocused ] = useState(false);
|
||||
const handleChange = useCallback((e: NativeSyntheticEvent<TextInputChangeEventData>) => {
|
||||
const { nativeEvent: { text } } = e;
|
||||
|
@ -52,38 +86,71 @@ const Input = ({
|
|||
onChange?.('');
|
||||
}, []);
|
||||
|
||||
const blur = useCallback(() => {
|
||||
const handleBlur = useCallback((e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
||||
setFocused(false);
|
||||
onBlur?.(e);
|
||||
}, []);
|
||||
|
||||
const focus = useCallback(() => {
|
||||
const handleFocus = useCallback((e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
||||
setFocused(true);
|
||||
onFocus?.(e);
|
||||
}, []);
|
||||
|
||||
const handleKeyPress = useCallback((e: NativeSyntheticEvent<TextInputKeyPressEventData>) => {
|
||||
onKeyPress?.(e);
|
||||
}, []);
|
||||
|
||||
const handleSubmitEditing = useCallback((e: NativeSyntheticEvent<TextInputSubmitEditingEventData>) => {
|
||||
const { nativeEvent: { text } } = e;
|
||||
|
||||
onSubmitEditing?.(text);
|
||||
}, []);
|
||||
|
||||
return (<View style = { [ styles.inputContainer, customStyles?.container ] }>
|
||||
{label && <Text style = { styles.label }>{label}</Text>}
|
||||
{label && <Text style = { styles.label }>{ label }</Text>}
|
||||
<View style = { styles.fieldContainer as StyleProp<ViewStyle> }>
|
||||
{icon && <Icon
|
||||
size = { 22 }
|
||||
src = { icon }
|
||||
style = { styles.icon } />}
|
||||
<TextInput
|
||||
accessibilityLabel = { accessibilityLabel }
|
||||
// @ts-ignore
|
||||
autoCapitalize = { autoCapitalize }
|
||||
autoComplete = { 'off' }
|
||||
autoCorrect = { false }
|
||||
autoFocus = { autoFocus }
|
||||
blurOnSubmit = { blurOnSubmit }
|
||||
editable = { !disabled }
|
||||
onBlur = { blur }
|
||||
keyboardType = { keyboardType }
|
||||
maxLength = { maxLength }
|
||||
minHeight = { minHeight }
|
||||
multiline = { multiline }
|
||||
numberOfLines = { numberOfLines }
|
||||
onBlur = { handleBlur }
|
||||
onChange = { handleChange }
|
||||
onFocus = { focus }
|
||||
onFocus = { handleFocus }
|
||||
onKeyPress = { handleKeyPress }
|
||||
onSubmitEditing = { handleSubmitEditing }
|
||||
placeholder = { placeholder }
|
||||
placeholderTextColor = { BaseTheme.palette.text02 }
|
||||
style = { [ styles.input,
|
||||
disabled && styles.inputDisabled,
|
||||
ref = { ref }
|
||||
returnKeyType = { returnKeyType }
|
||||
secureTextEntry = { secureTextEntry }
|
||||
spellCheck = { false }
|
||||
style = { [
|
||||
styles.input,
|
||||
clearable && styles.clearableInput,
|
||||
icon && styles.iconInput,
|
||||
focused && styles.inputFocused,
|
||||
customStyles?.input,
|
||||
disabled && styles.inputDisabled,
|
||||
error && styles.inputError,
|
||||
customStyles?.input
|
||||
focused && styles.inputFocused,
|
||||
icon && styles.iconInput,
|
||||
multiline && styles.inputMultiline
|
||||
] }
|
||||
value = { `${value}` } />
|
||||
{clearable && !disabled && value !== '' && (
|
||||
textContentType = { textContentType }
|
||||
value = { typeof value === 'number' ? `${value}` : value } />
|
||||
{ clearable && !disabled && value !== '' && (
|
||||
<TouchableOpacity
|
||||
onPress = { clearInput }
|
||||
style = { styles.clearButton as StyleProp<ViewStyle> }>
|
||||
|
@ -95,6 +162,6 @@ const Input = ({
|
|||
)}
|
||||
</View>
|
||||
</View>);
|
||||
};
|
||||
});
|
||||
|
||||
export default Input;
|
||||
|
|
|
@ -10,7 +10,7 @@ export default {
|
|||
...BaseTheme.typography.bodyShortRegularLarge,
|
||||
lineHeight: 0,
|
||||
color: BaseTheme.palette.text01,
|
||||
marginBottom: 8
|
||||
marginBottom: BaseTheme.spacing[2]
|
||||
},
|
||||
|
||||
fieldContainer: {
|
||||
|
@ -20,8 +20,8 @@ export default {
|
|||
icon: {
|
||||
position: 'absolute',
|
||||
zIndex: 1,
|
||||
top: 13,
|
||||
left: 16
|
||||
top: 14,
|
||||
left: 14
|
||||
},
|
||||
|
||||
input: {
|
||||
|
@ -32,7 +32,8 @@ export default {
|
|||
borderWidth: 2,
|
||||
color: BaseTheme.palette.text01,
|
||||
paddingHorizontal: BaseTheme.spacing[3],
|
||||
height: 48
|
||||
height: BaseTheme.spacing[7],
|
||||
lineHeight: 20
|
||||
},
|
||||
|
||||
inputDisabled: {
|
||||
|
@ -51,6 +52,11 @@ export default {
|
|||
paddingLeft: BaseTheme.spacing[6]
|
||||
},
|
||||
|
||||
inputMultiline: {
|
||||
height: BaseTheme.spacing[10],
|
||||
paddingTop: BaseTheme.spacing[2]
|
||||
},
|
||||
|
||||
clearableInput: {
|
||||
paddingRight: BaseTheme.spacing[6]
|
||||
},
|
||||
|
@ -60,9 +66,9 @@ export default {
|
|||
borderWidth: 0,
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
top: 13,
|
||||
width: 40,
|
||||
height: 48
|
||||
top: 14,
|
||||
width: BaseTheme.spacing[6],
|
||||
height: BaseTheme.spacing[7]
|
||||
},
|
||||
|
||||
clearIcon: {
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { Platform, TextInput, TouchableOpacity, View } from 'react-native';
|
||||
import { Platform } from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { Icon, IconSend } from '../../../base/icons';
|
||||
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
|
||||
import { IconSend } from '../../../base/icons/svg';
|
||||
import IconButton from '../../../base/ui/components/native/IconButton';
|
||||
import Input from '../../../base/ui/components/native/Input';
|
||||
import { BUTTON_TYPES } from '../../../base/ui/constants.native';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
|
@ -70,32 +71,30 @@ class ChatInputBar extends Component<Props, State> {
|
|||
*/
|
||||
render() {
|
||||
return (
|
||||
<View
|
||||
<SafeAreaView
|
||||
edges = { [ 'bottom' ] }
|
||||
style = { [
|
||||
styles.inputBar,
|
||||
this.state.addPadding ? styles.extraBarPadding : null
|
||||
] }>
|
||||
<TextInput
|
||||
<Input
|
||||
blurOnSubmit = { false }
|
||||
customStyles = {{ input: styles.customInput }}
|
||||
multiline = { false }
|
||||
onBlur = { this._onFocused(false) }
|
||||
onChangeText = { this._onChangeText }
|
||||
onChange = { this._onChangeText }
|
||||
onFocus = { this._onFocused(true) }
|
||||
onSubmitEditing = { this._onSubmit }
|
||||
placeholder = { this.props.t('chat.fieldPlaceHolder') }
|
||||
placeholderTextColor = { BaseTheme.palette.text03 }
|
||||
returnKeyType = 'send'
|
||||
selectionColor = { BaseTheme.palette.text03 }
|
||||
style = { styles.inputField }
|
||||
value = { this.state.message } />
|
||||
{
|
||||
this.state.showSend && <TouchableOpacity onPress = { this._onSubmit }>
|
||||
<Icon
|
||||
src = { IconSend }
|
||||
style = { styles.sendButtonIcon } />
|
||||
</TouchableOpacity>
|
||||
}
|
||||
</View>
|
||||
<IconButton
|
||||
disabled = { !this.state.message }
|
||||
onPress = { this._onSubmit }
|
||||
src = { IconSend }
|
||||
style = { styles.sendButton }
|
||||
type = { BUTTON_TYPES.PRIMARY } />
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -54,17 +54,14 @@ export default {
|
|||
|
||||
inputBar: {
|
||||
alignItems: 'center',
|
||||
borderTopColor: 'rgb(209, 219, 231)',
|
||||
borderTopWidth: 1,
|
||||
flexDirection: 'row',
|
||||
paddingBottom: '4%',
|
||||
paddingHorizontal: BaseTheme.spacing[3]
|
||||
justifyContent: 'space-between',
|
||||
marginLeft: BaseTheme.spacing[3],
|
||||
width: '100%'
|
||||
},
|
||||
|
||||
inputField: {
|
||||
color: BaseTheme.palette.text01,
|
||||
flex: 1,
|
||||
height: 48
|
||||
customInput: {
|
||||
width: 280
|
||||
},
|
||||
|
||||
messageBubble: {
|
||||
|
@ -96,9 +93,8 @@ export default {
|
|||
flexDirection: 'row'
|
||||
},
|
||||
|
||||
sendButtonIcon: {
|
||||
color: BaseTheme.palette.icon01,
|
||||
fontSize: 22
|
||||
sendButton: {
|
||||
marginRight: BaseTheme.spacing[5]
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,9 +5,9 @@ import { useDispatch, useSelector } from 'react-redux';
|
|||
|
||||
import { createGifSentEvent, sendAnalytics } from '../../../analytics';
|
||||
import JitsiScreen from '../../../base/modal/components/JitsiScreen';
|
||||
import Input from '../../../base/ui/components/native/Input';
|
||||
import { sendMessage } from '../../../chat/actions.any';
|
||||
import { goBack } from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
|
||||
import ClearableInput from '../../../participants-pane/components/native/ClearableInput';
|
||||
import { formatGifUrlMessage, getGifRating, getGifUrl } from '../../functions';
|
||||
|
||||
import GifsMenuFooter from './GifsMenuFooter';
|
||||
|
@ -45,8 +45,9 @@ const GifsMenu = () => {
|
|||
<JitsiScreen
|
||||
footerComponent = { GifsMenuFooter }
|
||||
style = { styles.container }>
|
||||
<ClearableInput
|
||||
customStyles = { styles.clearableInput }
|
||||
<Input
|
||||
clearable = { true }
|
||||
customStyles = {{ container: styles.customContainer }}
|
||||
onChange = { setSearchQuery }
|
||||
placeholder = { t('giphy.search') }
|
||||
value = { searchQuery } />
|
||||
|
|
|
@ -6,15 +6,9 @@ export default {
|
|||
flex: 1
|
||||
},
|
||||
|
||||
clearableInput: {
|
||||
wrapper: {
|
||||
marginBottom: BaseTheme.spacing[3],
|
||||
marginTop: BaseTheme.spacing[3]
|
||||
},
|
||||
|
||||
input: {
|
||||
textAlign: 'left'
|
||||
}
|
||||
customContainer: {
|
||||
marginHorizontal: BaseTheme.spacing[3],
|
||||
marginVertical: BaseTheme.spacing[2]
|
||||
},
|
||||
|
||||
grid: {
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
// @flow
|
||||
|
||||
import _ from 'lodash';
|
||||
import React from 'react';
|
||||
import React, { ReactElement } from 'react';
|
||||
import {
|
||||
ActivityIndicator,
|
||||
FlatList,
|
||||
TouchableOpacity,
|
||||
View
|
||||
} from 'react-native';
|
||||
import { withTheme } from 'react-native-paper';
|
||||
|
||||
import { AlertDialog, openDialog } from '../../../../base/dialog';
|
||||
import { translate } from '../../../../base/i18n';
|
||||
|
@ -21,14 +18,12 @@ import {
|
|||
IconShare
|
||||
} from '../../../../base/icons';
|
||||
import JitsiScreen from '../../../../base/modal/components/JitsiScreen';
|
||||
import {
|
||||
AvatarListItem,
|
||||
type Item
|
||||
} from '../../../../base/react';
|
||||
import { AvatarListItem, type Item } from '../../../../base/react';
|
||||
import { connect } from '../../../../base/redux';
|
||||
import BaseTheme from '../../../../base/ui/components/BaseTheme.native';
|
||||
import Input from '../../../../base/ui/components/native/Input';
|
||||
import HeaderNavigationButton
|
||||
from '../../../../mobile/navigation/components/HeaderNavigationButton';
|
||||
import ClearableInput from '../../../../participants-pane/components/native/ClearableInput';
|
||||
import { beginShareRoom } from '../../../../share-room';
|
||||
import { INVITE_TYPES } from '../../../constants';
|
||||
import AbstractAddPeopleDialog, {
|
||||
|
@ -37,10 +32,7 @@ import AbstractAddPeopleDialog, {
|
|||
_mapStateToProps as _abstractMapStateToProps
|
||||
} from '../AbstractAddPeopleDialog';
|
||||
|
||||
import styles, {
|
||||
AVATAR_SIZE,
|
||||
DARK_GREY
|
||||
} from './styles';
|
||||
import styles, { AVATAR_SIZE } from './styles';
|
||||
|
||||
type Props = AbstractProps & {
|
||||
|
||||
|
@ -109,6 +101,8 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
|
|||
/**
|
||||
* TimeoutID to delay the search for the time the user is probably typing.
|
||||
*/
|
||||
|
||||
/* eslint-disable-next-line no-undef */
|
||||
searchTimeout: TimeoutID;
|
||||
|
||||
/**
|
||||
|
@ -131,6 +125,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
|
|||
this._onShareMeeting = this._onShareMeeting.bind(this);
|
||||
this._onTypeQuery = this._onTypeQuery.bind(this);
|
||||
this._renderShareMeetingButton = this._renderShareMeetingButton.bind(this);
|
||||
this._renderIcon = this._renderIcon.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -189,8 +184,6 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
|
|||
_dialOutEnabled
|
||||
} = this.props;
|
||||
const { inviteItems, selectableItems } = this.state;
|
||||
const { theme } = this.props;
|
||||
const { palette } = theme;
|
||||
|
||||
let placeholderKey = 'searchPlaceholder';
|
||||
|
||||
|
@ -204,26 +197,13 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
|
|||
<JitsiScreen
|
||||
footerComponent = { this._renderShareMeetingButton }
|
||||
style = { styles.addPeopleContainer }>
|
||||
<ClearableInput
|
||||
<Input
|
||||
autoFocus = { false }
|
||||
customStyles = {{
|
||||
wrapper: styles.searchFieldWrapper,
|
||||
input: styles.searchField,
|
||||
clearButton: styles.clearButton,
|
||||
clearIcon: styles.clearIcon
|
||||
}}
|
||||
clearable = { true }
|
||||
customStyles = {{ container: styles.customContainer }}
|
||||
icon = { this._renderIcon }
|
||||
onChange = { this._onTypeQuery }
|
||||
placeholder = { this.props.t(`inviteDialog.${placeholderKey}`) }
|
||||
placeholderColor = { palette.text04 }
|
||||
prefixComponent = { <View style = { styles.searchIconWrapper }>
|
||||
{this.state.searchInprogress
|
||||
? <ActivityIndicator
|
||||
color = { DARK_GREY }
|
||||
size = 'small' />
|
||||
: <Icon
|
||||
src = { IconSearch }
|
||||
style = { styles.searchIcon } />}
|
||||
</View> }
|
||||
value = { this.state.fieldValue } />
|
||||
{ Boolean(inviteItems.length) && <View style = { styles.invitedList }>
|
||||
<FlatList
|
||||
|
@ -424,7 +404,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
|
|||
|
||||
_query: (string) => Promise<Array<Object>>;
|
||||
|
||||
_renderInvitedItem: Object => React$Element<any> | null;
|
||||
_renderInvitedItem: Object => ReactElement | null;
|
||||
|
||||
/**
|
||||
* Renders a single item in the invited {@code FlatList}.
|
||||
|
@ -434,7 +414,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
|
|||
* @param {number} index - The index of the currently rendered item.
|
||||
* @returns {?React$Element<any>}
|
||||
*/
|
||||
_renderInvitedItem(flatListItem, index): React$Element<any> | null {
|
||||
_renderInvitedItem(flatListItem, index): ReactElement | null {
|
||||
const { item } = flatListItem;
|
||||
const renderableItem = this._getRenderableItem(flatListItem);
|
||||
|
||||
|
@ -461,7 +441,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
|
|||
);
|
||||
}
|
||||
|
||||
_renderItem: Object => React$Element<any> | null;
|
||||
_renderItem: Object => ReactElement | null;
|
||||
|
||||
/**
|
||||
* Renders a single item in the search result {@code FlatList}.
|
||||
|
@ -471,7 +451,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
|
|||
* @param {number} index - The index of the currently rendered item.
|
||||
* @returns {?React$Element<*>}
|
||||
*/
|
||||
_renderItem(flatListItem, index): React$Element<any> | null {
|
||||
_renderItem(flatListItem, index): ReactElement | null {
|
||||
const { item } = flatListItem;
|
||||
const { inviteItems } = this.state;
|
||||
let selected = false;
|
||||
|
@ -516,7 +496,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
|
|||
);
|
||||
}
|
||||
|
||||
_renderSeparator: () => React$Element<*> | null;
|
||||
_renderSeparator: () => ReactElement | null;
|
||||
|
||||
/**
|
||||
* Renders the item separator.
|
||||
|
@ -529,7 +509,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
|
|||
);
|
||||
}
|
||||
|
||||
_renderShareMeetingButton: () => React$Element<any>;
|
||||
_renderShareMeetingButton: () => ReactElement;
|
||||
|
||||
/**
|
||||
* Renders a button to share the meeting info.
|
||||
|
@ -554,6 +534,30 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
|
|||
);
|
||||
}
|
||||
|
||||
_renderIcon: () => ReactElement;
|
||||
|
||||
/**
|
||||
* Renders an icon.
|
||||
*
|
||||
* @returns {React#Element<*>}
|
||||
*/
|
||||
_renderIcon() {
|
||||
|
||||
if (this.state.searchInprogress) {
|
||||
return (
|
||||
<ActivityIndicator
|
||||
color = { BaseTheme.palette.icon01 }
|
||||
size = 'small' />
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Icon
|
||||
src = { IconSearch }
|
||||
style = { styles.searchIcon } />
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an alert telling the user that some invitees were failed to be
|
||||
* invited.
|
||||
|
@ -586,4 +590,4 @@ function _mapStateToProps(state: Object) {
|
|||
};
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(withTheme(AddPeopleDialog)));
|
||||
export default translate(connect(_mapStateToProps)(AddPeopleDialog));
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
// @flow
|
||||
|
||||
import { BoxModel } from '../../../../base/styles';
|
||||
import BaseTheme from '../../../../base/ui/components/BaseTheme.native';
|
||||
|
||||
export const AVATAR_SIZE = 40;
|
||||
export const DARK_GREY = 'rgb(28, 32, 37)';
|
||||
export const LIGHT_GREY = 'rgb(209, 219, 232)';
|
||||
export const ICON_SIZE = 15;
|
||||
|
||||
export default {
|
||||
|
||||
|
@ -19,6 +16,11 @@ export default {
|
|||
backgroundColor: LIGHT_GREY
|
||||
},
|
||||
|
||||
customContainer: {
|
||||
marginHorizontal: BaseTheme.spacing[3],
|
||||
marginVertical: BaseTheme.spacing[2]
|
||||
},
|
||||
|
||||
avatarText: {
|
||||
color: DARK_GREY,
|
||||
fontSize: 12
|
||||
|
@ -41,15 +43,6 @@ export default {
|
|||
textAlign: 'center'
|
||||
},
|
||||
|
||||
clearIconContainer: {
|
||||
alignItems: 'center',
|
||||
backgroundColor: BaseTheme.palette.section01,
|
||||
borderRadius: 12,
|
||||
justifyContent: 'center',
|
||||
height: 24,
|
||||
width: 24
|
||||
},
|
||||
|
||||
/**
|
||||
* A special padding to avoid issues on some devices (such as Android devices with custom suggestions bar).
|
||||
*/
|
||||
|
@ -92,18 +85,6 @@ export default {
|
|||
padding: 5
|
||||
},
|
||||
|
||||
searchField: {
|
||||
backgroundColor: BaseTheme.palette.section01,
|
||||
borderBottomRightRadius: 10,
|
||||
borderTopRightRadius: 10,
|
||||
color: DARK_GREY,
|
||||
flex: 1,
|
||||
fontSize: 17,
|
||||
paddingVertical: 7,
|
||||
paddingLeft: 0,
|
||||
textAlign: 'left'
|
||||
},
|
||||
|
||||
selectedIcon: {
|
||||
color: BaseTheme.palette.icon01,
|
||||
fontSize: 20,
|
||||
|
@ -117,29 +98,9 @@ export default {
|
|||
marginLeft: 85
|
||||
},
|
||||
|
||||
searchFieldWrapper: {
|
||||
backgroundColor: BaseTheme.palette.section01,
|
||||
alignItems: 'stretch',
|
||||
flexDirection: 'row',
|
||||
height: 36,
|
||||
marginHorizontal: 15,
|
||||
marginVertical: 8,
|
||||
borderWidth: 0,
|
||||
borderRadius: 10,
|
||||
overflow: 'hidden'
|
||||
},
|
||||
|
||||
searchIcon: {
|
||||
color: DARK_GREY,
|
||||
fontSize: ICON_SIZE
|
||||
},
|
||||
|
||||
searchIconWrapper: {
|
||||
alignItems: 'center',
|
||||
backgroundColor: BaseTheme.palette.section01,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
width: ICON_SIZE + 16
|
||||
color: BaseTheme.palette.icon01,
|
||||
fontSize: 22
|
||||
},
|
||||
|
||||
shareIcon: {
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { Text, TextInput, View } from 'react-native';
|
||||
import React, { ReactElement } from 'react';
|
||||
import { Text, View } from 'react-native';
|
||||
|
||||
import { getConferenceName } from '../../../base/conference/functions';
|
||||
import { translate } from '../../../base/i18n';
|
||||
|
@ -9,8 +7,9 @@ import JitsiScreen from '../../../base/modal/components/JitsiScreen';
|
|||
import { LoadingIndicator } from '../../../base/react';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { ASPECT_RATIO_NARROW } from '../../../base/responsive-ui';
|
||||
import BaseTheme from '../../../base/ui/components/BaseTheme';
|
||||
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
|
||||
import Button from '../../../base/ui/components/native/Button';
|
||||
import Input from '../../../base/ui/components/native/Input';
|
||||
import { BUTTON_TYPES } from '../../../base/ui/constants';
|
||||
import { BrandingImageBackground } from '../../../dynamic-branding/components/native';
|
||||
import { LargeVideo } from '../../../large-video/components';
|
||||
|
@ -25,6 +24,7 @@ import AbstractLobbyScreen, {
|
|||
|
||||
import styles from './styles';
|
||||
|
||||
|
||||
type Props = AbstractProps & {
|
||||
|
||||
/**
|
||||
|
@ -99,9 +99,9 @@ class LobbyScreen extends AbstractLobbyScreen<Props> {
|
|||
|
||||
_onSwitchToPasswordMode: () => void;
|
||||
|
||||
_renderContent: () => React$Element<*>;
|
||||
_renderContent: () => ReactElement;
|
||||
|
||||
_renderToolbarButtons: () => React$Element<*>;
|
||||
_renderToolbarButtons: () => ReactElement;
|
||||
|
||||
_onNavigateToLobbyChat: () => void;
|
||||
|
||||
|
@ -152,10 +152,10 @@ class LobbyScreen extends AbstractLobbyScreen<Props> {
|
|||
const { displayName } = this.state;
|
||||
|
||||
return (
|
||||
<TextInput
|
||||
onChangeText = { this._onChangeDisplayName }
|
||||
<Input
|
||||
customStyles = {{ input: styles.customInput }}
|
||||
onChange = { this._onChangeDisplayName }
|
||||
placeholder = { t('lobby.nameField') }
|
||||
style = { styles.field }
|
||||
value = { displayName } />
|
||||
);
|
||||
}
|
||||
|
@ -179,13 +179,13 @@ class LobbyScreen extends AbstractLobbyScreen<Props> {
|
|||
|
||||
return (
|
||||
<View style = { styles.formWrapper }>
|
||||
<TextInput
|
||||
<Input
|
||||
autoCapitalize = 'none'
|
||||
autoCompleteType = 'off'
|
||||
onChangeText = { this._onChangePassword }
|
||||
customStyles = {{ input: styles.customInput }}
|
||||
onChange = { this._onChangePassword }
|
||||
placeholder = { t('lobby.passwordField') }
|
||||
secureTextEntry = { true }
|
||||
style = { styles.field }
|
||||
value = { this.state.password } />
|
||||
{ _passwordJoinFailed && <Text style = { styles.fieldError }>
|
||||
{ t('lobby.invalidPassword') }
|
||||
|
|
|
@ -124,20 +124,12 @@ export default {
|
|||
|
||||
formWrapper: {
|
||||
alignSelf: 'stretch',
|
||||
justifyContent: 'center'
|
||||
justifyContent: 'center',
|
||||
marginTop: 38
|
||||
},
|
||||
|
||||
field: {
|
||||
alignSelf: 'stretch',
|
||||
backgroundColor: BaseTheme.palette.field02,
|
||||
borderColor: SECONDARY_COLOR,
|
||||
borderRadius: BaseTheme.shape.borderRadius,
|
||||
borderWidth: 2,
|
||||
color: BaseTheme.palette.text06,
|
||||
height: BaseTheme.spacing[7],
|
||||
marginTop: 38,
|
||||
customInput: {
|
||||
marginHorizontal: BaseTheme.spacing[3],
|
||||
padding: BaseTheme.spacing[2],
|
||||
textAlign: 'center'
|
||||
},
|
||||
|
||||
|
|
|
@ -1,195 +0,0 @@
|
|||
// @flow
|
||||
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { TextInput, TouchableOpacity, View } from 'react-native';
|
||||
import { withTheme } from 'react-native-paper';
|
||||
|
||||
import { Icon, IconCloseCircle } from '../../../base/icons';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* If the input should be focused on display.
|
||||
*/
|
||||
autoFocus?: boolean,
|
||||
|
||||
/**
|
||||
* Custom styles for the component.
|
||||
*/
|
||||
customStyles?: Object,
|
||||
|
||||
/**
|
||||
* Callback for the onBlur event of the field.
|
||||
*/
|
||||
onBlur?: Function,
|
||||
|
||||
/**
|
||||
* Callback for the onChange event of the field.
|
||||
*/
|
||||
onChange: Function,
|
||||
|
||||
/**
|
||||
* Callback for the onFocus event of the field.
|
||||
*/
|
||||
onFocus?: Function,
|
||||
|
||||
/**
|
||||
* Callback to be used when the user hits Enter in the field.
|
||||
*/
|
||||
onSubmit?: Function,
|
||||
|
||||
/**
|
||||
* Placeholder text for the field.
|
||||
*/
|
||||
placeholder: string,
|
||||
|
||||
/**
|
||||
* Placeholder text color.
|
||||
*/
|
||||
placeholderColor?: string,
|
||||
|
||||
/**
|
||||
* Component to be added to the beginning of the the input.
|
||||
*/
|
||||
prefixComponent?: React$Node,
|
||||
|
||||
/**
|
||||
* The type of the return key.
|
||||
*/
|
||||
returnKeyType?: 'done' | 'go' | 'next' | 'search' | 'send' | 'none' | 'previous' | 'default',
|
||||
|
||||
/**
|
||||
* Color of the caret and selection.
|
||||
*/
|
||||
selectionColor?: string,
|
||||
|
||||
/**
|
||||
* Theme used for styles.
|
||||
*/
|
||||
theme: Object,
|
||||
|
||||
/**
|
||||
* Externally provided value.
|
||||
*/
|
||||
value?: string
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements a pre-styled clearable input field.
|
||||
*
|
||||
* @param {Props} props - The props of the component.
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
function ClearableInput({
|
||||
autoFocus = false,
|
||||
customStyles = {},
|
||||
onBlur,
|
||||
onChange,
|
||||
onFocus,
|
||||
onSubmit,
|
||||
placeholder,
|
||||
placeholderColor,
|
||||
prefixComponent,
|
||||
returnKeyType = 'search',
|
||||
selectionColor,
|
||||
theme,
|
||||
value
|
||||
}: Props) {
|
||||
const [ val, setVal ] = useState(value || '');
|
||||
const [ focused, setFocused ] = useState(false);
|
||||
const inputRef = React.createRef();
|
||||
|
||||
useEffect(() => {
|
||||
if (value && value !== val) {
|
||||
setVal(value);
|
||||
}
|
||||
}, [ value ]);
|
||||
|
||||
|
||||
/**
|
||||
* Callback for the onBlur event of the field.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
const _onBlur = useCallback(() => {
|
||||
setFocused(false);
|
||||
|
||||
onBlur && onBlur();
|
||||
}, [ onBlur ]);
|
||||
|
||||
/**
|
||||
* Callback for the onChange event of the field.
|
||||
*
|
||||
* @param {Object} evt - The static event.
|
||||
* @returns {void}
|
||||
*/
|
||||
const _onChange = useCallback(evt => {
|
||||
const { nativeEvent: { text } } = evt;
|
||||
|
||||
setVal(text);
|
||||
onChange && onChange(text);
|
||||
}, [ onChange ]);
|
||||
|
||||
/**
|
||||
* Callback for the onFocus event of the field.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
const _onFocus = useCallback(() => {
|
||||
setFocused(true);
|
||||
|
||||
onFocus && onFocus();
|
||||
}, [ onFocus ]);
|
||||
|
||||
/**
|
||||
* Clears the input.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
const _clearInput = useCallback(() => {
|
||||
if (inputRef.current) {
|
||||
inputRef.current.focus();
|
||||
}
|
||||
setVal('');
|
||||
onChange && onChange('');
|
||||
}, [ onChange ]);
|
||||
|
||||
return (
|
||||
<View
|
||||
style = { [
|
||||
styles.clearableInput,
|
||||
focused ? styles.clearableInputFocus : {},
|
||||
customStyles?.wrapper
|
||||
] }>
|
||||
{prefixComponent}
|
||||
<TextInput
|
||||
autoCorrect = { false }
|
||||
autoFocus = { autoFocus }
|
||||
onBlur = { _onBlur }
|
||||
onChange = { _onChange }
|
||||
onFocus = { _onFocus }
|
||||
onSubmitEditing = { onSubmit }
|
||||
placeholder = { placeholder }
|
||||
placeholderTextColor = { placeholderColor ?? theme.palette.text01 }
|
||||
ref = { inputRef }
|
||||
returnKeyType = { returnKeyType }
|
||||
selectionColor = { selectionColor }
|
||||
style = { [ styles.clearableInputTextInput, customStyles?.input ] }
|
||||
value = { val } />
|
||||
{val !== '' && (
|
||||
<TouchableOpacity
|
||||
onPress = { _clearInput }
|
||||
style = { [ styles.clearButton, customStyles?.clearButton ] }>
|
||||
<Icon
|
||||
size = { 22 }
|
||||
src = { IconCloseCircle }
|
||||
style = { [ styles.clearIcon, customStyles?.clearIcon ] } />
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
export default withTheme(ClearableInput);
|
|
@ -1,4 +1,3 @@
|
|||
import { MD_ITEM_HEIGHT } from '../../../base/dialog/components/native/styles';
|
||||
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
|
||||
|
||||
/**
|
||||
|
@ -264,54 +263,6 @@ export default {
|
|||
backgroundColor: BaseTheme.palette.dividerColor
|
||||
},
|
||||
|
||||
clearableInput: {
|
||||
display: 'flex',
|
||||
height: MD_ITEM_HEIGHT,
|
||||
borderWidth: 1,
|
||||
borderStyle: 'solid',
|
||||
borderColor: BaseTheme.palette.ui05,
|
||||
backgroundColor: BaseTheme.palette.uiBackground,
|
||||
borderRadius: BaseTheme.shape.borderRadius,
|
||||
marginLeft: BaseTheme.spacing[3],
|
||||
marginRight: BaseTheme.spacing[3],
|
||||
marginBottom: BaseTheme.spacing[4]
|
||||
},
|
||||
|
||||
clearableInputFocus: {
|
||||
borderWidth: 3,
|
||||
borderColor: BaseTheme.palette.field01Focus
|
||||
},
|
||||
|
||||
clearButton: {
|
||||
backgroundColor: 'transparent',
|
||||
borderWidth: 0,
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
top: 0,
|
||||
paddingTop: 12,
|
||||
paddingLeft: BaseTheme.spacing[2],
|
||||
width: 40,
|
||||
height: MD_ITEM_HEIGHT
|
||||
},
|
||||
|
||||
clearIcon: {
|
||||
color: BaseTheme.palette.icon02
|
||||
},
|
||||
|
||||
clearableInputTextInput: {
|
||||
backgroundColor: 'transparent',
|
||||
borderWidth: 0,
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
textAlign: 'center',
|
||||
color: BaseTheme.palette.text01,
|
||||
paddingTop: BaseTheme.spacing[2],
|
||||
paddingBottom: BaseTheme.spacing[2],
|
||||
paddingLeft: BaseTheme.spacing[3],
|
||||
paddingRight: BaseTheme.spacing[3],
|
||||
fontSize: 16
|
||||
},
|
||||
|
||||
inputContainer: {
|
||||
marginLeft: BaseTheme.spacing[3],
|
||||
marginRight: BaseTheme.spacing[3],
|
||||
|
|
|
@ -48,10 +48,9 @@ const AbstractPollCreate = (Component: AbstractComponent<AbstractProps>) => (pro
|
|||
const [ answers, setAnswers ] = useState([ '', '' ]);
|
||||
|
||||
const setAnswer = useCallback((i, answer) => {
|
||||
const newAnswers = [ ...answers ];
|
||||
answers[i] = answer;
|
||||
|
||||
newAnswers[i] = answer;
|
||||
setAnswers(newAnswers);
|
||||
setAnswers([ ...answers ]);
|
||||
});
|
||||
|
||||
const addAnswer = useCallback((i: ?number) => {
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
// @flow
|
||||
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { FlatList, Platform, Text, TextInput, View } from 'react-native';
|
||||
import { FlatList, Platform, Text, View } from 'react-native';
|
||||
import { Divider, TouchableRipple } from 'react-native-paper';
|
||||
|
||||
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
|
||||
import Button from '../../../base/ui/components/native/Button';
|
||||
import Input from '../../../base/ui/components/native/Input';
|
||||
import { BUTTON_TYPES } from '../../../base/ui/constants';
|
||||
import styles
|
||||
from '../../../settings/components/native/styles';
|
||||
|
@ -42,12 +40,11 @@ const PollCreate = (props: AbstractProps) => {
|
|||
return;
|
||||
}
|
||||
answerInputs.current[i] = input;
|
||||
},
|
||||
[ answerInputs ]
|
||||
);
|
||||
}, [ answerInputs ]);
|
||||
|
||||
useEffect(() => {
|
||||
answerInputs.current = answerInputs.current.slice(0, answers.length);
|
||||
|
||||
}, [ answers ]);
|
||||
|
||||
/*
|
||||
|
@ -105,22 +102,16 @@ const PollCreate = (props: AbstractProps) => {
|
|||
(
|
||||
<View
|
||||
style = { dialogStyles.optionContainer }>
|
||||
<Text style = { dialogStyles.optionFieldLabel }>
|
||||
{ t('polls.create.pollOption', { index: index + 1 }) }
|
||||
</Text>
|
||||
<TextInput
|
||||
<Input
|
||||
blurOnSubmit = { false }
|
||||
label = { t('polls.create.pollOption', { index: index + 1 }) }
|
||||
maxLength = { CHAR_LIMIT }
|
||||
multiline = { true }
|
||||
onChangeText = { text => setAnswer(index, text) }
|
||||
onChange = { text => setAnswer(index, text) }
|
||||
onKeyPress = { ev => onAnswerKeyDown(index, ev) }
|
||||
placeholder = { t('polls.create.answerPlaceholder', { index: index + 1 }) }
|
||||
placeholderTextColor = { BaseTheme.palette.text03 }
|
||||
ref = { input => registerFieldRef(index, input) }
|
||||
selectionColor = { BaseTheme.palette.action01 }
|
||||
style = { dialogStyles.field }
|
||||
value = { answers[index] } />
|
||||
|
||||
{
|
||||
answers.length > 2
|
||||
&& createRemoveOptionButton(() => removeAnswer(index))
|
||||
|
@ -133,20 +124,16 @@ const PollCreate = (props: AbstractProps) => {
|
|||
return (
|
||||
<View style = { chatStyles.pollCreateContainer }>
|
||||
<View style = { chatStyles.pollCreateSubContainer }>
|
||||
<Text style = { chatStyles.questionFieldLabel }>
|
||||
{ t('polls.create.pollQuestion') }
|
||||
</Text>
|
||||
<TextInput
|
||||
<Input
|
||||
autoFocus = { true }
|
||||
blurOnSubmit = { false }
|
||||
customStyles = {{ container: dialogStyles.customContainer }}
|
||||
label = { t('polls.create.pollQuestion') }
|
||||
maxLength = { CHAR_LIMIT }
|
||||
multiline = { true }
|
||||
onChangeText = { setQuestion }
|
||||
onChange = { setQuestion }
|
||||
onSubmitEditing = { onQuestionKeyDown }
|
||||
placeholder = { t('polls.create.questionPlaceholder') }
|
||||
placeholderTextColor = { BaseTheme.palette.text03 }
|
||||
selectionColor = { BaseTheme.palette.action01 }
|
||||
style = { dialogStyles.questionField }
|
||||
value = { question } />
|
||||
<Divider style = { styles.fieldSeparator } />
|
||||
<FlatList
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
// @flow
|
||||
|
||||
import { createStyleSheet } from '../../../base/styles';
|
||||
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
|
||||
|
||||
|
||||
export const dialogStyles = createStyleSheet({
|
||||
|
||||
customContainer: {
|
||||
marginBottom: BaseTheme.spacing[3],
|
||||
marginHorizontal: BaseTheme.spacing[3],
|
||||
marginTop: BaseTheme.spacing[2]
|
||||
},
|
||||
|
||||
questionText: {
|
||||
...BaseTheme.typography.bodyShortBold,
|
||||
color: BaseTheme.palette.text01,
|
||||
|
@ -19,31 +24,12 @@ export const dialogStyles = createStyleSheet({
|
|||
marginLeft: BaseTheme.spacing[2]
|
||||
},
|
||||
|
||||
questionField: {
|
||||
borderWidth: 1,
|
||||
borderColor: BaseTheme.palette.border05,
|
||||
borderRadius: BaseTheme.shape.borderRadius,
|
||||
color: BaseTheme.palette.text01,
|
||||
fontSize: 14,
|
||||
marginHorizontal: BaseTheme.spacing[3],
|
||||
marginBottom: BaseTheme.spacing[3],
|
||||
paddingBottom: BaseTheme.spacing[2],
|
||||
paddingLeft: BaseTheme.spacing[3],
|
||||
paddingRight: BaseTheme.spacing[3],
|
||||
paddingTop: BaseTheme.spacing[2]
|
||||
},
|
||||
|
||||
optionContainer: {
|
||||
flexDirection: 'column',
|
||||
marginTop: BaseTheme.spacing[3],
|
||||
marginHorizontal: BaseTheme.spacing[3]
|
||||
},
|
||||
|
||||
optionFieldLabel: {
|
||||
color: BaseTheme.palette.text03,
|
||||
marginBottom: BaseTheme.spacing[2]
|
||||
},
|
||||
|
||||
optionRemoveButtonText: {
|
||||
color: BaseTheme.palette.actionDangerActive
|
||||
},
|
||||
|
@ -62,6 +48,7 @@ export const dialogStyles = createStyleSheet({
|
|||
});
|
||||
|
||||
export const resultsStyles = createStyleSheet({
|
||||
|
||||
title: {
|
||||
fontSize: 24,
|
||||
fontWeight: 'bold'
|
||||
|
@ -120,11 +107,6 @@ export const resultsStyles = createStyleSheet({
|
|||
});
|
||||
|
||||
export const chatStyles = createStyleSheet({
|
||||
questionFieldLabel: {
|
||||
color: BaseTheme.palette.text03,
|
||||
marginBottom: BaseTheme.spacing[2],
|
||||
marginLeft: BaseTheme.spacing[3]
|
||||
},
|
||||
|
||||
noPollContent: {
|
||||
alignItems: 'center',
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* eslint-disable lines-around-comment */
|
||||
/* eslint-disable lines-around-comment */
|
||||
|
||||
import { useIsFocused } from '@react-navigation/native';
|
||||
import React, { useCallback, useEffect, useLayoutEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
@ -7,14 +8,12 @@ import {
|
|||
Platform,
|
||||
StyleProp,
|
||||
Text,
|
||||
TextInput,
|
||||
TextStyle,
|
||||
View,
|
||||
ViewStyle
|
||||
} from 'react-native';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
// @ts-ignore
|
||||
import { appNavigate } from '../../../app/actions.native';
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { setAudioOnly } from '../../../base/audio-only/actions';
|
||||
|
@ -24,16 +23,15 @@ import { IconCloseLarge } from '../../../base/icons/svg';
|
|||
// @ts-ignore
|
||||
import JitsiScreen from '../../../base/modal/components/JitsiScreen';
|
||||
import { getLocalParticipant } from '../../../base/participants/functions';
|
||||
// @ts-ignore
|
||||
import { getFieldValue } from '../../../base/react';
|
||||
import { getFieldValue } from '../../../base/react/functions';
|
||||
import { ASPECT_RATIO_NARROW } from '../../../base/responsive-ui/constants';
|
||||
import { updateSettings } from '../../../base/settings/actions';
|
||||
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
|
||||
import Button from '../../../base/ui/components/native/Button';
|
||||
import { BUTTON_TYPES } from '../../../base/ui/constants';
|
||||
import Input from '../../../base/ui/components/native/Input';
|
||||
import { BUTTON_TYPES } from '../../../base/ui/constants.native';
|
||||
import { BrandingImageBackground } from '../../../dynamic-branding/components/native';
|
||||
// @ts-ignore
|
||||
import { LargeVideo } from '../../../large-video/components';
|
||||
import LargeVideo from '../../../large-video/components/LargeVideo.native';
|
||||
// @ts-ignore
|
||||
import HeaderNavigationButton from '../../../mobile/navigation/components/HeaderNavigationButton';
|
||||
// @ts-ignore
|
||||
|
@ -162,11 +160,12 @@ const Prejoin: React.FC<IPrejoinProps> = ({ navigation }: IPrejoinProps) => {
|
|||
}
|
||||
<View style = { contentContainerStyles }>
|
||||
<View style = { styles.formWrapper as StyleProp<ViewStyle> }>
|
||||
<TextInput
|
||||
onChangeText = { onChangeDisplayName }
|
||||
<Input
|
||||
// @ts-ignore
|
||||
autoFocus = { true }
|
||||
customStyles = {{ input: styles.customInput }}
|
||||
onChange = { onChangeDisplayName }
|
||||
placeholder = { t('dialog.enterDisplayName') }
|
||||
placeholderTextColor = { BaseTheme.palette.text03 }
|
||||
style = { styles.field as StyleProp<TextStyle> }
|
||||
value = { displayName } />
|
||||
<Button
|
||||
accessibilityLabel = 'prejoin.joinMeeting'
|
||||
|
|
|
@ -79,6 +79,10 @@ export default {
|
|||
marginHorizontal: BaseTheme.spacing[3]
|
||||
},
|
||||
|
||||
customInput: {
|
||||
textAlign: 'center'
|
||||
},
|
||||
|
||||
field: {
|
||||
backgroundColor: BaseTheme.palette.field02,
|
||||
borderColor: SECONDARY_COLOR,
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { Linking, Text, TextInput, TouchableOpacity, View } from 'react-native';
|
||||
import { Linking, Text, TouchableOpacity, View } from 'react-native';
|
||||
|
||||
import { _abstractMapStateToProps } from '../../../../base/dialog';
|
||||
import { translate } from '../../../../base/i18n';
|
||||
import { connect } from '../../../../base/redux';
|
||||
import { StyleType } from '../../../../base/styles';
|
||||
import Input from '../../../../base/ui/components/native/Input';
|
||||
import AbstractStreamKeyForm, {
|
||||
type Props as AbstractProps
|
||||
} from '../AbstractStreamKeyForm';
|
||||
import { getLiveStreaming } from '../functions';
|
||||
|
||||
import styles, { PLACEHOLDER_COLOR } from './styles';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
type Props = AbstractProps & {
|
||||
|
||||
|
@ -65,15 +65,10 @@ class StreamKeyForm extends AbstractStreamKeyForm<Props> {
|
|||
t('dialog.streamKey')
|
||||
}
|
||||
</Text>
|
||||
<TextInput
|
||||
onChangeText = { this._onInputChange }
|
||||
<Input
|
||||
customStyles = {{ input: styles.streamKeyInput }}
|
||||
onChange = { this._onInputChange }
|
||||
placeholder = { t('liveStreaming.enterStreamKey') }
|
||||
placeholderTextColor = { PLACEHOLDER_COLOR }
|
||||
selectionColor = { PLACEHOLDER_COLOR }
|
||||
style = { [
|
||||
_dialogStyles.text,
|
||||
styles.streamKeyInput
|
||||
] }
|
||||
value = { this.props.value } />
|
||||
<View style = { styles.formFooter }>
|
||||
{
|
||||
|
|
|
@ -8,11 +8,6 @@ import BaseTheme from '../../../../base/ui/components/BaseTheme.native';
|
|||
*/
|
||||
export const ACTIVE_OPACITY = 0.3;
|
||||
|
||||
/**
|
||||
* Color for the key input field placeholder.
|
||||
*/
|
||||
export const PLACEHOLDER_COLOR = BaseTheme.palette.text03;
|
||||
|
||||
/**
|
||||
* Underlay of the TouchableHighlight.
|
||||
*/
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
// @flow
|
||||
|
||||
import React, { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Platform, SafeAreaView, ScrollView, Text, TextInput, View } from 'react-native';
|
||||
import { Button, withTheme } from 'react-native-paper';
|
||||
import { Platform, SafeAreaView, ScrollView, Text, View } from 'react-native';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { Icon, IconSearch } from '../../../base/icons';
|
||||
import { IconSearch } from '../../../base/icons';
|
||||
import JitsiScreen from '../../../base/modal/components/JitsiScreen';
|
||||
import { LoadingIndicator } from '../../../base/react';
|
||||
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
|
||||
import Button from '../../../base/ui/components/native/Button';
|
||||
import Input from '../../../base/ui/components/native/Input';
|
||||
import { BUTTON_TYPES } from '../../../base/ui/constants.native';
|
||||
import { navigate } from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
|
||||
import { screen } from '../../../mobile/navigation/routes';
|
||||
import { CONTENT_HEIGHT_OFFSET, LIST_HEIGHT_OFFSET, NOTES_LINES, NOTES_MAX_LENGTH } from '../../constants';
|
||||
|
@ -67,22 +66,21 @@ const SalesforceLinkDialog = () => {
|
|||
style = { [ styles.selectedRecord, { height: clientHeight - CONTENT_HEIGHT_OFFSET } ] }>
|
||||
<View style = { styles.recordInfo }>
|
||||
<RecordItem { ...selectedRecord } />
|
||||
{selectedRecordOwner && <RecordItem { ...selectedRecordOwner } />}
|
||||
{hasDetailsErrors && renderDetailsErrors()}
|
||||
{ selectedRecordOwner && <RecordItem { ...selectedRecordOwner } /> }
|
||||
{ hasDetailsErrors && renderDetailsErrors() }
|
||||
</View>
|
||||
<Text style = { styles.addNote }>
|
||||
{t('dialog.addOptionalNote')}
|
||||
</Text>
|
||||
<TextInput
|
||||
<Input
|
||||
customStyles = {{ container: styles.notes }}
|
||||
maxLength = { NOTES_MAX_LENGTH }
|
||||
minHeight = { Platform.OS === 'ios' && NOTES_LINES ? 20 * NOTES_LINES : null }
|
||||
multiline = { true }
|
||||
numberOfLines = { Platform.OS === 'ios' ? null : NOTES_LINES }
|
||||
/* eslint-disable-next-line react/jsx-no-bind */
|
||||
onChangeText = { value => setNotes(value) }
|
||||
onChange = { value => setNotes(value) }
|
||||
placeholder = { t('dialog.addMeetingNote') }
|
||||
placeholderTextColor = { BaseTheme.palette.text03 }
|
||||
style = { styles.notes }
|
||||
value = { notes } />
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
|
@ -90,17 +88,12 @@ const SalesforceLinkDialog = () => {
|
|||
|
||||
const renderRecordsSearch = () => (
|
||||
<View style = { styles.recordsSearchContainer }>
|
||||
<Icon
|
||||
color = { BaseTheme.palette.icon03 }
|
||||
src = { IconSearch }
|
||||
style = { styles.searchIcon } />
|
||||
<TextInput
|
||||
<Input
|
||||
icon = { IconSearch }
|
||||
maxLength = { NOTES_MAX_LENGTH }
|
||||
/* eslint-disable-next-line react/jsx-no-bind */
|
||||
onChangeText = { value => setSearchTerm(value) }
|
||||
onChange = { value => setSearchTerm(value) }
|
||||
placeholder = { t('dialog.searchInSalesforce') }
|
||||
placeholderTextColor = { BaseTheme.palette.text03 }
|
||||
style = { styles.recordsSearch }
|
||||
value = { searchTerm } />
|
||||
{(!isLoading && !hasRecordsErrors) && (
|
||||
<Text style = { styles.resultLabel }>
|
||||
|
@ -173,20 +166,20 @@ const SalesforceLinkDialog = () => {
|
|||
selectedRecord
|
||||
&& <View style = { styles.footer }>
|
||||
<Button
|
||||
children = { t('dialog.Cancel') }
|
||||
mode = 'contained'
|
||||
labelKey = 'dialog.Cancel'
|
||||
/* eslint-disable-next-line react/jsx-no-bind */
|
||||
onPress = { () => setSelectedRecord(null) }
|
||||
style = { styles.cancelButton } />
|
||||
onClick = { () => setSelectedRecord(null) }
|
||||
style = { styles.cancelButton }
|
||||
type = { BUTTON_TYPES.SECONDARY } />
|
||||
<Button
|
||||
children = { t('dialog.linkMeeting') }
|
||||
mode = 'contained'
|
||||
onPress = { handlePress }
|
||||
style = { styles.linkButton } />
|
||||
labelKey = 'dialog.linkMeeting'
|
||||
onClick = { handlePress }
|
||||
style = { styles.linkButton }
|
||||
type = { BUTTON_TYPES.PRIMARY } />
|
||||
</View>
|
||||
}
|
||||
</JitsiScreen>
|
||||
);
|
||||
};
|
||||
|
||||
export default withTheme(SalesforceLinkDialog);
|
||||
export default SalesforceLinkDialog;
|
||||
|
|
|
@ -9,12 +9,11 @@ export default {
|
|||
backgroundColor: BaseTheme.palette.ui01
|
||||
},
|
||||
recordsSearchContainer: {
|
||||
paddingHorizontal: BaseTheme.spacing[3],
|
||||
paddingTop: BaseTheme.spacing[3],
|
||||
backgroundColor: BaseTheme.palette.ui01,
|
||||
alignSelf: 'stretch',
|
||||
position: 'relative',
|
||||
marginTop: BaseTheme.spacing[3]
|
||||
backgroundColor: BaseTheme.palette.ui01,
|
||||
paddingHorizontal: BaseTheme.spacing[3],
|
||||
paddingTop: BaseTheme.spacing[2],
|
||||
position: 'relative'
|
||||
},
|
||||
searchIcon: {
|
||||
color: BaseTheme.palette.text03,
|
||||
|
@ -32,17 +31,6 @@ export default {
|
|||
paddingBottom: 8,
|
||||
paddingTop: 16
|
||||
},
|
||||
recordsSearch: {
|
||||
backgroundColor: BaseTheme.palette.field01,
|
||||
borderColor: BaseTheme.palette.ui05,
|
||||
borderRadius: BaseTheme.shape.borderRadius,
|
||||
borderWidth: 1,
|
||||
color: BaseTheme.palette.text01,
|
||||
paddingLeft: 44,
|
||||
paddingRight: 16,
|
||||
paddingVertical: 10,
|
||||
width: '100%'
|
||||
},
|
||||
recordsSpinner: {
|
||||
alignItems: 'center',
|
||||
display: 'flex',
|
||||
|
@ -107,16 +95,15 @@ export default {
|
|||
color: BaseTheme.palette.field02,
|
||||
lineHeight: 18,
|
||||
marginHorizontal: BaseTheme.spacing[3],
|
||||
marginVertical: BaseTheme.spacing[2],
|
||||
overflow: 'hidden',
|
||||
padding: BaseTheme.spacing[2],
|
||||
textAlignVertical: 'top'
|
||||
},
|
||||
cancelButton: {
|
||||
backgroundColor: BaseTheme.palette.action02,
|
||||
margin: BaseTheme.spacing[2]
|
||||
},
|
||||
linkButton: {
|
||||
backgroundColor: BaseTheme.palette.action01,
|
||||
marginBottom: BaseTheme.spacing[2],
|
||||
marginHorizontal: BaseTheme.spacing[2]
|
||||
},
|
||||
|
|
|
@ -10,7 +10,6 @@ import { translate } from '../../../../base/i18n';
|
|||
import JitsiScreen from '../../../../base/modal/components/JitsiScreen';
|
||||
import { isLocalParticipantModerator } from '../../../../base/participants';
|
||||
import { connect } from '../../../../base/redux';
|
||||
import BaseTheme from '../../../../base/ui/components/BaseTheme';
|
||||
import Button from '../../../../base/ui/components/native/Button';
|
||||
import Input from '../../../../base/ui/components/native/Input';
|
||||
import Switch from '../../../../base/ui/components/native/Switch';
|
||||
|
@ -352,10 +351,9 @@ class SecurityDialog extends PureComponent<Props, State> {
|
|||
accessibilityLabel = { t('info.addPassword') }
|
||||
autoFocus = { true }
|
||||
clearable = { true }
|
||||
customStyles = {{ container: styles.passwordInput }}
|
||||
customStyles = {{ container: styles.customContainer }}
|
||||
onChange = { this._onChangeText }
|
||||
placeholder = { t('dialog.password') }
|
||||
placeholderTextColor = { BaseTheme.palette.text03 }
|
||||
value = { passwordInputValue }
|
||||
{ ...textInputProps } />
|
||||
);
|
||||
|
|
|
@ -74,8 +74,7 @@ export default {
|
|||
color: BaseTheme.palette.text01
|
||||
},
|
||||
|
||||
passwordInput: {
|
||||
color: BaseTheme.palette.text01,
|
||||
customContainer: {
|
||||
width: 208
|
||||
},
|
||||
|
||||
|
|
|
@ -12,13 +12,9 @@ import {
|
|||
Text,
|
||||
View
|
||||
} from 'react-native';
|
||||
import {
|
||||
Divider,
|
||||
TextInput
|
||||
} from 'react-native-paper';
|
||||
import { Divider } from 'react-native-paper';
|
||||
|
||||
// @ts-ignore
|
||||
import { getDefaultURL } from '../../../app/functions';
|
||||
import { getDefaultURL } from '../../../app/functions.native';
|
||||
import { IReduxState } from '../../../app/types';
|
||||
// @ts-ignore
|
||||
import { Avatar } from '../../../base/avatar';
|
||||
|
@ -28,21 +24,20 @@ import JitsiScreen from '../../../base/modal/components/JitsiScreen';
|
|||
import { getLocalParticipant } from '../../../base/participants/functions';
|
||||
import { connect } from '../../../base/redux/functions';
|
||||
import { updateSettings } from '../../../base/settings/actions';
|
||||
import BaseThemeNative from '../../../base/ui/components/BaseTheme.native';
|
||||
import Input from '../../../base/ui/components/native/Input';
|
||||
import Switch from '../../../base/ui/components/native/Switch';
|
||||
// @ts-ignore
|
||||
import { screen } from '../../../mobile/navigation/routes';
|
||||
// @ts-ignore
|
||||
import { AVATAR_SIZE } from '../../../welcome/components/styles';
|
||||
// @ts-ignore
|
||||
import { isServerURLChangeEnabled, normalizeUserInputURL } from '../../functions';
|
||||
import { isServerURLChangeEnabled, normalizeUserInputURL } from '../../functions.native';
|
||||
|
||||
// @ts-ignore
|
||||
import FormRow from './FormRow';
|
||||
// @ts-ignore
|
||||
import FormSectionAccordion from './FormSectionAccordion';
|
||||
// @ts-ignore
|
||||
import styles, { PLACEHOLDER_COLOR, PLACEHOLDER_TEXT_COLOR } from './styles';
|
||||
import styles from './styles';
|
||||
|
||||
/**
|
||||
* Application information module.
|
||||
|
@ -205,9 +200,9 @@ class SettingsView extends Component<IProps, IState> {
|
|||
disableCrashReporting,
|
||||
disableP2P,
|
||||
disableSelfView,
|
||||
displayName,
|
||||
email,
|
||||
serverURL,
|
||||
displayName: displayName || '',
|
||||
email: email || '',
|
||||
serverURL: serverURL || '',
|
||||
startCarMode,
|
||||
startWithAudioMuted,
|
||||
startWithVideoMuted
|
||||
|
@ -275,16 +270,6 @@ class SettingsView extends Component<IProps, IState> {
|
|||
t
|
||||
} = this.props;
|
||||
|
||||
const textInputTheme = {
|
||||
colors: {
|
||||
background: BaseThemeNative.palette.ui01,
|
||||
placeholder: BaseThemeNative.palette.text01,
|
||||
primary: PLACEHOLDER_COLOR,
|
||||
underlineColor: 'transparent',
|
||||
text: BaseThemeNative.palette.text01
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<JitsiScreen
|
||||
disableForcedKeyboardDismiss = { true }
|
||||
|
@ -298,51 +283,39 @@ class SettingsView extends Component<IProps, IState> {
|
|||
</View>
|
||||
<FormSectionAccordion
|
||||
label = 'settingsView.profileSection'>
|
||||
<TextInput
|
||||
autoCorrect = { false }
|
||||
<Input
|
||||
// @ts-ignore
|
||||
customStyles = {{ container: styles.customContainer }}
|
||||
label = { t('settingsView.displayName') }
|
||||
mode = 'outlined'
|
||||
onChangeText = { this._onChangeDisplayName }
|
||||
onChange = { this._onChangeDisplayName }
|
||||
placeholder = { t('settingsView.displayNamePlaceholderText') }
|
||||
placeholderTextColor = { PLACEHOLDER_TEXT_COLOR }
|
||||
spellCheck = { false }
|
||||
style = { styles.textInputContainer }
|
||||
textContentType = { 'name' } // iOS only
|
||||
theme = { textInputTheme }
|
||||
value = { displayName } />
|
||||
<Divider style = { styles.fieldSeparator } />
|
||||
<TextInput
|
||||
<Input
|
||||
// @ts-ignore
|
||||
autoCapitalize = 'none'
|
||||
autoCorrect = { false }
|
||||
customStyles = {{ container: styles.customContainer }}
|
||||
keyboardType = { 'email-address' }
|
||||
label = { t('settingsView.email') }
|
||||
mode = 'outlined'
|
||||
onChangeText = { this._onChangeEmail }
|
||||
placeholder = 'email@example.com'
|
||||
placeholderTextColor = { PLACEHOLDER_TEXT_COLOR }
|
||||
spellCheck = { false }
|
||||
style = { styles.textInputContainer }
|
||||
onChange = { this._onChangeEmail }
|
||||
placeholder = { t('settingsView.emailPlaceholderText') }
|
||||
textContentType = { 'emailAddress' } // iOS only
|
||||
theme = { textInputTheme }
|
||||
value = { email } />
|
||||
</FormSectionAccordion>
|
||||
<FormSectionAccordion
|
||||
label = 'settingsView.conferenceSection'>
|
||||
<TextInput
|
||||
<Input
|
||||
// @ts-ignore
|
||||
autoCapitalize = 'none'
|
||||
autoCorrect = { false }
|
||||
customStyles = {{ container: styles.customContainer }}
|
||||
editable = { this.props._serverURLChangeEnabled }
|
||||
keyboardType = { 'url' }
|
||||
label = { t('settingsView.serverURL') }
|
||||
mode = 'outlined'
|
||||
onBlur = { this._onBlurServerURL }
|
||||
onChangeText = { this._onChangeServerURL }
|
||||
onChange = { this._onChangeServerURL }
|
||||
placeholder = { this.props._serverURL }
|
||||
placeholderTextColor = { PLACEHOLDER_TEXT_COLOR }
|
||||
spellCheck = { false }
|
||||
style = { styles.textInputContainer }
|
||||
textContentType = { 'URL' } // iOS only
|
||||
theme = { textInputTheme }
|
||||
value = { serverURL } />
|
||||
<Divider style = { styles.fieldSeparator } />
|
||||
<FormRow label = 'settingsView.startCarModeInLowBandwidthMode'>
|
||||
|
|
|
@ -98,7 +98,10 @@ export default {
|
|||
},
|
||||
|
||||
formSectionTitleText: {
|
||||
color: BaseTheme.palette.text01
|
||||
color: BaseTheme.palette.text01,
|
||||
fontSize: 14,
|
||||
opacity: 0.6,
|
||||
textAlign: 'center'
|
||||
},
|
||||
|
||||
section: {
|
||||
|
@ -133,9 +136,7 @@ export default {
|
|||
/**
|
||||
* Text input container style.
|
||||
*/
|
||||
textInputContainer: {
|
||||
flex: 1,
|
||||
height: BaseTheme.spacing[7],
|
||||
customContainer: {
|
||||
marginBottom: BaseTheme.spacing[3],
|
||||
marginHorizontal: BaseTheme.spacing[3],
|
||||
marginTop: BaseTheme.spacing[2]
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
// @flow
|
||||
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import JitsiScreen from '../../../base/modal/components/JitsiScreen';
|
||||
import { escapeRegexp } from '../../../base/util';
|
||||
import { initSearch, resetSearchCriteria } from '../../actions';
|
||||
import { resetSearchCriteria } from '../../actions';
|
||||
|
||||
|
||||
import SpeakerStatsList from './SpeakerStatsList';
|
||||
|
@ -19,17 +16,15 @@ import style from './styles';
|
|||
*/
|
||||
const SpeakerStats = () => {
|
||||
const dispatch = useDispatch();
|
||||
const onSearch = useCallback((criteria = '') => {
|
||||
dispatch(initSearch(escapeRegexp(criteria)));
|
||||
}
|
||||
, [ dispatch ]);
|
||||
|
||||
useEffect(() => () => dispatch(resetSearchCriteria()), []);
|
||||
useEffect(() => {
|
||||
dispatch(resetSearchCriteria());
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<JitsiScreen
|
||||
style = { style.speakerStatsContainer }>
|
||||
<SpeakerStatsSearch onSearch = { onSearch } />
|
||||
<SpeakerStatsSearch />
|
||||
<SpeakerStatsList />
|
||||
</JitsiScreen>
|
||||
);
|
||||
|
|
|
@ -1,38 +1,32 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { withTheme } from 'react-native-paper';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import { Icon, IconSearch } from '../../../base/icons';
|
||||
import ClearableInput from '../../../participants-pane/components/native/ClearableInput';
|
||||
import { IconSearch } from '../../../base/icons';
|
||||
import Input from '../../../base/ui/components/native/Input';
|
||||
import { escapeRegexp } from '../../../base/util';
|
||||
import { initSearch } from '../../actions';
|
||||
import { isSpeakerStatsSearchDisabled } from '../../functions';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link SpeakerStatsSearch}.
|
||||
*/
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The function to initiate the change in the speaker stats table.
|
||||
*/
|
||||
onSearch: Function,
|
||||
|
||||
/**
|
||||
* Theme used for styles.
|
||||
*/
|
||||
theme: Object
|
||||
};
|
||||
|
||||
/**
|
||||
* React component for display an individual user's speaker stats.
|
||||
*
|
||||
* @returns {React$Element<any>}
|
||||
*/
|
||||
function SpeakerStatsSearch({ onSearch, theme }: Props) {
|
||||
const SpeakerStatsSearch = () => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useDispatch();
|
||||
const [ searchQuery, setSearchQuery ] = useState('');
|
||||
|
||||
const onSearch = useCallback((criteria = '') => {
|
||||
dispatch(initSearch(escapeRegexp(criteria)));
|
||||
setSearchQuery(escapeRegexp(criteria));
|
||||
}, [ dispatch ]);
|
||||
|
||||
|
||||
const disableSpeakerStatsSearch = useSelector(isSpeakerStatsSearchDisabled);
|
||||
|
||||
|
@ -41,20 +35,14 @@ function SpeakerStatsSearch({ onSearch, theme }: Props) {
|
|||
}
|
||||
|
||||
return (
|
||||
<ClearableInput
|
||||
customStyles = { styles.speakerStatsSearch }
|
||||
<Input
|
||||
clearable = { true }
|
||||
customStyles = {{ container: styles.customContainer }}
|
||||
icon = { IconSearch }
|
||||
onChange = { onSearch }
|
||||
placeholder = { t('speakerStats.search') }
|
||||
placeholderColor = { theme.palette.text03 }
|
||||
prefixComponent = {
|
||||
<Icon
|
||||
color = { theme.palette.text03 }
|
||||
size = { 20 }
|
||||
src = { IconSearch }
|
||||
style = { styles.speakerStatsSearch.searchIcon } />
|
||||
}
|
||||
selectionColor = { theme.palette.text01 } />
|
||||
value = { searchQuery } />
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default withTheme(SpeakerStatsSearch);
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
|
||||
|
||||
export default {
|
||||
|
||||
customContainer: {
|
||||
marginVertical: BaseTheme.spacing[2]
|
||||
},
|
||||
|
||||
speakerStatsContainer: {
|
||||
flexDirection: 'column',
|
||||
flex: 1,
|
||||
|
@ -8,54 +13,43 @@ export default {
|
|||
paddingHorizontal: BaseTheme.spacing[3],
|
||||
backgroundColor: BaseTheme.palette.ui01
|
||||
},
|
||||
|
||||
speakerStatsItemContainer: {
|
||||
flexDirection: 'row',
|
||||
alignSelf: 'stretch',
|
||||
height: BaseTheme.spacing[9],
|
||||
alignItems: 'center'
|
||||
},
|
||||
|
||||
speakerStatsAvatar: {
|
||||
width: BaseTheme.spacing[5],
|
||||
height: BaseTheme.spacing[5],
|
||||
marginRight: BaseTheme.spacing[3]
|
||||
},
|
||||
|
||||
speakerStatsNameTime: {
|
||||
flexDirection: 'row',
|
||||
flex: 1,
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center'
|
||||
},
|
||||
|
||||
speakerStatsText: {
|
||||
...BaseTheme.typography.bodyShortRegularLarge,
|
||||
color: BaseTheme.palette.text01
|
||||
},
|
||||
|
||||
speakerStatsTime: {
|
||||
paddingHorizontal: 4,
|
||||
paddingVertical: 2,
|
||||
borderRadius: 4
|
||||
},
|
||||
|
||||
speakerStatsDominant: {
|
||||
backgroundColor: BaseTheme.palette.success02
|
||||
},
|
||||
|
||||
speakerStatsLeft: {
|
||||
color: BaseTheme.palette.text03
|
||||
},
|
||||
speakerStatsSearch: {
|
||||
wrapper: {
|
||||
marginLeft: 0,
|
||||
marginRight: 0,
|
||||
marginTop: BaseTheme.spacing[3],
|
||||
marginBottom: BaseTheme.spacing[3],
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center'
|
||||
},
|
||||
input: {
|
||||
textAlign: 'left'
|
||||
},
|
||||
searchIcon: {
|
||||
width: 10,
|
||||
height: 20,
|
||||
marginLeft: BaseTheme.spacing[3]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,13 +1,5 @@
|
|||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import {
|
||||
Animated,
|
||||
SafeAreaView,
|
||||
TextInput,
|
||||
TouchableHighlight,
|
||||
View
|
||||
} from 'react-native';
|
||||
import { Animated, SafeAreaView, TouchableHighlight, View } from 'react-native';
|
||||
|
||||
import { getName } from '../../app/functions';
|
||||
import { translate } from '../../base/i18n';
|
||||
|
@ -15,7 +7,8 @@ import { Icon, IconWarning } from '../../base/icons';
|
|||
import JitsiStatusBar from '../../base/modal/components/JitsiStatusBar';
|
||||
import { LoadingIndicator, Text } from '../../base/react';
|
||||
import { connect } from '../../base/redux';
|
||||
import BaseTheme from '../../base/ui/components/BaseTheme';
|
||||
import BaseTheme from '../../base/ui/components/BaseTheme.native';
|
||||
import Input from '../../base/ui/components/native/Input';
|
||||
import WelcomePageTabs
|
||||
from '../../mobile/navigation/components/welcome/components/WelcomePageTabs';
|
||||
|
||||
|
@ -24,7 +17,7 @@ import {
|
|||
AbstractWelcomePage,
|
||||
_mapStateToProps as _abstractMapStateToProps
|
||||
} from './AbstractWelcomePage';
|
||||
import styles, { PLACEHOLDER_TEXT_COLOR } from './styles';
|
||||
import styles from './styles';
|
||||
|
||||
|
||||
type Props = AbstractProps & {
|
||||
|
@ -251,7 +244,7 @@ class WelcomePage extends AbstractWelcomePage<*> {
|
|||
.start();
|
||||
}
|
||||
|
||||
_renderHintBox: () => React$Element<any>;
|
||||
_renderHintBox: () => React.ReactElement;
|
||||
|
||||
/**
|
||||
* Renders the hint box if necessary.
|
||||
|
@ -344,22 +337,19 @@ class WelcomePage extends AbstractWelcomePage<*> {
|
|||
<Text style = { styles.enterRoomText }>
|
||||
{ t('welcomepage.roomname') }
|
||||
</Text>
|
||||
<TextInput
|
||||
<Input
|
||||
accessibilityLabel = { t(roomnameAccLabel) }
|
||||
autoCapitalize = { 'none' }
|
||||
autoComplete = { 'off' }
|
||||
autoCorrect = { false }
|
||||
autoFocus = { false }
|
||||
customStyles = {{ input: styles.customInput }}
|
||||
onBlur = { this._onFieldBlur }
|
||||
onChangeText = { this._onRoomChange }
|
||||
onChange = { this._onRoomChange }
|
||||
onFocus = { this._onFieldFocus }
|
||||
onSubmitEditing = { this._onJoin }
|
||||
placeholder = { this.state.roomPlaceholder }
|
||||
placeholderTextColor = { PLACEHOLDER_TEXT_COLOR }
|
||||
returnKeyType = { 'go' }
|
||||
spellCheck = { false }
|
||||
style = { styles.textInput }
|
||||
underlineColorAndroid = 'transparent'
|
||||
value = { this.state.room } />
|
||||
{
|
||||
this._renderInsecureRoomNameWarning()
|
||||
|
|
|
@ -214,6 +214,12 @@ export default {
|
|||
overflow: 'hidden'
|
||||
},
|
||||
|
||||
customInput: {
|
||||
fontSize: 24,
|
||||
lineHeight: 32,
|
||||
textAlign: 'center'
|
||||
},
|
||||
|
||||
recentList: {
|
||||
backgroundColor: BaseTheme.palette.uiBackground,
|
||||
flex: 1,
|
||||
|
|
Loading…
Reference in New Issue