From 0a48fadf1678d6cffbfe2503e0e6c561ad87d055 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Sun, 20 Aug 2017 21:11:46 -0300 Subject: [PATCH] saga finished --- app/actions/actionsTypes.js | 3 +- app/actions/login.js | 13 +++- app/actions/navigator.js | 8 +++ app/animations/fade.js | 53 ++++++++++++++++ app/components/banner.js | 6 +- app/images/logo.png | Bin 0 -> 56449 bytes app/images/logo.svg | 77 +++++++++++++++++++++++ app/index.js | 80 +++++++++++++++++++++++ app/lib/createStore.js | 2 +- app/lib/realm.js | 5 +- app/lib/rocketchat.js | 17 +++-- app/navigation.js | 13 ++-- app/reducers/index.js | 5 +- app/reducers/login.js | 14 ++--- app/reducers/navigator.js | 13 ++++ app/sagas/login.js | 107 ++++++++++++++++++++++--------- app/sagas/messages.js | 8 +-- app/sagas/rooms.js | 1 + app/sagas/selectServer.js | 12 +--- app/views/login.js | 122 +++++++++++++++++++++++++----------- app/views/roomsList.js | 57 +++++++++++------ app/views/serverList.js | 41 ++++++++---- package-lock.json | 10 +++ package.json | 2 + 24 files changed, 531 insertions(+), 138 deletions(-) create mode 100644 app/actions/navigator.js create mode 100644 app/animations/fade.js create mode 100644 app/images/logo.png create mode 100644 app/images/logo.svg create mode 100644 app/index.js create mode 100644 app/reducers/navigator.js diff --git a/app/actions/actionsTypes.js b/app/actions/actionsTypes.js index 07ca9a4c..efacd963 100644 --- a/app/actions/actionsTypes.js +++ b/app/actions/actionsTypes.js @@ -10,9 +10,10 @@ function createRequestTypes(base, types = defaultTypes) { } // Login events -export const LOGIN = createRequestTypes('LOGIN', [...defaultTypes, 'SET_TOKEN']); +export const LOGIN = createRequestTypes('LOGIN', [...defaultTypes, 'SET_TOKEN', 'SUBMIT']); export const ROOMS = createRequestTypes('ROOMS'); export const MESSAGES = createRequestTypes('MESSAGES'); +export const NAVIGATION = createRequestTypes('NAVIGATION', ['SET']); export const SERVER = createRequestTypes('SERVER', ['SELECT', 'CHANGED']); export const METEOR = createRequestTypes('METEOR_CONNECT', [...defaultTypes, 'DISCONNECT']); export const LOGOUT = 'LOGOUT'; // logout is always success diff --git a/app/actions/login.js b/app/actions/login.js index 4f8c248d..cffc3cdd 100644 --- a/app/actions/login.js +++ b/app/actions/login.js @@ -1,9 +1,15 @@ import * as types from './actionsTypes'; +export function loginSubmit(credentials) { + return { + type: types.LOGIN.SUBMIT, + credentials + }; +} export function loginRequest(credentials) { return { type: types.LOGIN.REQUEST, - ...credentials + credentials }; } @@ -22,10 +28,11 @@ export function loginFailure(err) { }; } -export function setToken(token) { +export function setToken(user) { return { type: types.LOGIN.SET_TOKEN, - token + token: user.token, + user }; } diff --git a/app/actions/navigator.js b/app/actions/navigator.js new file mode 100644 index 00000000..b328a235 --- /dev/null +++ b/app/actions/navigator.js @@ -0,0 +1,8 @@ +import * as types from './actionsTypes'; + +export default function setNavigation(navigator = {}) { + return { + type: types.NAVIGATION.SET, + navigator + }; +} diff --git a/app/animations/fade.js b/app/animations/fade.js new file mode 100644 index 00000000..725ccbaa --- /dev/null +++ b/app/animations/fade.js @@ -0,0 +1,53 @@ +import React from 'react'; +import { Animated, Text } from 'react-native'; + +export default class Fade extends React.Component { + constructor(props) { + super(props); + this.state = { + visible: props.visible + }; + } + + componentWillMount() { + this._visibility = new Animated.Value(this.props.visible ? 1 : 0); + } + + componentWillReceiveProps(nextProps) { + if (nextProps.visible) { + this.setState({ visible: true }); + } + Animated.timing(this._visibility, { + toValue: nextProps.visible ? 1 : 0, + duration: 300 + }).start(() => { + this.setState({ visible: nextProps.visible }); + }); + } + + render() { + const { visible, style, children, ...rest } = this.props; + + const containerStyle = { + opacity: this._visibility.interpolate({ + inputRange: [0, 1], + outputRange: [0, 1] + }), + transform: [ + { + scale: this._visibility.interpolate({ + inputRange: [0, 1], + outputRange: [1.1, 1] + }) + } + ] + }; + + const combinedStyle = [containerStyle, style]; + return ( + + {this.state.visible ? children : null} + + ); + } +} diff --git a/app/components/banner.js b/app/components/banner.js index 77a03a1e..eb159c49 100644 --- a/app/components/banner.js +++ b/app/components/banner.js @@ -5,7 +5,11 @@ import { connect } from 'react-redux'; const styles = StyleSheet.create({ bannerContainer: { - backgroundColor: '#ddd' + backgroundColor: '#ddd', + position: 'absolute', + top: '0%', + zIndex: 10, + width: '100%' }, bannerText: { textAlign: 'center', diff --git a/app/images/logo.png b/app/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..57a423a6bc508408495923b024dea05727abb4a3 GIT binary patch literal 56449 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 M?`tX*E119iKQWuktpET3 literal 0 HcmV?d00001 diff --git a/app/images/logo.svg b/app/images/logo.svg new file mode 100644 index 00000000..33663753 --- /dev/null +++ b/app/images/logo.svg @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/index.js b/app/index.js new file mode 100644 index 00000000..89795d76 --- /dev/null +++ b/app/index.js @@ -0,0 +1,80 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { Text } from 'react-native'; +import setNavigator from './actions/navigator'; +import LoginView from './views/login'; +import ListServerView from './views/serverList'; + +import store from './lib/createStore'; + +// +// export const authenticated = (view) => { +// if (!store.getState().login.authenticated) { +// return store.getState().navigator.resetTo({ +// screen: 'Login' +// }); +// } +// return view; +// }; + +export const authenticated = WrappedComponent => class _p extends React.PureComponent { + constructor() { + super(); + this.login = store.getState().login; + console.log('this.login.token', this.login.token); + if (!this.login.token || this.login.failure) { + return store.getState().navigator.resetTo({ + screen: 'Login' + }); + } + } + render() { + // Wraps the input component in a container, without mutating it. Good! + return ; + } +}; +// +export class PublicScreen extends React.PureComponent { + // componentWillMount() { + // this.props.setNavigator(this.props.navigator); + // if (this.props.currentServer) { + // return this.props.navigator.navigate('private'); + // } + // } + render() { + return !this.login.isAuthenticated || !this.login.user ? null : (); + } +} + + +@connect(null, dispatch => ({ + setNavigator: navigator => dispatch(setNavigator(navigator)) +})) +export class PrivateScreen extends React.PureComponent { + componentWillMount() { + // this.props.setNavigator(this.props.navigator); + } + render() { + // if (this.props.logged) { + // return (oi); + // } + return (); + } +} +@connect(state => ({ + // logged: state.login.isAuthenticated +}), dispatch => ({ + // navigate: routeName => dispatch(NavigationActions.navigate({ routeName })), + setNavigator: navigator => dispatch(setNavigator(navigator)) +})) +export const HomeScreen = class extends React.PureComponent { + componentWillMount() { + this.props.setNavigator(this.props.navigator); + this.props.navigator.resetTo({ + screen: 'public' + }); + } + render() { + return (oieee); + } +}; diff --git a/app/lib/createStore.js b/app/lib/createStore.js index 7e6599e5..d187127f 100644 --- a/app/lib/createStore.js +++ b/app/lib/createStore.js @@ -13,7 +13,7 @@ let middleware; if (__DEV__) { /* eslint-disable global-require */ const reduxImmutableStateInvariant = require('redux-immutable-state-invariant').default(); - middleware = [sagaMiddleware, reduxImmutableStateInvariant, logger]; + middleware = [sagaMiddleware, reduxImmutableStateInvariant]; } else { middleware = [sagaMiddleware]; } diff --git a/app/lib/realm.js b/app/lib/realm.js index b1219a3b..c58b4a75 100644 --- a/app/lib/realm.js +++ b/app/lib/realm.js @@ -1,4 +1,5 @@ import Realm from 'realm'; +import { AsyncStorage } from 'react-native'; const serversSchema = { name: 'servers', @@ -153,9 +154,9 @@ const messagesSchema = { // ] // } }; - +// // Realm.clearTestState(); - +// AsyncStorage.clear(); const realm = new Realm({ schema: [settingsSchema, serversSchema, subscriptionSchema, messagesSchema, usersSchema, attachment] }); diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 900cc6a6..a776eebe 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -51,9 +51,9 @@ const RocketChat = { reduxStore.dispatch(connectSuccess()); resolve(); }); - Meteor.ddp.on('loggin', () => { - reduxStore.dispatch(loginSuccess({})); - }); + // Meteor.ddp.on('loggin', () => { + // reduxStore.dispatch(loginSuccess({})); + // }); Meteor.ddp.on('connected', () => { Meteor.call('public-settings/get', (err, data) => { if (err) { @@ -105,11 +105,13 @@ const RocketChat = { }, login(params, callback) { + console.log('login(params, callback)'); return new Promise((resolve, reject) => { Meteor._startLoggingIn(); return Meteor.call('login', params, (err, result) => { Meteor._endLoggingIn(); Meteor._handleLoginCallback(err, result); + console.log('login(params, callback)asdas', err, result); if (err) { reject(err); } else { @@ -224,6 +226,7 @@ const RocketChat = { getMessage(rid, msg = {}) { const _id = Random.id(); + // console.log('reduxStore.getState().login.id ', reduxStore.getState().login); const message = { _id, rid, @@ -233,8 +236,8 @@ const RocketChat = { temp: true, _server: { id: reduxStore.getState().server }, u: { - _id: reduxStore.getState()._id, - username: reduxStore.getState()._id + _id: reduxStore.getState().login.user.id || '1', + username: reduxStore.getState().login.user.id } }; @@ -367,14 +370,15 @@ const RocketChat = { getRooms() { // Meteor.Accounts.onLogin(() => { return Promise.all([call('subscriptions/get'), call('rooms/get')]).then(([subscriptions, rooms]) => { + // console.log('getRooms resolved', reduxStore.getState().server, subscriptions); subscriptions = subscriptions.sort((s1, s2) => (s1.rid > s2.rid ? 1 : -1)); rooms = rooms.sort((s1, s2) => (s1._id > s2._id ? 1 : -1)); const data = subscriptions.map((subscription, index) => { subscription._updatedAt = rooms[index]._updatedAt; return subscription; }); - Meteor.subscribe('stream-notify-user', `${ Meteor.userId() }/subscriptions-changed`, false); // Meteor.subscribe('stream-notify-user', `${ Meteor.userId() }/rooms-changed`, false); + console.log('getRooms resolved', reduxStore.getState().server, data); realm.write(() => { data.forEach((subscription) => { // const subscription = { @@ -388,6 +392,7 @@ const RocketChat = { realm.create('subscriptions', subscription, true); }); }); + Meteor.subscribe('stream-notify-user', `${ reduxStore.getState().user.id }/subscriptions-changed`, false); return data; }).then(data => data); // }); diff --git a/app/navigation.js b/app/navigation.js index 65a87c97..9ee61d2f 100644 --- a/app/navigation.js +++ b/app/navigation.js @@ -9,8 +9,13 @@ import RoomView from './views/room'; import PhotoView from './views/Photo'; import CreateChannel from './views/CreateChannel'; import store from './lib/createStore'; +import { PrivateScreen, HomeScreen, authenticated } from './index'; -Navigation.registerComponent('Rooms', () => RoomsListView, store, Provider); +// console.log('fisateile/', PublicRoute(PublicScreen)); +Navigation.registerComponent('home', () => HomeScreen, store, Provider); +Navigation.registerComponent('private', () => PrivateScreen, store, Provider); +Navigation.registerComponent('public', () => ListServerView, store, Provider); +Navigation.registerComponent('Rooms', () => authenticated(RoomsListView), store, Provider); Navigation.registerComponent('Room', () => RoomView, store, Provider); Navigation.registerComponent('Photo', () => PhotoView, store, Provider); Navigation.registerComponent('ListServer', () => ListServerView, store, Provider); @@ -20,8 +25,8 @@ Navigation.registerComponent('CreateChannel', () => CreateChannel, store, Provid Navigation.startSingleScreenApp({ screen: { - screen: 'ListServer', - title: 'ListServer' + screen: 'home', + title: 'private' }, - animationType: 'none' + animationType: 'slide-up' }); diff --git a/app/reducers/index.js b/app/reducers/index.js index bc162c81..108f9add 100644 --- a/app/reducers/index.js +++ b/app/reducers/index.js @@ -1,11 +1,12 @@ import { combineReducers } from 'redux'; -import * as reducers from './reducers'; +import settings from './reducers'; import login from './login'; import meteor from './connect'; import messages from './messages'; import server from './server'; +import navigator from './navigator'; export default combineReducers({ - ...reducers, login, meteor, messages, server + settings, login, meteor, messages, server, navigator }); diff --git a/app/reducers/login.js b/app/reducers/login.js index 4aacbd59..72f36d52 100644 --- a/app/reducers/login.js +++ b/app/reducers/login.js @@ -11,16 +11,18 @@ const initialState = { export default function login(state = initialState, action) { switch (action.type) { case types.LOGIN.REQUEST: + console.log('types.LOGIN.REQUEST', action); return { ...state, isFetching: true, - isAuthenticated: false + isAuthenticated: false, + failure: false }; case types.LOGIN.SUCCESS: return { ...state, isFetching: false, isAuthenticated: true, user: action.user, - // token: action.token, + token: action.user.token, failure: false // user: action.user }; @@ -32,13 +34,11 @@ export default function login(state = initialState, action) { errorMessage: action.err }; case types.LOGOUT: - return { ...state, - isFetching: false, - isAuthenticated: false - }; + return initialState; case types.LOGIN.SET_TOKEN: return { ...state, - token: action.token + token: action.token, + user: action.user }; default: return state; diff --git a/app/reducers/navigator.js b/app/reducers/navigator.js new file mode 100644 index 00000000..75c2cf09 --- /dev/null +++ b/app/reducers/navigator.js @@ -0,0 +1,13 @@ +import * as types from '../actions/actionsTypes'; + +const initialState = {}; + +export default function navigations(state = initialState, action) { + switch (action.type) { + case types.NAVIGATION.SET: + return action.navigator + ; + default: + return state; + } +} diff --git a/app/sagas/login.js b/app/sagas/login.js index 6462ff71..b21d2503 100644 --- a/app/sagas/login.js +++ b/app/sagas/login.js @@ -1,55 +1,102 @@ import { AsyncStorage } from 'react-native'; -import { take, put, call, takeEvery, fork, select, all } from 'redux-saga/effects'; +import { take, put, call, takeEvery, fork, select, all, race } from 'redux-saga/effects'; import * as types from '../actions/actionsTypes'; import { loginRequest, loginSuccess, loginFailure, setToken } from '../actions/login'; import RocketChat from '../lib/rocketchat'; const TOKEN_KEY = 'reactnativemeteor_usertoken'; -const getUser = state => state.login.user; +const getUser = state => state.login; const getServer = state => state.server; const loginCall = args => (args.resume ? RocketChat.login(args) : RocketChat.loginWithPassword(args)); const getToken = function* getToken() { const currentServer = yield select(getServer); - console.log('currentServer', currentServer); - const token = yield call([AsyncStorage, 'getItem'], `${ TOKEN_KEY }-${ currentServer }`); - console.log('currentServer TOKEN', token); - if (token) { yield put(setToken(token)); } - // yield call([AsyncStorage, 'setItem'], TOKEN_KEY, token || ''); - return token; -}; - -const sagaLogin = function* sagaLogin(payload) { - try { - const response = yield call(loginCall, payload); - yield put(loginSuccess(response)); - } catch (err) { - yield put(loginFailure(err)); + const user = yield call([AsyncStorage, 'getItem'], `${ TOKEN_KEY }-${ currentServer }`); + if (user) { + try { + yield put(setToken(JSON.parse(user))); + yield call([AsyncStorage, 'setItem'], TOKEN_KEY, JSON.parse(user).token || ''); + return JSON.parse(user); + } catch (e) { + console.log('getTokenerr', e); + } } }; -const watchLoginRequest = function* watchLoginRequest() { - do { - try { - yield all([take(types.METEOR.SUCCESS), take(types.SERVER.CHANGED)]); - const token = yield call(getToken); - if (token) { - yield put(loginRequest({ resume: token })); - } - } catch (e) { - console.log(e); + +const handleLoginWhenServerChanges = function* handleLoginWhenServerChanges() { + // do { + try { + yield take(types.METEOR.SUCCESS); + const { navigator } = yield select(state => state); + navigator.resetTo({ + screen: 'Rooms' + }); + const user = yield select(getUser); + if (user.token) { + yield put(loginRequest({ resume: user.token })); + // console.log('AEEEEEEEEOOOOO'); + // // wait for a response + // const { error } = yield race({ + // success: take(types.LOGIN.SUCCESS), + // error: take(types.LOGIN.FAILURE) + // }); + // console.log('AEEEEEEEEOOOOO', error); + // if (!error) { + // navigator.resetTo({ + // screen: 'Rooms' + // }); + // } } - } while (true); + } catch (e) { + console.log(e); + } + // } while (true); }; const saveToken = function* saveToken() { const [server, user] = yield all([select(getServer), select(getUser)]); yield AsyncStorage.setItem(TOKEN_KEY, user.token); - yield AsyncStorage.setItem(`${ TOKEN_KEY }-${ server }`, user.token); + yield AsyncStorage.setItem(`${ TOKEN_KEY }-${ server }`, JSON.stringify(user)); +}; + +const handleLoginRequest = function* handleLoginRequest() { + while (true) { + const { credentials } = yield take(types.LOGIN.REQUEST); + try { + const response = yield call(loginCall, credentials); + yield put(loginSuccess(response)); + } catch (err) { + // console.log('login failed'); + yield put(loginFailure(err)); + } + } +}; + +const handleLoginSubmit = function* handleLoginSubmit() { + while (true) { + const { credentials } = yield take(types.LOGIN.SUBMIT); + // put a login request + yield put(loginRequest(credentials)); + // wait for a response + const { error } = yield race({ + success: take(types.LOGIN.SUCCESS), + error: take(types.LOGIN.FAILURE) + }); + + if (!error) { + const { navigator } = yield select(state => state); + navigator.resetTo({ + screen: 'Rooms' + }); + } + } }; const root = function* root() { - yield fork(watchLoginRequest); - yield takeEvery(types.LOGIN.REQUEST, sagaLogin); + yield takeEvery(types.SERVER.CHANGED, getToken); + yield takeEvery(types.SERVER.CHANGED, handleLoginWhenServerChanges); + yield fork(handleLoginRequest); yield takeEvery(types.LOGIN.SUCCESS, saveToken); + yield fork(handleLoginSubmit); }; export default root; diff --git a/app/sagas/messages.js b/app/sagas/messages.js index 47774474..e379398f 100644 --- a/app/sagas/messages.js +++ b/app/sagas/messages.js @@ -5,6 +5,7 @@ import RocketChat from '../lib/rocketchat'; const get = function* get({ rid }) { const auth = yield select(state => state.login.isAuthenticated); + console.log('hey now', yield select(state => state.login)); if (!auth) { yield take(LOGIN.SUCCESS); } @@ -19,9 +20,4 @@ const get = function* get({ rid }) { const getData = function* getData() { yield takeLatest(MESSAGES.REQUEST, get); }; - -const getMessages = function* getMessages() { - yield takeEvery(LOGIN.SUCCESS, getData); -}; - -export default getMessages; +export default getData; diff --git a/app/sagas/rooms.js b/app/sagas/rooms.js index 9cf6c7b9..a751d6b8 100644 --- a/app/sagas/rooms.js +++ b/app/sagas/rooms.js @@ -9,6 +9,7 @@ const getRooms = function* getRooms() { const watchRoomsRequest = function* watchRoomsRequest() { try { + console.log('getRooms'); yield call(getRooms); yield put(roomsSuccess()); } catch (err) { diff --git a/app/sagas/selectServer.js b/app/sagas/selectServer.js index 2e81c25b..f8df5c07 100644 --- a/app/sagas/selectServer.js +++ b/app/sagas/selectServer.js @@ -5,15 +5,9 @@ import { connectRequest, disconnect } from '../actions/connect'; import { changedServer } from '../actions/server'; const selectServer = function* selectServer(server) { - try { - yield put(disconnect()); - yield put(changedServer(server)); - yield (server && put(connectRequest(server))); - // console.log(Actions.login()); - // Actions.replace('login', {}); - } catch (e) { - console.log(e); - } + yield put(disconnect()); + yield put(changedServer(server)); + yield put(connectRequest(server)); }; const root = function* root() { yield takeEvery(SERVER.SELECT, selectServer); diff --git a/app/views/login.js b/app/views/login.js index 48c71e66..e32e21cd 100644 --- a/app/views/login.js +++ b/app/views/login.js @@ -1,41 +1,78 @@ import React from 'react'; + +import Spinner from 'react-native-loading-spinner-overlay'; + import PropTypes from 'prop-types'; -import { Text, TextInput, StyleSheet } from 'react-native'; +import { Keyboard, Text, TextInput, StyleSheet, View, Image, TouchableOpacity } from 'react-native'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; // import * as actions from '../actions'; import * as loginActions from '../actions/login'; import KeyboardView from '../components/KeyboardView'; +// import { Keyboard } from 'react-native' const styles = StyleSheet.create({ view: { flex: 1, flexDirection: 'column', justifyContent: 'center', + padding: 20, alignItems: 'stretch', - backgroundColor: '#fff' + backgroundColor: '#2f343d' + }, + logoContainer: { + flex: 1, + alignItems: 'center', + flexGrow: 1, + justifyContent: 'center' + }, + logo: { + width: 150, + // backgroundColor: 'red' + // height: 150, + resizeMode: 'contain' + }, + formContainer: { + // marginBottom: 20 }, input: { height: 40, - borderColor: '#aaa', - marginLeft: 20, - marginRight: 20, - marginTop: 10, - padding: 5, + marginBottom: 20, + borderRadius: 2, + paddingHorizontal: 10, borderWidth: 0, - backgroundColor: '#f6f6f6' + backgroundColor: 'rgba(255,255,255,.2)', + color: 'white' + }, + buttonContainer: { + paddingVertical: 15, + backgroundColor: '#414852', + marginBottom: 20 + }, + button: { + textAlign: 'center', + color: 'white', + borderRadius: 2, + fontWeight: '700' }, error: { textAlign: 'center', color: 'red', paddingTop: 5 + }, + loading: { + flex: 1, + position: 'absolute', + backgroundColor: 'rgba(255,255,255,.2)', + left: 0, + top: 0 } }); class LoginView extends React.Component { static propTypes = { navigator: PropTypes.object.isRequired, - loginRequest: PropTypes.func.isRequired, + loginSubmit: PropTypes.func.isRequired, server: PropTypes.string.isRequired, Accounts_EmailOrUsernamePlaceholder: PropTypes.string, Accounts_PasswordPlaceholder: PropTypes.string @@ -65,9 +102,8 @@ class LoginView extends React.Component { } submit = () => { const { username, password, code } = this.state; - console.log({ username, password, code }); - this.props.loginRequest({ username, password, code }); - this.props.navigator.dismissModal(); + this.props.loginSubmit({ username, password, code }); + Keyboard.dismiss(); } renderTOTP = () => { @@ -92,29 +128,45 @@ class LoginView extends React.Component { render() { return ( - this.setState({ username })} - keyboardType='email-address' - autoCorrect={false} - returnKeyType='done' - autoCapitalize='none' - autoFocus - onSubmitEditing={this.submit} - placeholder={this.props.Accounts_EmailOrUsernamePlaceholder || 'Email or username'} - /> - this.setState({ password })} - secureTextEntry - autoCorrect={false} - returnKeyType='done' - autoCapitalize='none' - onSubmitEditing={this.submit} - placeholder={this.props.Accounts_PasswordPlaceholder || 'Password'} - /> - {this.renderTOTP()} - {this.state.error} + + + + + this.setState({ username })} + keyboardType='email-address' + autoCorrect={false} + returnKeyType='done' + autoCapitalize='none' + autoFocus + + underlineColorAndroid='transparent' + onSubmitEditing={this.submit} + placeholder={this.props.Accounts_EmailOrUsernamePlaceholder || 'Email or username'} + /> + this.setState({ password })} + secureTextEntry + autoCorrect={false} + returnKeyType='done' + autoCapitalize='none' + + underlineColorAndroid='transparent' + onSubmitEditing={this.submit} + placeholder={this.props.Accounts_PasswordPlaceholder || 'Password'} + /> + {this.renderTOTP()} + + LOGIN + + {this.props.login.error && {this.props.login.error}} + + + ); } diff --git a/app/views/roomsList.js b/app/views/roomsList.js index fc89ea94..98b27260 100644 --- a/app/views/roomsList.js +++ b/app/views/roomsList.js @@ -1,9 +1,9 @@ import ActionButton from 'react-native-action-button'; -// import { Navigation } from 'react-native-navigation'; +import { Navigation } from 'react-native-navigation'; import { ListView } from 'realm/react-native'; import React from 'react'; import PropTypes from 'prop-types'; -import { View, StyleSheet, TextInput } from 'react-native'; +import { View, StyleSheet, TextInput, Platform } from 'react-native'; import { connect } from 'react-redux'; import * as actions from '../actions'; import * as server from '../actions/connect'; @@ -67,7 +67,7 @@ const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 }); export default class RoomsListView extends React.Component { static propTypes = { - // navigator: PropTypes.object.isRequired, + navigator: PropTypes.object.isRequired, server: PropTypes.string } @@ -81,8 +81,29 @@ export default class RoomsListView extends React.Component { searchText: '', login: false }; + this.data.addListener(this.updateState); + this.props.navigator.setOnNavigatorEvent(event => event.type === 'NavBarButtonPress' && event.id === 'servers' && + Navigation.showModal({ + screen: 'ListServer', + passProps: {}, + navigatorStyle: {}, + navigatorButtons: {}, + animationType: 'slide-up' + })); + this.props.navigator.setSubTitle({ + subtitle: this.props.server + }); + } + componentWillMount() { + const button = Platform.OS === 'ios' ? 'leftButtons' : 'rightButtons'; + this.props.navigator.setButtons({ + [button]: [{ + id: 'servers', + title: 'Servers' + }], + animated: true + }); } - componentWillUnmount() { this.data.removeListener(this.updateState); } @@ -148,16 +169,16 @@ export default class RoomsListView extends React.Component { updateState = () => { this.setState({ - dataSource: ds.cloneWithRows(this.state.data) + dataSource: ds.cloneWithRows(this.data) }); }; _onPressItem = (id, item = {}) => { const navigateToRoom = (room) => { - // this.props.navigator.push({ - // screen: 'Room', - // passProps: room - // }); + this.props.navigator.push({ + screen: 'Room', + passProps: room + }); }; const clearSearch = () => { @@ -218,6 +239,7 @@ export default class RoomsListView extends React.Component { this._onPressItem(item._id, item)} /> ) @@ -234,15 +256,10 @@ export default class RoomsListView extends React.Component { ) renderCreateButtons = () => ( ); - render= () => { - if (this.props.canShowList) { - return ( - - - {this.renderList()} - {this.renderCreateButtons()} - ); - } - return null; - } + render= () => ( + + + {this.renderList()} + {this.renderCreateButtons()} + ) } diff --git a/app/views/serverList.js b/app/views/serverList.js index ab7156cb..421e7bc5 100644 --- a/app/views/serverList.js +++ b/app/views/serverList.js @@ -1,4 +1,6 @@ import React from 'react'; + +import Icon from 'react-native-vector-icons/Ionicons'; import PropTypes from 'prop-types'; import { Navigation } from 'react-native-navigation'; import Zeroconf from 'react-native-zeroconf'; @@ -6,6 +8,8 @@ import { View, Text, SectionList, Platform, StyleSheet } from 'react-native'; import { connect } from 'react-redux'; import { setServer } from '../actions/server'; import realm from '../lib/realm'; +import Fade from '../animations/fade'; +import Banner from '../components/banner'; const styles = StyleSheet.create({ view: { @@ -27,11 +31,6 @@ const styles = StyleSheet.create({ textAlign: 'center', color: '#888' }, - listItem: { - lineHeight: 18, - color: '#666', - padding: 14 - }, container: { flex: 1 }, @@ -44,6 +43,21 @@ const styles = StyleSheet.create({ lineHeight: 24, paddingLeft: 14, color: '#888' + }, + serverItem: { + flex: 1, + flexDirection: 'row', + // justifyContent: 'center', + alignItems: 'center', + backgroundColor: '#fff', + padding: 14 + }, + + listItem: { + color: '#666', flexGrow: 1, lineHeight: 30 + }, + serverChecked: { + flexGrow: 0 } }); @@ -166,12 +180,16 @@ export default class ListServerView extends React.Component { } renderItem = ({ item }) => ( - { this.onPressItem(item); }} - > - {item.id} - + + + { this.onPressItem(item); }} + > + {item.id} + + + ); renderSectionHeader = ({ section }) => ( @@ -185,6 +203,7 @@ export default class ListServerView extends React.Component { render() { return ( +