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:
Thomas Hopkins 2016-10-18 13:32:07 -07:00 committed by GitHub
parent 0697bfc066
commit d4a98c082a
7 changed files with 115 additions and 106 deletions

View file

@ -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",

View file

@ -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>

View file

@ -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()}

View file

@ -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'

View file

@ -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>
);

View file

@ -8,6 +8,7 @@ import ChannelsListView from 'components/channels_list_view';
function mapStateToProps(state) {
return {
teams: state.entities.teams,
channels: state.entities.channels
};
}

View file

@ -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
}
});
});