[NEW] Onboarding layout (#1954)
* Onboarding texts
* OnboardingView
* FormContainer
* Minor fixes
* NewServerView
* Remove code
* Refactor
* WorkspaceView
* Stash
* Login with email working
* Login with
* Join open
* Revert "Login with"
This reverts commit d05dc507d2
.
* Fix create account styles
* Register
* Refactor
* LoginServices component
* Refactor
* Multiple servers
* Remove native images
* Refactor styles
* Fix testid
* Fix add server on tablet
* i18n
* Fix close modal
* Fix TOTP
* [FIX] Registration disabled
* [FIX] Login Services separator
* Fix logos
* Fix AppVersion name
* I18n
* Minor fixes
* [FIX] Custom Fields
Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com>
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 78 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 987 B |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 111 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 73 KiB |
Before Width: | Height: | Size: 177 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 102 KiB |
Before Width: | Height: | Size: 246 KiB |
Before Width: | Height: | Size: 4.5 KiB |
|
@ -1,4 +1,4 @@
|
||||||
export const MAX_SIDEBAR_WIDTH = 321;
|
export const MAX_SIDEBAR_WIDTH = 321;
|
||||||
export const MAX_CONTENT_WIDTH = '90%';
|
export const MAX_CONTENT_WIDTH = '90%';
|
||||||
export const MAX_SCREEN_CONTENT_WIDTH = '45%';
|
export const MAX_SCREEN_CONTENT_WIDTH = '50%';
|
||||||
export const MIN_WIDTH_SPLIT_LAYOUT = 700;
|
export const MIN_WIDTH_SPLIT_LAYOUT = 700;
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { StyleSheet, View, Text } from 'react-native';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import { themes } from '../constants/colors';
|
||||||
|
import sharedStyles from '../views/Styles';
|
||||||
|
import { getReadableVersion } from '../utils/deviceInfo';
|
||||||
|
import I18n from '../i18n';
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'flex-end'
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
...sharedStyles.textRegular,
|
||||||
|
fontSize: 13
|
||||||
|
},
|
||||||
|
bold: {
|
||||||
|
...sharedStyles.textSemibold
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const AppVersion = React.memo(({ theme }) => (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<Text style={[styles.text, { color: themes[theme].auxiliaryText }]}>{I18n.t('Version_no', { version: '' })}<Text style={styles.bold}>{getReadableVersion}</Text></Text>
|
||||||
|
</View>
|
||||||
|
));
|
||||||
|
|
||||||
|
AppVersion.propTypes = {
|
||||||
|
theme: PropTypes.string
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AppVersion;
|
|
@ -9,15 +9,19 @@ import ActivityIndicator from '../ActivityIndicator';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
paddingHorizontal: 15,
|
paddingHorizontal: 14,
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
height: 48,
|
height: 48,
|
||||||
borderRadius: 2,
|
borderRadius: 2,
|
||||||
marginBottom: 10
|
marginBottom: 12
|
||||||
},
|
},
|
||||||
text: {
|
text: {
|
||||||
fontSize: 18,
|
fontSize: 16,
|
||||||
textAlign: 'center'
|
textAlign: 'center',
|
||||||
|
...sharedStyles.textMedium
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
opacity: 0.3
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -30,6 +34,8 @@ export default class Button extends React.PureComponent {
|
||||||
backgroundColor: PropTypes.string,
|
backgroundColor: PropTypes.string,
|
||||||
loading: PropTypes.bool,
|
loading: PropTypes.bool,
|
||||||
theme: PropTypes.string,
|
theme: PropTypes.string,
|
||||||
|
color: PropTypes.string,
|
||||||
|
fontSize: PropTypes.string,
|
||||||
style: PropTypes.any
|
style: PropTypes.any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,9 +49,15 @@ export default class Button extends React.PureComponent {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
title, type, onPress, disabled, backgroundColor, loading, style, theme, ...otherProps
|
title, type, onPress, disabled, backgroundColor, color, loading, style, theme, fontSize, ...otherProps
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const isPrimary = type === 'primary';
|
const isPrimary = type === 'primary';
|
||||||
|
|
||||||
|
let textColor = isPrimary ? themes[theme].buttonText : themes[theme].bodyText;
|
||||||
|
if (color) {
|
||||||
|
textColor = color;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Touchable
|
<Touchable
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
|
@ -55,20 +67,20 @@ export default class Button extends React.PureComponent {
|
||||||
backgroundColor
|
backgroundColor
|
||||||
? { backgroundColor }
|
? { backgroundColor }
|
||||||
: { backgroundColor: isPrimary ? themes[theme].actionTintColor : themes[theme].backgroundColor },
|
: { backgroundColor: isPrimary ? themes[theme].actionTintColor : themes[theme].backgroundColor },
|
||||||
disabled && { backgroundColor: themes[theme].borderColor },
|
disabled && styles.disabled,
|
||||||
style
|
style
|
||||||
]}
|
]}
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
loading
|
loading
|
||||||
? <ActivityIndicator color={isPrimary ? themes[theme].buttonText : themes[theme].actionTintColor} />
|
? <ActivityIndicator color={textColor} />
|
||||||
: (
|
: (
|
||||||
<Text
|
<Text
|
||||||
style={[
|
style={[
|
||||||
styles.text,
|
styles.text,
|
||||||
isPrimary ? sharedStyles.textMedium : sharedStyles.textBold,
|
{ color: textColor },
|
||||||
{ color: isPrimary ? themes[theme].buttonText : themes[theme].actionTintColor }
|
fontSize && { fontSize }
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
{title}
|
{title}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { ScrollView, StyleSheet, View } from 'react-native';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { SafeAreaView } from 'react-navigation';
|
||||||
|
|
||||||
|
import { themes } from '../constants/colors';
|
||||||
|
import sharedStyles from '../views/Styles';
|
||||||
|
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
||||||
|
import KeyboardView from '../presentation/KeyboardView';
|
||||||
|
import StatusBar from './StatusBar';
|
||||||
|
import AppVersion from './AppVersion';
|
||||||
|
import { isTablet } from '../utils/deviceInfo';
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
scrollView: {
|
||||||
|
minHeight: '100%'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export const FormContainerInner = ({ children }) => (
|
||||||
|
<View style={[sharedStyles.container, isTablet && sharedStyles.tabletScreenContent]}>
|
||||||
|
{children}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
|
||||||
|
const FormContainer = ({ children, theme }) => (
|
||||||
|
<KeyboardView
|
||||||
|
style={{ backgroundColor: themes[theme].backgroundColor }}
|
||||||
|
contentContainerStyle={sharedStyles.container}
|
||||||
|
keyboardVerticalOffset={128}
|
||||||
|
>
|
||||||
|
<StatusBar theme={theme} />
|
||||||
|
<ScrollView {...scrollPersistTaps} style={sharedStyles.container} contentContainerStyle={[sharedStyles.containerScrollView, styles.scrollView]}>
|
||||||
|
<SafeAreaView style={sharedStyles.container} forceInset={{ top: 'never' }}>
|
||||||
|
{children}
|
||||||
|
<AppVersion theme={theme} />
|
||||||
|
</SafeAreaView>
|
||||||
|
</ScrollView>
|
||||||
|
</KeyboardView>
|
||||||
|
);
|
||||||
|
|
||||||
|
FormContainer.propTypes = {
|
||||||
|
theme: PropTypes.string,
|
||||||
|
children: PropTypes.element
|
||||||
|
};
|
||||||
|
|
||||||
|
FormContainerInner.propTypes = {
|
||||||
|
children: PropTypes.element
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FormContainer;
|
|
@ -36,9 +36,9 @@ export const DrawerButton = React.memo(({ navigation, testID, ...otherProps }) =
|
||||||
</CustomHeaderButtons>
|
</CustomHeaderButtons>
|
||||||
));
|
));
|
||||||
|
|
||||||
export const CloseModalButton = React.memo(({ navigation, testID }) => (
|
export const CloseModalButton = React.memo(({ navigation, testID, onPress = () => navigation.pop() }) => (
|
||||||
<CustomHeaderButtons left>
|
<CustomHeaderButtons left>
|
||||||
<Item title='close' iconName='cross' onPress={() => navigation.pop()} testID={testID} />
|
<Item title='close' iconName='cross' onPress={onPress} testID={testID} />
|
||||||
</CustomHeaderButtons>
|
</CustomHeaderButtons>
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -76,7 +76,8 @@ DrawerButton.propTypes = {
|
||||||
};
|
};
|
||||||
CloseModalButton.propTypes = {
|
CloseModalButton.propTypes = {
|
||||||
navigation: PropTypes.object.isRequired,
|
navigation: PropTypes.object.isRequired,
|
||||||
testID: PropTypes.string.isRequired
|
testID: PropTypes.string.isRequired,
|
||||||
|
onPress: PropTypes.func
|
||||||
};
|
};
|
||||||
CloseShareExtensionButton.propTypes = {
|
CloseShareExtensionButton.propTypes = {
|
||||||
onPress: PropTypes.func.isRequired,
|
onPress: PropTypes.func.isRequired,
|
||||||
|
|
|
@ -1,42 +1,32 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import {
|
import {
|
||||||
Text, View, ScrollView, Image, StyleSheet, Animated, Easing
|
View, StyleSheet, Text, Animated, Easing, Image
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { Base64 } from 'js-base64';
|
import { Base64 } from 'js-base64';
|
||||||
import { SafeAreaView } from 'react-navigation';
|
import { withNavigation } from 'react-navigation';
|
||||||
import { BorderlessButton } from 'react-native-gesture-handler';
|
|
||||||
import equal from 'deep-equal';
|
|
||||||
|
|
||||||
import Touch from '../utils/touch';
|
|
||||||
import sharedStyles from './Styles';
|
|
||||||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
|
||||||
import random from '../utils/random';
|
|
||||||
import Button from '../containers/Button';
|
|
||||||
import I18n from '../i18n';
|
|
||||||
import { LegalButton } from '../containers/HeaderButton';
|
|
||||||
import StatusBar from '../containers/StatusBar';
|
|
||||||
import { themes } from '../constants/colors';
|
|
||||||
import { withTheme } from '../theme';
|
import { withTheme } from '../theme';
|
||||||
import { themedHeader } from '../utils/navigation';
|
import sharedStyles from '../views/Styles';
|
||||||
import { isTablet } from '../utils/deviceInfo';
|
import { themes } from '../constants/colors';
|
||||||
|
import { loginRequest as loginRequestAction } from '../actions/login';
|
||||||
|
import Button from './Button';
|
||||||
|
import OnboardingSeparator from './OnboardingSeparator';
|
||||||
|
import Touch from '../utils/touch';
|
||||||
|
import I18n from '../i18n';
|
||||||
|
import random from '../utils/random';
|
||||||
|
|
||||||
|
const SERVICE_HEIGHT = 58;
|
||||||
|
const SERVICES_COLLAPSED_HEIGHT = 174;
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
|
||||||
paddingVertical: 30
|
|
||||||
},
|
|
||||||
safeArea: {
|
|
||||||
paddingBottom: 30,
|
|
||||||
flex: 1
|
|
||||||
},
|
|
||||||
serviceButton: {
|
serviceButton: {
|
||||||
borderRadius: 2,
|
borderRadius: 2,
|
||||||
marginBottom: 10
|
marginBottom: 10
|
||||||
},
|
},
|
||||||
serviceButtonContainer: {
|
serviceButtonContainer: {
|
||||||
borderRadius: 2,
|
borderRadius: 2,
|
||||||
borderWidth: 1,
|
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: 48,
|
height: 48,
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
|
@ -56,124 +46,32 @@ const styles = StyleSheet.create({
|
||||||
fontSize: 16
|
fontSize: 16
|
||||||
},
|
},
|
||||||
serviceName: {
|
serviceName: {
|
||||||
...sharedStyles.textBold
|
...sharedStyles.textSemibold
|
||||||
},
|
},
|
||||||
registerDisabled: {
|
options: {
|
||||||
...sharedStyles.textRegular,
|
marginBottom: 0
|
||||||
...sharedStyles.textAlignCenter,
|
|
||||||
fontSize: 16
|
|
||||||
},
|
|
||||||
servicesTogglerContainer: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
marginTop: 5,
|
|
||||||
marginBottom: 30
|
|
||||||
},
|
|
||||||
servicesToggler: {
|
|
||||||
width: 32,
|
|
||||||
height: 31
|
|
||||||
},
|
|
||||||
separatorContainer: {
|
|
||||||
marginTop: 5,
|
|
||||||
marginBottom: 15
|
|
||||||
},
|
|
||||||
separatorLine: {
|
|
||||||
flex: 1,
|
|
||||||
height: 1
|
|
||||||
},
|
|
||||||
separatorLineLeft: {
|
|
||||||
marginRight: 15
|
|
||||||
},
|
|
||||||
separatorLineRight: {
|
|
||||||
marginLeft: 15
|
|
||||||
},
|
|
||||||
inverted: {
|
|
||||||
transform: [{ scaleY: -1 }]
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const SERVICE_HEIGHT = 58;
|
class LoginServices extends React.PureComponent {
|
||||||
const SERVICES_COLLAPSED_HEIGHT = 174;
|
|
||||||
|
|
||||||
class LoginSignupView extends React.Component {
|
|
||||||
static navigationOptions = ({ navigation, screenProps }) => {
|
|
||||||
const title = navigation.getParam('title', 'Rocket.Chat');
|
|
||||||
return {
|
|
||||||
...themedHeader(screenProps.theme),
|
|
||||||
title,
|
|
||||||
headerRight: <LegalButton testID='welcome-view-more' navigation={navigation} />
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
navigation: PropTypes.object,
|
navigation: PropTypes.object,
|
||||||
server: PropTypes.string,
|
server: PropTypes.string,
|
||||||
services: PropTypes.object,
|
services: PropTypes.object,
|
||||||
Site_Name: PropTypes.string,
|
|
||||||
Gitlab_URL: PropTypes.string,
|
Gitlab_URL: PropTypes.string,
|
||||||
CAS_enabled: PropTypes.bool,
|
CAS_enabled: PropTypes.bool,
|
||||||
CAS_login_url: PropTypes.string,
|
CAS_login_url: PropTypes.string,
|
||||||
Accounts_ShowFormLogin: PropTypes.bool,
|
separator: PropTypes.bool,
|
||||||
Accounts_RegistrationForm: PropTypes.string,
|
|
||||||
Accounts_RegistrationForm_LinkReplacementText: PropTypes.string,
|
|
||||||
theme: PropTypes.string
|
theme: PropTypes.string
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props) {
|
static defaultProps = {
|
||||||
super(props);
|
separator: true
|
||||||
this.state = {
|
|
||||||
collapsed: true,
|
|
||||||
servicesHeight: new Animated.Value(SERVICES_COLLAPSED_HEIGHT)
|
|
||||||
};
|
|
||||||
const { Site_Name } = this.props;
|
|
||||||
this.setTitle(Site_Name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
state = {
|
||||||
const { collapsed, servicesHeight } = this.state;
|
collapsed: true,
|
||||||
const {
|
servicesHeight: new Animated.Value(SERVICES_COLLAPSED_HEIGHT)
|
||||||
server, Site_Name, services, Accounts_ShowFormLogin, Accounts_RegistrationForm, Accounts_RegistrationForm_LinkReplacementText, theme
|
|
||||||
} = this.props;
|
|
||||||
if (nextState.collapsed !== collapsed) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (nextState.servicesHeight !== servicesHeight) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (nextProps.server !== server) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (nextProps.Site_Name !== Site_Name) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (nextProps.theme !== theme) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (nextProps.Accounts_ShowFormLogin !== Accounts_ShowFormLogin) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (nextProps.Accounts_RegistrationForm !== Accounts_RegistrationForm) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (nextProps.Accounts_RegistrationForm_LinkReplacementText !== Accounts_RegistrationForm_LinkReplacementText) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!equal(nextProps.services, services)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
|
||||||
const { Site_Name } = this.props;
|
|
||||||
if (Site_Name && prevProps.Site_Name !== Site_Name) {
|
|
||||||
this.setTitle(Site_Name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setTitle = (title) => {
|
|
||||||
const { navigation } = this.props;
|
|
||||||
navigation.setParams({ title });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onPressFacebook = () => {
|
onPressFacebook = () => {
|
||||||
|
@ -300,16 +198,6 @@ class LoginSignupView extends React.Component {
|
||||||
navigation.navigate('AuthenticationWebView', { url, authType, ssoToken });
|
navigation.navigate('AuthenticationWebView', { url, authType, ssoToken });
|
||||||
}
|
}
|
||||||
|
|
||||||
login = () => {
|
|
||||||
const { navigation, Site_Name } = this.props;
|
|
||||||
navigation.navigate('LoginView', { title: Site_Name });
|
|
||||||
}
|
|
||||||
|
|
||||||
register = () => {
|
|
||||||
const { navigation, Site_Name } = this.props;
|
|
||||||
navigation.navigate('RegisterView', { title: Site_Name });
|
|
||||||
}
|
|
||||||
|
|
||||||
transitionServicesTo = (height) => {
|
transitionServicesTo = (height) => {
|
||||||
const { servicesHeight } = this.state;
|
const { servicesHeight } = this.state;
|
||||||
if (this._animation) {
|
if (this._animation) {
|
||||||
|
@ -350,27 +238,28 @@ class LoginSignupView extends React.Component {
|
||||||
|
|
||||||
renderServicesSeparator = () => {
|
renderServicesSeparator = () => {
|
||||||
const { collapsed } = this.state;
|
const { collapsed } = this.state;
|
||||||
const {
|
const { services, separator, theme } = this.props;
|
||||||
services, theme, Accounts_ShowFormLogin, Accounts_RegistrationForm
|
|
||||||
} = this.props;
|
|
||||||
const { length } = Object.values(services);
|
const { length } = Object.values(services);
|
||||||
|
|
||||||
if (length > 3 && Accounts_ShowFormLogin && Accounts_RegistrationForm) {
|
if (length > 3 && separator) {
|
||||||
return (
|
return (
|
||||||
<View style={styles.servicesTogglerContainer}>
|
<>
|
||||||
<View style={[styles.separatorLine, styles.separatorLineLeft, { backgroundColor: themes[theme].auxiliaryText }]} />
|
<Button
|
||||||
<BorderlessButton onPress={this.toggleServices}>
|
title={collapsed ? I18n.t('Onboarding_more_options') : I18n.t('Onboarding_less_options')}
|
||||||
<Image source={{ uri: 'options' }} style={[styles.servicesToggler, !collapsed && styles.inverted]} />
|
type='secondary'
|
||||||
</BorderlessButton>
|
onPress={this.toggleServices}
|
||||||
<View style={[styles.separatorLine, styles.separatorLineRight, { backgroundColor: themes[theme].auxiliaryText }]} />
|
theme={theme}
|
||||||
</View>
|
style={styles.options}
|
||||||
|
color={themes[theme].actionTintColor}
|
||||||
|
/>
|
||||||
|
<OnboardingSeparator theme={theme} />
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
if (length > 0 && separator) {
|
||||||
<View style={styles.separatorContainer}>
|
return <OnboardingSeparator theme={theme} />;
|
||||||
<View style={styles.separatorLine} />
|
}
|
||||||
</View>
|
return null;
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderItem = (service) => {
|
renderItem = (service) => {
|
||||||
|
@ -412,14 +301,19 @@ class LoginSignupView extends React.Component {
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const backgroundColor = isSaml && service.buttonColor ? service.buttonColor : themes[theme].chatComponentBackground;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Touch
|
<Touch
|
||||||
key={service.name}
|
key={service.name}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
style={[styles.serviceButton, isSaml && { backgroundColor: service.buttonColor }]}
|
style={[styles.serviceButton, { backgroundColor }]}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
|
activeOpacity={0.5}
|
||||||
|
underlayColor={themes[theme].buttonText}
|
||||||
>
|
>
|
||||||
<View style={[styles.serviceButtonContainer, { borderColor: themes[theme].borderColor }]}>
|
<View style={styles.serviceButtonContainer}>
|
||||||
{service.authType === 'oauth' ? <Image source={{ uri: icon }} style={styles.serviceIcon} /> : null}
|
{service.authType === 'oauth' ? <Image source={{ uri: icon }} style={styles.serviceIcon} /> : null}
|
||||||
<Text style={[styles.serviceText, { color: themes[theme].titleText }]}>{buttonText}</Text>
|
<Text style={[styles.serviceText, { color: themes[theme].titleText }]}>{buttonText}</Text>
|
||||||
</View>
|
</View>
|
||||||
|
@ -427,100 +321,44 @@ class LoginSignupView extends React.Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderServices = () => {
|
render() {
|
||||||
const { servicesHeight } = this.state;
|
const { servicesHeight } = this.state;
|
||||||
const { services, Accounts_ShowFormLogin, Accounts_RegistrationForm } = this.props;
|
const { services, separator } = this.props;
|
||||||
const { length } = Object.values(services);
|
const { length } = Object.values(services);
|
||||||
const style = {
|
const style = {
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
height: servicesHeight
|
height: servicesHeight
|
||||||
};
|
};
|
||||||
|
|
||||||
if (length > 3 && Accounts_ShowFormLogin && Accounts_RegistrationForm) {
|
if (length > 3 && separator) {
|
||||||
return (
|
return (
|
||||||
<Animated.View style={style}>
|
<>
|
||||||
{Object.values(services).map(service => this.renderItem(service))}
|
<Animated.View style={style}>
|
||||||
</Animated.View>
|
{Object.values(services).map(service => this.renderItem(service))}
|
||||||
|
</Animated.View>
|
||||||
|
{this.renderServicesSeparator()}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<View>
|
<>
|
||||||
{Object.values(services).map(service => this.renderItem(service))}
|
{Object.values(services).map(service => this.renderItem(service))}
|
||||||
</View>
|
{this.renderServicesSeparator()}
|
||||||
);
|
</>
|
||||||
}
|
|
||||||
|
|
||||||
renderLogin = () => {
|
|
||||||
const { Accounts_ShowFormLogin, theme } = this.props;
|
|
||||||
if (!Accounts_ShowFormLogin) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
title={<Text>{I18n.t('Login_with')} <Text style={{ ...sharedStyles.textBold }}>{I18n.t('email')}</Text></Text>}
|
|
||||||
type='primary'
|
|
||||||
onPress={() => this.login()}
|
|
||||||
theme={theme}
|
|
||||||
testID='welcome-view-login'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderRegister = () => {
|
|
||||||
const { Accounts_RegistrationForm, Accounts_RegistrationForm_LinkReplacementText, theme } = this.props;
|
|
||||||
if (Accounts_RegistrationForm !== 'Public') {
|
|
||||||
return <Text style={[styles.registerDisabled, { color: themes[theme].auxiliaryText }]}>{Accounts_RegistrationForm_LinkReplacementText}</Text>;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
title={I18n.t('Create_account')}
|
|
||||||
type='secondary'
|
|
||||||
onPress={() => this.register()}
|
|
||||||
theme={theme}
|
|
||||||
testID='welcome-view-register'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { theme } = this.props;
|
|
||||||
return (
|
|
||||||
<SafeAreaView
|
|
||||||
testID='welcome-view'
|
|
||||||
forceInset={{ vertical: 'never' }}
|
|
||||||
style={[styles.safeArea, { backgroundColor: themes[theme].backgroundColor }]}
|
|
||||||
>
|
|
||||||
<ScrollView
|
|
||||||
style={[
|
|
||||||
sharedStyles.containerScrollView,
|
|
||||||
sharedStyles.container,
|
|
||||||
styles.container,
|
|
||||||
{ backgroundColor: themes[theme].backgroundColor },
|
|
||||||
isTablet && sharedStyles.tabletScreenContent
|
|
||||||
]}
|
|
||||||
{...scrollPersistTaps}
|
|
||||||
>
|
|
||||||
<StatusBar theme={theme} />
|
|
||||||
{this.renderServices()}
|
|
||||||
{this.renderServicesSeparator()}
|
|
||||||
{this.renderLogin()}
|
|
||||||
{this.renderRegister()}
|
|
||||||
</ScrollView>
|
|
||||||
</SafeAreaView>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
server: state.server.server,
|
server: state.server.server,
|
||||||
Site_Name: state.settings.Site_Name,
|
|
||||||
Gitlab_URL: state.settings.API_Gitlab_URL,
|
Gitlab_URL: state.settings.API_Gitlab_URL,
|
||||||
CAS_enabled: state.settings.CAS_enabled,
|
CAS_enabled: state.settings.CAS_enabled,
|
||||||
CAS_login_url: state.settings.CAS_login_url,
|
CAS_login_url: state.settings.CAS_login_url,
|
||||||
Accounts_ShowFormLogin: state.settings.Accounts_ShowFormLogin,
|
|
||||||
Accounts_RegistrationForm: state.settings.Accounts_RegistrationForm,
|
|
||||||
Accounts_RegistrationForm_LinkReplacementText: state.settings.Accounts_RegistrationForm_LinkReplacementText,
|
|
||||||
services: state.login.services
|
services: state.login.services
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps)(withTheme(LoginSignupView));
|
const mapDispatchToProps = dispatch => ({
|
||||||
|
loginRequest: params => dispatch(loginRequestAction(params))
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(withNavigation(LoginServices)));
|
|
@ -0,0 +1,43 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { View, StyleSheet, Text } from 'react-native';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import I18n from '../i18n';
|
||||||
|
import sharedStyles from '../views/Styles';
|
||||||
|
import { themes } from '../constants/colors';
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginVertical: 24
|
||||||
|
},
|
||||||
|
line: {
|
||||||
|
height: 1,
|
||||||
|
flex: 1
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
fontSize: 14,
|
||||||
|
marginLeft: 14,
|
||||||
|
marginRight: 14,
|
||||||
|
...sharedStyles.textMedium
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const DateSeparator = React.memo(({ theme }) => {
|
||||||
|
const line = { backgroundColor: themes[theme].borderColor };
|
||||||
|
const text = { color: themes[theme].auxiliaryText };
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<View style={[styles.line, line]} />
|
||||||
|
<Text style={[styles.text, styles.marginRight, styles.marginLeft, text]}>{I18n.t('OR')}</Text>
|
||||||
|
<View style={[styles.line, line]} />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
DateSeparator.propTypes = {
|
||||||
|
theme: PropTypes.string
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DateSeparator;
|
|
@ -139,7 +139,6 @@ export default {
|
||||||
Collaborative: 'Kollaborativ',
|
Collaborative: 'Kollaborativ',
|
||||||
Confirm: 'Bestätigen',
|
Confirm: 'Bestätigen',
|
||||||
Connect: 'Verbinden',
|
Connect: 'Verbinden',
|
||||||
Connect_to_a_server: 'Verbinden Sie sich mit einem Server',
|
|
||||||
Connected: 'Verbunden',
|
Connected: 'Verbunden',
|
||||||
connecting_server: 'verbinde zum Server',
|
connecting_server: 'verbinde zum Server',
|
||||||
Connecting: 'Verbinden ...',
|
Connecting: 'Verbinden ...',
|
||||||
|
@ -198,7 +197,6 @@ export default {
|
||||||
Finish_recording: 'Beenden Sie die Aufnahme',
|
Finish_recording: 'Beenden Sie die Aufnahme',
|
||||||
Following_thread: 'Thread folgen',
|
Following_thread: 'Thread folgen',
|
||||||
For_your_security_you_must_enter_your_current_password_to_continue: 'Zu Ihrer Sicherheit müssen Sie Ihr aktuelles Passwort eingeben, um fortzufahren',
|
For_your_security_you_must_enter_your_current_password_to_continue: 'Zu Ihrer Sicherheit müssen Sie Ihr aktuelles Passwort eingeben, um fortzufahren',
|
||||||
Forgot_my_password: 'Ich habe mein Passwort vergessen',
|
|
||||||
Forgot_password_If_this_email_is_registered: 'Wenn diese E-Mail registriert ist, senden wir Anweisungen zum Zurücksetzen Ihres Passworts. Wenn Sie in Kürze keine E-Mail erhalten, kommen Sie bitte zurück und versuchen Sie es erneut.',
|
Forgot_password_If_this_email_is_registered: 'Wenn diese E-Mail registriert ist, senden wir Anweisungen zum Zurücksetzen Ihres Passworts. Wenn Sie in Kürze keine E-Mail erhalten, kommen Sie bitte zurück und versuchen Sie es erneut.',
|
||||||
Forgot_password: 'Passwort vergessen',
|
Forgot_password: 'Passwort vergessen',
|
||||||
Forgot_Password: 'Passwort vergessen',
|
Forgot_Password: 'Passwort vergessen',
|
||||||
|
@ -237,7 +235,6 @@ export default {
|
||||||
Invalid_server_version: 'Der Server, zu dem Sie eine Verbindung herstellen möchten, verwendet eine Version, die von der App nicht mehr unterstützt wird: {{currentVersion}}.\n\nWir benötigen Version {{MinVersion}}.',
|
Invalid_server_version: 'Der Server, zu dem Sie eine Verbindung herstellen möchten, verwendet eine Version, die von der App nicht mehr unterstützt wird: {{currentVersion}}.\n\nWir benötigen Version {{MinVersion}}.',
|
||||||
Invite_Link: 'Einladungs-Link',
|
Invite_Link: 'Einladungs-Link',
|
||||||
Invite_users: 'Benutzer einladen',
|
Invite_users: 'Benutzer einladen',
|
||||||
Join_the_community: 'Trete der Community bei',
|
|
||||||
Join: 'Beitreten',
|
Join: 'Beitreten',
|
||||||
Just_invited_people_can_access_this_channel: 'Nur eingeladene Personen können auf diesen Kanal zugreifen',
|
Just_invited_people_can_access_this_channel: 'Nur eingeladene Personen können auf diesen Kanal zugreifen',
|
||||||
Language: 'Sprache',
|
Language: 'Sprache',
|
||||||
|
@ -308,6 +305,7 @@ export default {
|
||||||
Notification_Preferences: 'Benachrichtigungseinstellungen',
|
Notification_Preferences: 'Benachrichtigungseinstellungen',
|
||||||
Offline: 'Offline',
|
Offline: 'Offline',
|
||||||
Oops: 'Hoppla!',
|
Oops: 'Hoppla!',
|
||||||
|
Onboarding_title: 'Willkommen bei Rocket.Chat',
|
||||||
Online: 'Online',
|
Online: 'Online',
|
||||||
Only_authorized_users_can_write_new_messages: 'Nur autorisierte Benutzer können neue Nachrichten schreiben',
|
Only_authorized_users_can_write_new_messages: 'Nur autorisierte Benutzer können neue Nachrichten schreiben',
|
||||||
Open_emoji_selector: 'Öffne die Emoji-Auswahl',
|
Open_emoji_selector: 'Öffne die Emoji-Auswahl',
|
||||||
|
@ -481,7 +479,6 @@ export default {
|
||||||
Voice_call: 'Sprachanruf',
|
Voice_call: 'Sprachanruf',
|
||||||
Websocket_disabled: 'Websockets sind auf diesem Server nicht aktiviert.\n{{contact}}',
|
Websocket_disabled: 'Websockets sind auf diesem Server nicht aktiviert.\n{{contact}}',
|
||||||
Welcome: 'Herzlich willkommen',
|
Welcome: 'Herzlich willkommen',
|
||||||
Welcome_to_RocketChat: 'Willkommen bei Rocket.Chat',
|
|
||||||
Whats_your_2fa: 'Wie lautet Ihr 2FA-Code?',
|
Whats_your_2fa: 'Wie lautet Ihr 2FA-Code?',
|
||||||
Without_Servers: 'Ohne Server',
|
Without_Servers: 'Ohne Server',
|
||||||
Write_External_Permission_Message: 'Rocket.Chat benötigt Zugriff auf Ihre Galerie um Bilder speichern zu können.',
|
Write_External_Permission_Message: 'Rocket.Chat benötigt Zugriff auf Ihre Galerie um Bilder speichern zu können.',
|
||||||
|
|
|
@ -139,7 +139,6 @@ export default {
|
||||||
Collaborative: 'Collaborative',
|
Collaborative: 'Collaborative',
|
||||||
Confirm: 'Confirm',
|
Confirm: 'Confirm',
|
||||||
Connect: 'Connect',
|
Connect: 'Connect',
|
||||||
Connect_to_a_server: 'Connect to a server',
|
|
||||||
Connected: 'Connected',
|
Connected: 'Connected',
|
||||||
connecting_server: 'connecting to server',
|
connecting_server: 'connecting to server',
|
||||||
Connecting: 'Connecting...',
|
Connecting: 'Connecting...',
|
||||||
|
@ -174,7 +173,8 @@ export default {
|
||||||
Direct_Messages: 'Direct Messages',
|
Direct_Messages: 'Direct Messages',
|
||||||
Disable_notifications: 'Disable notifications',
|
Disable_notifications: 'Disable notifications',
|
||||||
Discussions: 'Discussions',
|
Discussions: 'Discussions',
|
||||||
Dont_Have_An_Account: 'Don\'t have an account?',
|
Dont_Have_An_Account: 'Don\'t you have an account?',
|
||||||
|
Do_you_have_an_account: 'Do you have an account?',
|
||||||
Do_you_have_a_certificate: 'Do you have a certificate?',
|
Do_you_have_a_certificate: 'Do you have a certificate?',
|
||||||
Do_you_really_want_to_key_this_room_question_mark: 'Do you really want to {{key}} this room?',
|
Do_you_really_want_to_key_this_room_question_mark: 'Do you really want to {{key}} this room?',
|
||||||
edit: 'edit',
|
edit: 'edit',
|
||||||
|
@ -198,9 +198,8 @@ export default {
|
||||||
Finish_recording: 'Finish recording',
|
Finish_recording: 'Finish recording',
|
||||||
Following_thread: 'Following thread',
|
Following_thread: 'Following thread',
|
||||||
For_your_security_you_must_enter_your_current_password_to_continue: 'For your security, you must enter your current password to continue',
|
For_your_security_you_must_enter_your_current_password_to_continue: 'For your security, you must enter your current password to continue',
|
||||||
Forgot_my_password: 'Forgot my password',
|
|
||||||
Forgot_password_If_this_email_is_registered: 'If this email is registered, we\'ll send instructions on how to reset your password. If you do not receive an email shortly, please come back and try again.',
|
Forgot_password_If_this_email_is_registered: 'If this email is registered, we\'ll send instructions on how to reset your password. If you do not receive an email shortly, please come back and try again.',
|
||||||
Forgot_password: 'Forgot password',
|
Forgot_password: 'Forgot your password?',
|
||||||
Forgot_Password: 'Forgot Password',
|
Forgot_Password: 'Forgot Password',
|
||||||
Full_table: 'Click to see full table',
|
Full_table: 'Click to see full table',
|
||||||
Generate_New_Link: 'Generate New Link',
|
Generate_New_Link: 'Generate New Link',
|
||||||
|
@ -237,8 +236,9 @@ export default {
|
||||||
Invalid_server_version: 'The server you\'re trying to connect is using a version that\'s not supported by the app anymore: {{currentVersion}}.\n\nWe require version {{minVersion}}',
|
Invalid_server_version: 'The server you\'re trying to connect is using a version that\'s not supported by the app anymore: {{currentVersion}}.\n\nWe require version {{minVersion}}',
|
||||||
Invite_Link: 'Invite Link',
|
Invite_Link: 'Invite Link',
|
||||||
Invite_users: 'Invite users',
|
Invite_users: 'Invite users',
|
||||||
Join_the_community: 'Join the community',
|
|
||||||
Join: 'Join',
|
Join: 'Join',
|
||||||
|
Join_our_open_workspace: 'Join our open workspace',
|
||||||
|
Join_your_workspace: 'Join your workspace',
|
||||||
Just_invited_people_can_access_this_channel: 'Just invited people can access this channel',
|
Just_invited_people_can_access_this_channel: 'Just invited people can access this channel',
|
||||||
Language: 'Language',
|
Language: 'Language',
|
||||||
last_message: 'last message',
|
last_message: 'last message',
|
||||||
|
@ -308,10 +308,19 @@ export default {
|
||||||
Notification_Preferences: 'Notification Preferences',
|
Notification_Preferences: 'Notification Preferences',
|
||||||
Offline: 'Offline',
|
Offline: 'Offline',
|
||||||
Oops: 'Oops!',
|
Oops: 'Oops!',
|
||||||
|
Onboarding_description: 'A workspace is your team or organization’s space to collaborate. Ask the workspace admin for address to join or create one for your team.',
|
||||||
|
Onboarding_join_workspace: 'Join a workspace',
|
||||||
|
Onboarding_subtitle: 'Beyond Team Collaboration',
|
||||||
|
Onboarding_title: 'Welcome to Rocket.Chat',
|
||||||
|
Onboarding_join_open_description: 'Join our open workspace to chat with the Rocket.Chat team and community.',
|
||||||
|
Onboarding_agree_terms: 'By continuing, you agree to Rocket.Chat',
|
||||||
|
Onboarding_less_options: 'Less options',
|
||||||
|
Onboarding_more_options: 'More options',
|
||||||
Online: 'Online',
|
Online: 'Online',
|
||||||
Only_authorized_users_can_write_new_messages: 'Only authorized users can write new messages',
|
Only_authorized_users_can_write_new_messages: 'Only authorized users can write new messages',
|
||||||
Open_emoji_selector: 'Open emoji selector',
|
Open_emoji_selector: 'Open emoji selector',
|
||||||
Open_Source_Communication: 'Open Source Communication',
|
Open_Source_Communication: 'Open Source Communication',
|
||||||
|
OR: 'OR',
|
||||||
Overwrites_the_server_configuration_and_use_room_config: 'Overwrites the server configuration and use room config',
|
Overwrites_the_server_configuration_and_use_room_config: 'Overwrites the server configuration and use room config',
|
||||||
Password: 'Password',
|
Password: 'Password',
|
||||||
Permalink_copied_to_clipboard: 'Permalink copied to clipboard!',
|
Permalink_copied_to_clipboard: 'Permalink copied to clipboard!',
|
||||||
|
@ -481,9 +490,9 @@ export default {
|
||||||
Voice_call: 'Voice call',
|
Voice_call: 'Voice call',
|
||||||
Websocket_disabled: 'Websocket is disabled for this server.\n{{contact}}',
|
Websocket_disabled: 'Websocket is disabled for this server.\n{{contact}}',
|
||||||
Welcome: 'Welcome',
|
Welcome: 'Welcome',
|
||||||
Welcome_to_RocketChat: 'Welcome to Rocket.Chat',
|
|
||||||
Whats_your_2fa: 'What\'s your 2FA code?',
|
Whats_your_2fa: 'What\'s your 2FA code?',
|
||||||
Without_Servers: 'Without Servers',
|
Without_Servers: 'Without Servers',
|
||||||
|
Workspaces: 'Workspaces',
|
||||||
Write_External_Permission_Message: 'Rocket Chat needs access to your gallery so you can save images.',
|
Write_External_Permission_Message: 'Rocket Chat needs access to your gallery so you can save images.',
|
||||||
Write_External_Permission: 'Gallery Permission',
|
Write_External_Permission: 'Gallery Permission',
|
||||||
Yes_action_it: 'Yes, {{action}} it!',
|
Yes_action_it: 'Yes, {{action}} it!',
|
||||||
|
@ -503,6 +512,7 @@ export default {
|
||||||
Your_invite_link_will_expire_on__date__or_after__usesLeft__uses: 'Your invite link will expire on {{date}} or after {{usesLeft}} uses.',
|
Your_invite_link_will_expire_on__date__or_after__usesLeft__uses: 'Your invite link will expire on {{date}} or after {{usesLeft}} uses.',
|
||||||
Your_invite_link_will_expire_on__date__: 'Your invite link will expire on {{date}}.',
|
Your_invite_link_will_expire_on__date__: 'Your invite link will expire on {{date}}.',
|
||||||
Your_invite_link_will_never_expire: 'Your invite link will never expire.',
|
Your_invite_link_will_never_expire: 'Your invite link will never expire.',
|
||||||
|
Your_workspace: 'Your workspace',
|
||||||
Version_no: 'Version: {{version}}',
|
Version_no: 'Version: {{version}}',
|
||||||
You_will_not_be_able_to_recover_this_message: 'You will not be able to recover this message!',
|
You_will_not_be_able_to_recover_this_message: 'You will not be able to recover this message!',
|
||||||
Change_Language: 'Change Language',
|
Change_Language: 'Change Language',
|
||||||
|
|
|
@ -134,7 +134,6 @@ export default {
|
||||||
Collaborative: 'Colaborativo',
|
Collaborative: 'Colaborativo',
|
||||||
Confirm: 'Confirmar',
|
Confirm: 'Confirmar',
|
||||||
Connect: 'Conectar',
|
Connect: 'Conectar',
|
||||||
Connect_to_a_server: 'Conectar a servidor',
|
|
||||||
Connected: 'Conectado',
|
Connected: 'Conectado',
|
||||||
connecting_server: 'conectando a servidor',
|
connecting_server: 'conectando a servidor',
|
||||||
Connecting: 'Conectando...',
|
Connecting: 'Conectando...',
|
||||||
|
@ -188,7 +187,6 @@ export default {
|
||||||
Finish_recording: 'Finalizar grabación',
|
Finish_recording: 'Finalizar grabación',
|
||||||
Following_thread: 'Siguiendo hilo',
|
Following_thread: 'Siguiendo hilo',
|
||||||
For_your_security_you_must_enter_your_current_password_to_continue: 'Por seguridad, debes introducir tu contraseña para continuar',
|
For_your_security_you_must_enter_your_current_password_to_continue: 'Por seguridad, debes introducir tu contraseña para continuar',
|
||||||
Forgot_my_password: 'He olvidado mi contraseña',
|
|
||||||
Forgot_password_If_this_email_is_registered: 'Si este email está registrado, te enviaremos las instrucciones para resetear tu contraseña.Si no recibes un email en un rato, vuelve aquí e inténtalo de nuevo.',
|
Forgot_password_If_this_email_is_registered: 'Si este email está registrado, te enviaremos las instrucciones para resetear tu contraseña.Si no recibes un email en un rato, vuelve aquí e inténtalo de nuevo.',
|
||||||
Forgot_password: 'Restablecer mi contraseña',
|
Forgot_password: 'Restablecer mi contraseña',
|
||||||
Forgot_Password: 'Restabler mi Contraseña',
|
Forgot_Password: 'Restabler mi Contraseña',
|
||||||
|
@ -207,7 +205,6 @@ export default {
|
||||||
is_not_a_valid_RocketChat_instance: 'no es una instancia válida Rocket.Chat',
|
is_not_a_valid_RocketChat_instance: 'no es una instancia válida Rocket.Chat',
|
||||||
is_typing: 'escribiendo',
|
is_typing: 'escribiendo',
|
||||||
Invalid_server_version: 'El servidor que intentas conectar está usando una versión que ya no es soportada por la aplicación : {{currentVersion}}. Requerimos una versión {{minVersion}}.',
|
Invalid_server_version: 'El servidor que intentas conectar está usando una versión que ya no es soportada por la aplicación : {{currentVersion}}. Requerimos una versión {{minVersion}}.',
|
||||||
Join_the_community: 'Conectar con la comunidad',
|
|
||||||
Join: 'Conectar',
|
Join: 'Conectar',
|
||||||
Just_invited_people_can_access_this_channel: 'Sólo gente invitada puede acceder a este canal.',
|
Just_invited_people_can_access_this_channel: 'Sólo gente invitada puede acceder a este canal.',
|
||||||
Language: 'Idioma',
|
Language: 'Idioma',
|
||||||
|
@ -270,6 +267,7 @@ export default {
|
||||||
Notification_Preferences: 'Configuración de notificaciones',
|
Notification_Preferences: 'Configuración de notificaciones',
|
||||||
Offline: 'Sin conexión',
|
Offline: 'Sin conexión',
|
||||||
Oops: 'Oops!',
|
Oops: 'Oops!',
|
||||||
|
Onboarding_title: 'Bienvenido a Rocket.Chat',
|
||||||
Online: 'Conectado',
|
Online: 'Conectado',
|
||||||
Only_authorized_users_can_write_new_messages: 'Sólo pueden escribir mensajes usuarios autorizados',
|
Only_authorized_users_can_write_new_messages: 'Sólo pueden escribir mensajes usuarios autorizados',
|
||||||
Open_emoji_selector: 'Abrir selector de emojis',
|
Open_emoji_selector: 'Abrir selector de emojis',
|
||||||
|
@ -427,7 +425,6 @@ export default {
|
||||||
Voice_call: 'Llamada de voz',
|
Voice_call: 'Llamada de voz',
|
||||||
Websocket_disabled: 'Websocket está deshabilitado para este servidor.\n{{contact}}',
|
Websocket_disabled: 'Websocket está deshabilitado para este servidor.\n{{contact}}',
|
||||||
Welcome: 'Bienvenido',
|
Welcome: 'Bienvenido',
|
||||||
Welcome_to_RocketChat: 'Bienvenido a Rocket.Chat',
|
|
||||||
Whats_your_2fa: '¿Cuál es tu código 2FA?',
|
Whats_your_2fa: '¿Cuál es tu código 2FA?',
|
||||||
Without_Servers: 'Sin servidores',
|
Without_Servers: 'Sin servidores',
|
||||||
Yes_action_it: 'Sí, {{action}}!',
|
Yes_action_it: 'Sí, {{action}}!',
|
||||||
|
|
|
@ -122,7 +122,6 @@ export default {
|
||||||
Collaborative: 'Collaborative',
|
Collaborative: 'Collaborative',
|
||||||
Confirm: 'Confirmer',
|
Confirm: 'Confirmer',
|
||||||
Connect: 'Se connecter',
|
Connect: 'Se connecter',
|
||||||
Connect_to_a_server: 'Se connecter à un serveur',
|
|
||||||
Connected: 'Connecté',
|
Connected: 'Connecté',
|
||||||
Connecting: 'Connexion ...',
|
Connecting: 'Connexion ...',
|
||||||
Continue_with: 'Continuer avec',
|
Continue_with: 'Continuer avec',
|
||||||
|
@ -159,7 +158,6 @@ export default {
|
||||||
File_name: 'Nom de fichier',
|
File_name: 'Nom de fichier',
|
||||||
Finish_recording: 'Terminer l\'enregistrement',
|
Finish_recording: 'Terminer l\'enregistrement',
|
||||||
For_your_security_you_must_enter_your_current_password_to_continue: 'Pour votre sécurité, vous devez entrer votre mot de passe actuel pour continuer.',
|
For_your_security_you_must_enter_your_current_password_to_continue: 'Pour votre sécurité, vous devez entrer votre mot de passe actuel pour continuer.',
|
||||||
Forgot_my_password: 'J\'ai oublié mon mot de passe',
|
|
||||||
Forgot_password_If_this_email_is_registered: 'Si cet e-mail est enregistré, nous vous enverrons des instructions pour réinitialiser votre mot de passe. Si vous ne recevez pas d\'e-mail sous peu, veuillez revenir et réessayer.',
|
Forgot_password_If_this_email_is_registered: 'Si cet e-mail est enregistré, nous vous enverrons des instructions pour réinitialiser votre mot de passe. Si vous ne recevez pas d\'e-mail sous peu, veuillez revenir et réessayer.',
|
||||||
Forgot_password: 'Mot de passe oublié',
|
Forgot_password: 'Mot de passe oublié',
|
||||||
Forgot_Password: 'Mot de passe oublié',
|
Forgot_Password: 'Mot de passe oublié',
|
||||||
|
@ -173,7 +171,6 @@ export default {
|
||||||
is_not_a_valid_RocketChat_instance: 'n\'est pas une instance valide de Rocket.Chat',
|
is_not_a_valid_RocketChat_instance: 'n\'est pas une instance valide de Rocket.Chat',
|
||||||
is_typing: 'est en train d\'écrire',
|
is_typing: 'est en train d\'écrire',
|
||||||
Invalid_server_version: 'Le serveur que vous essayez de connecter utilise une version qui n\'est plus prise en charge par l\'application: {{currentVersion}}.\n\nNous exigeons la version {{minVersion}}',
|
Invalid_server_version: 'Le serveur que vous essayez de connecter utilise une version qui n\'est plus prise en charge par l\'application: {{currentVersion}}.\n\nNous exigeons la version {{minVersion}}',
|
||||||
Join_the_community: 'Rejoindre la communauté',
|
|
||||||
Join: 'Rejoindre',
|
Join: 'Rejoindre',
|
||||||
Just_invited_people_can_access_this_channel: 'Seuls les invités peuvent accéder à ce canal',
|
Just_invited_people_can_access_this_channel: 'Seuls les invités peuvent accéder à ce canal',
|
||||||
Language: 'Langue',
|
Language: 'Langue',
|
||||||
|
@ -223,6 +220,7 @@ export default {
|
||||||
Notify_all_in_this_room: 'Notifier tous dans cette salle',
|
Notify_all_in_this_room: 'Notifier tous dans cette salle',
|
||||||
Offline: 'Hors ligne',
|
Offline: 'Hors ligne',
|
||||||
Oops: 'Oops!',
|
Oops: 'Oops!',
|
||||||
|
Onboarding_title: 'Bienvenue sur Rocket.Chat',
|
||||||
Online: 'En ligne',
|
Online: 'En ligne',
|
||||||
Only_authorized_users_can_write_new_messages: 'Seuls les utilisateurs autorisés peuvent écrire de nouveaux messages.',
|
Only_authorized_users_can_write_new_messages: 'Seuls les utilisateurs autorisés peuvent écrire de nouveaux messages.',
|
||||||
Open_emoji_selector: 'Ouvrir sélecteur emoji',
|
Open_emoji_selector: 'Ouvrir sélecteur emoji',
|
||||||
|
@ -338,7 +336,6 @@ export default {
|
||||||
Video_call: 'Appel vidéo',
|
Video_call: 'Appel vidéo',
|
||||||
Voice_call: 'Appel vocal',
|
Voice_call: 'Appel vocal',
|
||||||
Welcome: 'Bienvenue',
|
Welcome: 'Bienvenue',
|
||||||
Welcome_to_RocketChat: 'Bienvenue sur Rocket.Chat',
|
|
||||||
Whats_your_2fa: 'Quel est votre code 2FA?',
|
Whats_your_2fa: 'Quel est votre code 2FA?',
|
||||||
Yes_action_it: 'Oui, {{action}} le!',
|
Yes_action_it: 'Oui, {{action}} le!',
|
||||||
Yesterday: 'Hier',
|
Yesterday: 'Hier',
|
||||||
|
|
|
@ -136,7 +136,6 @@ export default {
|
||||||
Collaborative: 'Collaborativo',
|
Collaborative: 'Collaborativo',
|
||||||
Confirm: 'Conferma',
|
Confirm: 'Conferma',
|
||||||
Connect: 'Connetti',
|
Connect: 'Connetti',
|
||||||
Connect_to_a_server: 'Connetti ad un server',
|
|
||||||
Connected: 'Connesso',
|
Connected: 'Connesso',
|
||||||
connecting_server: 'connessione al server',
|
connecting_server: 'connessione al server',
|
||||||
Connecting: 'Connessione...',
|
Connecting: 'Connessione...',
|
||||||
|
@ -192,7 +191,6 @@ export default {
|
||||||
Finish_recording: 'Termina registrazione',
|
Finish_recording: 'Termina registrazione',
|
||||||
Following_thread: 'Thread seguito',
|
Following_thread: 'Thread seguito',
|
||||||
For_your_security_you_must_enter_your_current_password_to_continue: 'Per garantire la sicurezza del tuo account, inserisci la password per continuare.',
|
For_your_security_you_must_enter_your_current_password_to_continue: 'Per garantire la sicurezza del tuo account, inserisci la password per continuare.',
|
||||||
Forgot_my_password: 'Ho dimenticato la password',
|
|
||||||
Forgot_password_If_this_email_is_registered: 'Se questa e-mail è registrata, manderemo istruzioni su come resettare la tua password. Se non ricevi nulla, torna qui e riprova di nuovo.',
|
Forgot_password_If_this_email_is_registered: 'Se questa e-mail è registrata, manderemo istruzioni su come resettare la tua password. Se non ricevi nulla, torna qui e riprova di nuovo.',
|
||||||
Forgot_password: 'Password dimenticata',
|
Forgot_password: 'Password dimenticata',
|
||||||
Forgot_Password: 'Password dimenticata',
|
Forgot_Password: 'Password dimenticata',
|
||||||
|
@ -215,7 +213,6 @@ export default {
|
||||||
Invalid_server_version: 'Il server a cui stai cercando di connetterti sta utilizzando una versione non più supportata dall\'app: {{currentVersion}}.\n\nVersione minima richiesta: {{minVersion}}',
|
Invalid_server_version: 'Il server a cui stai cercando di connetterti sta utilizzando una versione non più supportata dall\'app: {{currentVersion}}.\n\nVersione minima richiesta: {{minVersion}}',
|
||||||
Invite_Link: 'Link di invito',
|
Invite_Link: 'Link di invito',
|
||||||
Invite_users: 'Invita utenti',
|
Invite_users: 'Invita utenti',
|
||||||
Join_the_community: 'Unisciti alla community',
|
|
||||||
Join: 'Entra',
|
Join: 'Entra',
|
||||||
Just_invited_people_can_access_this_channel: 'Solo le persone invitate possono accedere a questo canale',
|
Just_invited_people_can_access_this_channel: 'Solo le persone invitate possono accedere a questo canale',
|
||||||
Language: 'Lingua',
|
Language: 'Lingua',
|
||||||
|
@ -281,6 +278,7 @@ export default {
|
||||||
Notification_Preferences: 'Impostazioni notifiche',
|
Notification_Preferences: 'Impostazioni notifiche',
|
||||||
Offline: 'Offline',
|
Offline: 'Offline',
|
||||||
Oops: 'Oops!',
|
Oops: 'Oops!',
|
||||||
|
Onboarding_title: 'Benvenuto in Rocket.Chat',
|
||||||
Online: 'Online',
|
Online: 'Online',
|
||||||
Only_authorized_users_can_write_new_messages: 'Solo gli utenti autorizzati possono scrivere nuovi messaggi',
|
Only_authorized_users_can_write_new_messages: 'Solo gli utenti autorizzati possono scrivere nuovi messaggi',
|
||||||
Open_emoji_selector: 'Apri selettore emoji',
|
Open_emoji_selector: 'Apri selettore emoji',
|
||||||
|
@ -441,7 +439,6 @@ export default {
|
||||||
Voice_call: 'Chiamata vocale',
|
Voice_call: 'Chiamata vocale',
|
||||||
Websocket_disabled: 'Websocket è disabilitato per questo server.\n{{contact}}',
|
Websocket_disabled: 'Websocket è disabilitato per questo server.\n{{contact}}',
|
||||||
Welcome: 'Benvenuto',
|
Welcome: 'Benvenuto',
|
||||||
Welcome_to_RocketChat: 'Benvenuto in Rocket.Chat',
|
|
||||||
Whats_your_2fa: 'Qual\'è il tuo codice 2FA?',
|
Whats_your_2fa: 'Qual\'è il tuo codice 2FA?',
|
||||||
Without_Servers: 'Senza server',
|
Without_Servers: 'Senza server',
|
||||||
Write_External_Permission_Message: 'Rocket.Chat ha bisogno dell\'accesso alla galleria per salvare le immagini.',
|
Write_External_Permission_Message: 'Rocket.Chat ha bisogno dell\'accesso alla galleria per salvare le immagini.',
|
||||||
|
|
|
@ -153,7 +153,6 @@ export default {
|
||||||
Collaborative: 'コラボ',
|
Collaborative: 'コラボ',
|
||||||
Confirm: '承認',
|
Confirm: '承認',
|
||||||
Connect: '接続',
|
Connect: '接続',
|
||||||
Connect_to_a_server: 'サーバーに接続',
|
|
||||||
Connected: '接続しました',
|
Connected: '接続しました',
|
||||||
connecting_server: 'サーバーに接続中',
|
connecting_server: 'サーバーに接続中',
|
||||||
Connecting: '接続中...',
|
Connecting: '接続中...',
|
||||||
|
@ -216,7 +215,6 @@ export default {
|
||||||
Following_thread: 'スレッド更新時に通知',
|
Following_thread: 'スレッド更新時に通知',
|
||||||
For_your_security_you_must_enter_your_current_password_to_continue:
|
For_your_security_you_must_enter_your_current_password_to_continue:
|
||||||
'セキュリティのため、続けるには現在のパスワードを入力してください。',
|
'セキュリティのため、続けるには現在のパスワードを入力してください。',
|
||||||
Forgot_my_password: 'パスワードを忘れた',
|
|
||||||
Forgot_password_If_this_email_is_registered:
|
Forgot_password_If_this_email_is_registered:
|
||||||
'送信したメールアドレスが登録されていれば、パスワードのリセット方法を送信しました。メールアドレスがすぐに来ない場合はやり直してください。',
|
'送信したメールアドレスが登録されていれば、パスワードのリセット方法を送信しました。メールアドレスがすぐに来ない場合はやり直してください。',
|
||||||
Forgot_password: 'パスワードを忘れた',
|
Forgot_password: 'パスワードを忘れた',
|
||||||
|
@ -242,7 +240,6 @@ export default {
|
||||||
'接続しようとしているサーバーのバージョン({{currentVersion}})はサポートされていません。\n\nサポートする最低バージョンは {{minVersion}} です',
|
'接続しようとしているサーバーのバージョン({{currentVersion}})はサポートされていません。\n\nサポートする最低バージョンは {{minVersion}} です',
|
||||||
Invite_Link: '招待リンク',
|
Invite_Link: '招待リンク',
|
||||||
Invite_users: 'ユーザーを招待',
|
Invite_users: 'ユーザーを招待',
|
||||||
Join_the_community: 'コミュニティに参加',
|
|
||||||
Join: '参加',
|
Join: '参加',
|
||||||
Just_invited_people_can_access_this_channel:
|
Just_invited_people_can_access_this_channel:
|
||||||
'招待されたユーザーだけがこのチャンネルに参加できます',
|
'招待されたユーザーだけがこのチャンネルに参加できます',
|
||||||
|
@ -311,6 +308,7 @@ export default {
|
||||||
Notification_Preferences: '通知設定',
|
Notification_Preferences: '通知設定',
|
||||||
Offline: 'オフライン',
|
Offline: 'オフライン',
|
||||||
Oops: 'おっと!',
|
Oops: 'おっと!',
|
||||||
|
Onboarding_title: 'Rocket.Chatへようこそ',
|
||||||
Online: 'オンライン',
|
Online: 'オンライン',
|
||||||
Only_authorized_users_can_write_new_messages:
|
Only_authorized_users_can_write_new_messages:
|
||||||
'承認されたユーザーだけが新しいメッセージを書き込めます',
|
'承認されたユーザーだけが新しいメッセージを書き込めます',
|
||||||
|
@ -487,7 +485,6 @@ export default {
|
||||||
Voice_call: '音声通話',
|
Voice_call: '音声通話',
|
||||||
Websocket_disabled: 'Websocketはこのサーバーでは無効化されています。\n{{contact}}',
|
Websocket_disabled: 'Websocketはこのサーバーでは無効化されています。\n{{contact}}',
|
||||||
Welcome: 'ようこそ',
|
Welcome: 'ようこそ',
|
||||||
Welcome_to_RocketChat: 'Rocket.Chatへようこそ',
|
|
||||||
Whats_your_2fa: '2段階認証のコードを入力してください',
|
Whats_your_2fa: '2段階認証のコードを入力してください',
|
||||||
Without_Servers: 'サーバーを除く',
|
Without_Servers: 'サーバーを除く',
|
||||||
Write_External_Permission_Message:
|
Write_External_Permission_Message:
|
||||||
|
|
|
@ -136,7 +136,6 @@ export default {
|
||||||
Collaborative: 'Samenwerkend',
|
Collaborative: 'Samenwerkend',
|
||||||
Confirm: 'Bevestig',
|
Confirm: 'Bevestig',
|
||||||
Connect: 'Verbind',
|
Connect: 'Verbind',
|
||||||
Connect_to_a_server: 'Verbind met een server',
|
|
||||||
Connected: 'Verbonden',
|
Connected: 'Verbonden',
|
||||||
connecting_server: 'Verbonden met een server',
|
connecting_server: 'Verbonden met een server',
|
||||||
Connecting: 'Aan het verbinden...',
|
Connecting: 'Aan het verbinden...',
|
||||||
|
@ -192,7 +191,6 @@ export default {
|
||||||
Finish_recording: 'Beëindig opname',
|
Finish_recording: 'Beëindig opname',
|
||||||
Following_thread: 'Volg thread',
|
Following_thread: 'Volg thread',
|
||||||
For_your_security_you_must_enter_your_current_password_to_continue: 'Voor je veiligheid moet je je wachtwoord invullen om door te gaan',
|
For_your_security_you_must_enter_your_current_password_to_continue: 'Voor je veiligheid moet je je wachtwoord invullen om door te gaan',
|
||||||
Forgot_my_password: 'Wachtwoord vergeten',
|
|
||||||
Forgot_password_If_this_email_is_registered: 'Als dit email adres bij ons bekend is, sturen we je instructies op om je wachtwoord te resetten. Als je geen email krijgt, probeer het dan nogmaals.',
|
Forgot_password_If_this_email_is_registered: 'Als dit email adres bij ons bekend is, sturen we je instructies op om je wachtwoord te resetten. Als je geen email krijgt, probeer het dan nogmaals.',
|
||||||
Forgot_password: 'Wachtwoord vergeten',
|
Forgot_password: 'Wachtwoord vergeten',
|
||||||
Forgot_Password: 'Wachtwoord Vergeten',
|
Forgot_Password: 'Wachtwoord Vergeten',
|
||||||
|
@ -215,7 +213,6 @@ export default {
|
||||||
Invalid_server_version: 'De server die je probeert te bereiken gebruikt een versie die niet meer door de app ondersteunt wordt: {{currentVersion}}.\n\nMinimale versienummer {{minVersion}}',
|
Invalid_server_version: 'De server die je probeert te bereiken gebruikt een versie die niet meer door de app ondersteunt wordt: {{currentVersion}}.\n\nMinimale versienummer {{minVersion}}',
|
||||||
Invite_Link: 'Uitnodigingslink',
|
Invite_Link: 'Uitnodigingslink',
|
||||||
Invite_users: 'Nodig gebruikers uit',
|
Invite_users: 'Nodig gebruikers uit',
|
||||||
Join_the_community: 'Word lid van de community',
|
|
||||||
Join: 'Word lid',
|
Join: 'Word lid',
|
||||||
Just_invited_people_can_access_this_channel: 'Alleen genodigden kunnen bij dit kanaal',
|
Just_invited_people_can_access_this_channel: 'Alleen genodigden kunnen bij dit kanaal',
|
||||||
Language: 'Taal',
|
Language: 'Taal',
|
||||||
|
@ -281,6 +278,7 @@ export default {
|
||||||
Notification_Preferences: 'Notificatievoorkeuren',
|
Notification_Preferences: 'Notificatievoorkeuren',
|
||||||
Offline: 'Offline',
|
Offline: 'Offline',
|
||||||
Oops: 'Oeps!',
|
Oops: 'Oeps!',
|
||||||
|
Onboarding_title: 'Welkom bij Rocket.Chat',
|
||||||
Online: 'Online',
|
Online: 'Online',
|
||||||
Only_authorized_users_can_write_new_messages: 'Alleen gebruikers met toestemming mogen nieuwe berichten maken',
|
Only_authorized_users_can_write_new_messages: 'Alleen gebruikers met toestemming mogen nieuwe berichten maken',
|
||||||
Open_emoji_selector: 'Open de emoji selector',
|
Open_emoji_selector: 'Open de emoji selector',
|
||||||
|
@ -448,7 +446,6 @@ export default {
|
||||||
Voice_call: 'Audiogesprek',
|
Voice_call: 'Audiogesprek',
|
||||||
Websocket_disabled: 'Websocket staat uit voor deze server.\n{{contact}}',
|
Websocket_disabled: 'Websocket staat uit voor deze server.\n{{contact}}',
|
||||||
Welcome: 'Welkom',
|
Welcome: 'Welkom',
|
||||||
Welcome_to_RocketChat: 'Welkom bij Rocket.Chat',
|
|
||||||
Whats_your_2fa: 'Wat is je 2FA code?',
|
Whats_your_2fa: 'Wat is je 2FA code?',
|
||||||
Without_Servers: 'Zonder Servers',
|
Without_Servers: 'Zonder Servers',
|
||||||
Write_External_Permission_Message: 'Rocket Chat moet bij je galerij kunnen om afbeeldingen op te slaan.',
|
Write_External_Permission_Message: 'Rocket Chat moet bij je galerij kunnen om afbeeldingen op te slaan.',
|
||||||
|
|
|
@ -142,7 +142,6 @@ export default {
|
||||||
Collaborative: 'Colaborativo',
|
Collaborative: 'Colaborativo',
|
||||||
Confirm: 'Confirmar',
|
Confirm: 'Confirmar',
|
||||||
Connect: 'Conectar',
|
Connect: 'Conectar',
|
||||||
Connect_to_a_server: 'Conectar a um servidor',
|
|
||||||
Connected: 'Conectado',
|
Connected: 'Conectado',
|
||||||
connecting_server: 'conectando no servidor',
|
connecting_server: 'conectando no servidor',
|
||||||
Connecting: 'Conectando...',
|
Connecting: 'Conectando...',
|
||||||
|
@ -171,6 +170,7 @@ export default {
|
||||||
Disable_notifications: 'Desabilitar notificações',
|
Disable_notifications: 'Desabilitar notificações',
|
||||||
Discussions: 'Discussões',
|
Discussions: 'Discussões',
|
||||||
Dont_Have_An_Account: 'Não tem uma conta?',
|
Dont_Have_An_Account: 'Não tem uma conta?',
|
||||||
|
Do_you_have_an_account: 'Você tem uma conta?',
|
||||||
Do_you_really_want_to_key_this_room_question_mark: 'Você quer realmente {{key}} esta sala?',
|
Do_you_really_want_to_key_this_room_question_mark: 'Você quer realmente {{key}} esta sala?',
|
||||||
edit: 'editar',
|
edit: 'editar',
|
||||||
edited: 'editado',
|
edited: 'editado',
|
||||||
|
@ -190,9 +190,8 @@ export default {
|
||||||
Finish_recording: 'Encerrar gravação',
|
Finish_recording: 'Encerrar gravação',
|
||||||
Following_thread: 'Começou a seguir tópico',
|
Following_thread: 'Começou a seguir tópico',
|
||||||
For_your_security_you_must_enter_your_current_password_to_continue: 'Para sua segurança, você precisa digitar sua senha',
|
For_your_security_you_must_enter_your_current_password_to_continue: 'Para sua segurança, você precisa digitar sua senha',
|
||||||
Forgot_my_password: 'Esqueci minha senha',
|
|
||||||
Forgot_password_If_this_email_is_registered: 'Se este e-mail estiver cadastrado, enviaremos instruções sobre como redefinir sua senha. Se você não receber um e-mail em breve, volte e tente novamente.',
|
Forgot_password_If_this_email_is_registered: 'Se este e-mail estiver cadastrado, enviaremos instruções sobre como redefinir sua senha. Se você não receber um e-mail em breve, volte e tente novamente.',
|
||||||
Forgot_password: 'Esqueci minha senha',
|
Forgot_password: 'Esqueceu sua senha?',
|
||||||
Forgot_Password: 'Esqueci minha senha',
|
Forgot_Password: 'Esqueci minha senha',
|
||||||
Full_table: 'Clique para ver a tabela completa',
|
Full_table: 'Clique para ver a tabela completa',
|
||||||
Generate_New_Link: 'Gerar novo convite',
|
Generate_New_Link: 'Gerar novo convite',
|
||||||
|
@ -224,8 +223,9 @@ export default {
|
||||||
Invalid_server_version: 'O servidor que você está conectando não é suportado mais por esta versão do aplicativo: {{currentVersion}}.\n\nEsta versão do aplicativo requer a versão {{minVersion}} do servidor para funcionar corretamente.',
|
Invalid_server_version: 'O servidor que você está conectando não é suportado mais por esta versão do aplicativo: {{currentVersion}}.\n\nEsta versão do aplicativo requer a versão {{minVersion}} do servidor para funcionar corretamente.',
|
||||||
Invite_Link: 'Link de Convite',
|
Invite_Link: 'Link de Convite',
|
||||||
Invite_users: 'Convidar usuários',
|
Invite_users: 'Convidar usuários',
|
||||||
Join_the_community: 'Junte-se à comunidade',
|
|
||||||
Join: 'Entrar',
|
Join: 'Entrar',
|
||||||
|
Join_our_open_workspace: 'Entra na nossa workspace pública',
|
||||||
|
Join_your_workspace: 'Entre na sua workspace',
|
||||||
Just_invited_people_can_access_this_channel: 'Apenas as pessoas convidadas podem acessar este canal',
|
Just_invited_people_can_access_this_channel: 'Apenas as pessoas convidadas podem acessar este canal',
|
||||||
Language: 'Idioma',
|
Language: 'Idioma',
|
||||||
last_message: 'última mensagem',
|
last_message: 'última mensagem',
|
||||||
|
@ -282,10 +282,19 @@ export default {
|
||||||
Not_RC_Server: 'Este não é um servidor Rocket.Chat.\n{{contact}}',
|
Not_RC_Server: 'Este não é um servidor Rocket.Chat.\n{{contact}}',
|
||||||
Offline: 'Offline',
|
Offline: 'Offline',
|
||||||
Oops: 'Ops!',
|
Oops: 'Ops!',
|
||||||
|
Onboarding_description: 'Workspace é o espaço de colaboração do seu time ou organização. Peça um convite ou o endereço ao seu administrador ou crie uma workspace para o seu time.',
|
||||||
|
Onboarding_join_workspace: 'Entre numa workspace',
|
||||||
|
Onboarding_subtitle: 'Além da colaboração em equipe',
|
||||||
|
Onboarding_title: 'Bem vindo ao Rocket.Chat',
|
||||||
|
Onboarding_join_open_description: 'Entre na nossa workspace pública para conversar com o time da Rocket.Chat e nossa comunidade.',
|
||||||
|
Onboarding_agree_terms: 'Ao continuar, você aceita nossos ',
|
||||||
|
Onboarding_less_options: 'Menos opções',
|
||||||
|
Onboarding_more_options: 'Mais opções',
|
||||||
Online: 'Online',
|
Online: 'Online',
|
||||||
Only_authorized_users_can_write_new_messages: 'Somente usuários autorizados podem escrever novas mensagens',
|
Only_authorized_users_can_write_new_messages: 'Somente usuários autorizados podem escrever novas mensagens',
|
||||||
Open_emoji_selector: 'Abrir seletor de emoji',
|
Open_emoji_selector: 'Abrir seletor de emoji',
|
||||||
Open_Source_Communication: 'Comunicação Open Source',
|
Open_Source_Communication: 'Comunicação Open Source',
|
||||||
|
OR: 'OU',
|
||||||
Overwrites_the_server_configuration_and_use_room_config: 'Substituir a configuração do servidor e usar a configuração da sala',
|
Overwrites_the_server_configuration_and_use_room_config: 'Substituir a configuração do servidor e usar a configuração da sala',
|
||||||
Password: 'Senha',
|
Password: 'Senha',
|
||||||
Permalink_copied_to_clipboard: 'Link-permanente copiado para a área de transferência!',
|
Permalink_copied_to_clipboard: 'Link-permanente copiado para a área de transferência!',
|
||||||
|
@ -432,9 +441,9 @@ export default {
|
||||||
Voice_call: 'Chamada de voz',
|
Voice_call: 'Chamada de voz',
|
||||||
Websocket_disabled: 'Websocket está desativado para esse servidor.\n{{contact}}',
|
Websocket_disabled: 'Websocket está desativado para esse servidor.\n{{contact}}',
|
||||||
Welcome: 'Bem vindo',
|
Welcome: 'Bem vindo',
|
||||||
Welcome_to_RocketChat: 'Bem vindo ao Rocket.Chat',
|
|
||||||
Whats_your_2fa: 'Qual seu código de autenticação?',
|
Whats_your_2fa: 'Qual seu código de autenticação?',
|
||||||
Without_Servers: 'Sem Servidores',
|
Without_Servers: 'Sem Servidores',
|
||||||
|
Workspaces: 'Workspaces',
|
||||||
Yes_action_it: 'Sim, {{action}}!',
|
Yes_action_it: 'Sim, {{action}}!',
|
||||||
Yesterday: 'Ontem',
|
Yesterday: 'Ontem',
|
||||||
You_are_in_preview_mode: 'Está é uma prévia do canal',
|
You_are_in_preview_mode: 'Está é uma prévia do canal',
|
||||||
|
@ -449,6 +458,7 @@ export default {
|
||||||
Your_invite_link_will_expire_on__date__or_after__usesLeft__uses: 'Seu link de convite irá vencer em {{date}} ou depois de {{usesLeft}} usos.',
|
Your_invite_link_will_expire_on__date__or_after__usesLeft__uses: 'Seu link de convite irá vencer em {{date}} ou depois de {{usesLeft}} usos.',
|
||||||
Your_invite_link_will_expire_on__date__: 'Seu link de convite irá vencer em {{date}}.',
|
Your_invite_link_will_expire_on__date__: 'Seu link de convite irá vencer em {{date}}.',
|
||||||
Your_invite_link_will_never_expire: 'Seu link de convite nunca irá vencer.',
|
Your_invite_link_will_never_expire: 'Seu link de convite nunca irá vencer.',
|
||||||
|
Your_workspace: 'Sua workspace',
|
||||||
You_will_not_be_able_to_recover_this_message: 'Você não será capaz de recuperar essa mensagem!',
|
You_will_not_be_able_to_recover_this_message: 'Você não será capaz de recuperar essa mensagem!',
|
||||||
Write_External_Permission_Message: 'Rocket Chat precisa de acesso à sua galeria para salvar imagens',
|
Write_External_Permission_Message: 'Rocket Chat precisa de acesso à sua galeria para salvar imagens',
|
||||||
Write_External_Permission: 'Acesso à Galeria',
|
Write_External_Permission: 'Acesso à Galeria',
|
||||||
|
|
|
@ -122,7 +122,6 @@ export default {
|
||||||
Collaborative: 'Colaborativa',
|
Collaborative: 'Colaborativa',
|
||||||
Confirm: 'Confirmar',
|
Confirm: 'Confirmar',
|
||||||
Connect: 'Ligar',
|
Connect: 'Ligar',
|
||||||
Connect_to_a_server: 'Ligue-se a um servidor',
|
|
||||||
Connected: 'Ligado',
|
Connected: 'Ligado',
|
||||||
Connecting: 'A ligar...',
|
Connecting: 'A ligar...',
|
||||||
Continue_with: 'Continuar com',
|
Continue_with: 'Continuar com',
|
||||||
|
@ -159,7 +158,6 @@ export default {
|
||||||
File_name: 'Nome do ficheiro',
|
File_name: 'Nome do ficheiro',
|
||||||
Finish_recording: 'Terminar a gravação',
|
Finish_recording: 'Terminar a gravação',
|
||||||
For_your_security_you_must_enter_your_current_password_to_continue: 'Para sua segurança, você deve escrever a sua palavra-passe actual para continuar',
|
For_your_security_you_must_enter_your_current_password_to_continue: 'Para sua segurança, você deve escrever a sua palavra-passe actual para continuar',
|
||||||
Forgot_my_password: 'Esqueci minha palavra-passe',
|
|
||||||
Forgot_password_If_this_email_is_registered: 'Se este e-mail estiver registado, enviaremos instruções sobre como repor a sua palavra-passe. Se você não receber um e-mail em breve, volte e tente novamente.',
|
Forgot_password_If_this_email_is_registered: 'Se este e-mail estiver registado, enviaremos instruções sobre como repor a sua palavra-passe. Se você não receber um e-mail em breve, volte e tente novamente.',
|
||||||
Forgot_password: 'Esquecer palavra-passe',
|
Forgot_password: 'Esquecer palavra-passe',
|
||||||
Forgot_Password: 'Esquecer Palavra-passe',
|
Forgot_Password: 'Esquecer Palavra-passe',
|
||||||
|
@ -174,7 +172,6 @@ export default {
|
||||||
is_not_a_valid_RocketChat_instance: 'is not a valid Rocket.Chat instance',
|
is_not_a_valid_RocketChat_instance: 'is not a valid Rocket.Chat instance',
|
||||||
is_typing: 'está a escrever',
|
is_typing: 'está a escrever',
|
||||||
Invalid_server_version: 'O servidor ao qual esta tentando ligar-se, utiliza uma versão que não é suporta pela aplicação: {{currentVersion}}.\n\nA versão mínima requerida é {{minVersion}}',
|
Invalid_server_version: 'O servidor ao qual esta tentando ligar-se, utiliza uma versão que não é suporta pela aplicação: {{currentVersion}}.\n\nA versão mínima requerida é {{minVersion}}',
|
||||||
Join_the_community: 'Junte-se à comunidade',
|
|
||||||
Join: 'Entrar',
|
Join: 'Entrar',
|
||||||
Just_invited_people_can_access_this_channel: 'Apenas utilizadores convidados podem aceder a este canal',
|
Just_invited_people_can_access_this_channel: 'Apenas utilizadores convidados podem aceder a este canal',
|
||||||
Language: 'Idioma',
|
Language: 'Idioma',
|
||||||
|
@ -224,6 +221,7 @@ export default {
|
||||||
Notify_all_in_this_room: 'Notifica todos os utilizadores nesta sala',
|
Notify_all_in_this_room: 'Notifica todos os utilizadores nesta sala',
|
||||||
Offline: 'Desligado',
|
Offline: 'Desligado',
|
||||||
Oops: 'Oops!',
|
Oops: 'Oops!',
|
||||||
|
Onboarding_title: 'Bem vindo(a) ao Rocket.Chat',
|
||||||
Online: 'Ligado',
|
Online: 'Ligado',
|
||||||
Only_authorized_users_can_write_new_messages: 'Apenas utilizadores autorizados podem escrever novas mensagens',
|
Only_authorized_users_can_write_new_messages: 'Apenas utilizadores autorizados podem escrever novas mensagens',
|
||||||
Open_emoji_selector: 'Abra o selector de emoticons',
|
Open_emoji_selector: 'Abra o selector de emoticons',
|
||||||
|
@ -341,7 +339,6 @@ export default {
|
||||||
Video_call: 'Video chamada',
|
Video_call: 'Video chamada',
|
||||||
Voice_call: 'Chamada de voz',
|
Voice_call: 'Chamada de voz',
|
||||||
Welcome: 'Bem vindo(a)',
|
Welcome: 'Bem vindo(a)',
|
||||||
Welcome_to_RocketChat: 'Bem vindo(a) ao Rocket.Chat',
|
|
||||||
Whats_your_2fa: 'Qual é o seu código 2FA?',
|
Whats_your_2fa: 'Qual é o seu código 2FA?',
|
||||||
Yes_action_it: 'Sim, {{action}}!',
|
Yes_action_it: 'Sim, {{action}}!',
|
||||||
Yesterday: 'Ontem',
|
Yesterday: 'Ontem',
|
||||||
|
|
|
@ -131,7 +131,6 @@ export default {
|
||||||
Collaborative: 'Совместный',
|
Collaborative: 'Совместный',
|
||||||
Confirm: 'Подтверждение',
|
Confirm: 'Подтверждение',
|
||||||
Connect: 'Соединение',
|
Connect: 'Соединение',
|
||||||
Connect_to_a_server: 'Подключиться к серверу',
|
|
||||||
Connected: 'Подключено',
|
Connected: 'Подключено',
|
||||||
connecting_server: 'подключение к серверу',
|
connecting_server: 'подключение к серверу',
|
||||||
Connecting: 'Соединение...',
|
Connecting: 'Соединение...',
|
||||||
|
@ -183,7 +182,6 @@ export default {
|
||||||
Finish_recording: 'Завершить запись',
|
Finish_recording: 'Завершить запись',
|
||||||
Following_thread: 'Следить за темой',
|
Following_thread: 'Следить за темой',
|
||||||
For_your_security_you_must_enter_your_current_password_to_continue: 'В целях вашей безопасности вы должны ввести свой текущий пароль для продолжения',
|
For_your_security_you_must_enter_your_current_password_to_continue: 'В целях вашей безопасности вы должны ввести свой текущий пароль для продолжения',
|
||||||
Forgot_my_password: 'Забыл свой пароль',
|
|
||||||
Forgot_password_If_this_email_is_registered: 'Если эта электронная почта зарегистрирована, мы отправим инструкции о том, как сбросить пароль. Если вы не получите письмо в ближайшее время, вернитесь и повторите попытку.',
|
Forgot_password_If_this_email_is_registered: 'Если эта электронная почта зарегистрирована, мы отправим инструкции о том, как сбросить пароль. Если вы не получите письмо в ближайшее время, вернитесь и повторите попытку.',
|
||||||
Forgot_password: 'Забыли пароль',
|
Forgot_password: 'Забыли пароль',
|
||||||
Forgot_Password: 'Забыли Пароль',
|
Forgot_Password: 'Забыли Пароль',
|
||||||
|
@ -202,7 +200,6 @@ export default {
|
||||||
is_not_a_valid_RocketChat_instance: 'не является действительным сервером Rocket.Chat',
|
is_not_a_valid_RocketChat_instance: 'не является действительным сервером Rocket.Chat',
|
||||||
is_typing: 'печатает',
|
is_typing: 'печатает',
|
||||||
Invalid_server_version: 'Сервер, к которому вы пытаетесь подключиться, использует версию, которая больше не поддерживается приложением: {{currentVersion}}.\n\nНам нужна версия {{minVersion}}',
|
Invalid_server_version: 'Сервер, к которому вы пытаетесь подключиться, использует версию, которая больше не поддерживается приложением: {{currentVersion}}.\n\nНам нужна версия {{minVersion}}',
|
||||||
Join_the_community: 'Присоединиться к сообществу',
|
|
||||||
Join: 'Присоединиться',
|
Join: 'Присоединиться',
|
||||||
Just_invited_people_can_access_this_channel: 'Только приглашенные люди могут получить доступ к этому каналу',
|
Just_invited_people_can_access_this_channel: 'Только приглашенные люди могут получить доступ к этому каналу',
|
||||||
Language: 'Язык',
|
Language: 'Язык',
|
||||||
|
@ -264,6 +261,7 @@ export default {
|
||||||
Notification_Preferences: 'Настройки уведомлений',
|
Notification_Preferences: 'Настройки уведомлений',
|
||||||
Offline: 'Офлайн',
|
Offline: 'Офлайн',
|
||||||
Oops: 'Упс!',
|
Oops: 'Упс!',
|
||||||
|
Onboarding_title: 'Добро пожаловать в Rocket.Chat',
|
||||||
Online: 'Онлайн',
|
Online: 'Онлайн',
|
||||||
Only_authorized_users_can_write_new_messages: 'Только авторизованные пользователи могут писать новые сообщения',
|
Only_authorized_users_can_write_new_messages: 'Только авторизованные пользователи могут писать новые сообщения',
|
||||||
Open_emoji_selector: 'Открыть селектор emoji',
|
Open_emoji_selector: 'Открыть селектор emoji',
|
||||||
|
@ -420,7 +418,6 @@ export default {
|
||||||
Voice_call: 'Голосовой вызов',
|
Voice_call: 'Голосовой вызов',
|
||||||
Websocket_disabled: 'Websocket отключен для этого сервера.\n{{contact}}',
|
Websocket_disabled: 'Websocket отключен для этого сервера.\n{{contact}}',
|
||||||
Welcome: 'Добро пожаловать,',
|
Welcome: 'Добро пожаловать,',
|
||||||
Welcome_to_RocketChat: 'Добро пожаловать в Rocket.Chat',
|
|
||||||
Whats_your_2fa: 'Какой у вас код 2FA?',
|
Whats_your_2fa: 'Какой у вас код 2FA?',
|
||||||
Without_Servers: 'Без серверов',
|
Without_Servers: 'Без серверов',
|
||||||
Yes_action_it: 'Да, {{action}} это!',
|
Yes_action_it: 'Да, {{action}} это!',
|
||||||
|
|
|
@ -122,7 +122,6 @@ export default {
|
||||||
Collaborative: '协作',
|
Collaborative: '协作',
|
||||||
Confirm: '确认',
|
Confirm: '确认',
|
||||||
Connect: '连接',
|
Connect: '连接',
|
||||||
Connect_to_a_server: '连接到服务器',
|
|
||||||
Connected: '已连接',
|
Connected: '已连接',
|
||||||
Connecting: '连接中',
|
Connecting: '连接中',
|
||||||
Continue_with: '继续采用',
|
Continue_with: '继续采用',
|
||||||
|
@ -156,7 +155,6 @@ export default {
|
||||||
Files: '文件',
|
Files: '文件',
|
||||||
Finish_recording: '完成录制',
|
Finish_recording: '完成录制',
|
||||||
For_your_security_you_must_enter_your_current_password_to_continue: '为了安全起见,您必须输入当前密码才能继续',
|
For_your_security_you_must_enter_your_current_password_to_continue: '为了安全起见,您必须输入当前密码才能继续',
|
||||||
Forgot_my_password: '忘记密码',
|
|
||||||
Forgot_password_If_this_email_is_registered: '如果这封邮件已注册,我们将发送如何重置密码的说明。如果您没有立即收到电子邮件,请回来再试一次。',
|
Forgot_password_If_this_email_is_registered: '如果这封邮件已注册,我们将发送如何重置密码的说明。如果您没有立即收到电子邮件,请回来再试一次。',
|
||||||
Forgot_password: '忘记密码',
|
Forgot_password: '忘记密码',
|
||||||
Forgot_Password: '忘记密码',
|
Forgot_Password: '忘记密码',
|
||||||
|
@ -170,7 +168,6 @@ export default {
|
||||||
is_a_valid_RocketChat_instance: '是一个有效的 Rocket.Chat 实例',
|
is_a_valid_RocketChat_instance: '是一个有效的 Rocket.Chat 实例',
|
||||||
is_not_a_valid_RocketChat_instance: '不是有效的 Rocket.Chat 实例',
|
is_not_a_valid_RocketChat_instance: '不是有效的 Rocket.Chat 实例',
|
||||||
is_typing: '正在输入',
|
is_typing: '正在输入',
|
||||||
Join_the_community: '加入社区',
|
|
||||||
Join: '加入',
|
Join: '加入',
|
||||||
Just_invited_people_can_access_this_channel: '刚被邀请的人可以进入这个频道',
|
Just_invited_people_can_access_this_channel: '刚被邀请的人可以进入这个频道',
|
||||||
Language: '语言',
|
Language: '语言',
|
||||||
|
@ -220,6 +217,7 @@ export default {
|
||||||
Notify_all_in_this_room: '通知这个房间的所有人',
|
Notify_all_in_this_room: '通知这个房间的所有人',
|
||||||
Offline: '离线',
|
Offline: '离线',
|
||||||
Oops: '哎呀!',
|
Oops: '哎呀!',
|
||||||
|
Onboarding_title: '欢迎来到 Rocket.Chat',
|
||||||
Online: '在线',
|
Online: '在线',
|
||||||
Only_authorized_users_can_write_new_messages: '只有经过授权的用户才能写新消息',
|
Only_authorized_users_can_write_new_messages: '只有经过授权的用户才能写新消息',
|
||||||
Open_emoji_selector: '打开emoji选择器',
|
Open_emoji_selector: '打开emoji选择器',
|
||||||
|
@ -333,7 +331,6 @@ export default {
|
||||||
Video_call: '视频电话',
|
Video_call: '视频电话',
|
||||||
Voice_call: '语音电话',
|
Voice_call: '语音电话',
|
||||||
Welcome: '欢迎',
|
Welcome: '欢迎',
|
||||||
Welcome_to_RocketChat: '欢迎来到 Rocket.Chat',
|
|
||||||
Yes_action_it: '是的,{{action}}它!',
|
Yes_action_it: '是的,{{action}}它!',
|
||||||
Yesterday: '昨天',
|
Yesterday: '昨天',
|
||||||
You_are_in_preview_mode: '您处于预览模式',
|
You_are_in_preview_mode: '您处于预览模式',
|
||||||
|
|
|
@ -74,8 +74,8 @@ const OutsideStack = createStackNavigator({
|
||||||
NewServerView: {
|
NewServerView: {
|
||||||
getScreen: () => require('./views/NewServerView').default
|
getScreen: () => require('./views/NewServerView').default
|
||||||
},
|
},
|
||||||
LoginSignupView: {
|
WorkspaceView: {
|
||||||
getScreen: () => require('./views/LoginSignupView').default
|
getScreen: () => require('./views/WorkspaceView').default
|
||||||
},
|
},
|
||||||
LoginView: {
|
LoginView: {
|
||||||
getScreen: () => require('./views/LoginView').default
|
getScreen: () => require('./views/LoginView').default
|
||||||
|
|
|
@ -91,7 +91,7 @@ export default async function() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const data = result.settings || [];
|
const data = result.settings || [];
|
||||||
const filteredSettings = this._prepareSettings(data.filter(item => item._id !== 'Assets_favicon_512'));
|
const filteredSettings = this._prepareSettings(data);
|
||||||
const filteredSettingsIds = filteredSettings.map(s => s._id);
|
const filteredSettingsIds = filteredSettings.map(s => s._id);
|
||||||
|
|
||||||
reduxStore.dispatch(actions.addSettings(this.parseSettings(filteredSettings)));
|
reduxStore.dispatch(actions.addSettings(this.parseSettings(filteredSettings)));
|
||||||
|
|
|
@ -89,7 +89,7 @@ const handleOpen = function* handleOpen({ params }) {
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Navigation.navigate('OnboardingView', { previousServer: server });
|
Navigation.navigate('NewServerView', { previousServer: server });
|
||||||
yield delay(1000);
|
yield delay(1000);
|
||||||
EventEmitter.emit('NewServer', { server: host });
|
EventEmitter.emit('NewServer', { server: host });
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import {
|
import {
|
||||||
put, take, takeLatest, fork, cancel, race, select
|
put, take, takeLatest, fork, cancel, race
|
||||||
} from 'redux-saga/effects';
|
} from 'redux-saga/effects';
|
||||||
import { Alert } from 'react-native';
|
import { Alert } from 'react-native';
|
||||||
import RNUserDefaults from 'rn-user-defaults';
|
import RNUserDefaults from 'rn-user-defaults';
|
||||||
|
@ -133,16 +133,9 @@ const handleServerRequest = function* handleServerRequest({ server, certificate
|
||||||
const serverInfo = yield getServerInfo({ server });
|
const serverInfo = yield getServerInfo({ server });
|
||||||
|
|
||||||
if (serverInfo) {
|
if (serverInfo) {
|
||||||
const loginServicesLength = yield RocketChat.getLoginServices(server);
|
yield RocketChat.getLoginServices(server);
|
||||||
yield RocketChat.getLoginSettings({ server });
|
yield RocketChat.getLoginSettings({ server });
|
||||||
|
Navigation.navigate('WorkspaceView');
|
||||||
const showFormLogin = yield select(state => state.settings.Accounts_ShowFormLogin);
|
|
||||||
|
|
||||||
if (!loginServicesLength && showFormLogin) {
|
|
||||||
Navigation.navigate('LoginView');
|
|
||||||
} else {
|
|
||||||
Navigation.navigate('LoginSignupView');
|
|
||||||
}
|
|
||||||
yield put(selectServerRequest(server, serverInfo.version, false));
|
yield put(selectServerRequest(server, serverInfo.version, false));
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -108,7 +108,7 @@ export const initTabletNav = (setState) => {
|
||||||
KeyCommands.deleteKeyCommands([...defaultCommands, ...keyCommands]);
|
KeyCommands.deleteKeyCommands([...defaultCommands, ...keyCommands]);
|
||||||
setState({ inside: false, showModal: false });
|
setState({ inside: false, showModal: false });
|
||||||
}
|
}
|
||||||
if (routeName === 'OnboardingView') {
|
if (routeName === 'OnboardingView' || routeName === 'NewServerView') {
|
||||||
KeyCommands.deleteKeyCommands([...defaultCommands, ...keyCommands]);
|
KeyCommands.deleteKeyCommands([...defaultCommands, ...keyCommands]);
|
||||||
setState({ inside: false, showModal: false });
|
setState({ inside: false, showModal: false });
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,18 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Text, ScrollView } from 'react-native';
|
import { Text } from 'react-native';
|
||||||
import { SafeAreaView } from 'react-navigation';
|
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import KeyboardView from '../presentation/KeyboardView';
|
|
||||||
import TextInput from '../containers/TextInput';
|
import TextInput from '../containers/TextInput';
|
||||||
import Button from '../containers/Button';
|
import Button from '../containers/Button';
|
||||||
import sharedStyles from './Styles';
|
import sharedStyles from './Styles';
|
||||||
import { showErrorAlert } from '../utils/info';
|
import { showErrorAlert } from '../utils/info';
|
||||||
import isValidEmail from '../utils/isValidEmail';
|
import isValidEmail from '../utils/isValidEmail';
|
||||||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
|
||||||
import I18n from '../i18n';
|
import I18n from '../i18n';
|
||||||
import RocketChat from '../lib/rocketchat';
|
import RocketChat from '../lib/rocketchat';
|
||||||
import StatusBar from '../containers/StatusBar';
|
|
||||||
import { withTheme } from '../theme';
|
import { withTheme } from '../theme';
|
||||||
import { themes } from '../constants/colors';
|
import { themes } from '../constants/colors';
|
||||||
import { themedHeader } from '../utils/navigation';
|
import { themedHeader } from '../utils/navigation';
|
||||||
|
import FormContainer, { FormContainerInner } from '../containers/FormContainer';
|
||||||
|
|
||||||
class ForgotPasswordView extends React.Component {
|
class ForgotPasswordView extends React.Component {
|
||||||
static navigationOptions = ({ navigation, screenProps }) => {
|
static navigationOptions = ({ navigation, screenProps }) => {
|
||||||
|
@ -88,39 +85,31 @@ class ForgotPasswordView extends React.Component {
|
||||||
const { theme } = this.props;
|
const { theme } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<KeyboardView
|
<FormContainer theme={theme}>
|
||||||
style={{ backgroundColor: themes[theme].backgroundColor }}
|
<FormContainerInner>
|
||||||
contentContainerStyle={sharedStyles.container}
|
<Text style={[sharedStyles.loginTitle, sharedStyles.textBold, { color: themes[theme].titleText }]}>{I18n.t('Forgot_password')}</Text>
|
||||||
keyboardVerticalOffset={128}
|
<TextInput
|
||||||
>
|
autoFocus
|
||||||
<StatusBar theme={theme} />
|
placeholder={I18n.t('Email')}
|
||||||
<ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}>
|
keyboardType='email-address'
|
||||||
<SafeAreaView style={sharedStyles.container} testID='forgot-password-view' forceInset={{ vertical: 'never' }}>
|
returnKeyType='send'
|
||||||
<Text style={[sharedStyles.loginTitle, sharedStyles.textBold, { color: themes[theme].titleText }]}>{I18n.t('Forgot_password')}</Text>
|
onChangeText={email => this.validate(email)}
|
||||||
<TextInput
|
onSubmitEditing={this.resetPassword}
|
||||||
autoFocus
|
testID='forgot-password-view-email'
|
||||||
placeholder={I18n.t('Email')}
|
containerStyle={sharedStyles.inputLastChild}
|
||||||
keyboardType='email-address'
|
theme={theme}
|
||||||
iconLeft='mail'
|
/>
|
||||||
returnKeyType='send'
|
<Button
|
||||||
onChangeText={email => this.validate(email)}
|
title={I18n.t('Reset_password')}
|
||||||
onSubmitEditing={this.resetPassword}
|
type='primary'
|
||||||
testID='forgot-password-view-email'
|
onPress={this.resetPassword}
|
||||||
containerStyle={sharedStyles.inputLastChild}
|
testID='forgot-password-view-submit'
|
||||||
theme={theme}
|
loading={isFetching}
|
||||||
/>
|
disabled={invalidEmail}
|
||||||
<Button
|
theme={theme}
|
||||||
title={I18n.t('Reset_password')}
|
/>
|
||||||
type='primary'
|
</FormContainerInner>
|
||||||
onPress={this.resetPassword}
|
</FormContainer>
|
||||||
testID='forgot-password-view-submit'
|
|
||||||
loading={isFetching}
|
|
||||||
disabled={invalidEmail}
|
|
||||||
theme={theme}
|
|
||||||
/>
|
|
||||||
</SafeAreaView>
|
|
||||||
</ScrollView>
|
|
||||||
</KeyboardView>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,50 +1,53 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import {
|
import {
|
||||||
Keyboard, Text, ScrollView, View, StyleSheet, Alert
|
Text, View, StyleSheet, Keyboard, Alert
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { SafeAreaView } from 'react-navigation';
|
|
||||||
import equal from 'deep-equal';
|
import equal from 'deep-equal';
|
||||||
import { analytics } from '../utils/log';
|
|
||||||
|
|
||||||
import KeyboardView from '../presentation/KeyboardView';
|
import { analytics } from '../utils/log';
|
||||||
import TextInput from '../containers/TextInput';
|
|
||||||
import Button from '../containers/Button';
|
|
||||||
import sharedStyles from './Styles';
|
import sharedStyles from './Styles';
|
||||||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
import Button from '../containers/Button';
|
||||||
import I18n from '../i18n';
|
import I18n from '../i18n';
|
||||||
import { loginRequest as loginRequestAction } from '../actions/login';
|
|
||||||
import { LegalButton } from '../containers/HeaderButton';
|
import { LegalButton } from '../containers/HeaderButton';
|
||||||
import StatusBar from '../containers/StatusBar';
|
|
||||||
import { themes } from '../constants/colors';
|
import { themes } from '../constants/colors';
|
||||||
import { animateNextTransition } from '../utils/layoutAnimation';
|
|
||||||
import { withTheme } from '../theme';
|
import { withTheme } from '../theme';
|
||||||
import { themedHeader } from '../utils/navigation';
|
import { themedHeader } from '../utils/navigation';
|
||||||
import { isTablet } from '../utils/deviceInfo';
|
import FormContainer, { FormContainerInner } from '../containers/FormContainer';
|
||||||
|
import TextInput from '../containers/TextInput';
|
||||||
|
import { animateNextTransition } from '../utils/layoutAnimation';
|
||||||
|
import { loginRequest as loginRequestAction } from '../actions/login';
|
||||||
|
import LoginServices from '../containers/LoginServices';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
bottomContainer: {
|
|
||||||
flexDirection: 'column',
|
|
||||||
alignItems: 'center',
|
|
||||||
marginTop: 10
|
|
||||||
},
|
|
||||||
registerDisabled: {
|
registerDisabled: {
|
||||||
...sharedStyles.textRegular,
|
...sharedStyles.textRegular,
|
||||||
...sharedStyles.textAlignCenter,
|
...sharedStyles.textAlignCenter,
|
||||||
fontSize: 13
|
fontSize: 16
|
||||||
},
|
},
|
||||||
dontHaveAccount: {
|
title: {
|
||||||
|
...sharedStyles.textBold,
|
||||||
|
fontSize: 22
|
||||||
|
},
|
||||||
|
inputContainer: {
|
||||||
|
marginVertical: 16
|
||||||
|
},
|
||||||
|
bottomContainer: {
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginBottom: 32
|
||||||
|
},
|
||||||
|
bottomContainerText: {
|
||||||
...sharedStyles.textRegular,
|
...sharedStyles.textRegular,
|
||||||
fontSize: 13
|
fontSize: 13
|
||||||
},
|
},
|
||||||
createAccount: {
|
bottomContainerTextBold: {
|
||||||
...sharedStyles.textSemibold,
|
...sharedStyles.textSemibold,
|
||||||
fontSize: 13
|
fontSize: 13
|
||||||
},
|
},
|
||||||
loginTitle: {
|
loginButton: {
|
||||||
marginVertical: 0,
|
marginTop: 16
|
||||||
marginTop: 15
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -52,29 +55,26 @@ class LoginView extends React.Component {
|
||||||
static navigationOptions = ({ navigation, screenProps }) => {
|
static navigationOptions = ({ navigation, screenProps }) => {
|
||||||
const title = navigation.getParam('title', 'Rocket.Chat');
|
const title = navigation.getParam('title', 'Rocket.Chat');
|
||||||
return {
|
return {
|
||||||
|
...themedHeader(screenProps.theme),
|
||||||
title,
|
title,
|
||||||
headerRight: <LegalButton navigation={navigation} testID='login-view-more' />,
|
headerRight: <LegalButton testID='login-view-more' navigation={navigation} />
|
||||||
...themedHeader(screenProps.theme)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
navigation: PropTypes.object,
|
navigation: PropTypes.object,
|
||||||
loginRequest: PropTypes.func.isRequired,
|
|
||||||
error: PropTypes.object,
|
|
||||||
Site_Name: PropTypes.string,
|
Site_Name: PropTypes.string,
|
||||||
|
Accounts_RegistrationForm: PropTypes.string,
|
||||||
|
Accounts_RegistrationForm_LinkReplacementText: PropTypes.string,
|
||||||
Accounts_EmailOrUsernamePlaceholder: PropTypes.string,
|
Accounts_EmailOrUsernamePlaceholder: PropTypes.string,
|
||||||
Accounts_PasswordPlaceholder: PropTypes.string,
|
Accounts_PasswordPlaceholder: PropTypes.string,
|
||||||
Accounts_PasswordReset: PropTypes.bool,
|
Accounts_PasswordReset: PropTypes.bool,
|
||||||
Accounts_RegistrationForm: PropTypes.string,
|
Accounts_ShowFormLogin: PropTypes.bool,
|
||||||
Accounts_RegistrationForm_LinkReplacementText: PropTypes.string,
|
|
||||||
isFetching: PropTypes.bool,
|
isFetching: PropTypes.bool,
|
||||||
|
error: PropTypes.object,
|
||||||
failure: PropTypes.bool,
|
failure: PropTypes.bool,
|
||||||
theme: PropTypes.string
|
theme: PropTypes.string,
|
||||||
}
|
loginRequest: PropTypes.func
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
Accounts_PasswordReset: true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -85,15 +85,11 @@ class LoginView extends React.Component {
|
||||||
code: '',
|
code: '',
|
||||||
showTOTP: false
|
showTOTP: false
|
||||||
};
|
};
|
||||||
const { Site_Name } = this.props;
|
|
||||||
this.setTitle(Site_Name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
const { Site_Name, error } = this.props;
|
const { error } = this.props;
|
||||||
if (nextProps.Site_Name && nextProps.Site_Name !== Site_Name) {
|
if (nextProps.failure && !equal(error, nextProps.error)) {
|
||||||
this.setTitle(nextProps.Site_Name);
|
|
||||||
} else if (nextProps.failure && !equal(error, nextProps.error)) {
|
|
||||||
if (nextProps.error && nextProps.error.error === 'totp-required') {
|
if (nextProps.error && nextProps.error.error === 'totp-required') {
|
||||||
animateNextTransition();
|
animateNextTransition();
|
||||||
this.setState({ showTOTP: true });
|
this.setState({ showTOTP: true });
|
||||||
|
@ -103,58 +99,19 @@ class LoginView extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
login = () => {
|
||||||
const {
|
const { navigation, Site_Name } = this.props;
|
||||||
user, password, code, showTOTP
|
navigation.navigate('LoginView', { title: Site_Name });
|
||||||
} = this.state;
|
|
||||||
const {
|
|
||||||
isFetching, failure, error, Site_Name, Accounts_EmailOrUsernamePlaceholder, Accounts_PasswordPlaceholder, Accounts_RegistrationForm, Accounts_RegistrationForm_LinkReplacementText, theme
|
|
||||||
} = this.props;
|
|
||||||
if (nextState.user !== user) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (nextState.password !== password) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (nextState.code !== code) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (nextState.showTOTP !== showTOTP) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (nextProps.isFetching !== isFetching) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (nextProps.failure !== failure) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (nextProps.theme !== theme) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (nextProps.Site_Name !== Site_Name) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (nextProps.Accounts_EmailOrUsernamePlaceholder !== Accounts_EmailOrUsernamePlaceholder) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (nextProps.Accounts_PasswordPlaceholder !== Accounts_PasswordPlaceholder) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (nextProps.Accounts_RegistrationForm !== Accounts_RegistrationForm) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (nextProps.Accounts_RegistrationForm_LinkReplacementText !== Accounts_RegistrationForm_LinkReplacementText) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!equal(nextProps.error, error)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setTitle = (title) => {
|
register = () => {
|
||||||
const { navigation } = this.props;
|
const { navigation, Site_Name } = this.props;
|
||||||
navigation.setParams({ title });
|
navigation.navigate('RegisterView', { title: Site_Name });
|
||||||
|
}
|
||||||
|
|
||||||
|
forgotPassword = () => {
|
||||||
|
const { navigation, Site_Name } = this.props;
|
||||||
|
navigation.navigate('ForgotPasswordView', { title: Site_Name });
|
||||||
}
|
}
|
||||||
|
|
||||||
valid = () => {
|
valid = () => {
|
||||||
|
@ -179,33 +136,86 @@ class LoginView extends React.Component {
|
||||||
analytics().logEvent('login');
|
analytics().logEvent('login');
|
||||||
}
|
}
|
||||||
|
|
||||||
register = () => {
|
renderUserForm = () => {
|
||||||
const { navigation, Site_Name } = this.props;
|
const {
|
||||||
navigation.navigate('RegisterView', { title: Site_Name });
|
Accounts_EmailOrUsernamePlaceholder, Accounts_PasswordPlaceholder, Accounts_PasswordReset, Accounts_RegistrationForm, Accounts_RegistrationForm_LinkReplacementText, isFetching, theme, Accounts_ShowFormLogin
|
||||||
}
|
} = this.props;
|
||||||
|
|
||||||
forgotPassword = () => {
|
if (!Accounts_ShowFormLogin) {
|
||||||
const { navigation, Site_Name } = this.props;
|
return null;
|
||||||
navigation.navigate('ForgotPasswordView', { title: Site_Name });
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Text style={[styles.title, sharedStyles.textBold, { color: themes[theme].titleText }]}>{I18n.t('Login')}</Text>
|
||||||
|
<TextInput
|
||||||
|
label='Email or username'
|
||||||
|
containerStyle={styles.inputContainer}
|
||||||
|
placeholder={Accounts_EmailOrUsernamePlaceholder || I18n.t('Username_or_email')}
|
||||||
|
keyboardType='email-address'
|
||||||
|
returnKeyType='next'
|
||||||
|
onChangeText={value => this.setState({ user: value })}
|
||||||
|
onSubmitEditing={() => { this.passwordInput.focus(); }}
|
||||||
|
testID='login-view-email'
|
||||||
|
textContentType='username'
|
||||||
|
autoCompleteType='username'
|
||||||
|
theme={theme}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
label='Password'
|
||||||
|
containerStyle={styles.inputContainer}
|
||||||
|
inputRef={(e) => { this.passwordInput = e; }}
|
||||||
|
placeholder={Accounts_PasswordPlaceholder || I18n.t('Password')}
|
||||||
|
returnKeyType='send'
|
||||||
|
secureTextEntry
|
||||||
|
onSubmitEditing={this.submit}
|
||||||
|
onChangeText={value => this.setState({ password: value })}
|
||||||
|
testID='login-view-password'
|
||||||
|
textContentType='password'
|
||||||
|
autoCompleteType='password'
|
||||||
|
theme={theme}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
title={I18n.t('Login')}
|
||||||
|
type='primary'
|
||||||
|
onPress={this.submit}
|
||||||
|
testID='login-view-submit'
|
||||||
|
loading={isFetching}
|
||||||
|
disabled={!this.valid()}
|
||||||
|
theme={theme}
|
||||||
|
style={styles.loginButton}
|
||||||
|
/>
|
||||||
|
{Accounts_PasswordReset && (
|
||||||
|
<Button
|
||||||
|
title={I18n.t('Forgot_password')}
|
||||||
|
type='secondary'
|
||||||
|
onPress={this.forgotPassword}
|
||||||
|
testID='login-view-forgot-password'
|
||||||
|
theme={theme}
|
||||||
|
color={themes[theme].auxiliaryText}
|
||||||
|
fontSize={14}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{Accounts_RegistrationForm === 'Public' ? (
|
||||||
|
<View style={styles.bottomContainer}>
|
||||||
|
<Text style={[styles.bottomContainerText, { color: themes[theme].auxiliaryText }]}>{I18n.t('Dont_Have_An_Account')}</Text>
|
||||||
|
<Text
|
||||||
|
style={[styles.bottomContainerTextBold, { color: themes[theme].actionTintColor }]}
|
||||||
|
onPress={this.register}
|
||||||
|
testID='login-view-register'
|
||||||
|
>{I18n.t('Create_account')}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
) : (<Text style={[styles.registerDisabled, { color: themes[theme].auxiliaryText }]}>{Accounts_RegistrationForm_LinkReplacementText}</Text>)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderTOTP = () => {
|
renderTOTP = () => {
|
||||||
const { isFetching, theme } = this.props;
|
const { isFetching, theme } = this.props;
|
||||||
return (
|
return (
|
||||||
<SafeAreaView
|
<>
|
||||||
style={[
|
<Text style={[styles.title, sharedStyles.textBold, { color: themes[theme].titleText }]}>{I18n.t('Two_Factor_Authentication')}</Text>
|
||||||
sharedStyles.container,
|
|
||||||
isTablet && sharedStyles.tabletScreenContent,
|
|
||||||
{ backgroundColor: themes[theme].backgroundColor }
|
|
||||||
]}
|
|
||||||
testID='login-view'
|
|
||||||
forceInset={{ vertical: 'never' }}
|
|
||||||
>
|
|
||||||
<Text
|
|
||||||
style={[sharedStyles.loginTitle, sharedStyles.textBold, styles.loginTitle, { color: themes[theme].titleText }]}
|
|
||||||
>
|
|
||||||
{I18n.t('Two_Factor_Authentication')}
|
|
||||||
</Text>
|
|
||||||
<Text
|
<Text
|
||||||
style={[sharedStyles.loginSubtitle, sharedStyles.textRegular, { color: themes[theme].titleText }]}
|
style={[sharedStyles.loginSubtitle, sharedStyles.textRegular, { color: themes[theme].titleText }]}
|
||||||
>
|
>
|
||||||
|
@ -232,114 +242,36 @@ class LoginView extends React.Component {
|
||||||
disabled={!this.valid()}
|
disabled={!this.valid()}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
/>
|
/>
|
||||||
</SafeAreaView>
|
</>
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderUserForm = () => {
|
|
||||||
const {
|
|
||||||
Accounts_EmailOrUsernamePlaceholder, Accounts_PasswordPlaceholder, Accounts_PasswordReset, Accounts_RegistrationForm, Accounts_RegistrationForm_LinkReplacementText, isFetching, theme
|
|
||||||
} = this.props;
|
|
||||||
return (
|
|
||||||
<SafeAreaView
|
|
||||||
style={[
|
|
||||||
sharedStyles.container,
|
|
||||||
isTablet && sharedStyles.tabletScreenContent,
|
|
||||||
{ backgroundColor: themes[theme].backgroundColor }
|
|
||||||
]}
|
|
||||||
testID='login-view'
|
|
||||||
forceInset={{ vertical: 'never' }}
|
|
||||||
>
|
|
||||||
<Text style={[sharedStyles.loginTitle, sharedStyles.textBold, { color: themes[theme].titleText }]}>{I18n.t('Login')}</Text>
|
|
||||||
<TextInput
|
|
||||||
autoFocus
|
|
||||||
placeholder={Accounts_EmailOrUsernamePlaceholder || I18n.t('Username_or_email')}
|
|
||||||
keyboardType='email-address'
|
|
||||||
returnKeyType='next'
|
|
||||||
iconLeft='at'
|
|
||||||
onChangeText={value => this.setState({ user: value })}
|
|
||||||
onSubmitEditing={() => { this.passwordInput.focus(); }}
|
|
||||||
testID='login-view-email'
|
|
||||||
textContentType='username'
|
|
||||||
autoCompleteType='username'
|
|
||||||
theme={theme}
|
|
||||||
/>
|
|
||||||
<TextInput
|
|
||||||
inputRef={(e) => { this.passwordInput = e; }}
|
|
||||||
placeholder={Accounts_PasswordPlaceholder || I18n.t('Password')}
|
|
||||||
returnKeyType='send'
|
|
||||||
iconLeft='key'
|
|
||||||
secureTextEntry
|
|
||||||
onSubmitEditing={this.submit}
|
|
||||||
onChangeText={value => this.setState({ password: value })}
|
|
||||||
testID='login-view-password'
|
|
||||||
containerStyle={sharedStyles.inputLastChild}
|
|
||||||
textContentType='password'
|
|
||||||
autoCompleteType='password'
|
|
||||||
theme={theme}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
title={I18n.t('Login')}
|
|
||||||
type='primary'
|
|
||||||
onPress={this.submit}
|
|
||||||
testID='login-view-submit'
|
|
||||||
loading={isFetching}
|
|
||||||
disabled={!this.valid()}
|
|
||||||
theme={theme}
|
|
||||||
/>
|
|
||||||
{Accounts_PasswordReset && (
|
|
||||||
<Button
|
|
||||||
title={I18n.t('Forgot_password')}
|
|
||||||
type='secondary'
|
|
||||||
onPress={this.forgotPassword}
|
|
||||||
testID='login-view-forgot-password'
|
|
||||||
theme={theme}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{Accounts_RegistrationForm === 'Public' ? (
|
|
||||||
<View style={styles.bottomContainer}>
|
|
||||||
<Text style={[styles.dontHaveAccount, { color: themes[theme].auxiliaryText }]}>{I18n.t('Dont_Have_An_Account')}</Text>
|
|
||||||
<Text
|
|
||||||
style={[styles.createAccount, { color: themes[theme].actionTintColor }]}
|
|
||||||
onPress={this.register}
|
|
||||||
testID='login-view-register'
|
|
||||||
>{I18n.t('Create_account')}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
) : (<Text style={[styles.registerDisabled, { color: themes[theme].auxiliaryText }]}>{Accounts_RegistrationForm_LinkReplacementText}</Text>)}
|
|
||||||
</SafeAreaView>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { showTOTP } = this.state;
|
const { showTOTP } = this.state;
|
||||||
const { theme } = this.props;
|
const { Accounts_ShowFormLogin, theme } = this.props;
|
||||||
return (
|
return (
|
||||||
<KeyboardView
|
<FormContainer theme={theme}>
|
||||||
style={{ backgroundColor: themes[theme].backgroundColor }}
|
<FormContainerInner>
|
||||||
contentContainerStyle={sharedStyles.container}
|
{!showTOTP ? <LoginServices separator={Accounts_ShowFormLogin} /> : null}
|
||||||
keyboardVerticalOffset={128}
|
|
||||||
key='login-view'
|
|
||||||
>
|
|
||||||
<StatusBar theme={theme} />
|
|
||||||
<ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}>
|
|
||||||
{!showTOTP ? this.renderUserForm() : null}
|
{!showTOTP ? this.renderUserForm() : null}
|
||||||
{showTOTP ? this.renderTOTP() : null}
|
{showTOTP ? this.renderTOTP() : null}
|
||||||
</ScrollView>
|
</FormContainerInner>
|
||||||
</KeyboardView>
|
</FormContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
|
server: state.server.server,
|
||||||
|
Site_Name: state.settings.Site_Name,
|
||||||
|
Accounts_ShowFormLogin: state.settings.Accounts_ShowFormLogin,
|
||||||
|
Accounts_RegistrationForm: state.settings.Accounts_RegistrationForm,
|
||||||
|
Accounts_RegistrationForm_LinkReplacementText: state.settings.Accounts_RegistrationForm_LinkReplacementText,
|
||||||
isFetching: state.login.isFetching,
|
isFetching: state.login.isFetching,
|
||||||
failure: state.login.failure,
|
failure: state.login.failure,
|
||||||
error: state.login.error && state.login.error.data,
|
error: state.login.error && state.login.error.data,
|
||||||
Site_Name: state.settings.Site_Name,
|
|
||||||
Accounts_EmailOrUsernamePlaceholder: state.settings.Accounts_EmailOrUsernamePlaceholder,
|
Accounts_EmailOrUsernamePlaceholder: state.settings.Accounts_EmailOrUsernamePlaceholder,
|
||||||
Accounts_PasswordPlaceholder: state.settings.Accounts_PasswordPlaceholder,
|
Accounts_PasswordPlaceholder: state.settings.Accounts_PasswordPlaceholder,
|
||||||
Accounts_RegistrationForm: state.settings.Accounts_RegistrationForm,
|
|
||||||
Accounts_RegistrationForm_LinkReplacementText: state.settings.Accounts_RegistrationForm_LinkReplacementText,
|
|
||||||
Accounts_PasswordReset: state.settings.Accounts_PasswordReset
|
Accounts_PasswordReset: state.settings.Accounts_PasswordReset
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,91 +1,95 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import {
|
import {
|
||||||
Text, ScrollView, Keyboard, Image, StyleSheet, TouchableOpacity, View, Alert
|
Text, Keyboard, StyleSheet, TouchableOpacity, View, Alert
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { SafeAreaView } from 'react-navigation';
|
|
||||||
import * as FileSystem from 'expo-file-system';
|
import * as FileSystem from 'expo-file-system';
|
||||||
import DocumentPicker from 'react-native-document-picker';
|
import DocumentPicker from 'react-native-document-picker';
|
||||||
import ActionSheet from 'react-native-action-sheet';
|
import ActionSheet from 'react-native-action-sheet';
|
||||||
import isEqual from 'deep-equal';
|
|
||||||
import RNUserDefaults from 'rn-user-defaults';
|
import RNUserDefaults from 'rn-user-defaults';
|
||||||
import { encode } from 'base-64';
|
import { encode } from 'base-64';
|
||||||
import parse from 'url-parse';
|
import parse from 'url-parse';
|
||||||
|
|
||||||
import { serverRequest } from '../actions/server';
|
import EventEmitter from '../utils/events';
|
||||||
|
import {
|
||||||
|
selectServerRequest, serverRequest, serverInitAdd, serverFinishAdd
|
||||||
|
} from '../actions/server';
|
||||||
|
import { appStart as appStartAction } from '../actions';
|
||||||
import sharedStyles from './Styles';
|
import sharedStyles from './Styles';
|
||||||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
|
||||||
import Button from '../containers/Button';
|
import Button from '../containers/Button';
|
||||||
import TextInput from '../containers/TextInput';
|
import TextInput from '../containers/TextInput';
|
||||||
|
import OnboardingSeparator from '../containers/OnboardingSeparator';
|
||||||
|
import FormContainer, { FormContainerInner } from '../containers/FormContainer';
|
||||||
import I18n from '../i18n';
|
import I18n from '../i18n';
|
||||||
import { verticalScale, moderateScale } from '../utils/scaling';
|
import { isIOS } from '../utils/deviceInfo';
|
||||||
import KeyboardView from '../presentation/KeyboardView';
|
|
||||||
import { isIOS, isNotch, isTablet } from '../utils/deviceInfo';
|
|
||||||
import { CustomIcon } from '../lib/Icons';
|
|
||||||
import StatusBar from '../containers/StatusBar';
|
|
||||||
import { themes } from '../constants/colors';
|
import { themes } from '../constants/colors';
|
||||||
import log from '../utils/log';
|
import log from '../utils/log';
|
||||||
import { animateNextTransition } from '../utils/layoutAnimation';
|
import { animateNextTransition } from '../utils/layoutAnimation';
|
||||||
import { withTheme } from '../theme';
|
import { withTheme } from '../theme';
|
||||||
import { setBasicAuth, BASIC_AUTH_KEY } from '../utils/fetch';
|
import { setBasicAuth, BASIC_AUTH_KEY } from '../utils/fetch';
|
||||||
|
import { themedHeader } from '../utils/navigation';
|
||||||
|
import { CloseModalButton } from '../containers/HeaderButton';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
image: {
|
|
||||||
alignSelf: 'center',
|
|
||||||
marginVertical: verticalScale(20),
|
|
||||||
width: 210,
|
|
||||||
height: 171
|
|
||||||
},
|
|
||||||
title: {
|
title: {
|
||||||
...sharedStyles.textBold,
|
...sharedStyles.textBold,
|
||||||
fontSize: moderateScale(22),
|
fontSize: 22
|
||||||
letterSpacing: 0,
|
|
||||||
alignSelf: 'center'
|
|
||||||
},
|
},
|
||||||
inputContainer: {
|
inputContainer: {
|
||||||
marginTop: 25,
|
marginTop: 24,
|
||||||
marginBottom: 15
|
marginBottom: 32
|
||||||
},
|
|
||||||
backButton: {
|
|
||||||
position: 'absolute',
|
|
||||||
paddingHorizontal: 9,
|
|
||||||
left: 15
|
|
||||||
},
|
},
|
||||||
certificatePicker: {
|
certificatePicker: {
|
||||||
flex: 1,
|
marginBottom: 32,
|
||||||
marginTop: 40,
|
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center'
|
justifyContent: 'flex-end'
|
||||||
},
|
},
|
||||||
chooseCertificateTitle: {
|
chooseCertificateTitle: {
|
||||||
fontSize: 15,
|
fontSize: 13,
|
||||||
...sharedStyles.textRegular
|
...sharedStyles.textRegular
|
||||||
},
|
},
|
||||||
chooseCertificate: {
|
chooseCertificate: {
|
||||||
fontSize: 15,
|
fontSize: 13,
|
||||||
...sharedStyles.textSemibold
|
...sharedStyles.textSemibold
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
...sharedStyles.textRegular,
|
||||||
|
fontSize: 14,
|
||||||
|
textAlign: 'left',
|
||||||
|
marginBottom: 24
|
||||||
|
},
|
||||||
|
connectButton: {
|
||||||
|
marginBottom: 0
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const defaultServer = 'https://open.rocket.chat';
|
|
||||||
|
|
||||||
class NewServerView extends React.Component {
|
class NewServerView extends React.Component {
|
||||||
static navigationOptions = () => ({
|
static navigationOptions = ({ screenProps, navigation }) => {
|
||||||
header: null
|
const previousServer = navigation.getParam('previousServer', null);
|
||||||
})
|
const close = navigation.getParam('close', () => {});
|
||||||
|
return {
|
||||||
|
headerLeft: previousServer ? <CloseModalButton navigation={navigation} onPress={close} /> : undefined,
|
||||||
|
title: I18n.t('Workspaces'),
|
||||||
|
...themedHeader(screenProps.theme)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
navigation: PropTypes.object,
|
navigation: PropTypes.object,
|
||||||
server: PropTypes.string,
|
|
||||||
theme: PropTypes.string,
|
theme: PropTypes.string,
|
||||||
connecting: PropTypes.bool.isRequired,
|
connecting: PropTypes.bool.isRequired,
|
||||||
connectServer: PropTypes.func.isRequired
|
connectServer: PropTypes.func.isRequired,
|
||||||
|
selectServer: PropTypes.func.isRequired,
|
||||||
|
currentServer: PropTypes.string,
|
||||||
|
initAdd: PropTypes.func,
|
||||||
|
finishAdd: PropTypes.func
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
const server = props.navigation.getParam('server');
|
this.previousServer = props.navigation.getParam('previousServer');
|
||||||
|
props.navigation.setParams({ close: this.close, previousServer: this.previousServer });
|
||||||
|
|
||||||
// Cancel
|
// Cancel
|
||||||
this.options = [I18n.t('Cancel')];
|
this.options = [I18n.t('Cancel')];
|
||||||
|
@ -96,47 +100,51 @@ class NewServerView extends React.Component {
|
||||||
this.DELETE_INDEX = 1;
|
this.DELETE_INDEX = 1;
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
text: server || '',
|
text: '',
|
||||||
autoFocus: !server,
|
connectingOpen: false,
|
||||||
certificate: null
|
certificate: null
|
||||||
};
|
};
|
||||||
|
EventEmitter.addEventListener('NewServer', this.handleNewServerEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { text } = this.state;
|
const { initAdd } = this.props;
|
||||||
const { connectServer } = this.props;
|
if (this.previousServer) {
|
||||||
if (text) {
|
initAdd();
|
||||||
connectServer(text);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
componentWillUnmount() {
|
||||||
const { text, certificate } = this.state;
|
EventEmitter.removeListener('NewServer', this.handleNewServerEvent);
|
||||||
const { connecting, theme } = this.props;
|
|
||||||
if (nextState.text !== text) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!isEqual(nextState.certificate, certificate)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (nextProps.connecting !== connecting) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (nextProps.theme !== theme) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onChangeText = (text) => {
|
onChangeText = (text) => {
|
||||||
this.setState({ text });
|
this.setState({ text });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
close = () => {
|
||||||
|
const { selectServer, currentServer, finishAdd } = this.props;
|
||||||
|
if (this.previousServer !== currentServer) {
|
||||||
|
selectServer(this.previousServer);
|
||||||
|
}
|
||||||
|
finishAdd();
|
||||||
|
}
|
||||||
|
|
||||||
|
handleNewServerEvent = (event) => {
|
||||||
|
let { server } = event;
|
||||||
|
const { connectServer } = this.props;
|
||||||
|
this.setState({ text: server });
|
||||||
|
server = this.completeUrl(server);
|
||||||
|
connectServer(server);
|
||||||
|
}
|
||||||
|
|
||||||
submit = async() => {
|
submit = async() => {
|
||||||
const { text, certificate } = this.state;
|
const { text, certificate } = this.state;
|
||||||
const { connectServer } = this.props;
|
const { connectServer } = this.props;
|
||||||
let cert = null;
|
let cert = null;
|
||||||
|
|
||||||
|
this.setState({ connectingOpen: false });
|
||||||
|
|
||||||
if (certificate) {
|
if (certificate) {
|
||||||
const certificatePath = `${ FileSystem.documentDirectory }/${ certificate.name }`;
|
const certificatePath = `${ FileSystem.documentDirectory }/${ certificate.name }`;
|
||||||
try {
|
try {
|
||||||
|
@ -158,6 +166,12 @@ class NewServerView extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connectOpen = () => {
|
||||||
|
this.setState({ connectingOpen: true });
|
||||||
|
const { connectServer } = this.props;
|
||||||
|
connectServer('https://open.rocket.chat');
|
||||||
|
}
|
||||||
|
|
||||||
basicAuth = async(server, text) => {
|
basicAuth = async(server, text) => {
|
||||||
try {
|
try {
|
||||||
const parsedUrl = parse(text, true);
|
const parsedUrl = parse(text, true);
|
||||||
|
@ -238,28 +252,6 @@ class NewServerView extends React.Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderBack = () => {
|
|
||||||
const { navigation, theme } = this.props;
|
|
||||||
|
|
||||||
let top = 15;
|
|
||||||
if (isIOS) {
|
|
||||||
top = isNotch ? 45 : 30;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TouchableOpacity
|
|
||||||
style={[styles.backButton, { top }]}
|
|
||||||
onPress={() => navigation.pop()}
|
|
||||||
>
|
|
||||||
<CustomIcon
|
|
||||||
name='back'
|
|
||||||
size={30}
|
|
||||||
color={themes[theme].tintColor}
|
|
||||||
/>
|
|
||||||
</TouchableOpacity>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderCertificatePicker = () => {
|
renderCertificatePicker = () => {
|
||||||
const { certificate } = this.state;
|
const { certificate } = this.state;
|
||||||
const { theme } = this.props;
|
const { theme } = this.props;
|
||||||
|
@ -292,49 +284,49 @@ class NewServerView extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { connecting, theme } = this.props;
|
const { connecting, theme } = this.props;
|
||||||
const { text, autoFocus } = this.state;
|
const { text, connectingOpen } = this.state;
|
||||||
return (
|
return (
|
||||||
<KeyboardView
|
<FormContainer theme={theme}>
|
||||||
style={{ backgroundColor: themes[theme].backgroundColor }}
|
<FormContainerInner>
|
||||||
contentContainerStyle={sharedStyles.container}
|
<Text style={[styles.title, { color: themes[theme].titleText }]}>{I18n.t('Join_your_workspace')}</Text>
|
||||||
keyboardVerticalOffset={128}
|
<TextInput
|
||||||
key='login-view'
|
label='Enter workspace URL'
|
||||||
>
|
placeholder='Ex. your-company.rocket.chat'
|
||||||
<StatusBar theme={theme} />
|
containerStyle={styles.inputContainer}
|
||||||
<ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}>
|
value={text}
|
||||||
<SafeAreaView style={sharedStyles.container} testID='new-server-view'>
|
returnKeyType='send'
|
||||||
<Image style={styles.image} source={{ uri: 'new_server' }} />
|
onChangeText={this.onChangeText}
|
||||||
<Text style={[styles.title, { color: themes[theme].titleText }]}>{I18n.t('Sign_in_your_server')}</Text>
|
testID='new-server-view-input'
|
||||||
<View style={isTablet && sharedStyles.tabletScreenContent}>
|
onSubmitEditing={this.submit}
|
||||||
<TextInput
|
clearButtonMode='while-editing'
|
||||||
autoFocus={autoFocus}
|
keyboardType='url'
|
||||||
containerStyle={styles.inputContainer}
|
textContentType='URL'
|
||||||
placeholder={defaultServer}
|
theme={theme}
|
||||||
value={text}
|
/>
|
||||||
returnKeyType='send'
|
<Button
|
||||||
onChangeText={this.onChangeText}
|
title={I18n.t('Connect')}
|
||||||
testID='new-server-view-input'
|
type='primary'
|
||||||
onSubmitEditing={this.submit}
|
onPress={this.submit}
|
||||||
clearButtonMode='while-editing'
|
disabled={!text || connecting}
|
||||||
keyboardType='url'
|
loading={!connectingOpen && connecting}
|
||||||
textContentType='URL'
|
style={styles.connectButton}
|
||||||
theme={theme}
|
testID='new-server-view-button'
|
||||||
/>
|
theme={theme}
|
||||||
<Button
|
/>
|
||||||
title={I18n.t('Connect')}
|
<OnboardingSeparator theme={theme} />
|
||||||
type='primary'
|
<Text style={[styles.description, { color: themes[theme].auxiliaryText }]}>{I18n.t('Onboarding_join_open_description')}</Text>
|
||||||
onPress={this.submit}
|
<Button
|
||||||
disabled={!text}
|
title={I18n.t('Join_our_open_workspace')}
|
||||||
loading={connecting}
|
type='secondary'
|
||||||
testID='new-server-view-button'
|
backgroundColor={themes[theme].chatComponentBackground}
|
||||||
theme={theme}
|
onPress={this.connectOpen}
|
||||||
/>
|
disabled={connecting}
|
||||||
{ isIOS ? this.renderCertificatePicker() : null }
|
loading={connectingOpen && connecting}
|
||||||
</View>
|
theme={theme}
|
||||||
</SafeAreaView>
|
/>
|
||||||
</ScrollView>
|
</FormContainerInner>
|
||||||
{this.renderBack()}
|
{ isIOS ? this.renderCertificatePicker() : null }
|
||||||
</KeyboardView>
|
</FormContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -344,7 +336,11 @@ const mapStateToProps = state => ({
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => ({
|
const mapDispatchToProps = dispatch => ({
|
||||||
connectServer: (server, certificate) => dispatch(serverRequest(server, certificate))
|
connectServer: (server, certificate) => dispatch(serverRequest(server, certificate)),
|
||||||
|
initAdd: () => dispatch(serverInitAdd()),
|
||||||
|
finishAdd: () => dispatch(serverFinishAdd()),
|
||||||
|
selectServer: server => dispatch(selectServerRequest(server)),
|
||||||
|
appStart: root => dispatch(appStartAction(root))
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(NewServerView));
|
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(NewServerView));
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { View, Text, TouchableWithoutFeedback } from 'react-native';
|
|
||||||
|
|
||||||
import styles from './styles';
|
|
||||||
import { themes } from '../../constants/colors';
|
|
||||||
import DisclosureIndicator from '../../containers/DisclosureIndicator';
|
|
||||||
|
|
||||||
export default class Button extends React.PureComponent {
|
|
||||||
static propTypes = {
|
|
||||||
title: PropTypes.string,
|
|
||||||
subtitle: PropTypes.string,
|
|
||||||
type: PropTypes.string,
|
|
||||||
theme: PropTypes.string,
|
|
||||||
icon: PropTypes.node.isRequired,
|
|
||||||
testID: PropTypes.string.isRequired,
|
|
||||||
onPress: PropTypes.func
|
|
||||||
}
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
title: 'Press me!',
|
|
||||||
type: 'primary',
|
|
||||||
onPress: () => alert('It works!')
|
|
||||||
}
|
|
||||||
|
|
||||||
state = {
|
|
||||||
active: false
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
title, subtitle, type, onPress, icon, testID, theme
|
|
||||||
} = this.props;
|
|
||||||
const { active } = this.state;
|
|
||||||
const activeStyle = active && styles.buttonActive;
|
|
||||||
const isPrimary = (type === 'primary');
|
|
||||||
const buttonContainerStyle = {
|
|
||||||
backgroundColor: isPrimary ? themes[theme].actionTintColor : themes[theme].focusedBackground,
|
|
||||||
borderColor: isPrimary ? themes[theme].actionTintColor : themes[theme].borderColor
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<TouchableWithoutFeedback
|
|
||||||
onPress={onPress}
|
|
||||||
onPressIn={() => this.setState({ active: true })}
|
|
||||||
onPressOut={() => this.setState({ active: false })}
|
|
||||||
testID={testID}
|
|
||||||
>
|
|
||||||
<View style={[styles.buttonContainer, buttonContainerStyle]}>
|
|
||||||
<View style={styles.buttonIconContainer}>
|
|
||||||
{icon}
|
|
||||||
</View>
|
|
||||||
<View style={styles.buttonCenter}>
|
|
||||||
<Text style={[styles.buttonTitle, { color: isPrimary ? themes[theme].buttonText : themes[theme].tintColor }, activeStyle]}>{title}</Text>
|
|
||||||
{subtitle ? <Text style={[styles.buttonSubtitle, activeStyle, { color: themes[theme].auxiliaryText }]}>{subtitle}</Text> : null}
|
|
||||||
</View>
|
|
||||||
{type === 'secondary' ? <DisclosureIndicator theme={theme} /> : null}
|
|
||||||
</View>
|
|
||||||
</TouchableWithoutFeedback>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +1,19 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {
|
import {
|
||||||
View, Text, Image, TouchableOpacity, BackHandler, Linking
|
View, Text, Image, BackHandler, Linking
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { SafeAreaView } from 'react-navigation';
|
|
||||||
import Orientation from 'react-native-orientation-locker';
|
import Orientation from 'react-native-orientation-locker';
|
||||||
|
|
||||||
import { selectServerRequest, serverInitAdd, serverFinishAdd } from '../../actions/server';
|
|
||||||
import { appStart as appStartAction } from '../../actions';
|
import { appStart as appStartAction } from '../../actions';
|
||||||
import I18n from '../../i18n';
|
import I18n from '../../i18n';
|
||||||
import Button from './Button';
|
import Button from '../../containers/Button';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
import { isIOS, isNotch, isTablet } from '../../utils/deviceInfo';
|
import { isTablet } from '../../utils/deviceInfo';
|
||||||
import EventEmitter from '../../utils/events';
|
|
||||||
import { CustomIcon } from '../../lib/Icons';
|
|
||||||
import StatusBar from '../../containers/StatusBar';
|
|
||||||
import { themes } from '../../constants/colors';
|
import { themes } from '../../constants/colors';
|
||||||
import { withTheme } from '../../theme';
|
import { withTheme } from '../../theme';
|
||||||
import sharedStyles from '../Styles';
|
import FormContainer, { FormContainerInner } from '../../containers/FormContainer';
|
||||||
|
|
||||||
class OnboardingView extends React.Component {
|
class OnboardingView extends React.Component {
|
||||||
static navigationOptions = () => ({
|
static navigationOptions = () => ({
|
||||||
|
@ -27,11 +22,6 @@ class OnboardingView extends React.Component {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
navigation: PropTypes.object,
|
navigation: PropTypes.object,
|
||||||
adding: PropTypes.bool,
|
|
||||||
selectServer: PropTypes.func.isRequired,
|
|
||||||
currentServer: PropTypes.string,
|
|
||||||
initAdd: PropTypes.func,
|
|
||||||
finishAdd: PropTypes.func,
|
|
||||||
appStart: PropTypes.func,
|
appStart: PropTypes.func,
|
||||||
theme: PropTypes.string
|
theme: PropTypes.string
|
||||||
}
|
}
|
||||||
|
@ -39,20 +29,11 @@ class OnboardingView extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
BackHandler.addEventListener('hardwareBackPress', this.handleBackPress);
|
BackHandler.addEventListener('hardwareBackPress', this.handleBackPress);
|
||||||
this.previousServer = props.navigation.getParam('previousServer');
|
|
||||||
if (!isTablet) {
|
if (!isTablet) {
|
||||||
Orientation.lockToPortrait();
|
Orientation.lockToPortrait();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
const { initAdd } = this.props;
|
|
||||||
if (this.previousServer) {
|
|
||||||
initAdd();
|
|
||||||
}
|
|
||||||
EventEmitter.addEventListener('NewServer', this.handleNewServerEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps) {
|
shouldComponentUpdate(nextProps) {
|
||||||
const { theme } = this.props;
|
const { theme } = this.props;
|
||||||
if (theme !== nextProps.theme) {
|
if (theme !== nextProps.theme) {
|
||||||
|
@ -62,16 +43,6 @@ class OnboardingView extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
const {
|
|
||||||
selectServer, currentServer, adding, finishAdd
|
|
||||||
} = this.props;
|
|
||||||
if (adding) {
|
|
||||||
if (this.previousServer !== currentServer) {
|
|
||||||
selectServer(this.previousServer);
|
|
||||||
}
|
|
||||||
finishAdd();
|
|
||||||
}
|
|
||||||
EventEmitter.removeListener('NewServer', this.handleNewServerEvent);
|
|
||||||
BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress);
|
BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,27 +52,9 @@ class OnboardingView extends React.Component {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
close = () => {
|
|
||||||
const { appStart } = this.props;
|
|
||||||
appStart('inside');
|
|
||||||
}
|
|
||||||
|
|
||||||
newServer = (server) => {
|
|
||||||
const { navigation } = this.props;
|
|
||||||
navigation.navigate('NewServerView', { server });
|
|
||||||
}
|
|
||||||
|
|
||||||
handleNewServerEvent = (event) => {
|
|
||||||
const { server } = event;
|
|
||||||
this.newServer(server);
|
|
||||||
}
|
|
||||||
|
|
||||||
connectServer = () => {
|
connectServer = () => {
|
||||||
this.newServer();
|
const { navigation } = this.props;
|
||||||
}
|
navigation.navigate('NewServerView');
|
||||||
|
|
||||||
joinCommunity = () => {
|
|
||||||
this.newServer('https://open.rocket.chat');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
createWorkspace = async() => {
|
createWorkspace = async() => {
|
||||||
|
@ -112,87 +65,38 @@ class OnboardingView extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderClose = () => {
|
|
||||||
const { theme } = this.props;
|
|
||||||
if (this.previousServer) {
|
|
||||||
let top = 15;
|
|
||||||
if (isIOS) {
|
|
||||||
top = isNotch ? 45 : 30;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<TouchableOpacity
|
|
||||||
style={[styles.closeModal, { top }]}
|
|
||||||
onPress={this.close}
|
|
||||||
testID='onboarding-close'
|
|
||||||
>
|
|
||||||
<CustomIcon
|
|
||||||
name='cross'
|
|
||||||
size={30}
|
|
||||||
color={themes[theme].actionTintColor}
|
|
||||||
/>
|
|
||||||
</TouchableOpacity>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { theme } = this.props;
|
const { theme } = this.props;
|
||||||
return (
|
return (
|
||||||
<SafeAreaView
|
<FormContainer theme={theme}>
|
||||||
style={[
|
<FormContainerInner>
|
||||||
styles.container,
|
<Image style={styles.onboarding} source={{ uri: 'logo' }} fadeDuration={0} />
|
||||||
{ backgroundColor: themes[theme].backgroundColor }
|
<Text style={[styles.title, { color: themes[theme].titleText }]}>{I18n.t('Onboarding_title')}</Text>
|
||||||
]}
|
<Text style={[styles.subtitle, { color: themes[theme].controlText }]}>{I18n.t('Onboarding_subtitle')}</Text>
|
||||||
testID='onboarding-view'
|
<Text style={[styles.description, { color: themes[theme].auxiliaryText }]}>{I18n.t('Onboarding_description')}</Text>
|
||||||
>
|
<View style={styles.buttonsContainer}>
|
||||||
<StatusBar theme={theme} />
|
<Button
|
||||||
<Image style={styles.onboarding} source={{ uri: 'onboarding' }} fadeDuration={0} />
|
title={I18n.t('Onboarding_join_workspace')}
|
||||||
<Text style={[styles.title, { color: themes[theme].titleText }]}>{I18n.t('Welcome_to_RocketChat')}</Text>
|
type='primary'
|
||||||
<Text style={[styles.subtitle, { color: themes[theme].auxiliaryText }]}>{I18n.t('Open_Source_Communication')}</Text>
|
onPress={this.connectServer}
|
||||||
<View style={[styles.buttonsContainer, isTablet && sharedStyles.tabletScreenContent]}>
|
theme={theme}
|
||||||
<Button
|
/>
|
||||||
type='secondary'
|
<Button
|
||||||
title={I18n.t('Connect_to_a_server')}
|
title={I18n.t('Create_a_new_workspace')}
|
||||||
icon={<CustomIcon name='permalink' size={30} color={themes[theme].actionTintColor} />}
|
type='secondary'
|
||||||
onPress={this.connectServer}
|
backgroundColor={themes[theme].chatComponentBackground}
|
||||||
testID='connect-server-button'
|
onPress={this.createWorkspace}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
/>
|
/>
|
||||||
<Button
|
</View>
|
||||||
type='secondary'
|
</FormContainerInner>
|
||||||
title={I18n.t('Join_the_community')}
|
</FormContainer>
|
||||||
subtitle='open.rocket.chat'
|
|
||||||
icon={<Image source={{ uri: 'logo_onboarding' }} style={{ width: 32, height: 27 }} fadeDuration={0} />}
|
|
||||||
onPress={this.joinCommunity}
|
|
||||||
testID='join-community-button'
|
|
||||||
theme={theme}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
type='primary'
|
|
||||||
title={I18n.t('Create_a_new_workspace')}
|
|
||||||
icon={<CustomIcon name='plus' size={30} color={themes[theme].buttonText} />}
|
|
||||||
onPress={this.createWorkspace}
|
|
||||||
testID='create-workspace-button'
|
|
||||||
theme={theme}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
{this.renderClose()}
|
|
||||||
</SafeAreaView>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
|
||||||
currentServer: state.server.server,
|
|
||||||
adding: state.server.adding
|
|
||||||
});
|
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => ({
|
const mapDispatchToProps = dispatch => ({
|
||||||
initAdd: () => dispatch(serverInitAdd()),
|
|
||||||
finishAdd: () => dispatch(serverFinishAdd()),
|
|
||||||
selectServer: server => dispatch(selectServerRequest(server)),
|
|
||||||
appStart: root => dispatch(appStartAction(root))
|
appStart: root => dispatch(appStartAction(root))
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(OnboardingView));
|
export default connect(null, mapDispatchToProps)(withTheme(OnboardingView));
|
||||||
|
|
|
@ -5,19 +5,14 @@ import { isTablet } from '../../utils/deviceInfo';
|
||||||
import sharedStyles from '../Styles';
|
import sharedStyles from '../Styles';
|
||||||
|
|
||||||
export default StyleSheet.create({
|
export default StyleSheet.create({
|
||||||
container: {
|
|
||||||
flex: 1,
|
|
||||||
flexDirection: 'column',
|
|
||||||
justifyContent: isTablet ? 'center' : 'flex-start'
|
|
||||||
},
|
|
||||||
onboarding: {
|
onboarding: {
|
||||||
alignSelf: 'center',
|
alignSelf: 'center',
|
||||||
marginTop: verticalScale(30),
|
marginTop: isTablet ? 0 : verticalScale(116),
|
||||||
marginBottom: verticalScale(35),
|
marginBottom: verticalScale(50),
|
||||||
maxHeight: verticalScale(150),
|
maxHeight: verticalScale(150),
|
||||||
resizeMode: 'contain',
|
resizeMode: 'contain',
|
||||||
width: 309,
|
width: 80,
|
||||||
height: 250
|
height: 70
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
...sharedStyles.textBold,
|
...sharedStyles.textBold,
|
||||||
|
@ -29,50 +24,18 @@ export default StyleSheet.create({
|
||||||
subtitle: {
|
subtitle: {
|
||||||
...sharedStyles.textRegular,
|
...sharedStyles.textRegular,
|
||||||
fontSize: moderateScale(16),
|
fontSize: moderateScale(16),
|
||||||
color: '#54585E',
|
alignSelf: 'center',
|
||||||
alignSelf: 'center'
|
marginBottom: verticalScale(24)
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
...sharedStyles.textRegular,
|
||||||
|
fontSize: moderateScale(14),
|
||||||
|
alignSelf: 'center',
|
||||||
|
textAlign: 'center',
|
||||||
|
marginHorizontal: 20
|
||||||
},
|
},
|
||||||
buttonsContainer: {
|
buttonsContainer: {
|
||||||
marginBottom: verticalScale(10),
|
marginBottom: verticalScale(10),
|
||||||
marginTop: verticalScale(30)
|
marginTop: verticalScale(30)
|
||||||
},
|
|
||||||
buttonContainer: {
|
|
||||||
marginHorizontal: 15,
|
|
||||||
marginVertical: 5,
|
|
||||||
flexDirection: 'row',
|
|
||||||
height: 60,
|
|
||||||
alignItems: 'center',
|
|
||||||
borderWidth: 1,
|
|
||||||
borderRadius: 2
|
|
||||||
},
|
|
||||||
buttonCenter: {
|
|
||||||
flex: 1,
|
|
||||||
flexDirection: 'column',
|
|
||||||
justifyContent: 'center'
|
|
||||||
},
|
|
||||||
buttonTitle: {
|
|
||||||
...sharedStyles.textSemibold,
|
|
||||||
fontSize: 17
|
|
||||||
},
|
|
||||||
buttonSubtitle: {
|
|
||||||
...sharedStyles.textRegular,
|
|
||||||
fontSize: 15
|
|
||||||
},
|
|
||||||
buttonIconContainer: {
|
|
||||||
width: 65,
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center'
|
|
||||||
},
|
|
||||||
buttonIcon: {
|
|
||||||
marginHorizontal: 10,
|
|
||||||
width: 20,
|
|
||||||
height: 20
|
|
||||||
},
|
|
||||||
buttonActive: {
|
|
||||||
opacity: 0.5
|
|
||||||
},
|
|
||||||
closeModal: {
|
|
||||||
position: 'absolute',
|
|
||||||
left: 15
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,30 +1,55 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Keyboard, Text, ScrollView } from 'react-native';
|
import {
|
||||||
|
Text, View, StyleSheet, Keyboard
|
||||||
|
} from 'react-native';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { SafeAreaView } from 'react-navigation';
|
|
||||||
import RNPickerSelect from 'react-native-picker-select';
|
import RNPickerSelect from 'react-native-picker-select';
|
||||||
import equal from 'deep-equal';
|
|
||||||
|
|
||||||
import TextInput from '../containers/TextInput';
|
import log from '../utils/log';
|
||||||
import Button from '../containers/Button';
|
|
||||||
import KeyboardView from '../presentation/KeyboardView';
|
|
||||||
import sharedStyles from './Styles';
|
import sharedStyles from './Styles';
|
||||||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
import Button from '../containers/Button';
|
||||||
import I18n from '../i18n';
|
import I18n from '../i18n';
|
||||||
|
import { LegalButton } from '../containers/HeaderButton';
|
||||||
|
import { themes } from '../constants/colors';
|
||||||
|
import { withTheme } from '../theme';
|
||||||
|
import { themedHeader } from '../utils/navigation';
|
||||||
|
import FormContainer, { FormContainerInner } from '../containers/FormContainer';
|
||||||
|
import TextInput from '../containers/TextInput';
|
||||||
|
import isValidEmail from '../utils/isValidEmail';
|
||||||
|
import { showErrorAlert } from '../utils/info';
|
||||||
import RocketChat from '../lib/rocketchat';
|
import RocketChat from '../lib/rocketchat';
|
||||||
import { loginRequest as loginRequestAction } from '../actions/login';
|
import { loginRequest as loginRequestAction } from '../actions/login';
|
||||||
import isValidEmail from '../utils/isValidEmail';
|
import openLink from '../utils/openLink';
|
||||||
import { LegalButton } from '../containers/HeaderButton';
|
import LoginServices from '../containers/LoginServices';
|
||||||
import StatusBar from '../containers/StatusBar';
|
|
||||||
import log from '../utils/log';
|
|
||||||
import { withTheme } from '../theme';
|
|
||||||
import { themes } from '../constants/colors';
|
|
||||||
import { themedHeader } from '../utils/navigation';
|
|
||||||
import { isTablet } from '../utils/deviceInfo';
|
|
||||||
import { showErrorAlert } from '../utils/info';
|
|
||||||
|
|
||||||
const shouldUpdateState = ['name', 'email', 'password', 'username', 'saving'];
|
const styles = StyleSheet.create({
|
||||||
|
title: {
|
||||||
|
...sharedStyles.textBold,
|
||||||
|
fontSize: 22
|
||||||
|
},
|
||||||
|
inputContainer: {
|
||||||
|
marginVertical: 16
|
||||||
|
},
|
||||||
|
bottomContainer: {
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginBottom: 32,
|
||||||
|
marginHorizontal: 30
|
||||||
|
},
|
||||||
|
bottomContainerText: {
|
||||||
|
...sharedStyles.textRegular,
|
||||||
|
fontSize: 13
|
||||||
|
},
|
||||||
|
bottomContainerTextBold: {
|
||||||
|
...sharedStyles.textSemibold,
|
||||||
|
fontSize: 13
|
||||||
|
},
|
||||||
|
registerButton: {
|
||||||
|
marginTop: 16,
|
||||||
|
marginBottom: 32
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
class RegisterView extends React.Component {
|
class RegisterView extends React.Component {
|
||||||
static navigationOptions = ({ navigation, screenProps }) => {
|
static navigationOptions = ({ navigation, screenProps }) => {
|
||||||
|
@ -32,17 +57,18 @@ class RegisterView extends React.Component {
|
||||||
return {
|
return {
|
||||||
...themedHeader(screenProps.theme),
|
...themedHeader(screenProps.theme),
|
||||||
title,
|
title,
|
||||||
headerRight: <LegalButton testID='register-view-more' navigation={navigation} />
|
headerRight: <LegalButton navigation={navigation} />
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
navigation: PropTypes.object,
|
navigation: PropTypes.object,
|
||||||
loginRequest: PropTypes.func,
|
server: PropTypes.string,
|
||||||
Site_Name: PropTypes.string,
|
|
||||||
Accounts_CustomFields: PropTypes.string,
|
Accounts_CustomFields: PropTypes.string,
|
||||||
Accounts_EmailVerification: PropTypes.bool,
|
Accounts_EmailVerification: PropTypes.bool,
|
||||||
theme: PropTypes.string
|
theme: PropTypes.string,
|
||||||
|
Site_Name: PropTypes.string,
|
||||||
|
loginRequest: PropTypes.func
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -71,29 +97,9 @@ class RegisterView extends React.Component {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
login = () => {
|
||||||
const { customFields } = this.state;
|
const { navigation, Site_Name } = this.props;
|
||||||
const { theme } = this.props;
|
navigation.navigate('LoginView', { title: Site_Name });
|
||||||
if (nextProps.theme !== theme) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!equal(nextState.customFields, customFields)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react/destructuring-assignment
|
|
||||||
return shouldUpdateState.some(key => nextState[key] !== this.state[key]);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
|
||||||
const { Site_Name } = this.props;
|
|
||||||
if (Site_Name && prevProps.Site_Name !== Site_Name) {
|
|
||||||
this.setTitle(Site_Name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setTitle = (title) => {
|
|
||||||
const { navigation } = this.props;
|
|
||||||
navigation.setParams({ title });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
valid = () => {
|
valid = () => {
|
||||||
|
@ -141,6 +147,14 @@ class RegisterView extends React.Component {
|
||||||
this.setState({ saving: false });
|
this.setState({ saving: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openContract = (route) => {
|
||||||
|
const { server, theme } = this.props;
|
||||||
|
if (!server) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
openLink(`${ server }/${ route }`, theme);
|
||||||
|
}
|
||||||
|
|
||||||
renderCustomFields = () => {
|
renderCustomFields = () => {
|
||||||
const { customFields } = this.state;
|
const { customFields } = this.state;
|
||||||
const { Accounts_CustomFields, theme } = this.props;
|
const { Accounts_CustomFields, theme } = this.props;
|
||||||
|
@ -166,7 +180,6 @@ class RegisterView extends React.Component {
|
||||||
inputRef={(e) => { this[key] = e; }}
|
inputRef={(e) => { this[key] = e; }}
|
||||||
placeholder={key}
|
placeholder={key}
|
||||||
value={customFields[key]}
|
value={customFields[key]}
|
||||||
iconLeft='flag'
|
|
||||||
testID='register-view-custom-picker'
|
testID='register-view-custom-picker'
|
||||||
theme={theme}
|
theme={theme}
|
||||||
/>
|
/>
|
||||||
|
@ -178,9 +191,9 @@ class RegisterView extends React.Component {
|
||||||
<TextInput
|
<TextInput
|
||||||
inputRef={(e) => { this[key] = e; }}
|
inputRef={(e) => { this[key] = e; }}
|
||||||
key={key}
|
key={key}
|
||||||
|
label={key}
|
||||||
placeholder={key}
|
placeholder={key}
|
||||||
value={customFields[key]}
|
value={customFields[key]}
|
||||||
iconLeft='flag'
|
|
||||||
onChangeText={(value) => {
|
onChangeText={(value) => {
|
||||||
const newValue = {};
|
const newValue = {};
|
||||||
newValue[key] = value;
|
newValue[key] = value;
|
||||||
|
@ -192,6 +205,7 @@ class RegisterView extends React.Component {
|
||||||
}
|
}
|
||||||
this.avatarUrl.focus();
|
this.avatarUrl.focus();
|
||||||
}}
|
}}
|
||||||
|
containerStyle={styles.inputContainer}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -205,77 +219,105 @@ class RegisterView extends React.Component {
|
||||||
const { saving } = this.state;
|
const { saving } = this.state;
|
||||||
const { theme } = this.props;
|
const { theme } = this.props;
|
||||||
return (
|
return (
|
||||||
<KeyboardView
|
<FormContainer theme={theme}>
|
||||||
style={{ backgroundColor: themes[theme].backgroundColor }}
|
<FormContainerInner>
|
||||||
contentContainerStyle={sharedStyles.container}
|
<LoginServices />
|
||||||
>
|
<Text style={[styles.title, sharedStyles.textBold, { color: themes[theme].titleText }]}>{I18n.t('Sign_Up')}</Text>
|
||||||
<StatusBar theme={theme} />
|
<TextInput
|
||||||
<ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}>
|
label='Name'
|
||||||
<SafeAreaView style={[sharedStyles.container, isTablet && sharedStyles.tabletScreenContent]} testID='register-view' forceInset={{ vertical: 'never' }}>
|
containerStyle={styles.inputContainer}
|
||||||
<Text style={[sharedStyles.loginTitle, sharedStyles.textBold, { color: themes[theme].titleText }]}>{I18n.t('Sign_Up')}</Text>
|
placeholder={I18n.t('Name')}
|
||||||
<TextInput
|
returnKeyType='next'
|
||||||
autoFocus
|
onChangeText={name => this.setState({ name })}
|
||||||
placeholder={I18n.t('Name')}
|
onSubmitEditing={() => { this.usernameInput.focus(); }}
|
||||||
returnKeyType='next'
|
testID='register-view-name'
|
||||||
iconLeft='user'
|
theme={theme}
|
||||||
onChangeText={name => this.setState({ name })}
|
/>
|
||||||
onSubmitEditing={() => { this.usernameInput.focus(); }}
|
<TextInput
|
||||||
testID='register-view-name'
|
label='Username'
|
||||||
theme={theme}
|
containerStyle={styles.inputContainer}
|
||||||
/>
|
inputRef={(e) => { this.usernameInput = e; }}
|
||||||
<TextInput
|
placeholder={I18n.t('Username')}
|
||||||
inputRef={(e) => { this.usernameInput = e; }}
|
returnKeyType='next'
|
||||||
placeholder={I18n.t('Username')}
|
onChangeText={username => this.setState({ username })}
|
||||||
returnKeyType='next'
|
onSubmitEditing={() => { this.emailInput.focus(); }}
|
||||||
iconLeft='at'
|
testID='register-view-username'
|
||||||
onChangeText={username => this.setState({ username })}
|
theme={theme}
|
||||||
onSubmitEditing={() => { this.emailInput.focus(); }}
|
/>
|
||||||
testID='register-view-username'
|
<TextInput
|
||||||
theme={theme}
|
label='Email'
|
||||||
/>
|
containerStyle={styles.inputContainer}
|
||||||
<TextInput
|
inputRef={(e) => { this.emailInput = e; }}
|
||||||
inputRef={(e) => { this.emailInput = e; }}
|
placeholder={I18n.t('Email')}
|
||||||
placeholder={I18n.t('Email')}
|
returnKeyType='next'
|
||||||
returnKeyType='next'
|
keyboardType='email-address'
|
||||||
keyboardType='email-address'
|
onChangeText={email => this.setState({ email })}
|
||||||
iconLeft='mail'
|
onSubmitEditing={() => { this.passwordInput.focus(); }}
|
||||||
onChangeText={email => this.setState({ email })}
|
testID='register-view-email'
|
||||||
onSubmitEditing={() => { this.passwordInput.focus(); }}
|
theme={theme}
|
||||||
testID='register-view-email'
|
/>
|
||||||
theme={theme}
|
<TextInput
|
||||||
/>
|
label='Password'
|
||||||
<TextInput
|
containerStyle={styles.inputContainer}
|
||||||
inputRef={(e) => { this.passwordInput = e; }}
|
inputRef={(e) => { this.passwordInput = e; }}
|
||||||
placeholder={I18n.t('Password')}
|
placeholder={I18n.t('Password')}
|
||||||
returnKeyType='send'
|
returnKeyType='send'
|
||||||
iconLeft='key'
|
secureTextEntry
|
||||||
secureTextEntry
|
onChangeText={value => this.setState({ password: value })}
|
||||||
onChangeText={value => this.setState({ password: value })}
|
onSubmitEditing={this.submit}
|
||||||
onSubmitEditing={this.submit}
|
testID='register-view-password'
|
||||||
testID='register-view-password'
|
theme={theme}
|
||||||
containerStyle={sharedStyles.inputLastChild}
|
/>
|
||||||
theme={theme}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{this.renderCustomFields()}
|
{this.renderCustomFields()}
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
title={I18n.t('Register')}
|
title={I18n.t('Register')}
|
||||||
type='primary'
|
type='primary'
|
||||||
onPress={this.submit}
|
onPress={this.submit}
|
||||||
testID='register-view-submit'
|
testID='register-view-submit'
|
||||||
disabled={!this.valid()}
|
disabled={!this.valid()}
|
||||||
loading={saving}
|
loading={saving}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
/>
|
style={styles.registerButton}
|
||||||
</SafeAreaView>
|
/>
|
||||||
</ScrollView>
|
|
||||||
</KeyboardView>
|
<View style={styles.bottomContainer}>
|
||||||
|
<Text style={[styles.bottomContainerText, { color: themes[theme].auxiliaryText }]}>
|
||||||
|
{`${ I18n.t('Onboarding_agree_terms') }\n`}
|
||||||
|
<Text
|
||||||
|
style={[styles.bottomContainerTextBold, { color: themes[theme].actionTintColor }]}
|
||||||
|
onPress={() => this.openContract('terms-of-service')}
|
||||||
|
>{I18n.t('Terms_of_Service')}
|
||||||
|
</Text> {I18n.t('and')}
|
||||||
|
<Text
|
||||||
|
style={[styles.bottomContainerTextBold, { color: themes[theme].actionTintColor }]}
|
||||||
|
onPress={() => this.openContract('privacy-policy')}
|
||||||
|
> {I18n.t('Privacy_Policy')}
|
||||||
|
</Text>
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.bottomContainer}>
|
||||||
|
<Text style={[styles.bottomContainerText, { color: themes[theme].auxiliaryText }]}>{I18n.t('Do_you_have_an_account')}</Text>
|
||||||
|
<Text
|
||||||
|
style={[styles.bottomContainerTextBold, { color: themes[theme].actionTintColor }]}
|
||||||
|
onPress={this.login}
|
||||||
|
>{I18n.t('Login')}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</FormContainerInner>
|
||||||
|
</FormContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
|
server: state.server.server,
|
||||||
|
Site_Name: state.settings.Site_Name,
|
||||||
|
Gitlab_URL: state.settings.API_Gitlab_URL,
|
||||||
|
CAS_enabled: state.settings.CAS_enabled,
|
||||||
|
CAS_login_url: state.settings.CAS_login_url,
|
||||||
Accounts_CustomFields: state.settings.Accounts_CustomFields,
|
Accounts_CustomFields: state.settings.Accounts_CustomFields,
|
||||||
Accounts_EmailVerification: state.settings.Accounts_EmailVerification
|
Accounts_EmailVerification: state.settings.Accounts_EmailVerification
|
||||||
});
|
});
|
||||||
|
|
|
@ -126,7 +126,7 @@ class ServerDropdown extends Component {
|
||||||
|
|
||||||
this.close();
|
this.close();
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
navigation.navigate('OnboardingView', { previousServer: server });
|
navigation.navigate('NewServerView', { previousServer: server });
|
||||||
}, ANIMATION_DURATION);
|
}, ANIMATION_DURATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -706,7 +706,7 @@ class RoomsListView extends React.Component {
|
||||||
} else if (handleCommandShowNewMessage(event)) {
|
} else if (handleCommandShowNewMessage(event)) {
|
||||||
navigation.navigate('NewMessageView', { onPressItem: this._onPressItem });
|
navigation.navigate('NewMessageView', { onPressItem: this._onPressItem });
|
||||||
} else if (handleCommandAddNewServer(event)) {
|
} else if (handleCommandAddNewServer(event)) {
|
||||||
navigation.navigate('OnboardingView', { previousServer: server });
|
navigation.navigate('NewServerView', { previousServer: server });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -135,7 +135,6 @@ class SetUsernameView extends React.Component {
|
||||||
autoFocus
|
autoFocus
|
||||||
placeholder={I18n.t('Username')}
|
placeholder={I18n.t('Username')}
|
||||||
returnKeyType='send'
|
returnKeyType='send'
|
||||||
iconLeft='at'
|
|
||||||
onChangeText={value => this.setState({ username: value })}
|
onChangeText={value => this.setState({ username: value })}
|
||||||
value={username}
|
value={username}
|
||||||
onSubmitEditing={this.submit}
|
onSubmitEditing={this.submit}
|
||||||
|
|
|
@ -4,7 +4,8 @@ import { MAX_SCREEN_CONTENT_WIDTH, MAX_CONTENT_WIDTH } from '../constants/tablet
|
||||||
|
|
||||||
export default StyleSheet.create({
|
export default StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
flex: 1
|
flex: 1,
|
||||||
|
flexDirection: 'column'
|
||||||
},
|
},
|
||||||
containerScrollView: {
|
containerScrollView: {
|
||||||
padding: 15,
|
padding: 15,
|
||||||
|
@ -18,6 +19,7 @@ export default StyleSheet.create({
|
||||||
maxWidth: MAX_CONTENT_WIDTH
|
maxWidth: MAX_CONTENT_WIDTH
|
||||||
},
|
},
|
||||||
tabletScreenContent: {
|
tabletScreenContent: {
|
||||||
|
justifyContent: 'center',
|
||||||
alignSelf: 'center',
|
alignSelf: 'center',
|
||||||
width: MAX_SCREEN_CONTENT_WIDTH
|
width: MAX_SCREEN_CONTENT_WIDTH
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { StyleSheet, View, Text } from 'react-native';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { createImageProgress } from 'react-native-image-progress';
|
||||||
|
import * as Progress from 'react-native-progress';
|
||||||
|
import FastImage from 'react-native-fast-image';
|
||||||
|
|
||||||
|
import sharedStyles from '../Styles';
|
||||||
|
import { themes } from '../../constants/colors';
|
||||||
|
import { isTablet } from '../../utils/deviceInfo';
|
||||||
|
|
||||||
|
const ImageProgress = createImageProgress(FastImage);
|
||||||
|
|
||||||
|
const SIZE = 96;
|
||||||
|
const MARGIN_TOP = isTablet ? 0 : 64;
|
||||||
|
const BORDER_RADIUS = 6;
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
marginBottom: 16,
|
||||||
|
width: '100%',
|
||||||
|
height: SIZE + MARGIN_TOP,
|
||||||
|
justifyContent: 'flex-end',
|
||||||
|
alignItems: 'center'
|
||||||
|
},
|
||||||
|
image: {
|
||||||
|
width: SIZE,
|
||||||
|
height: SIZE,
|
||||||
|
borderRadius: BORDER_RADIUS
|
||||||
|
},
|
||||||
|
fallback: {
|
||||||
|
width: SIZE,
|
||||||
|
height: SIZE,
|
||||||
|
borderRadius: BORDER_RADIUS,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
},
|
||||||
|
initial: {
|
||||||
|
...sharedStyles.textBold,
|
||||||
|
fontSize: 42
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const getInitial = url => url && url.replace(/http(s?):\/\//, '').slice(0, 1);
|
||||||
|
|
||||||
|
const Fallback = ({ theme, initial }) => (
|
||||||
|
<View style={[styles.container, styles.fallback, { backgroundColor: themes[theme].dangerColor }]}>
|
||||||
|
<Text style={[styles.initial, { color: themes[theme].buttonText }]}>{initial}</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
|
||||||
|
const ServerAvatar = React.memo(({ theme, url, image }) => (
|
||||||
|
<View style={styles.container}>
|
||||||
|
{image && (
|
||||||
|
<ImageProgress
|
||||||
|
style={[styles.image, { borderColor: themes[theme].borderColor }]}
|
||||||
|
source={{ uri: `${ url }/${ image }` }}
|
||||||
|
resizeMode={FastImage.resizeMode.cover}
|
||||||
|
indicator={Progress.Pie}
|
||||||
|
indicatorProps={{
|
||||||
|
color: themes[theme].actionTintColor
|
||||||
|
}}
|
||||||
|
renderError={() => <Fallback theme={theme} initial={getInitial(url)} />}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
));
|
||||||
|
|
||||||
|
ServerAvatar.propTypes = {
|
||||||
|
theme: PropTypes.string,
|
||||||
|
url: PropTypes.string,
|
||||||
|
image: PropTypes.string
|
||||||
|
};
|
||||||
|
ServerAvatar.displayName = 'ServerAvatar';
|
||||||
|
|
||||||
|
Fallback.propTypes = {
|
||||||
|
theme: PropTypes.string,
|
||||||
|
initial: PropTypes.string
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ServerAvatar;
|
|
@ -0,0 +1,89 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { View, Text } from 'react-native';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
import I18n from '../../i18n';
|
||||||
|
import Button from '../../containers/Button';
|
||||||
|
import styles from './styles';
|
||||||
|
import { themes } from '../../constants/colors';
|
||||||
|
import { withTheme } from '../../theme';
|
||||||
|
import FormContainer, { FormContainerInner } from '../../containers/FormContainer';
|
||||||
|
import { themedHeader } from '../../utils/navigation';
|
||||||
|
import ServerAvatar from './ServerAvatar';
|
||||||
|
|
||||||
|
class WorkspaceView extends React.Component {
|
||||||
|
static navigationOptions = ({ screenProps }) => ({
|
||||||
|
title: I18n.t('Your_workspace'),
|
||||||
|
...themedHeader(screenProps.theme)
|
||||||
|
})
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
navigation: PropTypes.object,
|
||||||
|
theme: PropTypes.string,
|
||||||
|
Site_Name: PropTypes.string,
|
||||||
|
Site_Url: PropTypes.string,
|
||||||
|
server: PropTypes.string,
|
||||||
|
Assets_favicon_512: PropTypes.object,
|
||||||
|
registrationEnabled: PropTypes.bool,
|
||||||
|
registrationText: PropTypes.string
|
||||||
|
}
|
||||||
|
|
||||||
|
login = () => {
|
||||||
|
const { navigation, Site_Name } = this.props;
|
||||||
|
navigation.navigate('LoginView', { title: Site_Name });
|
||||||
|
}
|
||||||
|
|
||||||
|
register = () => {
|
||||||
|
const { navigation, Site_Name } = this.props;
|
||||||
|
navigation.navigate('RegisterView', { title: Site_Name });
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
theme, Site_Name, Site_Url, Assets_favicon_512, server, registrationEnabled, registrationText
|
||||||
|
} = this.props;
|
||||||
|
return (
|
||||||
|
<FormContainer theme={theme}>
|
||||||
|
<FormContainerInner>
|
||||||
|
<View style={styles.alignItemsCenter}>
|
||||||
|
<ServerAvatar theme={theme} url={server} image={Assets_favicon_512 && Assets_favicon_512.defaultUrl} />
|
||||||
|
<Text style={[styles.serverName, { color: themes[theme].titleText }]}>{Site_Name}</Text>
|
||||||
|
<Text style={[styles.serverUrl, { color: themes[theme].auxiliaryText }]}>{Site_Url}</Text>
|
||||||
|
</View>
|
||||||
|
<Button
|
||||||
|
title={I18n.t('Login')}
|
||||||
|
type='primary'
|
||||||
|
onPress={this.login}
|
||||||
|
theme={theme}
|
||||||
|
/>
|
||||||
|
{
|
||||||
|
registrationEnabled ? (
|
||||||
|
<Button
|
||||||
|
title={I18n.t('Create_account')}
|
||||||
|
type='secondary'
|
||||||
|
backgroundColor={themes[theme].chatComponentBackground}
|
||||||
|
onPress={this.register}
|
||||||
|
theme={theme}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Text style={[styles.registrationText, { color: themes[theme].auxiliaryText }]}>{registrationText}</Text>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</FormContainerInner>
|
||||||
|
</FormContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
server: state.server.server,
|
||||||
|
adding: state.server.adding,
|
||||||
|
Site_Name: state.settings.Site_Name,
|
||||||
|
Site_Url: state.settings.Site_Url,
|
||||||
|
Assets_favicon_512: state.settings.Assets_favicon_512,
|
||||||
|
registrationEnabled: state.settings.Accounts_RegistrationForm === 'Public',
|
||||||
|
registrationText: state.settings.Accounts_RegistrationForm_LinkReplacementText
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps)(withTheme(WorkspaceView));
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { StyleSheet } from 'react-native';
|
||||||
|
|
||||||
|
import sharedStyles from '../Styles';
|
||||||
|
|
||||||
|
export default StyleSheet.create({
|
||||||
|
serverName: {
|
||||||
|
...sharedStyles.textSemibold,
|
||||||
|
fontSize: 16,
|
||||||
|
marginBottom: 4
|
||||||
|
},
|
||||||
|
serverUrl: {
|
||||||
|
...sharedStyles.textRegular,
|
||||||
|
fontSize: 14,
|
||||||
|
marginBottom: 24
|
||||||
|
},
|
||||||
|
registrationText: {
|
||||||
|
fontSize: 14,
|
||||||
|
...sharedStyles.textAlignCenter,
|
||||||
|
...sharedStyles.textRegular
|
||||||
|
},
|
||||||
|
alignItemsCenter: {
|
||||||
|
alignItems: 'center'
|
||||||
|
}
|
||||||
|
});
|
|
@ -2,17 +2,17 @@
|
||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"filename" : "logo@1x.png",
|
"filename" : "icon@1x.png",
|
||||||
"scale" : "1x"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"filename" : "logo@2x.png",
|
"filename" : "icon@2x.png",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"filename" : "logo@3x.png",
|
"filename" : "icon@3x.png",
|
||||||
"scale" : "3x"
|
"scale" : "3x"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 5.4 KiB |
|
@ -1,23 +0,0 @@
|
||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "logo_onboarding@1x.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "logo_onboarding@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "logo_onboarding@3x.png",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"version" : 1,
|
|
||||||
"author" : "xcode"
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 4.1 KiB |
|
@ -1,23 +0,0 @@
|
||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "new_server.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "new_server@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "new_server@3x.png",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"version" : 1,
|
|
||||||
"author" : "xcode"
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 73 KiB |
|
@ -1,23 +0,0 @@
|
||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "onboarding.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "onboarding@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "onboarding@3x.png",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"version" : 1,
|
|
||||||
"author" : "xcode"
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 111 KiB |
Before Width: | Height: | Size: 177 KiB |
|
@ -1,23 +0,0 @@
|
||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "options.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "options@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "options@3x.png",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"version" : 1,
|
|
||||||
"author" : "xcode"
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 987 B |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 3.2 KiB |