Create room (#42)

* Added select users view

* create room working

* - Show photo on avatar

* Switched state for redux

* Navigating to created room
This commit is contained in:
Diego Mello 2017-09-25 10:15:28 -03:00 committed by Guilherme Gazzo
parent d55db0fca5
commit e0777a969e
12 changed files with 1081 additions and 4950 deletions

View File

@ -1,11 +1,10 @@
const REQUEST = 'REQUEST'; const REQUEST = 'REQUEST';
const SUCCESS = 'SUCCESS'; const SUCCESS = 'SUCCESS';
const FAILURE = 'FAILURE'; const FAILURE = 'FAILURE';
const defaultTypes = [REQUEST, SUCCESS, FAILURE]; const defaultTypes = [REQUEST, SUCCESS, FAILURE];
function createRequestTypes(base, types = defaultTypes) { function createRequestTypes(base, types = defaultTypes) {
const res = {}; const res = {};
types.forEach(type => res[type] = `${ base }_${ type }`); types.forEach(type => (res[type] = `${ base }_${ type }`));
return res; return res;
} }
@ -14,7 +13,16 @@ export const LOGIN = createRequestTypes('LOGIN', [...defaultTypes, 'SET_TOKEN',
export const ROOMS = createRequestTypes('ROOMS'); export const ROOMS = createRequestTypes('ROOMS');
export const APP = createRequestTypes('APP', ['READY', 'INIT']); export const APP = createRequestTypes('APP', ['READY', 'INIT']);
export const MESSAGES = createRequestTypes('MESSAGES'); export const MESSAGES = createRequestTypes('MESSAGES');
export const CREATE_CHANNEL = createRequestTypes('CREATE_CHANNEL', [...defaultTypes, 'REQUEST_USERS', 'SUCCESS_USERS', 'FAILURE_USERS', 'SET_USERS']); export const CREATE_CHANNEL = createRequestTypes('CREATE_CHANNEL', [
...defaultTypes,
'REQUEST_USERS',
'SUCCESS_USERS',
'FAILURE_USERS',
'SET_USERS',
'ADD_USER',
'REMOVE_USER',
'RESET'
]);
export const NAVIGATION = createRequestTypes('NAVIGATION', ['SET']); export const NAVIGATION = createRequestTypes('NAVIGATION', ['SET']);
export const SERVER = createRequestTypes('SERVER', [...defaultTypes, 'SELECT', 'CHANGED', 'ADD']); export const SERVER = createRequestTypes('SERVER', [...defaultTypes, 'SELECT', 'CHANGED', 'ADD']);
export const METEOR = createRequestTypes('METEOR_CONNECT', [...defaultTypes, 'DISCONNECT']); export const METEOR = createRequestTypes('METEOR_CONNECT', [...defaultTypes, 'DISCONNECT']);

View File

@ -21,7 +21,6 @@ export function createChannelFailure(err) {
}; };
} }
export function createChannelRequestUsers(data) { export function createChannelRequestUsers(data) {
return { return {
type: types.CREATE_CHANNEL.REQUEST_USERS, type: types.CREATE_CHANNEL.REQUEST_USERS,
@ -49,3 +48,23 @@ export function createChannelFailureUsers(err) {
err err
}; };
} }
export function addUser(user) {
return {
type: types.CREATE_CHANNEL.ADD_USER,
user
};
}
export function removeUser(user) {
return {
type: types.CREATE_CHANNEL.REMOVE_USER,
user
};
}
export function reset() {
return {
type: types.CREATE_CHANNEL.RESET
};
}

View File

@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import { StackNavigator, DrawerNavigator } from 'react-navigation'; import { Button } from 'react-native';
import { StackNavigator, DrawerNavigator, NavigationActions } from 'react-navigation';
// import { Platform } from 'react-native'; // import { Platform } from 'react-native';
import Sidebar from '../../containers/Sidebar'; import Sidebar from '../../containers/Sidebar';
@ -8,10 +9,18 @@ import DrawerMenuButton from '../../presentation/DrawerMenuButton';
import RoomsListView from '../../views/RoomsListView'; import RoomsListView from '../../views/RoomsListView';
import RoomView from '../../views/RoomView'; import RoomView from '../../views/RoomView';
import CreateChannelView from '../../views/CreateChannelView'; import CreateChannelView from '../../views/CreateChannelView';
import SelectUsersView from '../../views/SelectUsersView';
const drawerPosition = 'left'; const drawerPosition = 'left';
const drawerIconPosition = 'headerLeft'; const drawerIconPosition = 'headerLeft';
const backToScreen = (navigation, routeName) => {
const action = NavigationActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName })]
});
navigation.dispatch(action);
};
const AuthRoutes = StackNavigator( const AuthRoutes = StackNavigator(
{ {
@ -20,7 +29,7 @@ const AuthRoutes = StackNavigator(
navigationOptions({ navigation }) { navigationOptions({ navigation }) {
return { return {
title: 'Rooms', title: 'Rooms',
[drawerIconPosition]: (<DrawerMenuButton navigation={navigation} />) [drawerIconPosition]: <DrawerMenuButton navigation={navigation} />
}; };
} }
}, },
@ -28,7 +37,10 @@ const AuthRoutes = StackNavigator(
screen: RoomView, screen: RoomView,
navigationOptions({ navigation }) { navigationOptions({ navigation }) {
return { return {
title: navigation.state.params.title || 'Room' title: navigation.state.params.title || 'Room',
headerLeft: (
<Button title={'Back'} onPress={() => backToScreen(navigation, 'RoomsList')} />
)
// [drawerIconPosition]: (<DrawerMenuButton navigation={navigation} />)÷ // [drawerIconPosition]: (<DrawerMenuButton navigation={navigation} />)÷
}; };
} }
@ -38,25 +50,33 @@ const AuthRoutes = StackNavigator(
navigationOptions: { navigationOptions: {
title: 'Create Channel' title: 'Create Channel'
} }
},
SelectUsers: {
screen: SelectUsersView,
navigationOptions: {
title: 'Select Users'
}
}
},
{}
);
const Routes = DrawerNavigator(
{
Home: {
screen: AuthRoutes,
navigationOptions({ navigation }) {
return {
title: 'Rooms',
[drawerIconPosition]: <DrawerMenuButton navigation={navigation} />
};
}
} }
}, },
{ {
contentComponent: Sidebar,
drawerPosition
} }
); );
const Routes = DrawerNavigator({
Home: {
screen: AuthRoutes,
navigationOptions({ navigation }) {
return {
title: 'Rooms',
[drawerIconPosition]: (<DrawerMenuButton navigation={navigation} />)
};
}
}
}, {
contentComponent: Sidebar,
drawerPosition
});
export default Routes; export default Routes;

View File

@ -3,6 +3,7 @@ import 'regenerator-runtime/runtime';
import { createStore, applyMiddleware } from 'redux'; import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga'; import createSagaMiddleware from 'redux-saga';
import logger from 'redux-logger';
import { composeWithDevTools } from 'remote-redux-devtools'; import { composeWithDevTools } from 'remote-redux-devtools';
import reducers from '../reducers'; import reducers from '../reducers';
import sagas from '../sagas'; import sagas from '../sagas';
@ -13,9 +14,11 @@ let enhacers;
if (__DEV__) { if (__DEV__) {
/* eslint-disable global-require */ /* eslint-disable global-require */
const reduxImmutableStateInvariant = require('redux-immutable-state-invariant').default(); const reduxImmutableStateInvariant = require('redux-immutable-state-invariant').default();
enhacers = composeWithDevTools( enhacers = composeWithDevTools(
applyMiddleware(reduxImmutableStateInvariant), applyMiddleware(reduxImmutableStateInvariant),
applyMiddleware(sagaMiddleware) applyMiddleware(sagaMiddleware),
applyMiddleware(logger)
); );
} else { } else {
enhacers = composeWithDevTools( enhacers = composeWithDevTools(

View File

@ -2,29 +2,45 @@ import { CREATE_CHANNEL } from '../actions/actionsTypes';
const initialState = { const initialState = {
isFetching: false, isFetching: false,
failure: false failure: false,
users: []
}; };
export default function messages(state = initialState, action) { export default function messages(state = initialState, action) {
switch (action.type) { switch (action.type) {
case CREATE_CHANNEL.REQUEST: case CREATE_CHANNEL.REQUEST:
return { ...state, return {
...state,
error: undefined, error: undefined,
failure: false, failure: false,
isFetching: true isFetching: true
}; };
case CREATE_CHANNEL.SUCCESS: case CREATE_CHANNEL.SUCCESS:
return { ...state, return {
...state,
isFetching: false, isFetching: false,
failure: false, failure: false,
result: action.data result: action.data
}; };
case CREATE_CHANNEL.FAILURE: case CREATE_CHANNEL.FAILURE:
return { ...state, return {
...state,
isFetching: false, isFetching: false,
failure: true, failure: true,
error: action.err error: action.err
}; };
case CREATE_CHANNEL.ADD_USER:
return {
...state,
users: state.users.concat(action.user)
};
case CREATE_CHANNEL.REMOVE_USER:
return {
...state,
users: state.users.filter(item => item.name !== action.user.name)
};
case CREATE_CHANNEL.RESET:
return initialState;
default: default:
return state; return state;
} }

View File

@ -1,31 +1,29 @@
import { delay } from 'redux-saga'; import { delay } from 'redux-saga';
import { select, put, call, take, takeEvery } from 'redux-saga/effects'; import { select, put, call, take, takeLatest } from 'redux-saga/effects';
import { CREATE_CHANNEL, LOGIN } from '../actions/actionsTypes'; import { CREATE_CHANNEL, LOGIN } from '../actions/actionsTypes';
import { createChannelSuccess, createChannelFailure } from '../actions/createChannel'; import { createChannelSuccess, createChannelFailure } from '../actions/createChannel';
import RocketChat from '../lib/rocketchat'; import RocketChat from '../lib/rocketchat';
const create = function* create(data) { const create = function* create(data) {
return yield RocketChat.createChannel(data); return yield RocketChat.createChannel(data);
}; };
const get = function* get({ data }) { const get = function* get({ data }) {
try { try {
yield delay(1000);
const auth = yield select(state => state.login.isAuthenticated); const auth = yield select(state => state.login.isAuthenticated);
if (!auth) { if (!auth) {
yield take(LOGIN.SUCCESS); yield take(LOGIN.SUCCESS);
} }
const result = yield call(create, data); const result = yield call(create, data);
yield put(createChannelSuccess(result)); yield put(createChannelSuccess(result));
select(({ navigator }) => navigator).dismissModal({
animationType: 'slide-down'
});
} catch (err) { } catch (err) {
yield delay(2000);
yield put(createChannelFailure(err)); yield put(createChannelFailure(err));
} }
}; };
const getData = function* getData() { const getData = function* getData() {
yield takeEvery(CREATE_CHANNEL.REQUEST, get); yield takeLatest(CREATE_CHANNEL.REQUEST, get);
}; };
export default getData; export default getData;

View File

@ -6,20 +6,25 @@ import { createChannelRequest } from '../actions/createChannel';
import styles from './Styles'; import styles from './Styles';
import KeyboardView from '../presentation/KeyboardView'; import KeyboardView from '../presentation/KeyboardView';
@connect(state => ({ @connect(
result: state.createChannel state => ({
}), dispatch => ({ result: state.createChannel,
createChannel: data => dispatch(createChannelRequest(data)) users: state.createChannel.users
})) }),
dispatch => ({
createChannel: data => dispatch(createChannelRequest(data))
})
)
export default class CreateChannelView extends React.Component { export default class CreateChannelView extends React.Component {
static navigationOptions = () => ({ static navigationOptions = () => ({
title: 'Create a New Channel' title: 'Create a New Channel'
}); });
static propTypes = { static propTypes = {
createChannel: PropTypes.func.isRequired, createChannel: PropTypes.func.isRequired,
result: PropTypes.object.isRequired result: PropTypes.object.isRequired,
} users: PropTypes.array.isRequired,
navigation: PropTypes.object.isRequired
};
constructor(props) { constructor(props) {
super(props); super(props);
@ -29,23 +34,42 @@ export default class CreateChannelView extends React.Component {
}; };
this.state = this.default; this.state = this.default;
} }
componentDidUpdate() {
if (!this.adding) {
return;
}
if (this.props.result.result && !this.props.result.failure) {
this.props.navigation.navigate('Room', { room: this.props.result.result });
this.adding = false;
}
}
submit() { submit() {
this.adding = true;
if (!this.state.channelName.trim() || this.props.result.isFetching) { if (!this.state.channelName.trim() || this.props.result.isFetching) {
return; return;
} }
const { channelName, users = [], type = true } = this.state; const { channelName, type = true } = this.state;
let { users } = this.props;
// transform users object into array of usernames
users = users.map(user => user.name);
// create channel
this.props.createChannel({ name: channelName, users, type }); this.props.createChannel({ name: channelName, users, type });
} }
renderChannelNameError() { renderChannelNameError() {
if (!this.props.result.failure || this.props.result.error.error !== 'error-duplicate-channel-name') { if (
!this.props.result.failure ||
this.props.result.error.error !== 'error-duplicate-channel-name'
) {
return null; return null;
} }
return ( return (
<Text style={[styles.label_white, styles.label_error]}> <Text style={[styles.label_white, styles.label_error]}>{this.props.result.error.reason}</Text>
{this.props.result.error.reason}
</Text>
); );
} }
@ -91,18 +115,22 @@ export default class CreateChannelView extends React.Component {
flexGrow: 1, flexGrow: 1,
paddingHorizontal: 0, paddingHorizontal: 0,
marginBottom: 20 marginBottom: 20
}]} }
]}
> >
{this.state.type ? {this.state.type ? (
'Everyone can access this channel' : 'Everyone can access this channel'
'Just invited people can access this channel'} ) : (
'Just invited people can access this channel'
)}
</Text> </Text>
<TouchableOpacity <TouchableOpacity
onPress={() => this.submit()} onPress={() => this.submit()}
style={[ style={[
styles.buttonContainer_white, styles.buttonContainer_white,
(this.state.channelName.length === 0 || this.props.result.isFetching) ? this.state.channelName.length === 0 || this.props.result.isFetching
styles.disabledButton : styles.enabledButton ? styles.disabledButton
: styles.enabledButton
]} ]}
> >
<Text style={styles.button_white}> <Text style={styles.button_white}>

View File

@ -43,16 +43,18 @@ const styles = StyleSheet.create({
} }
}); });
@connect(
@connect(state => ({ state => ({
server: state.server.server, server: state.server.server,
Site_Url: state.settings.Site_Url, Site_Url: state.settings.Site_Url,
Message_TimeFormat: state.settings.Message_TimeFormat, Message_TimeFormat: state.settings.Message_TimeFormat,
loading: state.messages.isFetching loading: state.messages.isFetching
}), dispatch => ({ }),
actions: bindActionCreators(actions, dispatch), dispatch => ({
getMessages: rid => dispatch(messagesRequest({ rid })) actions: bindActionCreators(actions, dispatch),
})) getMessages: rid => dispatch(messagesRequest({ rid }))
})
)
export default class RoomView extends React.Component { export default class RoomView extends React.Component {
static propTypes = { static propTypes = {
navigation: PropTypes.object.isRequired, navigation: PropTypes.object.isRequired,
@ -64,15 +66,21 @@ export default class RoomView extends React.Component {
Site_Url: PropTypes.string, Site_Url: PropTypes.string,
Message_TimeFormat: PropTypes.string, Message_TimeFormat: PropTypes.string,
loading: PropTypes.bool loading: PropTypes.bool
} };
constructor(props) { constructor(props) {
super(props); super(props);
this.sid = props.navigation.state.params.room.sid; this.sid = props.navigation.state.params.room.sid;
this.rid = props.rid || realm.objectForPrimaryKey('subscriptions', this.sid).rid; this.rid =
props.rid ||
props.navigation.state.params.room.rid ||
realm.objectForPrimaryKey('subscriptions', this.sid).rid;
this.data = realm.objects('messages').filtered('_server.id = $0 AND rid = $1', this.props.server, this.rid).sorted('ts', true); this.data = realm
.objects('messages')
.filtered('_server.id = $0 AND rid = $1', this.props.server, this.rid)
.sorted('ts', true);
this.state = { this.state = {
slow: false, slow: false,
dataSource: [], dataSource: [],
@ -83,7 +91,10 @@ export default class RoomView extends React.Component {
componentWillMount() { componentWillMount() {
this.props.navigation.setParams({ this.props.navigation.setParams({
title: this.props.name || realm.objectForPrimaryKey('subscriptions', this.sid).name title:
this.props.name ||
this.props.navigation.state.params.room.name ||
realm.objectForPrimaryKey('subscriptions', this.sid).name
}); });
this.timer = setTimeout(() => this.setState({ slow: true }), 5000); this.timer = setTimeout(() => this.setState({ slow: true }), 5000);
this.props.getMessages(this.rid); this.props.getMessages(this.rid);
@ -103,7 +114,12 @@ export default class RoomView extends React.Component {
onEndReached = () => { onEndReached = () => {
const rowCount = this.state.dataSource.getRowCount(); const rowCount = this.state.dataSource.getRowCount();
if (rowCount && this.state.loaded && this.state.loadingMore !== true && this.state.end !== true) { if (
rowCount &&
this.state.loaded &&
this.state.loadingMore !== true &&
this.state.end !== true
) {
this.setState({ this.setState({
// ...this.state, // ...this.state,
loadingMore: true loadingMore: true
@ -118,7 +134,7 @@ export default class RoomView extends React.Component {
}); });
}); });
} }
} };
updateState = () => { updateState = () => {
this.setState({ this.setState({
@ -135,13 +151,12 @@ export default class RoomView extends React.Component {
}); });
}; };
renderBanner = () => (this.state.slow && this.props.loading ? renderBanner = () =>
( (this.state.slow && this.props.loading ? (
<View style={styles.bannerContainer}> <View style={styles.bannerContainer}>
<Text style={styles.bannerText}>Loading new messages...</Text> <Text style={styles.bannerText}>Loading new messages...</Text>
</View> </View>
) : null) ) : null);
renderItem = ({ item }) => ( renderItem = ({ item }) => (
<Message <Message
@ -152,9 +167,7 @@ export default class RoomView extends React.Component {
/> />
); );
renderSeparator = () => ( renderSeparator = () => <View style={styles.separator} />;
<View style={styles.separator} />
);
renderFooter = () => { renderFooter = () => {
if (!this.state.joined) { if (!this.state.joined) {
@ -165,14 +178,8 @@ export default class RoomView extends React.Component {
</View> </View>
); );
} }
return ( return <MessageBox ref={box => (this.box = box)} onSubmit={this.sendMessage} rid={this.rid} />;
<MessageBox };
ref={box => this.box = box}
onSubmit={this.sendMessage}
rid={this.rid}
/>
);
}
renderHeader = () => { renderHeader = () => {
if (this.state.loadingMore) { if (this.state.loadingMore) {
@ -182,7 +189,7 @@ export default class RoomView extends React.Component {
if (this.state.end) { if (this.state.end) {
return <Text style={styles.header}>Start of conversation</Text>; return <Text style={styles.header}>Start of conversation</Text>;
} }
} };
render() { render() {
return ( return (

View File

@ -207,7 +207,7 @@ export default class RoomsListView extends React.Component {
} }
_createChannel() { _createChannel() {
this.props.navigation.navigate('CreateChannel'); this.props.navigation.navigate('SelectUsers');
} }
renderSearchBar = () => ( renderSearchBar = () => (

View File

@ -0,0 +1,271 @@
import ActionButton from 'react-native-action-button';
import { ListView } from 'realm/react-native';
import React from 'react';
import PropTypes from 'prop-types';
import Icon from 'react-native-vector-icons/Ionicons';
import { View, StyleSheet, TextInput, Text, TouchableOpacity } from 'react-native';
import { connect } from 'react-redux';
import * as actions from '../actions';
import * as server from '../actions/connect';
import * as createChannelActions from '../actions/createChannel';
import realm from '../lib/realm';
import RocketChat from '../lib/rocketchat';
import RoomItem from '../presentation/RoomItem';
import Banner from '../containers/Banner';
import Avatar from '../containers/Avatar';
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'stretch',
justifyContent: 'center'
},
list: {
width: '100%',
backgroundColor: '#FFFFFF'
},
actionButtonIcon: {
fontSize: 20,
height: 22,
color: 'white'
},
searchBoxView: {
backgroundColor: '#eee'
},
searchBox: {
backgroundColor: '#fff',
margin: 5,
borderRadius: 5,
padding: 5,
paddingLeft: 10,
color: '#aaa'
},
selectItemView: {
width: 80,
height: 80,
padding: 8,
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center'
}
});
const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
@connect(
state => ({
server: state.server.server,
login: state.login,
Site_Url: state.settings.Site_Url,
users: state.createChannel.users
}),
dispatch => ({
login: () => dispatch(actions.login()),
connect: () => dispatch(server.connectRequest()),
addUser: user => dispatch(createChannelActions.addUser(user)),
removeUser: user => dispatch(createChannelActions.removeUser(user)),
resetCreateChannel: () => dispatch(createChannelActions.reset())
})
)
export default class RoomsListView extends React.Component {
static propTypes = {
navigation: PropTypes.object.isRequired,
Site_Url: PropTypes.string,
server: PropTypes.string,
addUser: PropTypes.func.isRequired,
removeUser: PropTypes.func.isRequired,
resetCreateChannel: PropTypes.func.isRequired,
users: PropTypes.array
};
constructor(props) {
super(props);
this.data = realm
.objects('subscriptions')
.filtered('_server.id = $0 AND t = $1', this.props.server, 'd');
this.state = {
dataSource: ds.cloneWithRows(this.data),
searching: false,
searchDataSource: [],
searchText: '',
login: false
};
this.data.addListener(this.updateState);
}
componentWillUnmount() {
this.data.removeListener(this.updateState);
this.props.resetCreateChannel();
}
onSearchChangeText = (text) => {
const searchText = text.trim();
this.setState({
searchText: text,
searching: searchText !== ''
});
if (searchText === '') {
return this.setState({
dataSource: ds.cloneWithRows(this.data)
});
}
const data = this.data.filtered('name CONTAINS[c] $0', searchText).slice();
const usernames = [];
const dataSource = data.map((sub) => {
if (sub.t === 'd') {
usernames.push(sub.name);
}
return sub;
});
if (dataSource.length < 7) {
if (this.oldPromise) {
this.oldPromise();
}
Promise.race([
RocketChat.spotlight(searchText, usernames),
new Promise((resolve, reject) => (this.oldPromise = reject))
])
.then(
(results) => {
results.users.forEach((user) => {
dataSource.push({
...user,
name: user.username,
t: 'd',
search: true
});
});
this.setState({
dataSource: ds.cloneWithRows(dataSource)
});
},
() => console.log('spotlight stopped')
)
.then(() => delete this.oldPromise);
}
this.setState({
dataSource: ds.cloneWithRows(dataSource)
});
};
updateState = () => {
this.setState({
dataSource: ds.cloneWithRows(this.data)
});
};
toggleUser = (user) => {
const index = this.props.users.findIndex(el => el.name === user.name);
if (index === -1) {
this.props.addUser(user);
} else {
this.props.removeUser(user);
}
};
_onPressItem = (id, item = {}) => {
if (item.search) {
this.toggleUser({ _id: item._id, name: item.username });
} else {
this.toggleUser({ _id: item._id, name: item.name });
}
};
_onPressSelectedItem = item => this.toggleUser(item);
_createChannel = () => {
this.props.navigation.navigate('CreateChannel');
};
renderHeader = () => (
<View style={styles.container}>
{this.renderSearchBar()}
{this.renderSelected()}
</View>
);
renderSearchBar = () => (
<View style={styles.searchBoxView}>
<TextInput
underlineColorAndroid='transparent'
style={styles.searchBox}
value={this.state.searchText}
onChangeText={this.onSearchChangeText}
returnKeyType='search'
placeholder='Search'
clearButtonMode='while-editing'
blurOnSubmit
/>
</View>
);
renderSelected = () => {
if (this.props.users.length === 0) {
return null;
}
const usersDataSource = ds.cloneWithRows(this.props.users);
return (
<ListView
dataSource={usersDataSource}
style={styles.list}
renderRow={this.renderSelectedItem}
enableEmptySections
keyboardShouldPersistTaps='always'
horizontal
/>
);
};
renderSelectedItem = item => (
<TouchableOpacity
key={item._id}
style={styles.selectItemView}
onPress={() => this._onPressSelectedItem(item)}
>
<Avatar text={item.name} baseUrl={this.props.Site_Url} size={40} borderRadius={20} />
<Text ellipsizeMode='tail' numberOfLines={1} style={{ fontSize: 10 }}>
{item.name}
</Text>
</TouchableOpacity>
);
renderItem = item => (
<RoomItem
key={item._id}
name={item.name}
type={item.t}
baseUrl={this.props.Site_Url}
onPress={() => this._onPressItem(item._id, item)}
/>
);
renderList = () => (
<ListView
dataSource={this.state.dataSource}
style={styles.list}
renderRow={this.renderItem}
renderHeader={this.renderHeader}
contentOffset={{ x: 0, y: this.props.users.length > 0 ? 40 : 20 }}
enableEmptySections
keyboardShouldPersistTaps='always'
/>
);
renderCreateButton = () => {
if (this.props.users.length === 0) {
return null;
}
return (
<ActionButton
buttonColor='rgba(67, 165, 71, 1)'
onPress={() => this._createChannel()}
icon={<Icon name='md-arrow-forward' style={styles.actionButtonIcon} />}
/>
);
};
render = () => (
<View style={styles.container}>
<Banner />
{this.renderList()}
{this.renderCreateButton()}
</View>
);
}

View File

@ -800,7 +800,6 @@
TestTargetID = 13B07F861A680F5B00A75B9A; TestTargetID = 13B07F861A680F5B00A75B9A;
}; };
13B07F861A680F5B00A75B9A = { 13B07F861A680F5B00A75B9A = {
DevelopmentTeam = S6UPZG7ZR3;
ProvisioningStyle = Automatic; ProvisioningStyle = Automatic;
}; };
2D02E47A1E0B4A5D006451C7 = { 2D02E47A1E0B4A5D006451C7 = {
@ -1379,7 +1378,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEAD_CODE_STRIPPING = NO; DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = S6UPZG7ZR3; DEVELOPMENT_TEAM = "";
HEADER_SEARCH_PATHS = ( HEADER_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"$(SRCROOT)/../node_modules/realm/src/**", "$(SRCROOT)/../node_modules/realm/src/**",
@ -1412,7 +1411,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = S6UPZG7ZR3; DEVELOPMENT_TEAM = "";
HEADER_SEARCH_PATHS = ( HEADER_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"$(SRCROOT)/../node_modules/realm/src/**", "$(SRCROOT)/../node_modules/realm/src/**",

5484
package-lock.json generated

File diff suppressed because it is too large Load Diff