From 2b172b359ee24bb72de51aee7313e02385f88111 Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Fri, 18 May 2018 14:55:08 -0300 Subject: [PATCH] Deep linking fix and more (#294) * Fix - Any https link was deep linking to RocketChat * Keyboard dismiss after add new server * Room info bug fix * Opacity animation * Navigation when adding server fixed * Throttle for unnecessary render on receiving several messages * Search inputs without autocorrect and autocapitalize * Search messages fixed * Messagebox unnecessary render and spotlight fixed * react-native-keyboard-input updated --- android/app/build.gradle | 4 +- android/app/src/main/AndroidManifest.xml | 3 +- app/ReactotronConfig.js | 1 + app/actions/actionsTypes.js | 6 +- app/actions/room.js | 6 -- app/actions/server.js | 6 -- app/containers/EmojiPicker/index.js | 5 +- app/containers/MessageBox/index.js | 58 ++++++++-------- app/containers/MessageBox/styles.js | 17 +++-- app/containers/MessageErrorActions.js | 7 +- app/containers/Sidebar.js | 10 ++- app/lib/ddp.js | 30 ++++---- app/lib/methods/canOpenRoom.js | 12 +++- app/lib/methods/getCustomEmojis.js | 22 +++--- app/lib/methods/getPermissions.js | 19 +++-- app/lib/methods/getRooms.js | 27 +++++--- app/lib/methods/getSettings.js | 22 +++--- app/lib/methods/helpers/protectedFunction.js | 2 +- app/lib/methods/loadMessagesForRoom.js | 29 ++++---- app/lib/methods/loadMissedMessages.js | 27 ++++---- app/lib/methods/readMessages.js | 31 +++++---- app/lib/methods/sendMessage.js | 5 +- app/lib/methods/subscriptions/room.js | 14 +++- app/lib/methods/subscriptions/rooms.js | 12 +++- app/lib/rocketchat.js | 73 ++++++++++++-------- app/reducers/room.js | 8 +-- app/sagas/init.js | 4 +- app/sagas/login.js | 35 ++++++---- app/sagas/mentionedMessages.js | 30 +++++--- app/sagas/pinnedMessages.js | 30 +++++--- app/sagas/roomFiles.js | 30 +++++--- app/sagas/rooms.js | 68 +++++++++++------- app/sagas/selectServer.js | 26 +++---- app/sagas/snippetedMessages.js | 30 +++++--- app/sagas/starredMessages.js | 30 +++++--- app/sagas/state.js | 13 +++- app/utils/log.js | 8 +++ app/views/ForgotPasswordView.js | 4 -- app/views/ListServerView.js | 10 ++- app/views/NewServerView.js | 4 +- app/views/RoomActionsView/index.js | 23 ++++-- app/views/RoomInfoEditView/index.js | 11 ++- app/views/RoomInfoView/index.js | 35 ++++++---- app/views/RoomMembersView/index.js | 38 ++++++---- app/views/RoomView/Header/index.js | 14 +++- app/views/RoomView/ListView.js | 5 +- app/views/RoomView/index.js | 47 ++++++++----- app/views/RoomsListView/Header/index.js | 16 ++++- app/views/RoomsListView/index.js | 22 +++--- app/views/SearchMessagesView/index.js | 19 +++-- app/views/SelectedUsersView.js | 4 +- package-lock.json | 2 +- 52 files changed, 610 insertions(+), 404 deletions(-) create mode 100644 app/utils/log.js diff --git a/android/app/build.gradle b/android/app/build.gradle index cbef9d709..8179f8603 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -187,9 +187,9 @@ dependencies { compile project(':react-native-fast-image') compile project(':realm') compile fileTree(dir: "libs", include: ["*.jar"]) - compile "com.android.support:appcompat-v7:23.0.1" + compile "com.android.support:appcompat-v7:27.1.0" compile "com.android.support:support-v4:27.1.0" - compile 'com.android.support:customtabs:23.0.1' + compile 'com.android.support:customtabs:27.1.0' compile "com.facebook.react:react-native:+" // From node_modules compile 'com.facebook.fresco:fresco:1.7.1' compile 'com.facebook.fresco:animated-gif:1.7.1' diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 58303e7b6..f00c03278 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -44,7 +44,8 @@ - + + diff --git a/app/ReactotronConfig.js b/app/ReactotronConfig.js index e7fcf5bee..528ce16d6 100644 --- a/app/ReactotronConfig.js +++ b/app/ReactotronConfig.js @@ -12,4 +12,5 @@ if (__DEV__) { .connect(); // Running on android device // $ adb reverse tcp:9090 tcp:9090 + console.warn = Reactotron.log; } diff --git a/app/actions/actionsTypes.js b/app/actions/actionsTypes.js index a125553a4..985fde88b 100644 --- a/app/actions/actionsTypes.js +++ b/app/actions/actionsTypes.js @@ -42,8 +42,7 @@ export const ROOM = createRequestTypes('ROOM', [ 'ERASE', 'USER_TYPING', 'MESSAGE_RECEIVED', - 'SET_LAST_OPEN', - 'LAYOUT_ANIMATION' + 'SET_LAST_OPEN' ]); export const APP = createRequestTypes('APP', ['READY', 'INIT']); export const MESSAGES = createRequestTypes('MESSAGES', [ @@ -81,8 +80,7 @@ export const SERVER = createRequestTypes('SERVER', [ ...defaultTypes, 'SELECT', 'CHANGED', - 'ADD', - 'GOTO_ADD' + 'ADD' ]); export const METEOR = createRequestTypes('METEOR_CONNECT', [...defaultTypes, 'DISCONNECT', 'DISCONNECT_BY_USER']); export const LOGOUT = 'LOGOUT'; // logout is always success diff --git a/app/actions/room.js b/app/actions/room.js index ef6430c3b..2c2e603ad 100644 --- a/app/actions/room.js +++ b/app/actions/room.js @@ -69,9 +69,3 @@ export function setLastOpen(date = new Date()) { date }; } - -export function layoutAnimation() { - return { - type: types.ROOM.LAYOUT_ANIMATION - }; -} diff --git a/app/actions/server.js b/app/actions/server.js index b334981b5..cfc46ad89 100644 --- a/app/actions/server.js +++ b/app/actions/server.js @@ -41,9 +41,3 @@ export function changedServer(server) { server }; } - -export function gotoAddServer() { - return { - type: SERVER.GOTO_ADD - }; -} diff --git a/app/containers/EmojiPicker/index.js b/app/containers/EmojiPicker/index.js index e3edbe1bf..ac30b7c37 100644 --- a/app/containers/EmojiPicker/index.js +++ b/app/containers/EmojiPicker/index.js @@ -10,6 +10,7 @@ import styles from './styles'; import categories from './categories'; import database from '../../lib/realm'; import { emojisByCategory } from '../../emojis'; +import protectedFunction from '../../lib/methods/helpers/protectedFunction'; const scrollProps = { keyboardShouldPersistTaps: 'always', @@ -68,11 +69,11 @@ export default class EmojiPicker extends Component { } } - _addFrequentlyUsed = (emoji) => { + _addFrequentlyUsed = protectedFunction((emoji) => { database.write(() => { database.create('frequentlyUsedEmoji', emoji, true); }); - } + }) _getFrequentlyUsedCount = (content) => { const emojiRow = this.frequentlyUsed.filtered('content == $0', content); return emojiRow.length ? emojiRow[0].count + 1 : 1; diff --git a/app/containers/MessageBox/index.js b/app/containers/MessageBox/index.js index 4f62c84b6..90b2197f9 100644 --- a/app/containers/MessageBox/index.js +++ b/app/containers/MessageBox/index.js @@ -7,7 +7,7 @@ import { connect } from 'react-redux'; import { emojify } from 'react-emojione'; import { KeyboardAccessoryView } from 'react-native-keyboard-input'; -import { userTyping, layoutAnimation } from '../../actions/room'; +import { userTyping } from '../../actions/room'; import RocketChat from '../../lib/rocketchat'; import { editRequest, editCancel, clearInput } from '../../actions/messages'; import styles from './styles'; @@ -18,7 +18,7 @@ import CustomEmoji from '../EmojiPicker/CustomEmoji'; import { emojis } from '../../emojis'; import Recording from './Recording'; import './EmojiKeyboard'; - +import log from '../../utils/log'; const MENTIONS_TRACKING_TYPE_USERS = '@'; const MENTIONS_TRACKING_TYPE_EMOJIS = ':'; @@ -36,8 +36,7 @@ const onlyUnique = function onlyUnique(value, index, self) { editCancel: () => dispatch(editCancel()), editRequest: message => dispatch(editRequest(message)), typing: status => dispatch(userTyping(status)), - clearInput: () => dispatch(clearInput()), - layoutAnimation: () => dispatch(layoutAnimation()) + clearInput: () => dispatch(clearInput()) })) export default class MessageBox extends React.PureComponent { static propTypes = { @@ -49,8 +48,7 @@ export default class MessageBox extends React.PureComponent { message: PropTypes.object, editing: PropTypes.bool, typing: PropTypes.func, - clearInput: PropTypes.func, - layoutAnimation: PropTypes.func + clearInput: PropTypes.func } constructor(props) { @@ -58,7 +56,6 @@ export default class MessageBox extends React.PureComponent { this.state = { text: '', mentions: [], - showMentionsContainer: false, showEmojiKeyboard: false, recording: false }; @@ -176,7 +173,7 @@ export default class MessageBox extends React.PureComponent { if (response.didCancel) { console.warn('User cancelled image picker'); } else if (response.error) { - console.warn('ImagePicker Error: ', response.error); + log('ImagePicker Error', response.error); } else if (response.customButton) { console.warn('User tapped custom button: ', response.customButton); } else { @@ -272,11 +269,13 @@ export default class MessageBox extends React.PureComponent { RocketChat.spotlight(keyword, usernames, { users: true }), new Promise((resolve, reject) => (this.oldPromise = reject)) ]); - database.write(() => { - results.users.forEach((user) => { - database.create('users', user, true); + if (results.users && results.users.length) { + database.write(() => { + results.users.forEach((user) => { + database.create('users', user, true); + }); }); - }); + } } catch (e) { console.warn('spotlight canceled'); } finally { @@ -318,7 +317,9 @@ export default class MessageBox extends React.PureComponent { RocketChat.spotlight(keyword, [...rooms, ...this.roomsCache].map(r => r.name), { rooms: true }), new Promise((resolve, reject) => (this.oldPromise = reject)) ]); - this.roomsCache = [...this.roomsCache, ...results.rooms].filter(onlyUnique); + if (results.rooms && results.rooms.length) { + this.roomsCache = [...this.roomsCache, ...results.rooms].filter(onlyUnique); + } this.setState({ mentions: [...rooms.slice(), ...results.rooms] }); } catch (e) { console.warn('spotlight canceled'); @@ -338,7 +339,6 @@ export default class MessageBox extends React.PureComponent { stopTrackingMention() { this.setState({ - showMentionsContainer: false, mentions: [], trackingType: '' }); @@ -349,11 +349,7 @@ export default class MessageBox extends React.PureComponent { } identifyMentionKeyword(keyword, type) { - if (!this.state.showMentionsContainer) { - this.props.layoutAnimation(); - } this.setState({ - showMentionsContainer: true, showEmojiKeyboard: false, trackingType: type }); @@ -461,16 +457,22 @@ export default class MessageBox extends React.PureComponent { ); } - renderMentions = () => ( - this.renderMentionItem(item)} - keyExtractor={item => item._id || item} - keyboardShouldPersistTaps='always' - /> - ); + renderMentions = () => { + const { mentions, trackingType } = this.state; + if (!trackingType) { + return null; + } + return ( + this.renderMentionItem(item)} + keyExtractor={item => item._id || item} + keyboardShouldPersistTaps='always' + /> + ); + }; renderContent() { if (this.state.recording) { diff --git a/app/containers/MessageBox/styles.js b/app/containers/MessageBox/styles.js index dd10d720e..8293f6e25 100644 --- a/app/containers/MessageBox/styles.js +++ b/app/containers/MessageBox/styles.js @@ -15,7 +15,9 @@ export default StyleSheet.create({ flexDirection: 'row', alignItems: 'center', flexGrow: 0, - backgroundColor: '#fff' + backgroundColor: '#fff', + borderTopColor: '#ECECEC', + borderTopWidth: 1 }, textBoxInput: { textAlignVertical: 'center', @@ -40,19 +42,16 @@ export default StyleSheet.create({ flex: 0 }, mentionList: { - maxHeight: MENTION_HEIGHT * 4, - borderTopColor: '#ECECEC', - borderTopWidth: 1, - paddingHorizontal: 5, - backgroundColor: '#fff' + maxHeight: MENTION_HEIGHT * 4 }, mentionItem: { height: MENTION_HEIGHT, backgroundColor: '#F7F8FA', - borderBottomWidth: 1, - borderBottomColor: '#ECECEC', + borderTopWidth: 1, + borderTopColor: '#ECECEC', flexDirection: 'row', - alignItems: 'center' + alignItems: 'center', + paddingHorizontal: 5 }, mentionItemCustomEmoji: { margin: 8, diff --git a/app/containers/MessageErrorActions.js b/app/containers/MessageErrorActions.js index 4f3439fae..a65c016d7 100644 --- a/app/containers/MessageErrorActions.js +++ b/app/containers/MessageErrorActions.js @@ -6,6 +6,7 @@ import ActionSheet from 'react-native-actionsheet'; import { errorActionsHide } from '../actions/messages'; import RocketChat from '../lib/rocketchat'; import database from '../lib/realm'; +import protectedFunction from '../lib/methods/helpers/protectedFunction'; @connect( state => ({ @@ -38,14 +39,14 @@ export default class MessageErrorActions extends React.Component { } } - handleResend = () => RocketChat.resendMessage(this.props.actionMessage._id); + handleResend = protectedFunction(() => RocketChat.resendMessage(this.props.actionMessage._id)); - handleDelete = () => { + handleDelete = protectedFunction(() => { database.write(() => { const msg = database.objects('messages').filtered('_id = $0', this.props.actionMessage._id); database.delete(msg); }); - } + }) handleActionPress = (actionIndex) => { switch (actionIndex) { diff --git a/app/containers/Sidebar.js b/app/containers/Sidebar.js index 9e9122751..46ef2acbc 100644 --- a/app/containers/Sidebar.js +++ b/app/containers/Sidebar.js @@ -4,7 +4,7 @@ import { ScrollView, Text, View, StyleSheet, FlatList, TouchableHighlight } from import { connect } from 'react-redux'; import database from '../lib/realm'; -import { setServer, gotoAddServer } from '../actions/server'; +import { setServer } from '../actions/server'; import { logout } from '../actions/login'; const styles = StyleSheet.create({ @@ -40,16 +40,14 @@ const keyExtractor = item => item.id; server: state.server.server }), dispatch => ({ selectServer: server => dispatch(setServer(server)), - logout: () => dispatch(logout()), - gotoAddServer: () => dispatch(gotoAddServer()) + logout: () => dispatch(logout()) })) export default class Sidebar extends Component { static propTypes = { server: PropTypes.string.isRequired, selectServer: PropTypes.func.isRequired, navigation: PropTypes.object.isRequired, - logout: PropTypes.func.isRequired, - gotoAddServer: PropTypes.func.isRequired + logout: PropTypes.func.isRequired } constructor(props) { @@ -120,7 +118,7 @@ export default class Sidebar extends Component { { this.props.gotoAddServer(); }} + onPress={() => { this.props.navigation.navigate({ key: 'AddServer', routeName: 'AddServer' }); }} > diff --git a/app/lib/ddp.js b/app/lib/ddp.js index e42ec8666..7da3d98e9 100644 --- a/app/lib/ddp.js +++ b/app/lib/ddp.js @@ -1,7 +1,8 @@ import EJSON from 'ejson'; -import { Answers } from 'react-native-fabric'; import { AppState } from 'react-native'; + import debounce from '../utils/debounce'; +import log from '../utils/log'; // import { AppState, NativeModules } from 'react-native'; // const { WebSocketModule, BlobManager } = NativeModules; @@ -44,8 +45,7 @@ class EventEmitter { try { listener.apply(this, args); } catch (e) { - Answers.logCustom(e); - console.warn(e); + log('EventEmitter.emit', e); } }); } @@ -129,7 +129,11 @@ export default class Socket extends EventEmitter { this.send({ msg: 'connect', version: '1', support: ['1', 'pre2', 'pre1'] }); }); - this._connect(); + try { + this._connect(); + } catch (e) { + log('ddp.constructor._connect', e); + } } check() { if (!this.lastping) { @@ -213,7 +217,7 @@ export default class Socket extends EventEmitter { this.emit(data.msg, data); return data.collection && this.emit(data.collection, data); } catch (err) { - Answers.logCustom('EJSON parse', err); + log('EJSON parse', err); } }; }); @@ -234,16 +238,20 @@ export default class Socket extends EventEmitter { delete this.connection; this._logged = false; - this._timer = setTimeout(() => { + this._timer = setTimeout(async() => { delete this._timer; - this._connect(); + try { + await this._connect(); + } catch (e) { + log('ddp.reconnect._connect', e); + } }, 1000); } call(method, ...params) { return this.send({ msg: 'method', method, params }).then(data => data.result || data.subs).catch((err) => { - Answers.logCustom('DDP call Error', err); + log('DDP call Error', err); return Promise.reject(err); }); } @@ -256,8 +264,7 @@ export default class Socket extends EventEmitter { msg: 'unsub', id }).then(data => data.result || data.subs).catch((err) => { - console.warn('unsubscribe', err); - Answers.logCustom('DDP unsubscribe Error', err); + log('DDP unsubscribe Error', err); return Promise.reject(err); }); } @@ -277,8 +284,7 @@ export default class Socket extends EventEmitter { // console.log(args); return args; }).catch((err) => { - console.warn('subscribe', err); - Answers.logCustom('DDP subscribe Error', err); + log('DDP subscribe Error', err); return Promise.reject(err); }); } diff --git a/app/lib/methods/canOpenRoom.js b/app/lib/methods/canOpenRoom.js index a7625b97a..f336b1adc 100644 --- a/app/lib/methods/canOpenRoom.js +++ b/app/lib/methods/canOpenRoom.js @@ -1,5 +1,6 @@ import { post } from './helpers/rest'; import database from '../realm'; +import log from '../../utils/log'; // TODO: api fix const ddpTypes = { @@ -45,7 +46,12 @@ export default async function canOpenRoom({ rid, path }) { } const [type, name] = path.split('/'); - // eslint-disable-next-line - const data = await (this.ddp && this.ddp.status ? canOpenRoomDDP.call(this, { rid, type, name }) : canOpenRoomREST.call(this, { type, rid })); - return data; + + try { + // eslint-disable-next-line + const data = await (this.ddp && this.ddp.status ? canOpenRoomDDP.call(this, { rid, type, name }) : canOpenRoomREST.call(this, { type, rid })); + return data; + } catch (e) { + log('canOpenRoom', e); + } } diff --git a/app/lib/methods/getCustomEmojis.js b/app/lib/methods/getCustomEmojis.js index 391b2ed4f..48fea4e4c 100644 --- a/app/lib/methods/getCustomEmojis.js +++ b/app/lib/methods/getCustomEmojis.js @@ -1,9 +1,11 @@ import { InteractionManager } from 'react-native'; + import reduxStore from '../createStore'; // import { get } from './helpers/rest'; import database from '../realm'; import * as actions from '../../actions'; +import log from '../../utils/log'; const getLastMessage = () => { const setting = database.objects('customEmojis').sorted('_updatedAt', true)[0]; @@ -12,12 +14,16 @@ const getLastMessage = () => { export default async function() { - const lastMessage = getLastMessage(); - let emojis = await this.ddp.call('listEmojiCustom'); - emojis = emojis.filter(emoji => !lastMessage || emoji._updatedAt > lastMessage); - emojis = this._prepareEmojis(emojis); - InteractionManager.runAfterInteractions(() => database.write(() => { - emojis.forEach(emoji => database.create('customEmojis', emoji, true)); - })); - reduxStore.dispatch(actions.setCustomEmojis(this.parseEmojis(emojis))); + try { + const lastMessage = getLastMessage(); + let emojis = await this.ddp.call('listEmojiCustom'); + emojis = emojis.filter(emoji => !lastMessage || emoji._updatedAt > lastMessage); + emojis = this._prepareEmojis(emojis); + InteractionManager.runAfterInteractions(() => database.write(() => { + emojis.forEach(emoji => database.create('customEmojis', emoji, true)); + })); + reduxStore.dispatch(actions.setCustomEmojis(this.parseEmojis(emojis))); + } catch (e) { + log('getCustomEmojis', e); + } } diff --git a/app/lib/methods/getPermissions.js b/app/lib/methods/getPermissions.js index 542276a27..cfdc21c3d 100644 --- a/app/lib/methods/getPermissions.js +++ b/app/lib/methods/getPermissions.js @@ -1,9 +1,11 @@ import { InteractionManager } from 'react-native'; + import reduxStore from '../createStore'; // import { get } from './helpers/rest'; import database from '../realm'; import * as actions from '../../actions'; +import log from '../../utils/log'; const getLastMessage = () => { const setting = database.objects('permissions').sorted('_updatedAt', true)[0]; @@ -12,11 +14,14 @@ const getLastMessage = () => { export default async function() { - const lastMessage = getLastMessage(); - const result = await (!lastMessage ? this.ddp.call('permissions/get') : this.ddp.call('permissions/get', new Date(lastMessage))); - const permissions = this._preparePermissions(result.update || result); - console.log('getPermissions', permissions); - InteractionManager.runAfterInteractions(() => database.write(() => - permissions.forEach(permission => database.create('permissions', permission, true)))); - reduxStore.dispatch(actions.setAllPermissions(this.parsePermissions(permissions))); + try { + const lastMessage = getLastMessage(); + const result = await (!lastMessage ? this.ddp.call('permissions/get') : this.ddp.call('permissions/get', new Date(lastMessage))); + const permissions = this._preparePermissions(result.update || result); + InteractionManager.runAfterInteractions(() => database.write(() => + permissions.forEach(permission => database.create('permissions', permission, true)))); + reduxStore.dispatch(actions.setAllPermissions(this.parsePermissions(permissions))); + } catch (e) { + log('getPermissions', e); + } } diff --git a/app/lib/methods/getRooms.js b/app/lib/methods/getRooms.js index ef2732e00..fa2e95510 100644 --- a/app/lib/methods/getRooms.js +++ b/app/lib/methods/getRooms.js @@ -1,8 +1,10 @@ import { InteractionManager } from 'react-native'; + // import { showToast } from '../../utils/info'; import { get } from './helpers/rest'; import mergeSubscriptionsRooms, { merge } from './helpers/mergeSubscriptionsRooms'; import database from '../realm'; +import log from '../../utils/log'; const lastMessage = () => { const message = database @@ -34,18 +36,23 @@ const getRoomDpp = async function() { export default async function() { const { database: db } = database; - return new Promise(async(resolve) => { - // eslint-disable-next-line - const { subscriptions, rooms } = await (false && this.ddp.status ? getRoomDpp.apply(this) : getRoomRest.apply(this)); + return new Promise(async(resolve, reject) => { + try { + // eslint-disable-next-line + const { subscriptions, rooms } = await (false && this.ddp.status ? getRoomDpp.apply(this) : getRoomRest.apply(this)); - const data = rooms.map(room => ({ room, sub: database.objects('subscriptions').filtered('rid == $0', room._id) })); + const data = rooms.map(room => ({ room, sub: database.objects('subscriptions').filtered('rid == $0', room._id) })); - InteractionManager.runAfterInteractions(() => { - db.write(() => { - subscriptions.forEach(subscription => db.create('subscriptions', subscription, true)); - data.forEach(({ sub, room }) => sub[0] && merge(sub[0], room)); + InteractionManager.runAfterInteractions(() => { + db.write(() => { + subscriptions.forEach(subscription => db.create('subscriptions', subscription, true)); + data.forEach(({ sub, room }) => sub[0] && merge(sub[0], room)); + }); + resolve(data); }); - resolve(data); - }); + } catch (e) { + log('getRooms', e); + reject(e); + } }); } diff --git a/app/lib/methods/getSettings.js b/app/lib/methods/getSettings.js index d2c94acb9..9f671c6d6 100644 --- a/app/lib/methods/getSettings.js +++ b/app/lib/methods/getSettings.js @@ -1,9 +1,10 @@ import { InteractionManager } from 'react-native'; + import reduxStore from '../createStore'; // import { get } from './helpers/rest'; - import database from '../realm'; import * as actions from '../../actions'; +import log from '../../utils/log'; const getLastMessage = () => { const [setting] = database.objects('settings').sorted('_updatedAt', true); @@ -11,14 +12,17 @@ const getLastMessage = () => { }; export default async function() { - const lastMessage = getLastMessage(); - const result = await (!lastMessage ? this.ddp.call('public-settings/get') : this.ddp.call('public-settings/get', new Date(lastMessage))); - console.log('getSettings', lastMessage, result); + try { + const lastMessage = getLastMessage(); + const result = await (!lastMessage ? this.ddp.call('public-settings/get') : this.ddp.call('public-settings/get', new Date(lastMessage))); - const filteredSettings = this._prepareSettings(this._filterSettings(result.update || result)); + const filteredSettings = this._prepareSettings(this._filterSettings(result.update || result)); - InteractionManager.runAfterInteractions(() => - database.write(() => - filteredSettings.forEach(setting => database.create('settings', setting, true)))); - reduxStore.dispatch(actions.addSettings(this.parseSettings(filteredSettings))); + InteractionManager.runAfterInteractions(() => + database.write(() => + filteredSettings.forEach(setting => database.create('settings', setting, true)))); + reduxStore.dispatch(actions.addSettings(this.parseSettings(filteredSettings))); + } catch (e) { + log('getSettings', e); + } } diff --git a/app/lib/methods/helpers/protectedFunction.js b/app/lib/methods/helpers/protectedFunction.js index f44fe6f51..820a65022 100644 --- a/app/lib/methods/helpers/protectedFunction.js +++ b/app/lib/methods/helpers/protectedFunction.js @@ -4,7 +4,7 @@ export default fn => (params) => { try { fn(params); } catch (e) { - Answers.logCustom('erro', e); + Answers.logCustom('error', e); if (__DEV__) { alert(e); } diff --git a/app/lib/methods/loadMessagesForRoom.js b/app/lib/methods/loadMessagesForRoom.js index 9f12a93ea..5a5bf69c8 100644 --- a/app/lib/methods/loadMessagesForRoom.js +++ b/app/lib/methods/loadMessagesForRoom.js @@ -3,7 +3,7 @@ import { InteractionManager } from 'react-native'; import { get } from './helpers/rest'; import buildMessage from './helpers/buildMessage'; import database from '../realm'; - +import log from '../../utils/log'; // TODO: api fix const types = { @@ -46,23 +46,22 @@ async function loadMessagesForRoomDDP(...args) { } export default async function loadMessagesForRoom(...args) { - console.log('aqui'); const { database: db } = database; - console.log('database', db); - return new Promise(async(resolve) => { - // eslint-disable-next-line - const data = (await (false && this.ddp.status ? loadMessagesForRoomDDP.call(this, ...args) : loadMessagesForRoomRest.call(this, ...args))).map(buildMessage); - if (data) { - InteractionManager.runAfterInteractions(() => { - try { + return new Promise(async(resolve, reject) => { + try { + // eslint-disable-next-line + const data = (await (false && this.ddp.status ? loadMessagesForRoomDDP.call(this, ...args) : loadMessagesForRoomRest.call(this, ...args))).map(buildMessage); + if (data) { + InteractionManager.runAfterInteractions(() => { db.write(() => data.forEach(message => db.create('messages', message, true))); - resolve(data); - } catch (e) { - console.warn('loadMessagesForRoom', e); - } - }); + return resolve(data); + }); + } + return resolve([]); + } catch (e) { + log('loadMessagesForRoom', e); + reject(e); } - return resolve([]); }); } diff --git a/app/lib/methods/loadMissedMessages.js b/app/lib/methods/loadMissedMessages.js index 5bd0074c1..8efadeb0f 100644 --- a/app/lib/methods/loadMissedMessages.js +++ b/app/lib/methods/loadMissedMessages.js @@ -3,7 +3,7 @@ import { InteractionManager } from 'react-native'; import { get } from './helpers/rest'; import buildMessage from './helpers/buildMessage'; import database from '../realm'; - +import log from '../../utils/log'; async function loadMissedMessagesRest({ rid: roomId, lastOpen: lastUpdate }) { const { token, id } = this.ddp._login; @@ -40,21 +40,22 @@ async function loadMissedMessagesDDP(...args) { export default async function(...args) { const { database: db } = database; - return new Promise(async(resolve) => { - // eslint-disable-next-line - const data = (await (false && this.ddp.status ? loadMissedMessagesDDP.call(this, ...args) : loadMissedMessagesRest.call(this, ...args))); + return new Promise(async(resolve, reject) => { + try { + // eslint-disable-next-line + const data = (await (false && this.ddp.status ? loadMissedMessagesDDP.call(this, ...args) : loadMissedMessagesRest.call(this, ...args))); - if (data) { - data.forEach(buildMessage); - return InteractionManager.runAfterInteractions(() => { - try { + if (data) { + data.forEach(buildMessage); + return InteractionManager.runAfterInteractions(() => { db.write(() => data.forEach(message => db.create('messages', message, true))); resolve(data); - } catch (e) { - console.warn('loadMessagesForRoom', e); - } - }); + }); + } + resolve([]); + } catch (e) { + log('loadMissedMessages', e); + reject(e); } - resolve([]); }); } diff --git a/app/lib/methods/readMessages.js b/app/lib/methods/readMessages.js index 10ac99410..65d195785 100644 --- a/app/lib/methods/readMessages.js +++ b/app/lib/methods/readMessages.js @@ -1,5 +1,6 @@ import { post } from './helpers/rest'; import database from '../realm'; +import log from '../../utils/log'; const readMessagesREST = function readMessagesREST(rid) { const { token, id } = this.ddp._login; @@ -17,17 +18,21 @@ const readMessagesDDP = function readMessagesDDP(rid) { export default async function readMessages(rid) { const { database: db } = database; - // eslint-disable-next-line - const data = await (false && this.ddp.status ? readMessagesDDP.call(this, rid) : readMessagesREST.call(this, rid)); - const [subscription] = db.objects('subscriptions').filtered('rid = $0', rid); - db.write(() => { - subscription.open = true; - subscription.alert = false; - subscription.unread = 0; - subscription.userMentions = 0; - subscription.groupMentions = 0; - subscription.ls = new Date(); - subscription.lastOpen = new Date(); - }); - return data; + try { + // eslint-disable-next-line + const data = await (false && this.ddp.status ? readMessagesDDP.call(this, rid) : readMessagesREST.call(this, rid)); + const [subscription] = db.objects('subscriptions').filtered('rid = $0', rid); + db.write(() => { + subscription.open = true; + subscription.alert = false; + subscription.unread = 0; + subscription.userMentions = 0; + subscription.groupMentions = 0; + subscription.ls = new Date(); + subscription.lastOpen = new Date(); + }); + return data; + } catch (e) { + log('readMessages', e); + } } diff --git a/app/lib/methods/sendMessage.js b/app/lib/methods/sendMessage.js index eba1f5eac..4cd194692 100644 --- a/app/lib/methods/sendMessage.js +++ b/app/lib/methods/sendMessage.js @@ -1,10 +1,11 @@ import Random from 'react-native-meteor/lib/Random'; -import messagesStatus from '../../constants/messagesStatus'; +import messagesStatus from '../../constants/messagesStatus'; import buildMessage from '../methods/helpers/buildMessage'; import { post } from './helpers/rest'; import database from '../realm'; import reduxStore from '../createStore'; +import log from '../../utils/log'; export const getMessage = (rid, msg = {}) => { const _id = Random.id(); @@ -67,6 +68,6 @@ export default async function(rid, msg) { db.create('messages', buildMessage({ ...message, ...ret }), true); }); } catch (e) { - console.warn('sendMessage', e); + log('sendMessage', e); } } diff --git a/app/lib/methods/subscriptions/room.js b/app/lib/methods/subscriptions/room.js index b54d0091a..ca3e56c91 100644 --- a/app/lib/methods/subscriptions/room.js +++ b/app/lib/methods/subscriptions/room.js @@ -3,12 +3,16 @@ // import normalizeMessage from '../helpers/normalizeMessage'; // import _buildMessage from '../helpers/buildMessage'; // import protectedFunction from '../helpers/protectedFunction'; +import log from '../../../utils/log'; const subscribe = (ddp, rid) => Promise.all([ ddp.subscribe('stream-room-messages', rid, false), ddp.subscribe('stream-notify-room', `${ rid }/typing`, false) ]); -const unsubscribe = subscriptions => subscriptions.forEach(sub => sub.unsubscribe().catch(e => console.warn(e))); +const unsubscribe = subscriptions => + subscriptions.forEach(sub => sub.unsubscribe().catch((e) => { + log('unsubscribeRoom', e); + })); let timer = null; let promises; @@ -58,7 +62,7 @@ export default async function subscribeRoom({ rid, t }) { logged = this.ddp.on('logged', () => { clearTimeout(timer); timer = false; - promises = subscribe(this.ddp, rid); + // promises = subscribe(this.ddp, rid); }); disconnected = this.ddp.on('disconnected', () => { @@ -67,7 +71,11 @@ export default async function subscribeRoom({ rid, t }) { } }); - promises = subscribe(this.ddp, rid); + try { + promises = subscribe(this.ddp, rid); + } catch (e) { + log('subscribeRoom', e); + } } return { diff --git a/app/lib/methods/subscriptions/rooms.js b/app/lib/methods/subscriptions/rooms.js index 8ac87806e..db98e9ac6 100644 --- a/app/lib/methods/subscriptions/rooms.js +++ b/app/lib/methods/subscriptions/rooms.js @@ -1,5 +1,7 @@ import database from '../../realm'; import { merge } from '../helpers/mergeSubscriptionsRooms'; +import protectedFunction from '../helpers/protectedFunction'; +import log from '../../../utils/log'; export default async function subscribeRooms(id) { const subscriptions = Promise.all([ @@ -41,7 +43,7 @@ export default async function subscribeRooms(id) { } }); - this.ddp.on('stream-notify-user', (ddpMessage) => { + this.ddp.on('stream-notify-user', protectedFunction((ddpMessage) => { const [type, data] = ddpMessage.fields.args; const [, ev] = ddpMessage.fields.eventName.split('/'); if (/subscriptions/.test(ev)) { @@ -56,9 +58,13 @@ export default async function subscribeRooms(id) { merge(sub, data); }); } - }); + })); } - await subscriptions; + try { + await subscriptions; + } catch (e) { + log('subscribeRooms', e); + } // console.log(this.ddp.subscriptions); } diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index c8f08750f..a40a85972 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -2,13 +2,13 @@ import { AsyncStorage, Platform } from 'react-native'; import { hashPassword } from 'react-native-meteor/lib/utils'; import foreach from 'lodash/forEach'; import Random from 'react-native-meteor/lib/Random'; -import { Answers } from 'react-native-fabric'; - import RNFetchBlob from 'react-native-fetch-blob'; + import reduxStore from './createStore'; import settingsType from '../constants/settings'; import messagesStatus from '../constants/messagesStatus'; import database from './realm'; +import log from '../utils/log'; // import * as actions from '../actions'; import { setUser, setLoginServices, removeLoginServices, loginRequest, loginSuccess, loginFailure } from '../actions/login'; @@ -112,26 +112,30 @@ const RocketChat = { this.activeUsers[ddpMessage.id] = ddpMessage.fields; }, async loginSuccess(user) { - if (!user) { - const { user: u } = reduxStore.getState().login; - user = Object.assign({}, u); - } - - // TODO: one api call - // call /me only one time - if (!user.username) { - const me = await this.me({ token: user.token, userId: user.id }); - // eslint-disable-next-line - user.username = me.username; - } - if (user.username) { - const userInfo = await this.userInfo({ token: user.token, userId: user.id }); - user.username = userInfo.user.username; - if (userInfo.user.roles) { - user.roles = userInfo.user.roles; + try { + if (!user) { + const { user: u } = reduxStore.getState().login; + user = Object.assign({}, u); } + + // TODO: one api call + // call /me only one time + if (!user.username) { + const me = await this.me({ token: user.token, userId: user.id }); + // eslint-disable-next-line + user.username = me.username; + } + if (user.username) { + const userInfo = await this.userInfo({ token: user.token, userId: user.id }); + user.username = userInfo.user.username; + if (userInfo.user.roles) { + user.roles = userInfo.user.roles; + } + } + return reduxStore.dispatch(loginSuccess(user)); + } catch (e) { + log('rocketchat.loginSuccess', e); } - return reduxStore.dispatch(loginSuccess(user)); }, connect(url, login) { return new Promise((resolve) => { @@ -151,12 +155,12 @@ const RocketChat = { this.ddp.on('users', protectedFunction(ddpMessage => RocketChat._setUser(ddpMessage))); - this.ddp.on('background', () => this.getRooms().catch(e => console.warn('background getRooms', e))); + this.ddp.on('background', () => this.getRooms().catch(e => log('background getRooms', e))); this.ddp.on('disconnected', () => console.log('disconnected')); this.ddp.on('logged', protectedFunction((user) => { - this.getRooms().catch(e => console.warn('logged getRooms', e)); + this.getRooms().catch(e => log('logged getRooms', e)); this.loginSuccess(user); })); this.ddp.once('logged', protectedFunction(({ id }) => { this.subscribeRooms(id); })); @@ -420,11 +424,10 @@ const RocketChat = { this.roles[ddpMessage.id] = (ddpMessage.fields && ddpMessage.fields.description) || undefined; })); - this.ddp.on('error', protectedFunction((err) => { - console.warn('onError', JSON.stringify(err)); - Answers.logCustom('disconnect', err); + this.ddp.on('error', (err) => { + log('rocketchat.onerror', err); reduxStore.dispatch(connectFailure()); - })); + }); // TODO: fix api (get emojis by date/version....) @@ -440,7 +443,9 @@ const RocketChat = { this.ddp.subscribe('roles'); RocketChat.getCustomEmoji(); })); - }).catch(err => console.warn(`asd ${ err }`)); + }).catch((e) => { + log('rocketchat.connect catch', e); + }); }, register({ credentials }) { @@ -502,7 +507,11 @@ const RocketChat = { }, logout({ server }) { if (this.ddp) { - this.ddp.logout(); + try { + this.ddp.logout(); + } catch (e) { + log('rocketchat.logout', e); + } } database.deleteAll(); AsyncStorage.removeItem(TOKEN_KEY); @@ -703,7 +712,13 @@ const RocketChat = { return Promise.resolve(result); }, async getPermalink(message) { - const room = await RocketChat.getRoom(message.rid); + let room; + try { + room = await RocketChat.getRoom(message.rid); + } catch (e) { + log('rocketchat.getPermalink', e); + return null; + } const { server } = reduxStore.getState().server; const roomType = { p: 'group', diff --git a/app/reducers/room.js b/app/reducers/room.js index 4ed7c921b..03b1fa898 100644 --- a/app/reducers/room.js +++ b/app/reducers/room.js @@ -1,8 +1,7 @@ import * as types from '../actions/actionsTypes'; const initialState = { - usersTyping: [], - layoutAnimation: new Date() + usersTyping: [] }; export default function room(state = initialState, action) { @@ -32,11 +31,6 @@ export default function room(state = initialState, action) { ...state, usersTyping: [...state.usersTyping.filter(user => user !== action.username)] }; - case types.ROOM.LAYOUT_ANIMATION: - return { - ...state, - layoutAnimation: new Date() - }; default: return state; } diff --git a/app/sagas/init.js b/app/sagas/init.js index 0360d82b3..b7227e3fd 100644 --- a/app/sagas/init.js +++ b/app/sagas/init.js @@ -1,10 +1,12 @@ import { AsyncStorage } from 'react-native'; import { call, put, takeLatest } from 'redux-saga/effects'; + import * as actions from '../actions'; import { setServer } from '../actions/server'; import { restoreToken, setUser } from '../actions/login'; import { APP } from '../actions/actionsTypes'; import RocketChat from '../lib/rocketchat'; +import log from '../utils/log'; const restore = function* restore() { try { @@ -25,7 +27,7 @@ const restore = function* restore() { yield put(actions.appReady({})); } catch (e) { - console.warn('restore', e); + log('restore', e); } }; diff --git a/app/sagas/login.js b/app/sagas/login.js index 41de7368d..cd7abe7ee 100644 --- a/app/sagas/login.js +++ b/app/sagas/login.js @@ -19,6 +19,7 @@ import { } from '../actions/login'; import RocketChat from '../lib/rocketchat'; import * as NavigationService from '../containers/routes/NavigationService'; +import log from '../utils/log'; const getUser = state => state.login; const getServer = state => state.server.server; @@ -60,15 +61,19 @@ const forgotPasswordCall = args => RocketChat.forgotPassword(args); // }; const saveToken = function* saveToken() { - const [server, user] = yield all([select(getServer), select(getUser)]); - yield AsyncStorage.setItem(RocketChat.TOKEN_KEY, user.token); - yield AsyncStorage.setItem(`${ RocketChat.TOKEN_KEY }-${ server }`, JSON.stringify(user)); - const token = yield AsyncStorage.getItem('pushId'); - if (token) { - yield RocketChat.registerPushToken(user.user.id, token); - } - if (!user.user.username && !user.isRegistering) { - yield put(registerIncomplete()); + try { + const [server, user] = yield all([select(getServer), select(getUser)]); + yield AsyncStorage.setItem(RocketChat.TOKEN_KEY, user.token); + yield AsyncStorage.setItem(`${ RocketChat.TOKEN_KEY }-${ server }`, JSON.stringify(user)); + const token = yield AsyncStorage.getItem('pushId'); + if (token) { + yield RocketChat.registerPushToken(user.user.id, token); + } + if (!user.user.username && !user.isRegistering) { + yield put(registerIncomplete()); + } + } catch (e) { + log('saveToken', e); } }; @@ -130,7 +135,11 @@ const handleSetUsernameRequest = function* handleSetUsernameRequest({ credential const handleLogout = function* handleLogout() { const server = yield select(getServer); if (server) { - yield call(logoutCall, { server }); + try { + yield call(logoutCall, { server }); + } catch (e) { + log('handleLogout', e); + } } }; @@ -155,9 +164,9 @@ const watchLoginOpen = function* watchLoginOpen() { } const sub = yield RocketChat.subscribe('meteor.loginServiceConfiguration'); yield take(types.LOGIN.CLOSE); - sub.unsubscribe().catch(e => console.warn('watchLoginOpen unsubscribe', e)); - } catch (error) { - console.warn('watchLoginOpen', error); + sub.unsubscribe(); + } catch (e) { + log('watchLoginOpen', e); } }; diff --git a/app/sagas/mentionedMessages.js b/app/sagas/mentionedMessages.js index 0a1d0b464..b7e45dc60 100644 --- a/app/sagas/mentionedMessages.js +++ b/app/sagas/mentionedMessages.js @@ -1,26 +1,36 @@ import { put, takeLatest } from 'redux-saga/effects'; + import * as types from '../actions/actionsTypes'; import RocketChat from '../lib/rocketchat'; import { readyMentionedMessages } from '../actions/mentionedMessages'; +import log from '../utils/log'; let sub; let newSub; const openMentionedMessagesRoom = function* openMentionedMessagesRoom({ rid, limit }) { - newSub = yield RocketChat.subscribe('mentionedMessages', rid, limit); - yield put(readyMentionedMessages()); - if (sub) { - sub.unsubscribe().catch(e => console.warn('openMentionedMessagesRoom', e)); + try { + newSub = yield RocketChat.subscribe('mentionedMessages', rid, limit); + yield put(readyMentionedMessages()); + if (sub) { + sub.unsubscribe(); + } + sub = newSub; + } catch (e) { + log('openMentionedMessagesRoom', e); } - sub = newSub; }; const closeMentionedMessagesRoom = function* closeMentionedMessagesRoom() { - if (sub) { - yield sub.unsubscribe().catch(e => console.warn('closeMentionedMessagesRoom sub', e)); - } - if (newSub) { - yield newSub.unsubscribe().catch(e => console.warn('closeMentionedMessagesRoom newSub', e)); + try { + if (sub) { + yield sub.unsubscribe(); + } + if (newSub) { + yield newSub.unsubscribe(); + } + } catch (e) { + log('closeMentionedMessagesRoom', e); } }; diff --git a/app/sagas/pinnedMessages.js b/app/sagas/pinnedMessages.js index a451e322e..eb945abe2 100644 --- a/app/sagas/pinnedMessages.js +++ b/app/sagas/pinnedMessages.js @@ -1,26 +1,36 @@ import { put, takeLatest } from 'redux-saga/effects'; + import * as types from '../actions/actionsTypes'; import RocketChat from '../lib/rocketchat'; import { readyPinnedMessages } from '../actions/pinnedMessages'; +import log from '../utils/log'; let sub; let newSub; const openPinnedMessagesRoom = function* openPinnedMessagesRoom({ rid, limit }) { - newSub = yield RocketChat.subscribe('pinnedMessages', rid, limit); - yield put(readyPinnedMessages()); - if (sub) { - sub.unsubscribe().catch(e => console.warn('openPinnedMessagesRoom', e)); + try { + newSub = yield RocketChat.subscribe('pinnedMessages', rid, limit); + yield put(readyPinnedMessages()); + if (sub) { + sub.unsubscribe(); + } + sub = newSub; + } catch (e) { + log('openPinnedMessagesRoom', e); } - sub = newSub; }; const closePinnedMessagesRoom = function* closePinnedMessagesRoom() { - if (sub) { - yield sub.unsubscribe().catch(e => console.warn('closePinnedMessagesRoom sub', e)); - } - if (newSub) { - yield newSub.unsubscribe().catch(e => console.warn('closePinnedMessagesRoom newSub', e)); + try { + if (sub) { + yield sub.unsubscribe(); + } + if (newSub) { + yield newSub.unsubscribe(); + } + } catch (e) { + log('closePinnedMessagesRoom', e); } }; diff --git a/app/sagas/roomFiles.js b/app/sagas/roomFiles.js index 28e919dc4..a75b13dfd 100644 --- a/app/sagas/roomFiles.js +++ b/app/sagas/roomFiles.js @@ -1,26 +1,36 @@ import { put, takeLatest } from 'redux-saga/effects'; + import * as types from '../actions/actionsTypes'; import RocketChat from '../lib/rocketchat'; import { readyRoomFiles } from '../actions/roomFiles'; +import log from '../utils/log'; let sub; let newSub; const openRoomFiles = function* openRoomFiles({ rid, limit }) { - newSub = yield RocketChat.subscribe('roomFiles', rid, limit); - yield put(readyRoomFiles()); - if (sub) { - sub.unsubscribe().catch(e => console.warn('openRoomFiles', e)); + try { + newSub = yield RocketChat.subscribe('roomFiles', rid, limit); + yield put(readyRoomFiles()); + if (sub) { + sub.unsubscribe(); + } + sub = newSub; + } catch (e) { + log('openRoomFiles', e); } - sub = newSub; }; const closeRoomFiles = function* closeRoomFiles() { - if (sub) { - yield sub.unsubscribe().catch(e => console.warn('closeRoomFiles sub', e)); - } - if (newSub) { - yield newSub.unsubscribe().catch(e => console.warn('closeRoomFiles newSub', e)); + try { + if (sub) { + yield sub.unsubscribe(); + } + if (newSub) { + yield newSub.unsubscribe(); + } + } catch (e) { + log('closeRoomFiles', e); } }; diff --git a/app/sagas/rooms.js b/app/sagas/rooms.js index 63c1b335c..61a46a792 100644 --- a/app/sagas/rooms.js +++ b/app/sagas/rooms.js @@ -2,6 +2,7 @@ import { Alert } from 'react-native'; import { put, call, takeLatest, take, select, race, fork, cancel, takeEvery } from 'redux-saga/effects'; import { delay } from 'redux-saga'; import { BACKGROUND } from 'redux-enhancer-react-native-appstate'; + import * as types from '../actions/actionsTypes'; // import { roomsSuccess, roomsFailure } from '../actions/rooms'; import { addUserTyping, removeUserTyping, setLastOpen } from '../actions/room'; @@ -9,10 +10,14 @@ import { messagesRequest } from '../actions/messages'; import RocketChat from '../lib/rocketchat'; import database from '../lib/realm'; import * as NavigationService from '../containers/routes/NavigationService'; +import log from '../utils/log'; const leaveRoom = rid => RocketChat.leaveRoom(rid); const eraseRoom = rid => RocketChat.eraseRoom(rid); +let sub; +let thread; + // const getRooms = function* getRooms() { // return yield RocketChat.getRooms(); // }; @@ -66,30 +71,34 @@ const handleMessageReceived = function* handleMessageReceived({ message }) { }; const watchRoomOpen = function* watchRoomOpen({ room }) { - yield put(messagesRequest({ ...room })); - // const { open } = yield race({ - // messages: take(types.MESSAGES.SUCCESS), - // open: take(types.ROOM.OPEN) - // }); - // - // if (open) { - // return; - // } + try { + yield put(messagesRequest({ ...room })); + // const { open } = yield race({ + // messages: take(types.MESSAGES.SUCCESS), + // open: take(types.ROOM.OPEN) + // }); + // + // if (open) { + // return; + // } - RocketChat.readMessages(room.rid); - const sub = yield RocketChat.subscribeRoom(room); - // const subscriptions = yield Promise.all([RocketChat.subscribe('stream-room-messages', room.rid, false), RocketChat.subscribe('stream-notify-room', `${ room.rid }/typing`, false)]); - const thread = yield fork(usersTyping, { rid: room.rid }); - yield race({ - open: take(types.ROOM.OPEN), - close: take(types.ROOM.CLOSE) - }); - cancel(thread); - sub.stop(); + RocketChat.readMessages(room.rid); + sub = yield RocketChat.subscribeRoom(room); + // const subscriptions = yield Promise.all([RocketChat.subscribe('stream-room-messages', room.rid, false), RocketChat.subscribe('stream-notify-room', `${ room.rid }/typing`, false)]); + thread = yield fork(usersTyping, { rid: room.rid }); + yield race({ + open: take(types.ROOM.OPEN), + close: take(types.ROOM.CLOSE) + }); + cancel(thread); + sub.stop(); - // subscriptions.forEach((sub) => { - // sub.unsubscribe().catch(e => alert(e)); - // }); + // subscriptions.forEach((sub) => { + // sub.unsubscribe().catch(e => alert(e)); + // }); + } catch (e) { + log('watchRoomOpen', e); + } }; const watchuserTyping = function* watchuserTyping({ status }) { @@ -103,11 +112,16 @@ const watchuserTyping = function* watchuserTyping({ status }) { if (!room) { return; } - yield RocketChat.emitTyping(room.rid, status); - if (status) { - yield call(delay, 5000); - yield RocketChat.emitTyping(room.rid, false); + try { + yield RocketChat.emitTyping(room.rid, status); + + if (status) { + yield call(delay, 5000); + yield RocketChat.emitTyping(room.rid, false); + } + } catch (e) { + log('watchuserTyping', e); } }; @@ -136,6 +150,7 @@ const goRoomsListAndDelete = function* goRoomsListAndDelete(rid) { const handleLeaveRoom = function* handleLeaveRoom({ rid }) { try { + sub.stop(); yield call(leaveRoom, rid); yield goRoomsListAndDelete(rid); } catch (e) { @@ -149,6 +164,7 @@ const handleLeaveRoom = function* handleLeaveRoom({ rid }) { const handleEraseRoom = function* handleEraseRoom({ rid }) { try { + sub.stop(); yield call(eraseRoom, rid); yield goRoomsListAndDelete(rid); } catch (e) { diff --git a/app/sagas/selectServer.js b/app/sagas/selectServer.js index 8513138fb..a95a9517f 100644 --- a/app/sagas/selectServer.js +++ b/app/sagas/selectServer.js @@ -1,6 +1,7 @@ import { put, call, takeLatest, take } from 'redux-saga/effects'; import { delay } from 'redux-saga'; import { AsyncStorage } from 'react-native'; + import { SERVER, LOGIN } from '../actions/actionsTypes'; import * as actions from '../actions'; import { connectRequest } from '../actions/connect'; @@ -9,6 +10,7 @@ import { setRoles } from '../actions/roles'; import RocketChat from '../lib/rocketchat'; import database from '../lib/realm'; import { navigate } from '../containers/routes/NavigationService'; +import log from '../utils/log'; const validate = function* validate(server) { return yield RocketChat.testServer(server); @@ -36,7 +38,7 @@ const selectServer = function* selectServer({ server }) { yield put(connectRequest()); } catch (e) { - console.warn('selectServer', e); + log('selectServer', e); } }; @@ -52,23 +54,21 @@ const validateServer = function* validateServer({ server }) { }; const addServer = function* addServer({ server }) { - database.databases.serversDB.write(() => { - database.databases.serversDB.create('servers', { id: server, current: false }, true); - }); - yield put(setServer(server)); - yield take(LOGIN.SET_TOKEN); - navigate('LoginSignup'); -}; - -const handleGotoAddServer = function* handleGotoAddServer() { - yield call(AsyncStorage.removeItem, RocketChat.TOKEN_KEY); - yield call(navigate, 'AddServer'); + try { + database.databases.serversDB.write(() => { + database.databases.serversDB.create('servers', { id: server, current: false }, true); + }); + yield put(setServer(server)); + yield take(LOGIN.SET_TOKEN); + navigate('LoginSignup'); + } catch (e) { + log('addServer', e); + } }; const root = function* root() { yield takeLatest(SERVER.REQUEST, validateServer); yield takeLatest(SERVER.SELECT, selectServer); yield takeLatest(SERVER.ADD, addServer); - yield takeLatest(SERVER.GOTO_ADD, handleGotoAddServer); }; export default root; diff --git a/app/sagas/snippetedMessages.js b/app/sagas/snippetedMessages.js index 120cb12f9..6301afd67 100644 --- a/app/sagas/snippetedMessages.js +++ b/app/sagas/snippetedMessages.js @@ -1,26 +1,36 @@ import { put, takeLatest } from 'redux-saga/effects'; + import * as types from '../actions/actionsTypes'; import RocketChat from '../lib/rocketchat'; import { readySnippetedMessages } from '../actions/snippetedMessages'; +import log from '../utils/log'; let sub; let newSub; const openSnippetedMessagesRoom = function* openSnippetedMessagesRoom({ rid, limit }) { - newSub = yield RocketChat.subscribe('snippetedMessages', rid, limit); - yield put(readySnippetedMessages()); - if (sub) { - sub.unsubscribe().catch(e => console.warn('openSnippetedMessagesRoom', e)); + try { + newSub = yield RocketChat.subscribe('snippetedMessages', rid, limit); + yield put(readySnippetedMessages()); + if (sub) { + sub.unsubscribe(); + } + sub = newSub; + } catch (e) { + log('openSnippetedMessagesRoom', e); } - sub = newSub; }; const closeSnippetedMessagesRoom = function* closeSnippetedMessagesRoom() { - if (sub) { - yield sub.unsubscribe().catch(e => console.warn('closeSnippetedMessagesRoom sub', e)); - } - if (newSub) { - yield newSub.unsubscribe().catch(e => console.warn('closeSnippetedMessagesRoom newSub', e)); + try { + if (sub) { + yield sub.unsubscribe(); + } + if (newSub) { + yield newSub.unsubscribe(); + } + } catch (e) { + log('closeSnippetedMessagesRoom', e); } }; diff --git a/app/sagas/starredMessages.js b/app/sagas/starredMessages.js index 2ee8d2d1b..af9f5ffe6 100644 --- a/app/sagas/starredMessages.js +++ b/app/sagas/starredMessages.js @@ -1,26 +1,36 @@ import { put, takeLatest } from 'redux-saga/effects'; + import * as types from '../actions/actionsTypes'; import RocketChat from '../lib/rocketchat'; import { readyStarredMessages } from '../actions/starredMessages'; +import log from '../utils/log'; let sub; let newSub; const openStarredMessagesRoom = function* openStarredMessagesRoom({ rid, limit }) { - newSub = yield RocketChat.subscribe('starredMessages', rid, limit); - yield put(readyStarredMessages()); - if (sub) { - sub.unsubscribe().catch(e => console.warn('openStarredMessagesRoom', e)); + try { + newSub = yield RocketChat.subscribe('starredMessages', rid, limit); + yield put(readyStarredMessages()); + if (sub) { + sub.unsubscribe(); + } + sub = newSub; + } catch (e) { + log('openStarredMessagesRoom', e); } - sub = newSub; }; const closeStarredMessagesRoom = function* closeStarredMessagesRoom() { - if (sub) { - yield sub.unsubscribe().catch(e => console.warn('closeStarredMessagesRoom sub', e)); - } - if (newSub) { - yield newSub.unsubscribe().catch(e => console.warn('closeStarredMessagesRoom newSub', e)); + try { + if (sub) { + yield sub.unsubscribe(); + } + if (newSub) { + yield newSub.unsubscribe(); + } + } catch (e) { + log('closeStarredMessagesRoom', e); } }; diff --git a/app/sagas/state.js b/app/sagas/state.js index 58b9b7b92..f995ff9e0 100644 --- a/app/sagas/state.js +++ b/app/sagas/state.js @@ -2,13 +2,18 @@ import { takeLatest, select } from 'redux-saga/effects'; import { FOREGROUND, BACKGROUND, INACTIVE } from 'redux-enhancer-react-native-appstate'; import RocketChat from '../lib/rocketchat'; +import log from '../utils/log'; const appHasComeBackToForeground = function* appHasComeBackToForeground() { const auth = yield select(state => state.login.isAuthenticated); if (!auth) { return; } - return yield RocketChat.setUserPresenceOnline(); + try { + return yield RocketChat.setUserPresenceOnline(); + } catch (e) { + log('appHasComeBackToForeground', e); + } }; const appHasComeBackToBackground = function* appHasComeBackToBackground() { @@ -16,7 +21,11 @@ const appHasComeBackToBackground = function* appHasComeBackToBackground() { if (!auth) { return; } - return yield RocketChat.setUserPresenceAway(); + try { + return yield RocketChat.setUserPresenceAway(); + } catch (e) { + log('appHasComeBackToBackground', e); + } }; const root = function* root() { diff --git a/app/utils/log.js b/app/utils/log.js new file mode 100644 index 000000000..7bde33a48 --- /dev/null +++ b/app/utils/log.js @@ -0,0 +1,8 @@ +import { Answers } from 'react-native-fabric'; + +export default (event, error) => { + Answers.logCustom(event, error); + if (__DEV__) { + console.warn(event, error); + } +}; diff --git a/app/views/ForgotPasswordView.js b/app/views/ForgotPasswordView.js index 167bb5beb..f5f639b19 100644 --- a/app/views/ForgotPasswordView.js +++ b/app/views/ForgotPasswordView.js @@ -73,10 +73,6 @@ export default class ForgotPasswordView extends LoggedView { this.props.forgotPasswordRequest(email); } - backLogin = () => { - this.props.navigation.goBack(); - } - render() { return ( ({ selectServer: server => dispatch(setServer(server)) })) -export default class ListServerView extends LoggedView { +class ListServerView extends LoggedView { static propTypes = { navigation: PropTypes.object.isRequired, login: PropTypes.object.isRequired, @@ -127,8 +128,10 @@ export default class ListServerView extends LoggedView { jumpToSelectedServer() { if (this.props.server && !this.props.login.isRegistering) { setTimeout(() => { - this.openLogin(); - }, 300); + if (this.props.isFocused) { + this.openLogin(); + } + }, 500); } } @@ -219,3 +222,4 @@ export default class ListServerView extends LoggedView { ); } } +export default withNavigationFocus(ListServerView); diff --git a/app/views/NewServerView.js b/app/views/NewServerView.js index 8d536b48a..eb9849129 100644 --- a/app/views/NewServerView.js +++ b/app/views/NewServerView.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { Text, ScrollView, View, SafeAreaView } from 'react-native'; +import { Text, ScrollView, View, SafeAreaView, Keyboard } from 'react-native'; import { connect } from 'react-redux'; import { serverRequest, addServer } from '../actions/server'; @@ -48,6 +48,7 @@ export default class NewServerView extends LoggedView { } submit = () => { + Keyboard.dismiss(); this.props.addServer(this.completeUrl(this.state.text)); } @@ -114,6 +115,7 @@ export default class NewServerView extends LoggedView { placeholder={this.state.defaultServer} returnKeyType='done' onChangeText={this.onChangeText} + onSubmitEditing={this.submit} /> {this.renderValidation()} diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index ab73b6e32..1c87ba152 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -15,6 +15,7 @@ import database from '../../lib/realm'; import RocketChat from '../../lib/rocketchat'; import { leaveRoom } from '../../actions/room'; import { setLoading } from '../../actions/selectedUsers'; +import log from '../../utils/log'; import RoomTypeIcon from '../../containers/RoomTypeIcon'; const renderSeparator = () => ; @@ -87,14 +88,14 @@ export default class RoomActionsView extends LoggedView { } updateRoomMember = async() => { - if (this.state.room.t === 'd') { + if (this.state.room.t !== 'd') { return {}; } try { const member = await RocketChat.getRoomMember(this.state.room.rid, this.props.user_id); return { member }; - } catch (error) { - console.warn('RoomActions updateRoomMember', error); + } catch (e) { + log('RoomActions updateRoomMember', e); return {}; } } @@ -222,8 +223,8 @@ export default class RoomActionsView extends LoggedView { this.props.setLoadingInvite(true); await RocketChat.addUsersToRoom(rid); this.props.navigation.goBack(); - } catch (error) { - console.warn('RoomActions Add User', error); + } catch (e) { + log('RoomActions Add User', e); } finally { this.props.setLoadingInvite(false); } @@ -250,7 +251,11 @@ export default class RoomActionsView extends LoggedView { toggleBlockUser = () => { const { rid, blocked } = this.state.room; const { member } = this.state; - RocketChat.toggleBlockUser(rid, member._id, !blocked); + try { + RocketChat.toggleBlockUser(rid, member._id, !blocked); + } catch (e) { + log('toggleBlockUser', e); + } } leaveChannel = () => { @@ -274,7 +279,11 @@ export default class RoomActionsView extends LoggedView { toggleNotifications = () => { const { room } = this.state; - RocketChat.saveNotificationSettings(room.rid, 'mobilePushNotifications', room.notifications ? 'default' : 'nothing'); + try { + RocketChat.saveNotificationSettings(room.rid, 'mobilePushNotifications', room.notifications ? 'default' : 'nothing'); + } catch (e) { + log('toggleNotifications', e); + } } renderRoomInfo = ({ item }) => { diff --git a/app/views/RoomInfoEditView/index.js b/app/views/RoomInfoEditView/index.js index 001bfbe9f..034a35ba6 100644 --- a/app/views/RoomInfoEditView/index.js +++ b/app/views/RoomInfoEditView/index.js @@ -16,6 +16,7 @@ import RCTextInput from '../../containers/TextInput'; import Loading from '../../containers/Loading'; import SwitchContainer from './SwitchContainer'; import random from '../../utils/random'; +import log from '../../utils/log'; const PERMISSION_SET_READONLY = 'set-readonly'; const PERMISSION_SET_REACT_WHEN_READONLY = 'set-react-when-readonly'; @@ -182,6 +183,7 @@ export default class RoomInfoEditView extends LoggedView { this.setState({ nameError: e }); } error = true; + log('saveRoomSettings', e); } await this.setState({ saving: false }); @@ -230,8 +232,8 @@ export default class RoomInfoEditView extends LoggedView { onPress: () => { try { RocketChat.toggleArchiveRoom(this.state.room.rid, !archived); - } catch (error) { - console.warn('toggleArchive', error); + } catch (e) { + log('toggleArchive', e); } } } @@ -274,7 +276,6 @@ export default class RoomInfoEditView extends LoggedView { value={description} onChangeText={value => this.setState({ description: value })} onSubmitEditing={() => { this.topic.focus(); }} - inputProps={{ multiline: true }} /> { this.topic = e; }} @@ -282,7 +283,6 @@ export default class RoomInfoEditView extends LoggedView { value={topic} onChangeText={value => this.setState({ topic: value })} onSubmitEditing={() => { this.announcement.focus(); }} - inputProps={{ multiline: true }} /> { this.announcement = e; }} @@ -290,7 +290,6 @@ export default class RoomInfoEditView extends LoggedView { value={announcement} onChangeText={value => this.setState({ announcement: value })} onSubmitEditing={() => { this.joinCode.focus(); }} - inputProps={{ multiline: true }} /> { this.joinCode = e; }} @@ -298,7 +297,7 @@ export default class RoomInfoEditView extends LoggedView { value={joinCode} onChangeText={value => this.setState({ joinCode: value })} onSubmitEditing={this.submit} - inputProps={{ secureTextEntry: true }} + secureTextEntry /> ( + + {room.t === 'd' ? : null} + + ) + render() { const { room, roomUser } = this.state; - const { name, t } = room; + if (!room) { + return ; + } return ( - - {t === 'd' ? : null} - - - { getRoomTitle(room) } - + {this.renderAvatar(room, roomUser)} + { this.getRoomTitle(room) } - {!this.isDirect() && this.renderItem('description', room)} {!this.isDirect() && this.renderItem('topic', room)} {!this.isDirect() && this.renderItem('announcement', room)} diff --git a/app/views/RoomMembersView/index.js b/app/views/RoomMembersView/index.js index 9352720b3..c5b06bd71 100644 --- a/app/views/RoomMembersView/index.js +++ b/app/views/RoomMembersView/index.js @@ -6,7 +6,6 @@ import ActionSheet from 'react-native-actionsheet'; import LoggedView from '../View'; import styles from './styles'; - import RoomItem from '../../presentation/RoomItem'; import Touch from '../../utils/touch'; import scrollPersistTaps from '../../utils/scrollPersistTaps'; @@ -14,6 +13,7 @@ import RocketChat from '../../lib/rocketchat'; import { goRoom } from '../../containers/routes/NavigationService'; import database from '../../lib/realm'; import { showToast } from '../../utils/info'; +import log from '../../utils/log'; @connect(state => ({ user: state.login.user, @@ -93,20 +93,28 @@ export default class MentionedMessagesView extends LoggedView { } onPressToogleStatus = async() => { - const allUsers = !this.state.allUsers; - this.props.navigation.setParams({ allUsers }); - const membersResult = await RocketChat.getRoomMembers(this.state.rid, allUsers); - const members = membersResult.records; - this.setState({ allUsers, members }); + try { + const allUsers = !this.state.allUsers; + this.props.navigation.setParams({ allUsers }); + const membersResult = await RocketChat.getRoomMembers(this.state.rid, allUsers); + const members = membersResult.records; + this.setState({ allUsers, members }); + } catch (e) { + log('onPressToogleStatus', e); + } } onPressUser = async(item) => { - const subscriptions = database.objects('subscriptions').filtered('name = $0', item.username); - if (subscriptions.length) { - goRoom({ rid: subscriptions[0].rid, name: subscriptions[0].name }); - } else { - const room = await RocketChat.createDirectMessage(item.username); - goRoom({ room: room.rid, name: item.username }); + try { + const subscriptions = database.objects('subscriptions').filtered('name = $0', item.username); + if (subscriptions.length) { + goRoom({ rid: subscriptions[0].rid, name: subscriptions[0].name }); + } else { + const room = await RocketChat.createDirectMessage(item.username); + goRoom({ rid: room.rid, name: item.username }); + } + } catch (e) { + log('onPressUser', e); } } @@ -133,8 +141,8 @@ export default class MentionedMessagesView extends LoggedView { try { await RocketChat.toggleMuteUserInRoom(rid, userLongPressed.username, !userLongPressed.muted); showToast(`User has been ${ userLongPressed.muted ? 'unmuted' : 'muted' }!`); - } catch (error) { - console.warn('handleMute', error); + } catch (e) { + log('handleMute', e); } } @@ -158,6 +166,8 @@ export default class MentionedMessagesView extends LoggedView { placeholder='Search' clearButtonMode='while-editing' blurOnSubmit + autoCorrect={false} + autoCapitalize='none' /> ) diff --git a/app/views/RoomView/Header/index.js b/app/views/RoomView/Header/index.js index 89f4c2a4b..77596419a 100644 --- a/app/views/RoomView/Header/index.js +++ b/app/views/RoomView/Header/index.js @@ -11,6 +11,8 @@ import Avatar from '../../../containers/Avatar'; import { STATUS_COLORS } from '../../../constants/colors'; import styles from './styles'; import { closeRoom } from '../../../actions/room'; + +import log from '../../../utils/log'; import RoomTypeIcon from '../../../containers/RoomTypeIcon'; const title = (offline, connecting, authenticating, logged) => { @@ -108,7 +110,7 @@ export default class RoomHeaderView extends React.PureComponent { renderCenter() { if (!this.state.room.name) { - return null; + return ; } let accessibilityLabel = this.state.room.name; @@ -134,7 +136,7 @@ export default class RoomHeaderView extends React.PureComponent { style={styles.titleContainer} accessibilityLabel={accessibilityLabel} accessibilityTraits='header' - onPress={() => this.props.navigation.navigate({ key: 'RoomInfo', routeName: 'RoomInfo', params: { rid: this.state.rid } })} + onPress={() => this.props.navigation.navigate({ key: 'RoomInfo', routeName: 'RoomInfo', params: this.state.room })} > RocketChat.toggleFavorite(this.state.room.rid, this.state.room.f)} + onPress={() => { + try { + RocketChat.toggleFavorite(this.state.room.rid, this.state.room.f); + } catch (e) { + log('toggleFavorite', e); + } + }} accessibilityLabel='Star room' accessibilityTraits='button' > diff --git a/app/views/RoomView/ListView.js b/app/views/RoomView/ListView.js index 3dd10fbea..f67ca0d2e 100644 --- a/app/views/RoomView/ListView.js +++ b/app/views/RoomView/ListView.js @@ -12,6 +12,7 @@ import styles from './styles'; import Typing from '../../containers/Typing'; import database from '../../lib/realm'; import scrollPersistTaps from '../../utils/scrollPersistTaps'; +import throttle from '../../utils/throttle'; const DEFAULT_SCROLL_CALLBACK_THROTTLE = 100; @@ -54,13 +55,13 @@ export class List extends React.Component { this.data.removeAllListeners(); this.updateState.stop(); } - updateState = () => { + updateState = throttle(() => { // this.setState({ this.dataSource = this.dataSource.cloneWithRows(this.data); LayoutAnimation.easeInEaseOut(); this.forceUpdate(); // }); - }; + }, 1000); render() { return ( ({ @@ -27,8 +28,7 @@ import styles from './styles'; Message_TimeFormat: state.settings.Message_TimeFormat, loading: state.messages.isFetching, user: state.login.user, - actionMessage: state.messages.actionMessage, - layoutAnimation: state.room.layoutAnimation + actionMessage: state.messages.actionMessage }), dispatch => ({ actions: bindActionCreators(actions, dispatch), @@ -76,14 +76,6 @@ export default class RoomView extends LoggedView { async componentDidMount() { await this.updateRoom(); - await this.props.openRoom({ - ...this.state.room - }); - if (this.state.room.alert || this.state.room.unread || this.state.room.userMentions) { - this.props.setLastOpen(this.state.room.ls); - } else { - this.props.setLastOpen(null); - } this.rooms.addListener(this.updateRoom); } shouldComponentUpdate(nextProps, nextState) { @@ -116,16 +108,31 @@ export default class RoomView extends LoggedView { } onReactionPress = (shortname, messageId) => { - if (!messageId) { - RocketChat.setReaction(shortname, this.props.actionMessage._id); - return this.props.toggleReactionPicker(); + try { + if (!messageId) { + RocketChat.setReaction(shortname, this.props.actionMessage._id); + return this.props.toggleReactionPicker(); + } + RocketChat.setReaction(shortname, messageId); + } catch (e) { + log('RoomView.onReactionPress', e); } - RocketChat.setReaction(shortname, messageId); }; updateRoom = async() => { if (this.rooms.length > 0) { + const { room: prevRoom } = this.state; await this.setState({ room: JSON.parse(JSON.stringify(this.rooms[0])) }); + if (!prevRoom.rid) { + await this.props.openRoom({ + ...this.state.room + }); + if (this.state.room.alert || this.state.room.unread || this.state.room.userMentions) { + this.props.setLastOpen(this.state.room.ls); + } else { + this.props.setLastOpen(null); + } + } } } @@ -136,10 +143,14 @@ export default class RoomView extends LoggedView { }; joinRoom = async() => { - await RocketChat.joinRoom(this.props.rid); - this.setState({ - joined: true - }); + try { + await RocketChat.joinRoom(this.props.rid); + this.setState({ + joined: true + }); + } catch (e) { + log('joinRoom', e); + } }; renderItem = (item, previousItem) => ( diff --git a/app/views/RoomsListView/Header/index.js b/app/views/RoomsListView/Header/index.js index e07b3dc37..9fb5f5913 100644 --- a/app/views/RoomsListView/Header/index.js +++ b/app/views/RoomsListView/Header/index.js @@ -13,6 +13,7 @@ import RocketChat from '../../../lib/rocketchat'; import { STATUS_COLORS } from '../../../constants/colors'; import { setSearch } from '../../../actions/rooms'; import styles from './styles'; +import log from '../../../utils/log'; const title = (offline, connecting, authenticating, logged) => { if (offline) { @@ -65,7 +66,11 @@ export default class RoomsListHeaderView extends React.PureComponent { } onPressModalButton(status) { - RocketChat.setUserPresenceDefaultStatus(status); + try { + RocketChat.setUserPresenceDefaultStatus(status); + } catch (e) { + log('onPressModalButton', e); + } this.hideModal(); } @@ -103,8 +108,11 @@ export default class RoomsListHeaderView extends React.PureComponent { } createChannel() { - const params = this.props.navigation.state.params || {}; - params.createChannel(); + this.props.navigation.navigate({ + key: 'SelectedUsers', + routeName: 'SelectedUsers', + params: { nextAction: () => this.props.navigation.navigate('CreateChannel') } + }); } renderLeft() { @@ -234,6 +242,8 @@ export default class RoomsListHeaderView extends React.PureComponent { placeholder='Search' clearButtonMode='while-editing' blurOnSubmit + autoCorrect={false} + autoCapitalize='none' /> ); diff --git a/app/views/RoomsListView/index.js b/app/views/RoomsListView/index.js index 776b4a5ea..0164e40c2 100644 --- a/app/views/RoomsListView/index.js +++ b/app/views/RoomsListView/index.js @@ -4,6 +4,7 @@ import PropTypes from 'prop-types'; import Icon from 'react-native-vector-icons/Ionicons'; import { Platform, View, TextInput, FlatList, LayoutAnimation } from 'react-native'; import { connect } from 'react-redux'; + import database from '../../lib/realm'; import RocketChat from '../../lib/rocketchat'; import RoomItem from '../../presentation/RoomItem'; @@ -13,6 +14,7 @@ import RoomsListHeader from './Header'; import styles from './styles'; import throttle from '../../utils/throttle'; import LoggedView from '../View'; +import log from '../../utils/log'; @connect(state => ({ user: state.login.user, @@ -45,12 +47,6 @@ export default class RoomsListView extends LoggedView { componentDidMount() { this.data.addListener(this.updateState); - - this.props.navigation.setParams({ - createChannel: () => this._createChannel() - }); - - this.updateState(); } componentWillReceiveProps(props) { @@ -88,7 +84,7 @@ export default class RoomsListView extends LoggedView { let data = database.objects('subscriptions').filtered('name CONTAINS[c] $0', searchText).slice(0, 7); - const usernames = data.map(sub => sub.map); + const usernames = data.map(sub => sub.name); try { if (data.length < 7) { if (this.oldPromise) { @@ -124,21 +120,21 @@ export default class RoomsListView extends LoggedView { _onPressItem = async(item = {}) => { if (!item.search) { - return goRoom({ rid: item.rid }); + return goRoom({ rid: item.rid, name: item.name }); } if (item.t === 'd') { // if user is using the search we need first to join/create room try { const sub = await RocketChat.createDirectMessage(item.username); return goRoom(sub); - } catch (error) { - console.warn('_onPressItem', error); + } catch (e) { + log('RoomsListView._onPressItem', e); } } return goRoom(item); } - _createChannel() { + createChannel() { this.props.navigation.navigate({ key: 'SelectedUsers', routeName: 'SelectedUsers', @@ -160,6 +156,8 @@ export default class RoomsListView extends LoggedView { placeholder='Search' clearButtonMode='while-editing' blurOnSubmit + autoCorrect={false} + autoCapitalize='none' /> ); @@ -198,7 +196,7 @@ export default class RoomsListView extends LoggedView { renderCreateButtons = () => ( - { this._createChannel(); }} > + { this.createChannel(); }} > diff --git a/app/views/SearchMessagesView/index.js b/app/views/SearchMessagesView/index.js index 36040f82c..0b5929424 100644 --- a/app/views/SearchMessagesView/index.js +++ b/app/views/SearchMessagesView/index.js @@ -13,6 +13,7 @@ import RocketChat from '../../lib/rocketchat'; import buildMessage from '../../lib/methods/helpers/buildMessage'; import Message from '../../containers/message'; import scrollPersistTaps from '../../utils/scrollPersistTaps'; +import log from '../../utils/log'; @connect(state => ({ user: state.login.user, @@ -50,14 +51,14 @@ export default class SearchMessagesView extends LoggedView { let messages = []; try { const result = await Promise.race([RocketChat.messageSearch(this.searchText, this.props.navigation.state.params.rid, this.limit), cancel]); - messages = result.messages.map(message => buildMessage(message)); + messages = result.message.docs.map(message => buildMessage(message)); this.setState({ messages, searching: false, loadingMore: false }); - } catch (error) { + } catch (e) { this._cancel = null; - if (error !== 'cancel') { + if (e !== 'cancel') { return this.setState({ searching: false, loadingMore: false }); } - console.warn('search', error); + log('SearchMessagesView.search', e); } } @@ -92,9 +93,13 @@ export default class SearchMessagesView extends LoggedView { customTimeFormat='MMMM Do YYYY, h:mm:ss a' onLongPress={() => {}} onReactionPress={async(emoji) => { - await RocketChat.setReaction(emoji, item._id); - this.search(); - this.forceUpdate(); + try { + await RocketChat.setReaction(emoji, item._id); + this.search(); + this.forceUpdate(); + } catch (e) { + log('SearchMessagesView.onReactionPress', e); + } }} /> ); diff --git a/app/views/SelectedUsersView.js b/app/views/SelectedUsersView.js index 6ba96bb63..801dd1f51 100644 --- a/app/views/SelectedUsersView.js +++ b/app/views/SelectedUsersView.js @@ -101,7 +101,7 @@ export default class SelectedUsersView extends LoggedView { justifyContent: 'center' }} onPress={() => params.nextAction()} - accessibilityLabel='Create channel' + accessibilityLabel='Submit' accessibilityTraits='button' > ); diff --git a/package-lock.json b/package-lock.json index 3cb4700d2..abc8b8804 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15921,7 +15921,7 @@ } }, "react-native-keyboard-input": { - "version": "git+https://github.com/RocketChat/react-native-keyboard-input.git#1b5c45176e846ec5eb18e6d24c11c0481783a6d2", + "version": "git+https://github.com/RocketChat/react-native-keyboard-input.git#67a441ee3e6166fa8727b0e6969010da0d710db6", "requires": { "lodash": "4.17.5", "react-native-keyboard-tracking-view": "git+https://github.com/RocketChat/react-native-keyboard-tracking-view.git#82be12805eb3aa448c1f09f545c334e4776b3148"