Style views for SelectServer, Login, SelectTeam, & ChannelsList (#27)
* Allow user to change switch between teams & channels * Add react-native-button * Style SelectTeam view * Reuse SelectTeam styles in SelectServer & Login * Reuse SelectTeam styles in ChannelsList view * Display current team name in ChannelsList * Disable android underline in textinputs
This commit is contained in:
parent
0697bfc066
commit
d4a98c082a
7 changed files with 115 additions and 106 deletions
|
|
@ -7,6 +7,7 @@
|
|||
"lodash": "4.16.4",
|
||||
"react": "15.3.2",
|
||||
"react-native": "0.34.1",
|
||||
"react-native-button": "1.7.1",
|
||||
"react-native-keyboard-spacer": "0.3.0",
|
||||
"react-native-router-flux": "3.36.0",
|
||||
"react-redux": "4.4.5",
|
||||
|
|
|
|||
|
|
@ -2,59 +2,57 @@
|
|||
// See License.txt for license information.
|
||||
|
||||
import React, {Component, PropTypes} from 'react';
|
||||
import {ListView, StyleSheet, View, Text} from 'react-native';
|
||||
const {DataSource} = ListView;
|
||||
import {View, Text} from 'react-native';
|
||||
import {Actions as Routes} from 'react-native-router-flux';
|
||||
import Button from 'react-native-button';
|
||||
import _ from 'lodash';
|
||||
import ErrorText from 'components/error_text';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
paddingTop: 200,
|
||||
backgroundColor: 'white'
|
||||
}
|
||||
});
|
||||
import ErrorText from 'components/error_text';
|
||||
import {GlobalStyles} from 'styles';
|
||||
|
||||
const propTypes = {
|
||||
teams: PropTypes.object.isRequired,
|
||||
channels: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
class ChannelsListView extends Component {
|
||||
static propTypes = propTypes;
|
||||
ds: DataSource = new DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
|
||||
|
||||
componentWillMount() {
|
||||
this.props.actions.fetchChannels();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(props) {
|
||||
if (props.channels.currentChannelId &&
|
||||
!this.props.channels.currentChannelId) {
|
||||
const {currentChannelId} = props.channels;
|
||||
if (currentChannelId &&
|
||||
currentChannelId !== this.props.channels.currentChannelId) {
|
||||
Routes.goToPostsList();
|
||||
}
|
||||
}
|
||||
|
||||
setChannel(channel) {
|
||||
this.props.actions.selectChannel(channel);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {data: teams, currentTeamId} = this.props.teams;
|
||||
const currentTeam = teams[currentTeamId];
|
||||
const channels = _.values(this.props.channels.data);
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<ListView
|
||||
dataSource={this.ds.cloneWithRows(channels)}
|
||||
enableEmptySections={true}
|
||||
renderRow={(channel) => (
|
||||
<Text onPress={() => this.props.actions.selectChannel(channel)}>
|
||||
{channel.display_name}
|
||||
</Text>
|
||||
)}
|
||||
/>
|
||||
<View style={GlobalStyles.container}>
|
||||
<Text style={GlobalStyles.header}>
|
||||
{currentTeam.display_name}
|
||||
</Text>
|
||||
<Text style={GlobalStyles.subheader}>
|
||||
{'Your channels:'}
|
||||
</Text>
|
||||
{_.map(channels, (channel) => (
|
||||
<Button
|
||||
key={channel.id}
|
||||
onPress={() => this.props.actions.selectChannel(channel)}
|
||||
style={GlobalStyles.buttonListItemText}
|
||||
containerStyle={GlobalStyles.buttonListItem}
|
||||
>
|
||||
{channel.display_name}
|
||||
</Button>
|
||||
))}
|
||||
|
||||
<ErrorText error={this.props.channels.error}/>
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// See License.txt for license information.
|
||||
|
||||
import React, {Component, PropTypes} from 'react';
|
||||
import {Image, StyleSheet, Text, TextInput, View} from 'react-native';
|
||||
import {View, Text, TextInput, Image} from 'react-native';
|
||||
import {Actions as Routes} from 'react-native-router-flux';
|
||||
|
||||
import Button from 'components/button';
|
||||
|
|
@ -10,19 +10,6 @@ import ErrorText from 'components/error_text';
|
|||
import {GlobalStyles} from 'styles';
|
||||
import logo from 'images/logo.png';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
paddingTop: 200,
|
||||
backgroundColor: 'white'
|
||||
},
|
||||
logo: {
|
||||
marginBottom: 10
|
||||
}
|
||||
});
|
||||
|
||||
const propTypes = {
|
||||
login: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired
|
||||
|
|
@ -51,13 +38,13 @@ export default class LoginView extends Component {
|
|||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={GlobalStyles.container}>
|
||||
<Image
|
||||
style={styles.logo}
|
||||
style={GlobalStyles.logo}
|
||||
source={logo}
|
||||
/>
|
||||
<Text>{'Mattermost'}</Text>
|
||||
<Text>
|
||||
<Text style={GlobalStyles.header}>{'Mattermost'}</Text>
|
||||
<Text style={GlobalStyles.subheader}>
|
||||
{'All team communication in one place, searchable and accessible anywhere'}
|
||||
</Text>
|
||||
<TextInput
|
||||
|
|
@ -67,6 +54,7 @@ export default class LoginView extends Component {
|
|||
placeholder='Email or Username'
|
||||
autoCorrect={false}
|
||||
autoCapitalize='none'
|
||||
underlineColorAndroid='transparent'
|
||||
/>
|
||||
<TextInput
|
||||
value={this.state.password}
|
||||
|
|
@ -75,6 +63,7 @@ export default class LoginView extends Component {
|
|||
placeholder='Password'
|
||||
autoCorrect={false}
|
||||
autoCapitalize='none'
|
||||
underlineColorAndroid='transparent'
|
||||
/>
|
||||
<Button
|
||||
onPress={() => this.signIn()}
|
||||
|
|
|
|||
|
|
@ -2,32 +2,17 @@
|
|||
// See License.txt for license information.
|
||||
|
||||
import React, {Component} from 'react';
|
||||
import {View, Text, TextInput, Image} from 'react-native';
|
||||
import KeyboardSpacer from 'react-native-keyboard-spacer';
|
||||
import {Actions as Routes} from 'react-native-router-flux';
|
||||
import _ from 'lodash';
|
||||
|
||||
import Client from 'client/client_instance.js';
|
||||
import Config from 'config/config.js';
|
||||
|
||||
import Button from './button';
|
||||
import {Image, StyleSheet, Text, TextInput, View} from 'react-native';
|
||||
import KeyboardSpacer from 'react-native-keyboard-spacer';
|
||||
import {Actions as Routes} from 'react-native-router-flux';
|
||||
|
||||
import Button from 'components/button';
|
||||
import ErrorText from 'components/error_text';
|
||||
import {GlobalStyles} from 'styles';
|
||||
import logo from 'images/logo.png';
|
||||
import ErrorText from './error_text';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
paddingTop: 200,
|
||||
backgroundColor: 'white'
|
||||
},
|
||||
|
||||
logo: {
|
||||
marginBottom: 10
|
||||
}
|
||||
});
|
||||
|
||||
class SelectServerView extends Component {
|
||||
static propTypes = {
|
||||
|
|
@ -59,22 +44,25 @@ class SelectServerView extends Component {
|
|||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={GlobalStyles.container}>
|
||||
<Image
|
||||
style={styles.logo}
|
||||
style={GlobalStyles.logo}
|
||||
source={logo}
|
||||
/>
|
||||
<Text style={GlobalStyles.label}>{'Enter Server URL'}</Text>
|
||||
<Text style={_.at(GlobalStyles, ['header', 'label'])}>
|
||||
{'Enter Server URL'}
|
||||
</Text>
|
||||
<TextInput
|
||||
style={GlobalStyles.inputBox}
|
||||
value={this.state.serverUrl}
|
||||
onChangeText={(serverUrl) => this.setState({serverUrl})}
|
||||
onSubmitEditing={this.onClick}
|
||||
style={GlobalStyles.inputBox}
|
||||
autoCapitalize='none'
|
||||
autoCorrect={false}
|
||||
keyboardType='url'
|
||||
placeholder='https://mattermost.example.com'
|
||||
returnKeyType='go'
|
||||
value={this.state.serverUrl}
|
||||
underlineColorAndroid='transparent'
|
||||
/>
|
||||
<Button
|
||||
text='Proceed'
|
||||
|
|
|
|||
|
|
@ -3,26 +3,15 @@
|
|||
|
||||
import React, {Component, PropTypes} from 'react';
|
||||
|
||||
import {Image, StyleSheet, Picker, View} from 'react-native';
|
||||
import {View, Text, Image} from 'react-native';
|
||||
import {Actions as Routes} from 'react-native-router-flux';
|
||||
import Button from 'react-native-button';
|
||||
import _ from 'lodash';
|
||||
|
||||
import ErrorText from 'components/error_text';
|
||||
import {GlobalStyles} from 'styles';
|
||||
import logo from 'images/logo.png';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
paddingTop: 200,
|
||||
backgroundColor: 'white'
|
||||
},
|
||||
logo: {
|
||||
marginBottom: 10
|
||||
}
|
||||
});
|
||||
|
||||
const propTypes = {
|
||||
teams: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired
|
||||
|
|
@ -36,33 +25,40 @@ export default class SelectTeamView extends Component {
|
|||
}
|
||||
|
||||
componentWillReceiveProps(props) {
|
||||
if (props.teams.currentTeamId && !this.props.teams.currentTeamId) {
|
||||
const {currentTeamId} = props.teams;
|
||||
if (currentTeamId &&
|
||||
currentTeamId !== this.props.teams.currentTeamId) {
|
||||
Routes.goToChannelsList();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const teams = _.values(this.props.teams.data);
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={GlobalStyles.container}>
|
||||
<Image
|
||||
style={styles.logo}
|
||||
style={GlobalStyles.logo}
|
||||
source={logo}
|
||||
/>
|
||||
<Picker
|
||||
style={{width: 300}}
|
||||
onValueChange={(team) => {
|
||||
this.props.actions.selectTeam(team);
|
||||
}}
|
||||
>
|
||||
{_.map(this.props.teams.data, (team) => (
|
||||
<Picker.Item
|
||||
key={team.id}
|
||||
label={team.display_name}
|
||||
value={team}
|
||||
/>
|
||||
))}
|
||||
</Picker>
|
||||
|
||||
<Text style={GlobalStyles.header}>
|
||||
{'Mattermost'}
|
||||
</Text>
|
||||
<Text style={GlobalStyles.subheader}>
|
||||
{'All team communication in one place, searchable and accessible anywhere'}
|
||||
</Text>
|
||||
<Text style={GlobalStyles.subheader}>
|
||||
{'Your teams:'}
|
||||
</Text>
|
||||
{_.map(teams, (team) => (
|
||||
<Button
|
||||
key={team.id}
|
||||
onPress={() => this.props.actions.selectTeam(team)}
|
||||
style={GlobalStyles.buttonListItemText}
|
||||
containerStyle={GlobalStyles.buttonListItem}
|
||||
>
|
||||
{team.display_name}
|
||||
</Button>
|
||||
))}
|
||||
<ErrorText error={this.props.teams.error}/>
|
||||
</View>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import ChannelsListView from 'components/channels_list_view';
|
|||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
teams: state.entities.teams,
|
||||
channels: state.entities.channels
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,42 @@
|
|||
import {StyleSheet} from 'react-native';
|
||||
|
||||
export const GlobalStyles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
paddingTop: 200,
|
||||
backgroundColor: 'white'
|
||||
},
|
||||
logo: {
|
||||
marginBottom: 10
|
||||
},
|
||||
header: {
|
||||
fontSize: 36,
|
||||
fontWeight: '600'
|
||||
},
|
||||
subheader: {
|
||||
fontSize: 18,
|
||||
fontWeight: '300',
|
||||
color: '#777'
|
||||
},
|
||||
buttonListItemText: {
|
||||
textAlign: 'left',
|
||||
fontSize: 18,
|
||||
fontWeight: '400',
|
||||
color: '#777'
|
||||
},
|
||||
buttonListItem: {
|
||||
alignSelf: 'stretch',
|
||||
height: 50,
|
||||
marginHorizontal: 15,
|
||||
marginVertical: 5,
|
||||
padding: 13,
|
||||
backgroundColor: '#fafafa',
|
||||
borderWidth: 1,
|
||||
borderRadius: 3,
|
||||
borderColor: '#d5d5d5'
|
||||
},
|
||||
button: {
|
||||
margin: 3,
|
||||
paddingTop: 10,
|
||||
|
|
@ -47,4 +83,4 @@ export const GlobalStyles = StyleSheet.create({
|
|||
alignSelf: 'stretch',
|
||||
borderRadius: 3
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue