Stash
This commit is contained in:
parent
50e7d7dcf4
commit
f0408b3bcf
|
@ -44,7 +44,7 @@ export default class Button extends React.PureComponent {
|
|||
|
||||
render() {
|
||||
const {
|
||||
title, type, onPress, disabled, backgroundColor, loading, style, theme, ...otherProps
|
||||
title, type, onPress, disabled, backgroundColor, color, loading, style, theme, ...otherProps
|
||||
} = this.props;
|
||||
const isPrimary = type === 'primary';
|
||||
return (
|
||||
|
@ -68,7 +68,8 @@ export default class Button extends React.PureComponent {
|
|||
<Text
|
||||
style={[
|
||||
styles.text,
|
||||
{ color: isPrimary ? themes[theme].buttonText : themes[theme].bodyText }
|
||||
{ color: isPrimary ? themes[theme].buttonText : themes[theme].bodyText },
|
||||
color && { color }
|
||||
]}
|
||||
>
|
||||
{title}
|
||||
|
|
|
@ -13,10 +13,16 @@ import { isTablet } from '../utils/deviceInfo';
|
|||
|
||||
const styles = StyleSheet.create({
|
||||
scrollView: {
|
||||
height: '100%'
|
||||
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 }}
|
||||
|
@ -26,11 +32,11 @@ const FormContainer = ({ children, theme }) => (
|
|||
<StatusBar theme={theme} />
|
||||
<ScrollView {...scrollPersistTaps} style={sharedStyles.container} contentContainerStyle={[sharedStyles.containerScrollView, styles.scrollView]}>
|
||||
<SafeAreaView style={sharedStyles.container} forceInset={{ top: 'never' }}>
|
||||
<View style={[sharedStyles.container, isTablet && sharedStyles.tabletScreenContent]}>
|
||||
{children}
|
||||
</View>
|
||||
{/* <View style={[sharedStyles.container, isTablet && sharedStyles.tabletScreenContent]}> */}
|
||||
{children}
|
||||
<AppVersion theme={theme} />
|
||||
{/* </View> */}
|
||||
</SafeAreaView>
|
||||
<AppVersion theme={theme} />
|
||||
</ScrollView>
|
||||
</KeyboardView>
|
||||
);
|
||||
|
|
|
@ -21,6 +21,9 @@ import { themes } from '../constants/colors';
|
|||
import { withTheme } from '../theme';
|
||||
import { themedHeader } from '../utils/navigation';
|
||||
import { isTablet } from '../utils/deviceInfo';
|
||||
import FormContainer, { FormContainerInner } from '../containers/FormContainer';
|
||||
import OnboardingSeparator from '../containers/OnboardingSeparator';
|
||||
import TextInput from '../containers/TextInput';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
|
@ -36,7 +39,6 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
serviceButtonContainer: {
|
||||
borderRadius: 2,
|
||||
borderWidth: 1,
|
||||
width: '100%',
|
||||
height: 48,
|
||||
flexDirection: 'row',
|
||||
|
@ -89,7 +91,20 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
inverted: {
|
||||
transform: [{ scaleY: -1 }]
|
||||
}
|
||||
},
|
||||
title: {
|
||||
...sharedStyles.textBold,
|
||||
fontSize: 22
|
||||
},
|
||||
inputContainer: {
|
||||
marginTop: 24,
|
||||
marginBottom: 32
|
||||
},
|
||||
bottomContainer: {
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
marginBottom: 32
|
||||
},
|
||||
});
|
||||
|
||||
const SERVICE_HEIGHT = 58;
|
||||
|
@ -123,7 +138,11 @@ class LoginSignupView extends React.Component {
|
|||
super(props);
|
||||
this.state = {
|
||||
collapsed: true,
|
||||
servicesHeight: new Animated.Value(SERVICES_COLLAPSED_HEIGHT)
|
||||
servicesHeight: new Animated.Value(SERVICES_COLLAPSED_HEIGHT),
|
||||
user: '',
|
||||
password: '',
|
||||
code: '',
|
||||
showTOTP: false
|
||||
};
|
||||
const { Site_Name } = this.props;
|
||||
this.setTitle(Site_Name);
|
||||
|
@ -348,6 +367,16 @@ class LoginSignupView extends React.Component {
|
|||
return oauthProviders[name];
|
||||
}
|
||||
|
||||
valid = () => {
|
||||
const {
|
||||
user, password, code, showTOTP
|
||||
} = this.state;
|
||||
if (showTOTP) {
|
||||
return code.trim();
|
||||
}
|
||||
return user.trim() && password.trim();
|
||||
}
|
||||
|
||||
renderServicesSeparator = () => {
|
||||
const { collapsed } = this.state;
|
||||
const {
|
||||
|
@ -356,21 +385,30 @@ class LoginSignupView extends React.Component {
|
|||
const { length } = Object.values(services);
|
||||
|
||||
if (length > 3 && Accounts_ShowFormLogin && Accounts_RegistrationForm) {
|
||||
// return (
|
||||
// <View style={styles.servicesTogglerContainer}>
|
||||
// <View style={[styles.separatorLine, styles.separatorLineLeft, { backgroundColor: themes[theme].auxiliaryText }]} />
|
||||
// <BorderlessButton onPress={this.toggleServices}>
|
||||
// <Image source={{ uri: 'options' }} style={[styles.servicesToggler, !collapsed && styles.inverted]} />
|
||||
// </BorderlessButton>
|
||||
// <View style={[styles.separatorLine, styles.separatorLineRight, { backgroundColor: themes[theme].auxiliaryText }]} />
|
||||
// </View>
|
||||
// );
|
||||
return (
|
||||
<View style={styles.servicesTogglerContainer}>
|
||||
<View style={[styles.separatorLine, styles.separatorLineLeft, { backgroundColor: themes[theme].auxiliaryText }]} />
|
||||
<BorderlessButton onPress={this.toggleServices}>
|
||||
<Image source={{ uri: 'options' }} style={[styles.servicesToggler, !collapsed && styles.inverted]} />
|
||||
</BorderlessButton>
|
||||
<View style={[styles.separatorLine, styles.separatorLineRight, { backgroundColor: themes[theme].auxiliaryText }]} />
|
||||
</View>
|
||||
<>
|
||||
<Button
|
||||
title='More options'
|
||||
type='secondary'
|
||||
onPress={this.toggleServices}
|
||||
theme={theme}
|
||||
style={{ marginBottom: 0 }}
|
||||
color={themes[theme].actionTintColor}
|
||||
/>
|
||||
<OnboardingSeparator theme={theme} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<View style={styles.separatorContainer}>
|
||||
<View style={styles.separatorLine} />
|
||||
</View>
|
||||
);
|
||||
return <OnboardingSeparator theme={theme} />;
|
||||
}
|
||||
|
||||
renderItem = (service) => {
|
||||
|
@ -412,14 +450,19 @@ class LoginSignupView extends React.Component {
|
|||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const backgroundColor = isSaml && service.buttonColor ? service.buttonColor : themes[theme].chatComponentBackground;
|
||||
|
||||
return (
|
||||
<Touch
|
||||
key={service.name}
|
||||
onPress={onPress}
|
||||
style={[styles.serviceButton, isSaml && { backgroundColor: service.buttonColor }]}
|
||||
style={[styles.serviceButton, { backgroundColor }]}
|
||||
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}
|
||||
<Text style={[styles.serviceText, { color: themes[theme].titleText }]}>{buttonText}</Text>
|
||||
</View>
|
||||
|
@ -482,31 +525,89 @@ class LoginSignupView extends React.Component {
|
|||
);
|
||||
}
|
||||
|
||||
renderUserForm = () => {
|
||||
const {
|
||||
Accounts_EmailOrUsernamePlaceholder, Accounts_PasswordPlaceholder, Accounts_PasswordReset, Accounts_RegistrationForm, Accounts_RegistrationForm_LinkReplacementText, isFetching, theme
|
||||
} = this.props;
|
||||
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'
|
||||
iconLeft='at'
|
||||
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'
|
||||
iconLeft='key'
|
||||
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}
|
||||
/>
|
||||
{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>)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { showTOTP } = this.state;
|
||||
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} />
|
||||
<FormContainer theme={theme}>
|
||||
<FormContainerInner>
|
||||
{this.renderServices()}
|
||||
{this.renderServicesSeparator()}
|
||||
{this.renderLogin()}
|
||||
{this.renderRegister()}
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
{/* {this.renderLogin()}
|
||||
{this.renderRegister()} */}
|
||||
{!showTOTP ? this.renderUserForm() : null}
|
||||
{showTOTP ? this.renderTOTP() : null}
|
||||
</FormContainerInner>
|
||||
</FormContainer>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -520,7 +621,16 @@ const mapStateToProps = state => ({
|
|||
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,
|
||||
isFetching: state.login.isFetching,
|
||||
failure: state.login.failure,
|
||||
error: state.login.error && state.login.error.data,
|
||||
// Site_Name: state.settings.Site_Name,
|
||||
Accounts_EmailOrUsernamePlaceholder: state.settings.Accounts_EmailOrUsernamePlaceholder,
|
||||
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
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(withTheme(LoginSignupView));
|
||||
|
|
|
@ -18,7 +18,7 @@ import sharedStyles from './Styles';
|
|||
import Button from '../containers/Button';
|
||||
import TextInput from '../containers/TextInput';
|
||||
import OnboardingSeparator from '../containers/OnboardingSeparator';
|
||||
import FormContainer from '../containers/FormContainer';
|
||||
import FormContainer, { FormContainerInner } from '../containers/FormContainer';
|
||||
import I18n from '../i18n';
|
||||
import { isIOS, isTablet } from '../utils/deviceInfo';
|
||||
import { themes } from '../constants/colors';
|
||||
|
@ -31,9 +31,7 @@ import { themedHeader } from '../utils/navigation';
|
|||
const styles = StyleSheet.create({
|
||||
title: {
|
||||
...sharedStyles.textBold,
|
||||
fontSize: 22,
|
||||
letterSpacing: 0,
|
||||
textAlign: 'auto'
|
||||
fontSize: 22
|
||||
},
|
||||
inputContainer: {
|
||||
marginTop: 24,
|
||||
|
@ -264,7 +262,7 @@ class NewServerView extends React.Component {
|
|||
const { text } = this.state;
|
||||
return (
|
||||
<FormContainer theme={theme}>
|
||||
<View style={[sharedStyles.container, isTablet && { justifyContent: 'center' }]}>
|
||||
<FormContainerInner>
|
||||
<Text style={[styles.title, { color: themes[theme].titleText }]}>{I18n.t('Join_your_workspace')}</Text>
|
||||
<TextInput
|
||||
label='Enter workspace URL'
|
||||
|
@ -300,7 +298,7 @@ class NewServerView extends React.Component {
|
|||
// loading={connecting} TODO: connecting to open
|
||||
theme={theme}
|
||||
/>
|
||||
</View>
|
||||
</FormContainerInner>
|
||||
{ isIOS ? this.renderCertificatePicker() : null }
|
||||
</FormContainer>
|
||||
);
|
||||
|
|
|
@ -15,7 +15,7 @@ import { isTablet } from '../../utils/deviceInfo';
|
|||
import EventEmitter from '../../utils/events';
|
||||
import { themes } from '../../constants/colors';
|
||||
import { withTheme } from '../../theme';
|
||||
import FormContainer from '../../containers/FormContainer';
|
||||
import FormContainer, { FormContainerInner } from '../../containers/FormContainer';
|
||||
|
||||
class OnboardingView extends React.Component {
|
||||
static navigationOptions = () => ({
|
||||
|
@ -109,25 +109,27 @@ class OnboardingView extends React.Component {
|
|||
const { theme } = this.props;
|
||||
return (
|
||||
<FormContainer theme={theme}>
|
||||
<Image style={styles.onboarding} source={{ uri: 'logo' }} fadeDuration={0} />
|
||||
<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>
|
||||
<Text style={[styles.description, { color: themes[theme].auxiliaryText }]}>{I18n.t('Onboarding_description')}</Text>
|
||||
<View style={[styles.buttonsContainer]}>
|
||||
<Button
|
||||
title={I18n.t('Onboarding_join_workspace')}
|
||||
type='primary'
|
||||
onPress={this.connectServer}
|
||||
theme={theme}
|
||||
/>
|
||||
<Button
|
||||
title={I18n.t('Create_a_new_workspace')}
|
||||
type='secondary'
|
||||
backgroundColor={themes[theme].chatComponentBackground}
|
||||
onPress={this.createWorkspace}
|
||||
theme={theme}
|
||||
/>
|
||||
</View>
|
||||
<FormContainerInner>
|
||||
<Image style={styles.onboarding} source={{ uri: 'logo' }} fadeDuration={0} />
|
||||
<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>
|
||||
<Text style={[styles.description, { color: themes[theme].auxiliaryText }]}>{I18n.t('Onboarding_description')}</Text>
|
||||
<View style={[styles.buttonsContainer]}>
|
||||
<Button
|
||||
title={I18n.t('Onboarding_join_workspace')}
|
||||
type='primary'
|
||||
onPress={this.connectServer}
|
||||
theme={theme}
|
||||
/>
|
||||
<Button
|
||||
title={I18n.t('Create_a_new_workspace')}
|
||||
type='secondary'
|
||||
backgroundColor={themes[theme].chatComponentBackground}
|
||||
onPress={this.createWorkspace}
|
||||
theme={theme}
|
||||
/>
|
||||
</View>
|
||||
</FormContainerInner>
|
||||
</FormContainer>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -10,11 +10,12 @@ import { appStart as appStartAction } from '../../actions';
|
|||
import I18n from '../../i18n';
|
||||
import Button from '../../containers/Button';
|
||||
import styles from './styles';
|
||||
import sharedStyles from '../Styles';
|
||||
import { isTablet } from '../../utils/deviceInfo';
|
||||
import EventEmitter from '../../utils/events';
|
||||
import { themes } from '../../constants/colors';
|
||||
import { withTheme } from '../../theme';
|
||||
import FormContainer from '../../containers/FormContainer';
|
||||
import FormContainer, { FormContainerInner } from '../../containers/FormContainer';
|
||||
import { themedHeader } from '../../utils/navigation';
|
||||
import ServerAvatar from './ServerAvatar';
|
||||
|
||||
|
@ -37,7 +38,7 @@ class WorkspaceView extends React.Component {
|
|||
|
||||
login = () => {
|
||||
const { navigation } = this.props;
|
||||
navigation.navigate('LoginView');
|
||||
navigation.navigate('LoginSignupView');
|
||||
}
|
||||
|
||||
register = () => {
|
||||
|
@ -49,24 +50,26 @@ class WorkspaceView extends React.Component {
|
|||
const { theme, Site_Name, Site_Url, Assets_favicon_512, server } = this.props;
|
||||
return (
|
||||
<FormContainer theme={theme}>
|
||||
<View style={{ alignItems: 'center' }}>
|
||||
<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}
|
||||
/>
|
||||
<Button
|
||||
title={I18n.t('Create_account')}
|
||||
type='secondary'
|
||||
backgroundColor={themes[theme].chatComponentBackground}
|
||||
onPress={this.register}
|
||||
theme={theme}
|
||||
/>
|
||||
<FormContainerInner>
|
||||
<View style={{ alignItems: 'center' }}>
|
||||
<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}
|
||||
/>
|
||||
<Button
|
||||
title={I18n.t('Create_account')}
|
||||
type='secondary'
|
||||
backgroundColor={themes[theme].chatComponentBackground}
|
||||
onPress={this.register}
|
||||
theme={theme}
|
||||
/>
|
||||
</FormContainerInner>
|
||||
</FormContainer>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue