diff --git a/app/actions/actionsTypes.js b/app/actions/actionsTypes.js index b727d935f..4250f88bc 100644 --- a/app/actions/actionsTypes.js +++ b/app/actions/actionsTypes.js @@ -29,7 +29,26 @@ export const FORGOT_PASSWORD = createRequestTypes('FORGOT_PASSWORD', [ export const ROOMS = createRequestTypes('ROOMS'); export const ROOM = createRequestTypes('ROOM', ['ADD_USER_TYPING', 'REMOVE_USER_TYPING', 'USER_TYPING', 'OPEN', 'IM_TYPING']); export const APP = createRequestTypes('APP', ['READY', 'INIT']); -export const MESSAGES = createRequestTypes('MESSAGES'); +export const MESSAGES = createRequestTypes('MESSAGES', [ + ...defaultTypes, + 'DELETE_REQUEST', + 'DELETE_SUCCESS', + 'DELETE_FAILURE', + 'EDIT_INIT', + 'EDIT_REQUEST', + 'EDIT_SUCCESS', + 'EDIT_FAILURE', + 'STAR_REQUEST', + 'STAR_SUCCESS', + 'STAR_FAILURE', + 'PERMALINK_REQUEST', + 'PERMALINK_SUCCESS', + 'PERMALINK_FAILURE', + 'TOGGLE_PIN_REQUEST', + 'TOGGLE_PIN_SUCCESS', + 'TOGGLE_PIN_FAILURE', + 'SET_INPUT' +]); export const CREATE_CHANNEL = createRequestTypes('CREATE_CHANNEL', [ ...defaultTypes, 'REQUEST_USERS', diff --git a/app/actions/messages.js b/app/actions/messages.js index 2f92816ec..5f01815ef 100644 --- a/app/actions/messages.js +++ b/app/actions/messages.js @@ -19,3 +19,116 @@ export function messagesFailure(err) { err }; } + +export function deleteRequest(message) { + return { + type: types.MESSAGES.DELETE_REQUEST, + message + }; +} + +export function deleteSuccess() { + return { + type: types.MESSAGES.DELETE_SUCCESS + }; +} + +export function deleteFailure() { + return { + type: types.MESSAGES.DELETE_FAILURE + }; +} + + +export function editInit(message) { + return { + type: types.MESSAGES.EDIT_INIT, + message + }; +} + +export function editRequest(message) { + return { + type: types.MESSAGES.EDIT_REQUEST, + message + }; +} + +export function editSuccess() { + return { + type: types.MESSAGES.EDIT_SUCCESS + }; +} + +export function editFailure() { + return { + type: types.MESSAGES.EDIT_FAILURE + }; +} + +export function starRequest(message) { + return { + type: types.MESSAGES.STAR_REQUEST, + message + }; +} + +export function starSuccess() { + return { + type: types.MESSAGES.STAR_SUCCESS + }; +} + +export function starFailure() { + return { + type: types.MESSAGES.STAR_FAILURE + }; +} + +export function permalinkRequest(message) { + return { + type: types.MESSAGES.PERMALINK_REQUEST, + message + }; +} + +export function permalinkSuccess(permalink) { + return { + type: types.MESSAGES.PERMALINK_SUCCESS, + permalink + }; +} + +export function permalinkFailure(err) { + return { + type: types.MESSAGES.PERMALINK_FAILURE, + err + }; +} + +export function togglePinRequest(message) { + return { + type: types.MESSAGES.TOGGLE_PIN_REQUEST, + message + }; +} + +export function togglePinSuccess() { + return { + type: types.MESSAGES.TOGGLE_PIN_SUCCESS + }; +} + +export function togglePinFailure(err) { + return { + type: types.MESSAGES.TOGGLE_PIN_FAILURE, + err + }; +} + +export function setInput(message) { + return { + type: types.MESSAGES.SET_INPUT, + message + }; +} diff --git a/app/containers/Message.js b/app/containers/Message.js deleted file mode 100644 index da39c5f2d..000000000 --- a/app/containers/Message.js +++ /dev/null @@ -1,74 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { View, StyleSheet } from 'react-native'; -import { emojify } from 'react-emojione'; -import Markdown from 'react-native-easy-markdown'; - -import Card from './message/Card'; -import Avatar from './Avatar'; -import User from './message/User'; - -const styles = StyleSheet.create({ - content: { - flexGrow: 1, - flexShrink: 1 - }, - message: { - padding: 12, - paddingTop: 6, - paddingBottom: 6, - flexDirection: 'row', - transform: [{ scaleY: -1 }] - } -}); - -export default class Message extends React.PureComponent { - static propTypes = { - item: PropTypes.object.isRequired, - baseUrl: PropTypes.string.isRequired, - Message_TimeFormat: PropTypes.string.isRequired - } - - attachments() { - return this.props.item.attachments.length ? ( - - ) : null; - } - - render() { - const { item } = this.props; - - const extraStyle = {}; - if (item.temp) { - extraStyle.opacity = 0.3; - } - - const msg = emojify(item.msg, { output: 'unicode' }); - const username = item.alias || item.u.username; - - return ( - - - - - {this.attachments()} - - {msg} - - - - ); - } -} diff --git a/app/containers/MessageBox.js b/app/containers/MessageBox.js index 9eb32435c..ce8474e0c 100644 --- a/app/containers/MessageBox.js +++ b/app/containers/MessageBox.js @@ -6,6 +6,7 @@ import ImagePicker from 'react-native-image-picker'; import { connect } from 'react-redux'; import { imTyping } from '../actions/room'; import RocketChat from '../lib/rocketchat'; +import { editRequest } from '../actions/messages'; const styles = StyleSheet.create({ textBox: { @@ -22,7 +23,6 @@ const styles = StyleSheet.create({ textBoxInput: { height: 40, alignSelf: 'stretch', - backgroundColor: '#fff', flexGrow: 1 }, fileButton: { @@ -30,31 +30,50 @@ const styles = StyleSheet.create({ paddingTop: 10, paddingBottom: 10, fontSize: 20 + }, + editing: { + backgroundColor: '#fff5df' } }); -@connect( - null, - dispatch => ({ - typing: status => dispatch(imTyping(status)) - }) -) - -export default class MessageBox extends React.PureComponent { +@connect(state => ({ + message: state.messages.message, + editing: state.messages.editing +}), dispatch => ({ + editRequest: message => dispatch(editRequest(message)), + typing: status => dispatch(imTyping(status)) +})) +export default class MessageBox extends React.Component { static propTypes = { onSubmit: PropTypes.func.isRequired, - rid: PropTypes.string.isRequired + rid: PropTypes.string.isRequired, + editRequest: PropTypes.func.isRequired, + message: PropTypes.object, + editing: PropTypes.bool + } + + componentWillReceiveProps(nextProps) { + if (this.props.message !== nextProps.message) { + this.component.setNativeProps({ text: nextProps.message.msg }); + this.component.focus(); + } } submit(message) { - const text = message; - if (text.trim() === '') { + const { editing } = this.props; + if (message.trim() === '') { return; } - if (this.component) { - this.component.setNativeProps({ text: '' }); + + // if is editing a message + if (editing) { + const { _id, rid } = this.props.message; + this.props.editRequest({ _id, msg: message, rid }); + } else { + // if is submiting a new message + this.props.onSubmit(message); } - this.props.onSubmit(text); + this.component.setNativeProps({ text: '' }); } addFile = () => { @@ -86,7 +105,7 @@ export default class MessageBox extends React.PureComponent { render() { return ( - + this.component = component} diff --git a/app/containers/message/User.js b/app/containers/message/User.js index c75d88a37..873e96888 100644 --- a/app/containers/message/User.js +++ b/app/containers/message/User.js @@ -2,6 +2,8 @@ import React from 'react'; import PropTypes from 'prop-types'; import { View, Text, StyleSheet } from 'react-native'; import moment from 'moment'; +import Icon from 'react-native-vector-icons/FontAwesome'; +import Avatar from '../Avatar'; const styles = StyleSheet.create({ username: { @@ -21,6 +23,11 @@ const styles = StyleSheet.create({ fontSize: 10, color: '#888', paddingLeft: 5 + }, + edited: { + marginLeft: 5, + flexDirection: 'row', + alignItems: 'center' } }); @@ -28,7 +35,26 @@ export default class Message extends React.PureComponent { static propTypes = { item: PropTypes.object.isRequired, Message_TimeFormat: PropTypes.string.isRequired, - onPress: PropTypes.func + onPress: PropTypes.func, + baseUrl: PropTypes.string + } + + renderEdited(item) { + if (!item.editedBy) { + return null; + } + return ( + + + + + ); } render() { @@ -48,7 +74,9 @@ export default class Message extends React.PureComponent { {username} - {aliasUsername}{time} + {aliasUsername} + {time} + {this.renderEdited(item)} ); } diff --git a/app/containers/message/index.js b/app/containers/message/index.js new file mode 100644 index 000000000..2835a6d41 --- /dev/null +++ b/app/containers/message/index.js @@ -0,0 +1,272 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { View, StyleSheet, TouchableOpacity, Text, Alert, Clipboard } from 'react-native'; +import { emojify } from 'react-emojione'; +import Markdown from 'react-native-easy-markdown'; // eslint-disable-line +import ActionSheet from 'react-native-actionsheet'; +import { connect } from 'react-redux'; + +import Card from './Card'; +import User from './User'; +import Avatar from '../Avatar'; +import { + deleteRequest, + editInit, + starRequest, + permalinkRequest, + togglePinRequest, + setInput +} from '../../actions/messages'; +import RocketChat from '../../lib/rocketchat'; + +const title = 'Message actions'; +const options = ['Cancel', 'Reply', 'Edit', 'Permalink', 'Copy', 'Quote', 'Star Message', 'Pin Message', 'Delete']; +const CANCEL_INDEX = 0; +const DESTRUCTIVE_INDEX = 8; + +const styles = StyleSheet.create({ + content: { + flexGrow: 1, + flexShrink: 1 + }, + message: { + padding: 12, + paddingTop: 6, + paddingBottom: 6, + flexDirection: 'row', + transform: [{ scaleY: -1 }] + }, + textInfo: { + fontStyle: 'italic', + color: '#a0a0a0' + }, + editing: { + backgroundColor: '#fff5df' + } +}); + +@connect(state => ({ + message: state.messages.message, + permalink: state.messages.permalink, + user: state.login.user +}), dispatch => ({ + deleteRequest: message => dispatch(deleteRequest(message)), + editInit: message => dispatch(editInit(message)), + starRequest: message => dispatch(starRequest(message)), + permalinkRequest: message => dispatch(permalinkRequest(message)), + togglePinRequest: message => dispatch(togglePinRequest(message)), + setInput: message => dispatch(setInput(message)) +})) +export default class Message extends React.Component { + static propTypes = { + item: PropTypes.object.isRequired, + baseUrl: PropTypes.string.isRequired, + Message_TimeFormat: PropTypes.string.isRequired, + deleteRequest: PropTypes.func.isRequired, + editInit: PropTypes.func.isRequired, + starRequest: PropTypes.func.isRequired, + permalinkRequest: PropTypes.func.isRequired, + togglePinRequest: PropTypes.func.isRequired, + setInput: PropTypes.func.isRequired, + user: PropTypes.object.isRequired, + message: PropTypes.object, + permalink: PropTypes.string + } + + constructor(props) { + super(props); + this.state = { + copyPermalink: false, + reply: false, + quote: false + }; + this.handleActionPress = this.handleActionPress.bind(this); + this.showActions = this.showActions.bind(this); + } + + async componentWillReceiveProps(nextProps) { + if (this.props.permalink !== nextProps.permalink) { + // copy permalink + if (this.state.copyPermalink) { + this.setState({ copyPermalink: false }); + await Clipboard.setString(nextProps.permalink); + Alert.alert('Permalink copied to clipboard!'); + + // quote + } else if (this.state.quote) { + this.setState({ quote: false }); + const msg = `[ ](${ nextProps.permalink }) `; + this.props.setInput({ msg }); + + // reply + } else if (this.state.reply) { + this.setState({ reply: false }); + let msg = `[ ](${ nextProps.permalink }) `; + const room = await RocketChat.getRoom(this.props.item.rid); + + // if original message wasn't sent by current user and neither from a direct room + if (this.props.user.username !== this.props.item.u.username && room.t !== 'd') { + msg += `@${ this.props.item.u.username } `; + } + this.props.setInput({ msg }); + } + } + } + + isDeleted() { + return !this.props.item.msg; + } + + attachments() { + return this.props.item.attachments.length ? ( + + ) : null; + } + + showActions = () => { + this.ActionSheet.show(); + } + + handleDelete() { + Alert.alert( + 'Are you sure?', + 'You will not be able to recover this message!', + [ + { + text: 'Cancel', + style: 'cancel' + }, + { + text: 'Yes, delete it!', + style: 'destructive', + onPress: () => this.props.deleteRequest(this.props.item) + } + ], + { cancelable: false } + ); + } + + handleEdit() { + const { _id, msg, rid } = this.props.item; + this.props.editInit({ _id, msg, rid }); + } + + handleCopy = async() => { + await Clipboard.setString(this.props.item.msg); + Alert.alert('Copied to clipboard!'); + } + + handleStar() { + this.props.starRequest(this.props.item); + } + + handlePermalink() { + this.setState({ copyPermalink: true }); + this.props.permalinkRequest(this.props.item); + } + + handleTogglePin() { + this.props.togglePinRequest(this.props.item); + } + + handleReply() { + this.setState({ reply: true }); + this.props.permalinkRequest(this.props.item); + } + + handleQuote() { + this.setState({ quote: true }); + this.props.permalinkRequest(this.props.item); + } + + handleActionPress = (actionIndex) => { + // reply + if (actionIndex === 1) { + this.handleReply(); + // edit + } else if (actionIndex === 2) { + this.handleEdit(); + // permalink + } else if (actionIndex === 3) { + this.handlePermalink(); + // copy + } else if (actionIndex === 4) { + this.handleCopy(); + // quote + } else if (actionIndex === 5) { + this.handleQuote(); + // star + } else if (actionIndex === 6) { + this.handleStar(); + // toggle pin + } else if (actionIndex === 7) { + this.handleTogglePin(); + // delete + } else if (actionIndex === 8) { + this.handleDelete(); + } + } + + renderMessageContent() { + if (this.isDeleted()) { + return Message removed; + } + + const msg = emojify(this.props.item.msg, { output: 'unicode' }); + return ( + + {msg} + + ); + } + + render() { + const { item } = this.props; + + const extraStyle = {}; + if (item.temp) { + extraStyle.opacity = 0.3; + } + + const username = item.alias || item.u.username; + const isEditing = this.props.message._id === item._id; + + return ( + this.showActions()} + disabled={this.isDeleted()} + style={isEditing ? styles.editing : null} + > + + + + + {this.attachments()} + {this.renderMessageContent(item)} + + this.ActionSheet = o} + title={title} + options={options} + cancelButtonIndex={CANCEL_INDEX} + destructiveButtonIndex={DESTRUCTIVE_INDEX} + onPress={this.handleActionPress} + /> + + + ); + } +} diff --git a/app/lib/realm.js b/app/lib/realm.js index adf877feb..ee44086da 100644 --- a/app/lib/realm.js +++ b/app/lib/realm.js @@ -86,6 +86,14 @@ const attachment = { } }; +const messagesEditedBySchema = { + name: 'messagesEditedBy', + properties: { + _id: { type: 'string', optional: true }, + username: { type: 'string', optional: true } + } +}; + const messagesSchema = { name: 'messages', primaryKey: '_id', @@ -104,14 +112,26 @@ const messagesSchema = { avatar: { type: 'string', optional: true }, attachments: { type: 'list', objectType: 'attachment' }, _updatedAt: { type: 'date', optional: true }, - temp: { type: 'bool', optional: true } + temp: { type: 'bool', optional: true }, + pinned: { type: 'bool', optional: true }, + starred: { type: 'bool', optional: true }, + editedBy: 'messagesEditedBy' } }; // // Realm.clearTestState(); // AsyncStorage.clear(); const realm = new Realm({ - schema: [settingsSchema, serversSchema, subscriptionSchema, messagesSchema, usersSchema, roomsSchema, attachment] + schema: [ + settingsSchema, + serversSchema, + subscriptionSchema, + messagesSchema, + usersSchema, + roomsSchema, + attachment, + messagesEditedBySchema + ] }); export default realm; diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 481c10cd9..376a62798 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -70,6 +70,7 @@ const RocketChat = { message.temp = false; message._server = server; message.attachments = message.attachments || []; + message.starred = !!message.starred; realm.create('messages', message, true); }); } @@ -230,7 +231,7 @@ const RocketChat = { const data = { id: `RocketChatRN${ id }`, token: { [key]: token }, - appName: 'main', + appName: 'chat.rocket.reactnative', // TODO: try to get from config file userId: id, metadata: {} }; @@ -257,6 +258,7 @@ const RocketChat = { message._server = { id: reduxStore.getState().server.server }; message.attachments = message.attachments || []; // write('messages', message); + message.starred = !!message.starred; realm.create('messages', message, true); }); }); @@ -433,6 +435,38 @@ const RocketChat = { }); }, _filterSettings: settings => settings.filter(setting => settingsType[setting.type] && setting.value), + deleteMessage(message) { + return call('deleteMessage', { _id: message._id }); + }, + editMessage(message) { + const { _id, msg, rid } = message; + return call('updateMessage', { _id, msg, rid }); + }, + starMessage(message) { + return call('starMessage', { _id: message._id, rid: message.rid, starred: !message.starred }); + }, + togglePinMessage(message) { + if (message.pinned) { + return call('unpinMessage', message); + } + return call('pinMessage', message); + }, + getRoom(rid) { + const result = realm.objects('subscriptions').filtered('rid = $0', rid); + if (result.length === 0) { + return Promise.reject(new Error('Room not found')); + } + return Promise.resolve(result[0]); + }, + async getPermalink(message) { + const room = await RocketChat.getRoom(message.rid); + const roomType = { + p: 'group', + c: 'channel', + d: 'direct' + }[room.t]; + return `${ room._server.id }/${ roomType }/${ room.name }?msg=${ message._id }`; + }, subscribe(...args) { return Meteor.subscribe(...args); }, diff --git a/app/reducers/messages.js b/app/reducers/messages.js index 94f0f4f1f..4c1a73e2d 100644 --- a/app/reducers/messages.js +++ b/app/reducers/messages.js @@ -2,7 +2,10 @@ import * as types from '../actions/actionsTypes'; const initialState = { isFetching: false, - failure: false + failure: false, + message: {}, + editing: false, + permalink: '' }; export default function messages(state = initialState, action) { @@ -24,6 +27,34 @@ export default function messages(state = initialState, action) { failure: true, errorMessage: action.err }; + case types.MESSAGES.EDIT_INIT: + return { + ...state, + message: action.message, + editing: true + }; + case types.MESSAGES.EDIT_SUCCESS: + return { + ...state, + message: {}, + editing: false + }; + case types.MESSAGES.EDIT_FAILURE: + return { + ...state, + message: {}, + editing: false + }; + case types.MESSAGES.PERMALINK_SUCCESS: + return { + ...state, + permalink: action.permalink + }; + case types.MESSAGES.SET_INPUT: + return { + ...state, + message: action.message + }; // case types.LOGOUT: // return initialState; default: diff --git a/app/sagas/messages.js b/app/sagas/messages.js index e21b28ce9..b3d54db3e 100644 --- a/app/sagas/messages.js +++ b/app/sagas/messages.js @@ -1,8 +1,27 @@ -import { takeLatest, select, take, put } from 'redux-saga/effects'; +import { takeLatest, select, take, put, call } from 'redux-saga/effects'; import { MESSAGES, LOGIN } from '../actions/actionsTypes'; -import { messagesSuccess, messagesFailure } from '../actions/messages'; +import { + messagesSuccess, + messagesFailure, + deleteSuccess, + deleteFailure, + editSuccess, + editFailure, + starSuccess, + starFailure, + permalinkSuccess, + permalinkFailure, + togglePinSuccess, + togglePinFailure +} from '../actions/messages'; import RocketChat from '../lib/rocketchat'; +const deleteMessage = message => RocketChat.deleteMessage(message); +const editMessage = message => RocketChat.editMessage(message); +const starMessage = message => RocketChat.starMessage(message); +const getPermalink = message => RocketChat.getPermalink(message); +const togglePinMessage = message => RocketChat.togglePinMessage(message); + const get = function* get({ rid }) { const auth = yield select(state => state.login.isAuthenticated); if (!auth) { @@ -16,7 +35,58 @@ const get = function* get({ rid }) { yield put(messagesFailure(err.status)); } }; -const getData = function* getData() { - yield takeLatest(MESSAGES.REQUEST, get); + +const handleDeleteRequest = function* handleDeleteRequest({ message }) { + try { + yield call(deleteMessage, message); + yield put(deleteSuccess()); + } catch (error) { + yield put(deleteFailure()); + } }; -export default getData; + +const handleEditRequest = function* handleEditRequest({ message }) { + try { + yield call(editMessage, message); + yield put(editSuccess()); + } catch (error) { + yield put(editFailure()); + } +}; + +const handleStarRequest = function* handleStarRequest({ message }) { + try { + yield call(starMessage, message); + yield put(starSuccess()); + } catch (error) { + yield put(starFailure()); + } +}; + +const handlePermalinkRequest = function* handlePermalinkRequest({ message }) { + try { + const permalink = yield call(getPermalink, message); + yield put(permalinkSuccess(permalink)); + } catch (error) { + yield put(permalinkFailure(error)); + } +}; + +const handleTogglePinRequest = function* handleTogglePinRequest({ message }) { + try { + yield call(togglePinMessage, message); + yield put(togglePinSuccess()); + } catch (error) { + yield put(togglePinFailure(error)); + } +}; + +const root = function* root() { + yield takeLatest(MESSAGES.REQUEST, get); + yield takeLatest(MESSAGES.DELETE_REQUEST, handleDeleteRequest); + yield takeLatest(MESSAGES.EDIT_REQUEST, handleEditRequest); + yield takeLatest(MESSAGES.STAR_REQUEST, handleStarRequest); + yield takeLatest(MESSAGES.PERMALINK_REQUEST, handlePermalinkRequest); + yield takeLatest(MESSAGES.TOGGLE_PIN_REQUEST, handleTogglePinRequest); +}; +export default root; diff --git a/app/views/RoomView.js b/app/views/RoomView.js index 883a48ac2..307824611 100644 --- a/app/views/RoomView.js +++ b/app/views/RoomView.js @@ -9,7 +9,7 @@ import * as actions from '../actions'; import { openRoom } from '../actions/room'; import realm from '../lib/realm'; import RocketChat from '../lib/rocketchat'; -import Message from '../containers/Message'; +import Message from '../containers/message'; import MessageBox from '../containers/MessageBox'; import KeyboardView from '../presentation/KeyboardView'; diff --git a/ios/RocketChatRN.xcodeproj/project.pbxproj b/ios/RocketChatRN.xcodeproj/project.pbxproj index 265cb70e5..ccca670e4 100644 --- a/ios/RocketChatRN.xcodeproj/project.pbxproj +++ b/ios/RocketChatRN.xcodeproj/project.pbxproj @@ -403,6 +403,7 @@ 5A0EEFAF8AB14F5B9E796CDD /* libRNVectorIcons.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNVectorIcons.a; sourceTree = ""; }; 5A8684E7C27E426C9206E980 /* RealmReact.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RealmReact.xcodeproj; path = "../node_modules/realm/react-native/ios/RealmReact.xcodeproj"; sourceTree = ""; }; 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = ""; }; + 60B2A6A31FC4588700BD58E5 /* RocketChatRN.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = RocketChatRN.entitlements; path = RocketChatRN/RocketChatRN.entitlements; sourceTree = ""; }; 6533FB90166345D29F1B91C0 /* libRNFetchBlob.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNFetchBlob.a; sourceTree = ""; }; 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = ""; }; 7A30DA4B2D474348824CD05B /* FontAwesome.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = FontAwesome.ttf; path = "../node_modules/react-native-vector-icons/Fonts/FontAwesome.ttf"; sourceTree = ""; }; @@ -564,6 +565,7 @@ 13B07FAE1A68108700A75B9A /* RocketChatRN */ = { isa = PBXGroup; children = ( + 60B2A6A31FC4588700BD58E5 /* RocketChatRN.entitlements */, 008F07F21AC5B25A0029DE68 /* main.jsbundle */, 13B07FAF1A68108700A75B9A /* AppDelegate.h */, 13B07FB01A68108700A75B9A /* AppDelegate.m */, @@ -863,6 +865,11 @@ 13B07F861A680F5B00A75B9A = { DevelopmentTeam = S6UPZG7ZR3; ProvisioningStyle = Manual; + SystemCapabilities = { + com.apple.Push = { + enabled = 1; + }; + }; }; 2D02E47A1E0B4A5D006451C7 = { CreatedOnToolsVersion = 8.2.1; @@ -1483,6 +1490,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = RocketChatRN/RocketChatRN.entitlements; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 100; @@ -1519,6 +1527,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = RocketChatRN/RocketChatRN.entitlements; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 100; diff --git a/ios/RocketChatRN/RocketChatRN.entitlements b/ios/RocketChatRN/RocketChatRN.entitlements new file mode 100644 index 000000000..903def2af --- /dev/null +++ b/ios/RocketChatRN/RocketChatRN.entitlements @@ -0,0 +1,8 @@ + + + + + aps-environment + development + + diff --git a/ios/fastlane/Fastfile b/ios/fastlane/Fastfile index 3a2a79fe4..780a629ae 100644 --- a/ios/fastlane/Fastfile +++ b/ios/fastlane/Fastfile @@ -39,6 +39,7 @@ platform :ios do type: "appstore", git_url: "git@github.com:RocketChat/Rocket.Chat.ReactNative.FastLane.git" ) # more information: https://codesigning.guide + pem() gym(scheme: "RocketChatRN") # Build your app - more options available pilot @@ -66,6 +67,7 @@ platform :ios do type: "appstore", git_url: "git@github.com:RocketChat/Rocket.Chat.ReactNative.FastLane.git" ) # more information: https://codesigning.guide + pem() gym(scheme: "RocketChatRN") # Build your app - more options available # frameit end diff --git a/ios/fastlane/README.md b/ios/fastlane/README.md index ade625c4f..25c79d48b 100644 --- a/ios/fastlane/README.md +++ b/ios/fastlane/README.md @@ -12,9 +12,9 @@ xcode-select --install - + + diff --git a/package-lock.json b/package-lock.json index 641edeab8..ffe974829 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1058,12 +1058,6 @@ "integrity": "sha1-NOmzALFHnd2Y7HfqC76TQt/jloQ=", "dev": true }, - "babel-helper-is-react-class": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/babel-helper-is-react-class/-/babel-helper-is-react-class-1.0.0.tgz", - "integrity": "sha1-7282eLBcdtve7a3q16+YwnJNhDE=", - "dev": true - }, "babel-helper-is-void-0": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/babel-helper-is-void-0/-/babel-helper-is-void-0-0.2.0.tgz", @@ -1807,15 +1801,6 @@ "babel-runtime": "6.26.0" } }, - "babel-plugin-transform-react-inline-elements": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-inline-elements/-/babel-plugin-transform-react-inline-elements-6.22.0.tgz", - "integrity": "sha1-ZochGjK0mlLyLFc6K1UEol7xfFM=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, "babel-plugin-transform-react-jsx": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz", @@ -1845,15 +1830,6 @@ "babel-runtime": "6.26.0" } }, - "babel-plugin-transform-react-pure-class-to-function": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-pure-class-to-function/-/babel-plugin-transform-react-pure-class-to-function-1.0.1.tgz", - "integrity": "sha1-MqZJyX1lMlC0Gc/RSJMxsCkNnuQ=", - "dev": true, - "requires": { - "babel-helper-is-react-class": "1.0.0" - } - }, "babel-plugin-transform-react-remove-prop-types": { "version": "0.4.10", "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.10.tgz", @@ -1877,8 +1853,7 @@ "babel-plugin-transform-remove-console": { "version": "6.8.5", "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.8.5.tgz", - "integrity": "sha512-uuCKvtweCyIvvC8fi92EcWRtO2Kt5KMNMRK6BhpDXdeb3sxvGM7453RSmgeu4DlKns3OlvY9Ep5Q9m5a7RQAgg==", - "dev": true + "integrity": "sha512-uuCKvtweCyIvvC8fi92EcWRtO2Kt5KMNMRK6BhpDXdeb3sxvGM7453RSmgeu4DlKns3OlvY9Ep5Q9m5a7RQAgg==" }, "babel-plugin-transform-remove-debugger": { "version": "6.8.5", @@ -2178,26 +2153,6 @@ "react-transform-hmr": "1.0.4" } }, - "babel-preset-react-optimize": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-react-optimize/-/babel-preset-react-optimize-1.0.1.tgz", - "integrity": "sha1-wjUJ+6fLx2195wUOfSa80ivDBOg=", - "dev": true, - "requires": { - "babel-plugin-transform-react-constant-elements": "6.23.0", - "babel-plugin-transform-react-inline-elements": "6.22.0", - "babel-plugin-transform-react-pure-class-to-function": "1.0.1", - "babel-plugin-transform-react-remove-prop-types": "0.2.12" - }, - "dependencies": { - "babel-plugin-transform-react-remove-prop-types": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.2.12.tgz", - "integrity": "sha1-NAZpbfC4tFYIn51ybSfn4SPS+Sk=", - "dev": true - } - } - }, "babel-preset-stage-0": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-preset-stage-0/-/babel-preset-stage-0-6.24.1.tgz", @@ -12047,6 +12002,11 @@ "prop-types": "15.6.0" } }, + "react-native-actionsheet": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/react-native-actionsheet/-/react-native-actionsheet-2.3.0.tgz", + "integrity": "sha1-qVUqNW3Fk5gpBiNTgE1eVgno+Wk=" + }, "react-native-animatable": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/react-native-animatable/-/react-native-animatable-1.2.4.tgz", diff --git a/package.json b/package.json index a023642ab..eaf2cf1be 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "react-emojione": "^5.0.0", "react-native": "0.50.3", "react-native-action-button": "^2.8.1", + "react-native-actionsheet": "^2.3.0", "react-native-animatable": "^1.2.4", "react-native-card-view": "0.0.3", "react-native-easy-markdown": "git+https://github.com/lappalj4/react-native-easy-markdown.git",
Homebrew -Installer Script -RubyGems +HomebrewInstaller ScriptRubyGems
macOS