Several fixes for 1.2.1 (#448)

* Fix user.roles

* Better onLongPress handle on messages

* Indicator position

* Fix role undefined in system messages

* Add baseUrl in case of file attachments

* Join room fixed

* RoomView params

* Broadcast fixes

* Add server layout changes

* Use native images

* Subscribe to not joined channels

* Fix alerts without i18n

* Tests updated
This commit is contained in:
Diego Mello 2018-09-19 11:18:32 -03:00 committed by GitHub
parent c17c29546a
commit 5752b865b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
125 changed files with 3006 additions and 17507 deletions

View File

@ -0,0 +1,3 @@
export const RectButton = () => 'View';
export const State = () => 'View';
export const LongPressGestureHandler = () => 'View';

File diff suppressed because it is too large Load Diff

View File

@ -184,6 +184,8 @@ repositories {
} }
dependencies { dependencies {
implementation project(':react-native-device-info')
implementation project(':react-native-gesture-handler')
implementation project(':react-native-image-crop-picker') implementation project(':react-native-image-crop-picker')
implementation project(':react-native-i18n') implementation project(':react-native-i18n')
implementation project(':react-native-fabric') implementation project(':react-native-fabric')

View File

@ -25,6 +25,8 @@ import com.wix.reactnativenotifications.core.AppLifecycleFacade;
import com.wix.reactnativenotifications.core.JsIOHelper; import com.wix.reactnativenotifications.core.JsIOHelper;
import com.wix.reactnativenotifications.core.notification.INotificationsApplication; import com.wix.reactnativenotifications.core.notification.INotificationsApplication;
import com.wix.reactnativenotifications.core.notification.IPushNotification; import com.wix.reactnativenotifications.core.notification.IPushNotification;
import com.swmansion.gesturehandler.react.RNGestureHandlerPackage;
import com.learnium.RNDeviceInfo.RNDeviceInfo;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -57,6 +59,8 @@ public class MainApplication extends NavigationApplication implements INotificat
public List<ReactPackage> createAdditionalReactPackages() { public List<ReactPackage> createAdditionalReactPackages() {
return Arrays.<ReactPackage>asList( return Arrays.<ReactPackage>asList(
new MainReactPackage(), new MainReactPackage(),
new RNDeviceInfo(),
new RNGestureHandlerPackage(),
new PickerPackage(), new PickerPackage(),
new SvgPackage(), new SvgPackage(),
new VectorIconsPackage(), new VectorIconsPackage(),

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 979 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 487 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 635 B

View File

@ -1,4 +1,8 @@
rootProject.name = 'RocketChatRN' rootProject.name = 'RocketChatRN'
include ':react-native-device-info'
project(':react-native-device-info').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-device-info/android')
include ':react-native-gesture-handler'
project(':react-native-gesture-handler').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-gesture-handler/android')
include ':@remobile/react-native-toast' include ':@remobile/react-native-toast'
project(':@remobile/react-native-toast').projectDir = new File(rootProject.projectDir, '../node_modules/@remobile/react-native-toast/android') project(':@remobile/react-native-toast').projectDir = new File(rootProject.projectDir, '../node_modules/@remobile/react-native-toast/android')
include ':rn-fetch-blob' include ':rn-fetch-blob'

View File

@ -266,7 +266,7 @@ export default class MessageBox extends React.PureComponent {
await RocketChat.sendFileMessage(this.props.rid, fileInfo); await RocketChat.sendFileMessage(this.props.rid, fileInfo);
} catch (e) { } catch (e) {
if (e && e.error === 'error-file-too-large') { if (e && e.error === 'error-file-too-large') {
return Alert.alert('File is too large!'); return Alert.alert(I18n.t(e.error));
} }
log('finishAudioMessage', e); log('finishAudioMessage', e);
} }

View File

@ -1,9 +1,10 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { View, StyleSheet, TouchableOpacity, Text, Easing, Image } from 'react-native'; import { View, StyleSheet, Text, Easing, Image } from 'react-native';
import Video from 'react-native-video'; import Video from 'react-native-video';
import Slider from 'react-native-slider'; import Slider from 'react-native-slider';
import moment from 'moment'; import moment from 'moment';
import { BorderlessButton } from 'react-native-gesture-handler';
import Markdown from './Markdown'; import Markdown from './Markdown';
@ -116,7 +117,7 @@ export default class Audio extends React.PureComponent {
paused={paused} paused={paused}
repeat={false} repeat={false}
/> />
<TouchableOpacity <BorderlessButton
style={styles.playPauseButton} style={styles.playPauseButton}
onPress={() => this.togglePlayPause()} onPress={() => this.togglePlayPause()}
> >
@ -125,7 +126,7 @@ export default class Audio extends React.PureComponent {
<Image source={{ uri: 'play' }} style={styles.playPauseImage} /> : <Image source={{ uri: 'play' }} style={styles.playPauseImage} /> :
<Image source={{ uri: 'pause' }} style={styles.playPauseImage} /> <Image source={{ uri: 'pause' }} style={styles.playPauseImage} />
} }
</TouchableOpacity> </BorderlessButton>
<Slider <Slider
style={styles.slider} style={styles.slider}
value={this.state.currentTime} value={this.state.currentTime}

View File

@ -1,7 +1,7 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
import FastImage from 'react-native-fast-image'; import FastImage from 'react-native-fast-image';
import { TouchableOpacity } from 'react-native'; import { RectButton } from 'react-native-gesture-handler';
import PhotoModal from './PhotoModal'; import PhotoModal from './PhotoModal';
import Markdown from './Markdown'; import Markdown from './Markdown';
@ -20,6 +20,12 @@ export default class extends React.PureComponent {
state = { modalVisible: false }; state = { modalVisible: false };
onPressButton() {
this.setState({
modalVisible: true
});
}
getDescription() { getDescription() {
const { const {
file, customEmojis, baseUrl, user file, customEmojis, baseUrl, user
@ -29,13 +35,12 @@ export default class extends React.PureComponent {
} }
} }
_onPressButton() { isPressed = (state) => {
this.setState({ this.setState({ isPressed: state });
modalVisible: true
});
} }
render() { render() {
const { isPressed } = this.state;
const { baseUrl, file, user } = this.props; const { baseUrl, file, user } = this.props;
const img = `${ baseUrl }${ file.image_url }?rc_uid=${ user.id }&rc_token=${ user.token }`; const img = `${ baseUrl }${ file.image_url }?rc_uid=${ user.id }&rc_token=${ user.token }`;
@ -45,18 +50,20 @@ export default class extends React.PureComponent {
return ( return (
[ [
<TouchableOpacity <RectButton
key='image' key='image'
onPress={() => this._onPressButton()} onPress={() => this.onPressButton()}
onActiveStateChange={this.isPressed}
style={styles.imageContainer} style={styles.imageContainer}
underlayColor='#fff'
> >
<FastImage <FastImage
style={styles.image} style={[styles.image, isPressed && { opacity: 0.5 }]}
source={{ uri: encodeURI(img) }} source={{ uri: encodeURI(img) }}
resizeMode={FastImage.resizeMode.cover} resizeMode={FastImage.resizeMode.cover}
/> />
{this.getDescription()} {this.getDescription()}
</TouchableOpacity>, </RectButton>,
<PhotoModal <PhotoModal
key='modal' key='modal'
title={file.title} title={file.title}

View File

@ -52,17 +52,13 @@ export default class Markdown extends React.Component {
}; };
} }
return ( return (
<Text <Text style={mentionStyle} key={key}>
key={key}
onPress={() => alert(`Username ${ content }`)}
style={mentionStyle}
>
&nbsp;{content}&nbsp; &nbsp;{content}&nbsp;
</Text> </Text>
); );
}, },
hashtag: node => ( hashtag: node => (
<Text key={node.key} onPress={() => alert(`Room #${ node.content }`)} style={styles.mention}> <Text key={node.key} style={styles.mention}>
&nbsp;#{node.content}&nbsp; &nbsp;#{node.content}&nbsp;
</Text> </Text>
), ),

View File

@ -1,9 +1,10 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { View, Text, TouchableOpacity, ViewPropTypes, Image as ImageRN } from 'react-native'; import { View, Text, ViewPropTypes, Image as ImageRN } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons'; import Icon from 'react-native-vector-icons/MaterialIcons';
import moment from 'moment'; import moment from 'moment';
import { KeyboardUtils } from 'react-native-keyboard-input'; import { KeyboardUtils } from 'react-native-keyboard-input';
import { State, RectButton, LongPressGestureHandler } from 'react-native-gesture-handler';
import Image from './Image'; import Image from './Image';
import User from './User'; import User from './User';
@ -16,7 +17,6 @@ import Reply from './Reply';
import ReactionsModal from './ReactionsModal'; import ReactionsModal from './ReactionsModal';
import Emoji from './Emoji'; import Emoji from './Emoji';
import styles from './styles'; import styles from './styles';
import Touch from '../../utils/touch';
import I18n from '../../i18n'; import I18n from '../../i18n';
import messagesStatus from '../../constants/messagesStatus'; import messagesStatus from '../../constants/messagesStatus';
@ -247,15 +247,20 @@ export default class Message extends PureComponent {
renderReaction = (reaction) => { renderReaction = (reaction) => {
const reacted = reaction.usernames.findIndex(item => item.value === this.props.user.username) !== -1; const reacted = reaction.usernames.findIndex(item => item.value === this.props.user.username) !== -1;
const reactedContainerStyle = reacted && styles.reactedContainer; const underlayColor = reacted ? '#fff' : '#e1e5e8';
return ( return (
<TouchableOpacity <LongPressGestureHandler
onPress={() => this.props.onReactionPress(reaction.emoji)}
onLongPress={this.props.onReactionLongPress}
key={reaction.emoji} key={reaction.emoji}
testID={`message-reaction-${ reaction.emoji }`} onHandlerStateChange={({ nativeEvent }) => nativeEvent.state === State.ACTIVE && this.props.onReactionLongPress()}
> >
<View style={[styles.reactionContainer, reactedContainerStyle]}> <RectButton
onPress={() => this.props.onReactionPress(reaction.emoji)}
testID={`message-reaction-${ reaction.emoji }`}
style={[styles.reactionButton, reacted && { backgroundColor: '#e8f2ff' }]}
activeOpacity={0.8}
underlayColor={underlayColor}
>
<View style={[styles.reactionContainer, reacted && styles.reactedContainer]}>
<Emoji <Emoji
content={reaction.emoji} content={reaction.emoji}
customEmojis={this.props.customEmojis} customEmojis={this.props.customEmojis}
@ -265,7 +270,8 @@ export default class Message extends PureComponent {
/> />
<Text style={styles.reactionCount}>{ reaction.usernames.length }</Text> <Text style={styles.reactionCount}>{ reaction.usernames.length }</Text>
</View> </View>
</TouchableOpacity> </RectButton>
</LongPressGestureHandler>
); );
} }
@ -277,14 +283,18 @@ export default class Message extends PureComponent {
return ( return (
<View style={styles.reactionsContainer}> <View style={styles.reactionsContainer}>
{reactions.map(this.renderReaction)} {reactions.map(this.renderReaction)}
<TouchableOpacity <RectButton
onPress={this.props.toggleReactionPicker} onPress={this.props.toggleReactionPicker}
key='message-add-reaction' key='message-add-reaction'
testID='message-add-reaction' testID='message-add-reaction'
style={styles.reactionContainer} style={styles.reactionButton}
activeOpacity={0.8}
underlayColor='#e1e5e8'
> >
<View style={styles.reactionContainer}>
<ImageRN source={{ uri: 'add_reaction' }} style={styles.addReaction} /> <ImageRN source={{ uri: 'add_reaction' }} style={styles.addReaction} />
</TouchableOpacity> </View>
</RectButton>
</View> </View>
); );
} }
@ -292,15 +302,15 @@ export default class Message extends PureComponent {
renderBroadcastReply() { renderBroadcastReply() {
if (this.props.broadcast && !this.isOwn()) { if (this.props.broadcast && !this.isOwn()) {
return ( return (
<Touch <RectButton
onPress={this.props.replyBroadcast} onPress={this.props.replyBroadcast}
style={styles.broadcastButton} style={styles.broadcastButton}
activeOpacity={0.5}
underlayColor='#fff'
> >
<View style={styles.broadcastButtonContainer}>
<ImageRN source={{ uri: 'reply' }} style={styles.broadcastButtonIcon} /> <ImageRN source={{ uri: 'reply' }} style={styles.broadcastButtonIcon} />
<Text style={styles.broadcastButtonText}>Reply</Text> <Text style={styles.broadcastButtonText}>{I18n.t('Reply')}</Text>
</View> </RectButton>
</Touch>
); );
} }
return null; return null;
@ -313,14 +323,20 @@ export default class Message extends PureComponent {
const accessibilityLabel = I18n.t('Message_accessibility', { user: author.username, time: moment(ts).format(timeFormat), message: msg }); const accessibilityLabel = I18n.t('Message_accessibility', { user: author.username, time: moment(ts).format(timeFormat), message: msg });
return ( return (
<Touch <LongPressGestureHandler
onPress={this.onPress} onHandlerStateChange={({ nativeEvent }) => nativeEvent.state === State.ACTIVE && onLongPress()}
onLongPress={onLongPress} >
disabled={this.isInfoMessage() || this.hasError() || archived} <RectButton
accessibilityLabel={accessibilityLabel} enabled={!(this.isInfoMessage() || this.hasError() || archived)}
style={[styles.container, header && { marginBottom: 10 }]} style={[styles.container, header && { marginBottom: 10 }]}
onPress={this.onPress}
activeOpacity={0.8}
underlayColor='#e1e5e8'
>
<View
style={[styles.message, editing && styles.editing, style]}
accessibilityLabel={accessibilityLabel}
> >
<View style={[styles.message, editing && styles.editing, style]}>
<View style={styles.flex}> <View style={styles.flex}>
{this.renderError()} {this.renderError()}
{this.renderAvatar()} {this.renderAvatar()}
@ -345,7 +361,8 @@ export default class Message extends PureComponent {
: null : null
} }
</View> </View>
</Touch> </RectButton>
</LongPressGestureHandler>
); );
} }
} }

View File

@ -1,20 +0,0 @@
import React from 'react';
import { View, StyleSheet } from 'react-native';
import PropTypes from 'prop-types';
const styles = StyleSheet.create({
quoteSign: {
borderWidth: 2,
borderRadius: 4,
height: '100%',
marginRight: 5
}
});
const QuoteMark = ({ color }) => <View style={[styles.quoteSign, { borderColor: color || '#a0a0a0' }]} />;
QuoteMark.propTypes = {
color: PropTypes.string
};
export default QuoteMark;

View File

@ -2,10 +2,10 @@ import React from 'react';
import { View, Text, StyleSheet } from 'react-native'; import { View, Text, StyleSheet } from 'react-native';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import moment from 'moment'; import moment from 'moment';
import { RectButton } from 'react-native-gesture-handler';
import Markdown from './Markdown'; import Markdown from './Markdown';
import openLink from '../../utils/openLink'; import openLink from '../../utils/openLink';
import Touch from '../../utils/touch';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
button: { button: {
@ -13,13 +13,13 @@ const styles = StyleSheet.create({
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center', alignItems: 'center',
marginTop: 15, marginTop: 15,
alignSelf: 'flex-end' alignSelf: 'flex-end',
backgroundColor: '#f3f4f5'
}, },
attachmentContainer: { attachmentContainer: {
flex: 1, flex: 1,
borderRadius: 4, borderRadius: 4,
flexDirection: 'column', flexDirection: 'column',
backgroundColor: '#f3f4f5',
padding: 15 padding: 15
}, },
authorContainer: { authorContainer: {
@ -55,12 +55,15 @@ const styles = StyleSheet.create({
} }
}); });
const onPress = (attachment) => { const onPress = (attachment, baseUrl, user) => {
const url = attachment.title_link || attachment.author_link; let url = attachment.title_link || attachment.author_link;
if (!url) { if (!url) {
return; return;
} }
openLink(attachment.title_link || attachment.author_link); if (attachment.type === 'file') {
url = `${ baseUrl }${ url }?rc_uid=${ user.id }&rc_token=${ user.token }`;
}
openLink(url);
}; };
const Reply = ({ const Reply = ({
@ -91,9 +94,19 @@ const Reply = ({
); );
}; };
const renderText = () => ( const renderText = () => {
attachment.text ? <Markdown msg={attachment.text} customEmojis={customEmojis} baseUrl={baseUrl} username={user.username} /> : null const text = attachment.text || attachment.title;
if (text) {
return (
<Markdown
msg={text}
customEmojis={customEmojis}
baseUrl={baseUrl}
username={user.username}
/>
); );
}
};
const renderFields = () => { const renderFields = () => {
if (!attachment.fields) { if (!attachment.fields) {
@ -113,16 +126,18 @@ const Reply = ({
}; };
return ( return (
<Touch <RectButton
onPress={() => onPress(attachment)} onPress={() => onPress(attachment, baseUrl, user)}
style={[styles.button, index > 0 && styles.marginTop]} style={[styles.button, index > 0 && styles.marginTop]}
activeOpacity={0.5}
underlayColor='#fff'
> >
<View style={styles.attachmentContainer}> <View style={styles.attachmentContainer}>
{renderTitle()} {renderTitle()}
{renderText()} {renderText()}
{renderFields()} {renderFields()}
</View> </View>
</Touch> </RectButton>
); );
}; };

View File

@ -2,9 +2,9 @@ import React from 'react';
import { View, Text, StyleSheet } from 'react-native'; import { View, Text, StyleSheet } from 'react-native';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import FastImage from 'react-native-fast-image'; import FastImage from 'react-native-fast-image';
import { RectButton } from 'react-native-gesture-handler';
import openLink from '../../utils/openLink'; import openLink from '../../utils/openLink';
import Touch from '../../utils/touch';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
button: { button: {
@ -58,16 +58,19 @@ const Url = ({ url, index }) => {
return null; return null;
} }
return ( return (
<Touch onPress={() => onPress(url.url)} style={[styles.button, index > 0 && styles.marginTop]}> <RectButton
<View style={styles.container}> onPress={() => onPress(url.url)}
style={[styles.button, index > 0 && styles.marginTop, styles.container]}
activeOpacity={0.5}
underlayColor='#fff'
>
{url.image ? <FastImage source={{ uri: url.image }} style={styles.image} resizeMode={FastImage.resizeMode.cover} /> : null} {url.image ? <FastImage source={{ uri: url.image }} style={styles.image} resizeMode={FastImage.resizeMode.cover} /> : null}
<View style={styles.textContainer}> <View style={styles.textContainer}>
<Text style={styles.url} numberOfLines={1}>{url.url}</Text> <Text style={styles.url} numberOfLines={1}>{url.url}</Text>
<Text style={styles.title} numberOfLines={2}>{url.title}</Text> <Text style={styles.title} numberOfLines={2}>{url.title}</Text>
<Text style={styles.description} numberOfLines={2}>{url.description}</Text> <Text style={styles.description} numberOfLines={2}>{url.description}</Text>
</View> </View>
</View> </RectButton>
</Touch>
); );
}; };

View File

@ -36,8 +36,7 @@ export default class User extends React.PureComponent {
username: PropTypes.string, username: PropTypes.string,
alias: PropTypes.string, alias: PropTypes.string,
ts: PropTypes.instanceOf(Date), ts: PropTypes.instanceOf(Date),
temp: PropTypes.bool, temp: PropTypes.bool
onPress: PropTypes.func
} }
render() { render() {
@ -55,7 +54,7 @@ export default class User extends React.PureComponent {
return ( return (
<View style={styles.usernameView}> <View style={styles.usernameView}>
<Text onPress={this.props.onPress} style={styles.username}> <Text style={styles.username}>
{alias || username} {alias || username}
</Text> </Text>
{aliasUsername} {aliasUsername}

View File

@ -1,8 +1,10 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { StyleSheet, TouchableOpacity, Image, Platform, View } from 'react-native'; import { StyleSheet, Image, Platform, View } from 'react-native';
import Modal from 'react-native-modal'; import Modal from 'react-native-modal';
import VideoPlayer from 'react-native-video-controls'; import VideoPlayer from 'react-native-video-controls';
import { RectButton } from 'react-native-gesture-handler';
import Markdown from './Markdown'; import Markdown from './Markdown';
import openLink from '../../utils/openLink'; import openLink from '../../utils/openLink';
@ -70,15 +72,17 @@ export default class Video extends React.PureComponent {
return ( return (
[ [
<View key='button'> <View key='button'>
<TouchableOpacity <RectButton
style={styles.button} style={styles.button}
onPress={() => this.open()} onPress={() => this.open()}
activeOpacity={0.5}
underlayColor='#fff'
> >
<Image <Image
source={{ uri: 'play_video' }} source={{ uri: 'play_video' }}
style={styles.image} style={styles.image}
/> />
</TouchableOpacity> </RectButton>
<Markdown msg={description} customEmojis={customEmojis} baseUrl={baseUrl} username={user.username} /> <Markdown msg={description} customEmojis={customEmojis} baseUrl={baseUrl} username={user.username} />
</View>, </View>,
<Modal <Modal

View File

@ -146,7 +146,7 @@ export default class MessageContainer extends React.Component {
item, message, editing, user, style, archived, baseUrl, customEmojis, useRealName, broadcast item, message, editing, user, style, archived, baseUrl, customEmojis, useRealName, broadcast
} = this.props; } = this.props;
const { const {
msg, ts, attachments, urls, reactions, t, status, avatar, u, alias, editedBy msg, ts, attachments, urls, reactions, t, status, avatar, u, alias, editedBy, role
} = item; } = item;
const isEditing = message._id === item._id && editing; const isEditing = message._id === item._id && editing;
return ( return (
@ -173,6 +173,7 @@ export default class MessageContainer extends React.Component {
customEmojis={customEmojis} customEmojis={customEmojis}
reactionsModal={this.state.reactionsModal} reactionsModal={this.state.reactionsModal}
useRealName={useRealName} useRealName={useRealName}
role={role}
closeReactions={this.closeReactions} closeReactions={this.closeReactions}
onErrorPress={this.onErrorPress} onErrorPress={this.onErrorPress}
onLongPress={this.onLongPress} onLongPress={this.onLongPress}

View File

@ -51,6 +51,11 @@ export default StyleSheet.create({
flexWrap: 'wrap', flexWrap: 'wrap',
marginTop: 10 marginTop: 10
}, },
reactionButton: {
marginRight: 10,
marginBottom: 10,
borderRadius: 4
},
reactionContainer: { reactionContainer: {
flexDirection: 'row', flexDirection: 'row',
justifyContent: 'center', justifyContent: 'center',
@ -58,11 +63,11 @@ export default StyleSheet.create({
borderRadius: 4, borderRadius: 4,
borderWidth: 1.5, borderWidth: 1.5,
borderColor: '#e1e5e8', borderColor: '#e1e5e8',
marginRight: 10,
marginBottom: 10,
height: 28, height: 28,
minWidth: 46, minWidth: 46
backgroundColor: '#FFF' },
reactedContainer: {
borderColor: '#1d74f580'
}, },
reactionCount: { reactionCount: {
fontSize: 14, fontSize: 14,
@ -83,10 +88,6 @@ export default StyleSheet.create({
avatar: { avatar: {
marginTop: 5 marginTop: 5
}, },
reactedContainer: {
borderColor: '#1d74f580',
backgroundColor: '#e8f2ff'
},
addReaction: { addReaction: {
width: 17, width: 17,
height: 17 height: 17
@ -99,9 +100,7 @@ export default StyleSheet.create({
broadcastButton: { broadcastButton: {
width: 107, width: 107,
height: 44, height: 44,
marginTop: 15 marginTop: 15,
},
broadcastButtonContainer: {
flex: 1, flex: 1,
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center', alignItems: 'center',

View File

@ -142,6 +142,7 @@ export default {
Direct_Messages: 'Direct Messages', Direct_Messages: 'Direct Messages',
Do_you_really_want_to_key_this_room_question_mark: 'Do you really want to {{key}} this room?', Do_you_really_want_to_key_this_room_question_mark: 'Do you really want to {{key}} this room?',
edit: 'edit', edit: 'edit',
erasing_room: 'erasing room',
Edit: 'Edit', Edit: 'Edit',
Email_or_password_field_is_empty: 'Email or password field is empty', Email_or_password_field_is_empty: 'Email or password field is empty',
Email: 'Email', Email: 'Email',
@ -167,10 +168,12 @@ export default {
is_not_a_valid_RocketChat_instance: 'is not a valid Rocket.Chat instance', is_not_a_valid_RocketChat_instance: 'is not a valid Rocket.Chat instance',
is_typing: 'is typing', is_typing: 'is typing',
Join_the_community: 'Join the community', Join_the_community: 'Join the community',
Join: 'Join',
Just_invited_people_can_access_this_channel: 'Just invited people can access this channel', Just_invited_people_can_access_this_channel: 'Just invited people can access this channel',
Language: 'Language', Language: 'Language',
last_message: 'last message', last_message: 'last message',
Leave_channel: 'Leave channel', Leave_channel: 'Leave channel',
leaving_room: 'leaving room',
leave: 'leave', leave: 'leave',
Livechat: 'Livechat', Livechat: 'Livechat',
Login: 'Login', Login: 'Login',

View File

@ -6,7 +6,7 @@ import messagesStatus from '../../../constants/messagesStatus';
import log from '../../../utils/log'; import log from '../../../utils/log';
export default async function subscribeRooms(id) { export default async function subscribeRooms(id) {
const subscriptions = Promise.all([ const promises = Promise.all([
this.ddp.subscribe('stream-notify-user', `${ id }/subscriptions-changed`, false), this.ddp.subscribe('stream-notify-user', `${ id }/subscriptions-changed`, false),
this.ddp.subscribe('stream-notify-user', `${ id }/rooms-changed`, false), this.ddp.subscribe('stream-notify-user', `${ id }/rooms-changed`, false),
this.ddp.subscribe('stream-notify-user', `${ id }/message`, false) this.ddp.subscribe('stream-notify-user', `${ id }/message`, false)
@ -51,6 +51,18 @@ export default async function subscribeRooms(id) {
const [type, data] = ddpMessage.fields.args; const [type, data] = ddpMessage.fields.args;
const [, ev] = ddpMessage.fields.eventName.split('/'); const [, ev] = ddpMessage.fields.eventName.split('/');
if (/subscriptions/.test(ev)) { if (/subscriptions/.test(ev)) {
if (type === 'removed') {
let messages = [];
const [subscription] = database.objects('subscriptions').filtered('_id == $0', data._id);
if (subscription) {
messages = database.objects('messages').filtered('rid == $0', subscription.rid);
}
database.write(() => {
database.delete(messages);
database.delete(subscription);
});
} else {
const rooms = database.objects('rooms').filtered('_id == $0', data.rid); const rooms = database.objects('rooms').filtered('_id == $0', data.rid);
const tpm = merge(data, rooms[0]); const tpm = merge(data, rooms[0]);
database.write(() => { database.write(() => {
@ -58,6 +70,7 @@ export default async function subscribeRooms(id) {
database.delete(rooms); database.delete(rooms);
}); });
} }
}
if (/rooms/.test(ev)) { if (/rooms/.test(ev)) {
if (type === 'updated') { if (type === 'updated') {
const [sub] = database.objects('subscriptions').filtered('rid == $0', data._id); const [sub] = database.objects('subscriptions').filtered('rid == $0', data._id);
@ -93,9 +106,8 @@ export default async function subscribeRooms(id) {
} }
try { try {
await subscriptions; await promises;
} catch (e) { } catch (e) {
log('subscribeRooms', e); log('subscribeRooms', e);
} }
// console.log(this.ddp.subscriptions);
} }

View File

@ -470,9 +470,11 @@ const RocketChat = {
log('rocketchat.logout', e); log('rocketchat.logout', e);
} }
} }
// database.deleteAll();
AsyncStorage.removeItem(TOKEN_KEY); AsyncStorage.removeItem(TOKEN_KEY);
AsyncStorage.removeItem(`${ TOKEN_KEY }-${ server }`); AsyncStorage.removeItem(`${ TOKEN_KEY }-${ server }`);
setTimeout(() => {
database.deleteAll();
}, 1000);
}, },
registerPushToken(userId) { registerPushToken(userId) {
@ -750,7 +752,7 @@ const RocketChat = {
// transform room roles to array // transform room roles to array
const roomRoles = Array.from(Object.keys(roles), i => roles[i].value); const roomRoles = Array.from(Object.keys(roles), i => roles[i].value);
// get user roles on the server from redux // get user roles on the server from redux
const userRoles = reduxStore.getState().login.user.roles || []; const userRoles = (reduxStore.getState().login.user && reduxStore.getState().login.user.roles) || [];
// merge both roles // merge both roles
const mergedRoles = [...new Set([...roomRoles, ...userRoles])]; const mergedRoles = [...new Set([...roomRoles, ...userRoles])];

View File

@ -26,11 +26,7 @@ const handleRequest = function* handleRequest({ data }) {
screen: 'RoomView', screen: 'RoomView',
title: name, title: name,
backButtonTitle: '', backButtonTitle: '',
passProps: { passProps: { rid }
room: { rid, name },
rid,
name
}
}); });
} catch (err) { } catch (err) {
yield put(createChannelFailure(err)); yield put(createChannelFailure(err));

View File

@ -80,12 +80,9 @@ const goRoom = function* goRoom({ rid, name }) {
yield delay(1000); yield delay(1000);
NavigationActions.push({ NavigationActions.push({
screen: 'RoomView', screen: 'RoomView',
title: name,
backButtonTitle: '', backButtonTitle: '',
passProps: { passProps: { rid }
room: { rid, name },
rid,
name
}
}); });
}; };

View File

@ -10,6 +10,7 @@ import { messagesRequest, editCancel, replyCancel } from '../actions/messages';
import RocketChat from '../lib/rocketchat'; import RocketChat from '../lib/rocketchat';
import database from '../lib/realm'; import database from '../lib/realm';
import log from '../utils/log'; import log from '../utils/log';
import I18n from '../i18n';
import { NavigationActions } from '../Navigation'; import { NavigationActions } from '../Navigation';
const leaveRoom = rid => RocketChat.leaveRoom(rid); const leaveRoom = rid => RocketChat.leaveRoom(rid);
@ -63,41 +64,40 @@ const handleMessageReceived = function* handleMessageReceived({ message }) {
database.create('messages', message, true); database.create('messages', message, true);
}); });
if (room._id) {
RocketChat.readMessages(room.rid); RocketChat.readMessages(room.rid);
} }
}
} catch (e) { } catch (e) {
console.warn('handleMessageReceived', e); console.warn('handleMessageReceived', e);
} }
}; };
let opened = false;
const watchRoomOpen = function* watchRoomOpen({ room }) { const watchRoomOpen = function* watchRoomOpen({ room }) {
try { try {
yield put(messagesRequest({ ...room })); if (opened) {
// const { open } = yield race({ return;
// messages: take(types.MESSAGES.SUCCESS), }
// open: take(types.ROOM.OPEN) opened = true;
// });
//
// if (open) {
// return;
// }
yield put(messagesRequest({ ...room }));
if (room._id) {
RocketChat.readMessages(room.rid); RocketChat.readMessages(room.rid);
}
sub = yield RocketChat.subscribeRoom(room); 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 }); thread = yield fork(usersTyping, { rid: room.rid });
yield race({ yield race({
open: take(types.ROOM.OPEN), open: take(types.ROOM.OPEN),
close: take(types.ROOM.CLOSE) close: take(types.ROOM.CLOSE)
}); });
opened = false;
cancel(thread); cancel(thread);
sub.stop(); sub.stop();
yield put(editCancel()); yield put(editCancel());
yield put(replyCancel()); yield put(replyCancel());
// subscriptions.forEach((sub) => {
// sub.unsubscribe().catch(e => alert(e));
// });
} catch (e) { } catch (e) {
log('watchRoomOpen', e); log('watchRoomOpen', e);
} }
@ -161,9 +161,9 @@ const handleLeaveRoom = function* handleLeaveRoom({ rid }) {
yield goRoomsListAndDelete(rid); yield goRoomsListAndDelete(rid);
} catch (e) { } catch (e) {
if (e.error === 'error-you-are-last-owner') { if (e.error === 'error-you-are-last-owner') {
Alert.alert('You are the last owner. Please set new owner before leaving the room.'); Alert.alert(e.error);
} else { } else {
Alert.alert('Something happened when leaving room!'); Alert.alert(I18n.t('There_was_an_error_while_action', { action: I18n.t('leaving_room') }));
} }
} }
}; };
@ -174,7 +174,7 @@ const handleEraseRoom = function* handleEraseRoom({ rid }) {
yield call(eraseRoom, rid); yield call(eraseRoom, rid);
yield goRoomsListAndDelete(rid); yield goRoomsListAndDelete(rid);
} catch (e) { } catch (e) {
Alert.alert('Something happened when erasing room!'); Alert.alert(I18n.t('There_was_an_error_while_action', { action: I18n.t('erasing_room') }));
} }
}; };

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1021 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 527 B

7
app/utils/deviceInfo.js Normal file
View File

@ -0,0 +1,7 @@
import DeviceInfo from 'react-native-device-info';
export default {
isNotch: () => DeviceInfo.getModel() === 'iPhone X',
getBrand: () => DeviceInfo.getBrand(),
getReadableVersion: () => DeviceInfo.getReadableVersion()
};

View File

@ -37,8 +37,8 @@ const styles = StyleSheet.create({
fontWeight: '700' fontWeight: '700'
}, },
planetImage: { planetImage: {
width: 200, width: 210,
height: 162, height: 171,
marginVertical: 20 marginVertical: 20
} }
}); });
@ -283,10 +283,7 @@ export default class LoginSignupView extends LoggedView {
<View style={styles.container}> <View style={styles.container}>
<Text style={[sharedStyles.loginText, styles.header, { color: '#81848A' }]}>{I18n.t('Welcome_title_pt_1')}</Text> <Text style={[sharedStyles.loginText, styles.header, { color: '#81848A' }]}>{I18n.t('Welcome_title_pt_1')}</Text>
<Text style={[sharedStyles.loginText, styles.header]}>{I18n.t('Welcome_title_pt_2')}</Text> <Text style={[sharedStyles.loginText, styles.header]}>{I18n.t('Welcome_title_pt_2')}</Text>
<Image <Image style={styles.planetImage} source={{ uri: 'new_server' }} />
style={styles.planetImage}
source={require('../static/images/server.png')}
/>
<Button <Button
title={I18n.t('I_have_an_account')} title={I18n.t('I_have_an_account')}
type='primary' type='primary'

View File

@ -58,7 +58,7 @@ export default class LoginView extends LoggedView {
try { try {
await this.props.loginSubmit({ username, password, code }); await this.props.loginSubmit({ username, password, code });
Answers.logLogin('Email', true, { server: this.props.server }); Answers.logLogin('Email', true);
} catch (error) { } catch (error) {
console.warn('LoginView submit', error); console.warn('LoginView submit', error);
} }

View File

@ -1,9 +1,10 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Text, ScrollView, Keyboard, SafeAreaView, Image, Alert, StyleSheet } from 'react-native'; import { Text, ScrollView, Keyboard, SafeAreaView, Image, Alert, StyleSheet, TouchableOpacity } from 'react-native';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import Icon from 'react-native-vector-icons/Ionicons';
import { serverRequest, selectServerRequest, serverInitAdd, serverFinishAdd } from '../actions/server'; import { serverRequest } from '../actions/server';
import sharedStyles from './Styles'; import sharedStyles from './Styles';
import scrollPersistTaps from '../utils/scrollPersistTaps'; import scrollPersistTaps from '../utils/scrollPersistTaps';
import Button from '../containers/Button'; import Button from '../containers/Button';
@ -12,11 +13,14 @@ import LoggedView from './View';
import I18n from '../i18n'; import I18n from '../i18n';
import { scale, verticalScale, moderateScale } from '../utils/scaling'; import { scale, verticalScale, moderateScale } from '../utils/scaling';
import KeyboardView from '../presentation/KeyboardView'; import KeyboardView from '../presentation/KeyboardView';
import DeviceInfo from '../utils/deviceInfo';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
image: { image: {
alignSelf: 'center', alignSelf: 'center',
marginVertical: verticalScale(20) marginVertical: verticalScale(20),
width: 210,
height: 171
}, },
title: { title: {
alignSelf: 'center', alignSelf: 'center',
@ -36,6 +40,11 @@ const styles = StyleSheet.create({
paddingTop: 14, paddingTop: 14,
paddingBottom: 14, paddingBottom: 14,
paddingHorizontal: 16 paddingHorizontal: 16
},
backButton: {
position: 'absolute',
paddingHorizontal: 9,
left: 15
} }
}); });
@ -43,14 +52,9 @@ const defaultServer = 'https://open.rocket.chat';
@connect(state => ({ @connect(state => ({
connecting: state.server.connecting, connecting: state.server.connecting,
failure: state.server.failure, failure: state.server.failure
currentServer: state.server.server,
adding: state.server.adding
}), dispatch => ({ }), dispatch => ({
initAdd: () => dispatch(serverInitAdd()), connectServer: server => dispatch(serverRequest(server))
finishAdd: () => dispatch(serverFinishAdd()),
connectServer: server => dispatch(serverRequest(server)),
selectServer: server => dispatch(selectServerRequest(server))
})) }))
/** @extends React.Component */ /** @extends React.Component */
export default class NewServerView extends LoggedView { export default class NewServerView extends LoggedView {
@ -58,14 +62,8 @@ export default class NewServerView extends LoggedView {
navigator: PropTypes.object, navigator: PropTypes.object,
server: PropTypes.string, server: PropTypes.string,
connecting: PropTypes.bool.isRequired, connecting: PropTypes.bool.isRequired,
adding: PropTypes.bool,
failure: PropTypes.bool.isRequired, failure: PropTypes.bool.isRequired,
connectServer: PropTypes.func.isRequired, connectServer: PropTypes.func.isRequired
selectServer: PropTypes.func.isRequired,
previousServer: PropTypes.string,
currentServer: PropTypes.string,
initAdd: PropTypes.func,
finishAdd: PropTypes.func
} }
constructor(props) { constructor(props) {
@ -73,11 +71,10 @@ export default class NewServerView extends LoggedView {
this.state = { this.state = {
text: '' text: ''
}; };
props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
} }
componentDidMount() { componentDidMount() {
const { server, previousServer } = this.props; const { server } = this.props;
if (server) { if (server) {
this.props.connectServer(server); this.props.connectServer(server);
this.setState({ text: server }); this.setState({ text: server });
@ -86,9 +83,6 @@ export default class NewServerView extends LoggedView {
this.input.focus(); this.input.focus();
}, 600); }, 600);
} }
if (previousServer) {
this.props.initAdd();
}
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
@ -97,26 +91,6 @@ export default class NewServerView extends LoggedView {
} }
} }
componentWillUnmount() {
const {
selectServer, previousServer, currentServer, adding, finishAdd
} = this.props;
if (adding) {
if (previousServer !== currentServer) {
selectServer(previousServer);
}
finishAdd();
}
}
onNavigatorEvent(event) {
if (event.type === 'NavBarButtonPress') {
if (event.id === 'cancel') {
this.props.navigator.dismissModal();
}
}
}
onChangeText = (text) => { onChangeText = (text) => {
this.setState({ text }); this.setState({ text });
} }
@ -147,6 +121,26 @@ export default class NewServerView extends LoggedView {
return url.replace(/\/+$/, ''); return url.replace(/\/+$/, '');
} }
renderBack = () => {
let top = 15;
if (DeviceInfo.getBrand() === 'Apple') {
top = DeviceInfo.isNotch() ? 45 : 30;
}
return (
<TouchableOpacity
style={[styles.backButton, { top }]}
onPress={() => this.props.navigator.pop()}
>
<Icon
name='ios-arrow-back'
size={30}
color='#1D74F5'
/>
</TouchableOpacity>
);
}
render() { render() {
const { connecting } = this.props; const { connecting } = this.props;
const { text } = this.state; const { text } = this.state;
@ -158,7 +152,7 @@ export default class NewServerView extends LoggedView {
> >
<ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}> <ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}>
<SafeAreaView style={sharedStyles.container} testID='new-server-view'> <SafeAreaView style={sharedStyles.container} testID='new-server-view'>
<Image style={styles.image} source={require('../static/images/server.png')} /> <Image style={styles.image} source={{ uri: 'new_server' }} />
<Text style={styles.title}>{I18n.t('Sign_in_your_server')}</Text> <Text style={styles.title}>{I18n.t('Sign_in_your_server')}</Text>
<TextInput <TextInput
inputRef={e => this.input = e} inputRef={e => this.input = e}
@ -182,6 +176,7 @@ export default class NewServerView extends LoggedView {
/> />
</SafeAreaView> </SafeAreaView>
</ScrollView> </ScrollView>
{this.renderBack()}
</KeyboardView> </KeyboardView>
); );
} }

View File

@ -1,23 +1,64 @@
import React from 'react'; import React from 'react';
import { View, Text, Image, SafeAreaView } from 'react-native'; import { View, Text, Image, SafeAreaView, TouchableOpacity } from 'react-native';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Icon from 'react-native-vector-icons/MaterialIcons';
import { connect } from 'react-redux';
import { selectServerRequest, serverInitAdd, serverFinishAdd } from '../../actions/server';
import I18n from '../../i18n'; import I18n from '../../i18n';
import openLink from '../../utils/openLink'; import openLink from '../../utils/openLink';
import Button from './Button'; import Button from './Button';
import styles from './styles'; import styles from './styles';
import LoggedView from '../View'; import LoggedView from '../View';
import DeviceInfo from '../../utils/deviceInfo';
@connect(state => ({
currentServer: state.server.server,
adding: state.server.adding
}), dispatch => ({
initAdd: () => dispatch(serverInitAdd()),
finishAdd: () => dispatch(serverFinishAdd()),
selectServer: server => dispatch(selectServerRequest(server))
}))
/** @extends React.Component */ /** @extends React.Component */
export default class OnboardingView extends LoggedView { export default class OnboardingView extends LoggedView {
static propTypes = { static propTypes = {
navigator: PropTypes.object navigator: PropTypes.object,
previousServer: PropTypes.string,
adding: PropTypes.bool,
selectServer: PropTypes.func.isRequired,
currentServer: PropTypes.string,
initAdd: PropTypes.func,
finishAdd: PropTypes.func
} }
constructor(props) { constructor(props) {
super('CreateChannelView', props); super('CreateChannelView', props);
} }
componentDidMount() {
const { previousServer, initAdd } = this.props;
if (previousServer) {
initAdd();
}
}
componentWillUnmount() {
const {
selectServer, previousServer, currentServer, adding, finishAdd
} = this.props;
if (adding) {
if (previousServer !== currentServer) {
selectServer(previousServer);
}
finishAdd();
}
}
close = () => {
this.props.navigator.dismissModal();
}
connectServer = () => { connectServer = () => {
this.props.navigator.push({ this.props.navigator.push({
screen: 'NewServerView', screen: 'NewServerView',
@ -45,17 +86,39 @@ export default class OnboardingView extends LoggedView {
openLink('https://cloud.rocket.chat/trial'); openLink('https://cloud.rocket.chat/trial');
} }
renderClose = () => {
if (this.props.previousServer) {
let top = 15;
if (DeviceInfo.getBrand() === 'Apple') {
top = DeviceInfo.isNotch() ? 45 : 30;
}
return (
<TouchableOpacity
style={[styles.closeModal, { top }]}
onPress={this.close}
>
<Icon
name='close'
size={30}
color='#1D74F5'
/>
</TouchableOpacity>
);
}
return null;
}
render() { render() {
return ( return (
<SafeAreaView style={styles.container} testID='onboarding-view'> <SafeAreaView style={styles.container} testID='onboarding-view'>
<Image style={styles.onboarding} source={require('../../static/images/onboarding.png')} /> <Image style={styles.onboarding} source={{ uri: 'onboarding' }} />
<Text style={styles.title}>{I18n.t('Welcome_to_RocketChat')}</Text> <Text style={styles.title}>{I18n.t('Welcome_to_RocketChat')}</Text>
<Text style={styles.subtitle}>{I18n.t('Open_Source_Communication')}</Text> <Text style={styles.subtitle}>{I18n.t('Open_Source_Communication')}</Text>
<View style={styles.buttonsContainer}> <View style={styles.buttonsContainer}>
<Button <Button
type='secondary' type='secondary'
title={I18n.t('Connect_to_a_server')} title={I18n.t('Connect_to_a_server')}
icon={<Image source={require('../../static/images/connectServer.png')} />} icon={<Image source={{ uri: 'connect_server' }} style={{ width: 30, height: 30 }} />}
onPress={this.connectServer} onPress={this.connectServer}
testID='connect-server-button' testID='connect-server-button'
/> />
@ -63,18 +126,19 @@ export default class OnboardingView extends LoggedView {
type='secondary' type='secondary'
title={I18n.t('Join_the_community')} title={I18n.t('Join_the_community')}
subtitle='open.rocket.chat' subtitle='open.rocket.chat'
icon={<Image source={require('../../static/images/logoSmall.png')} />} icon={<Image source={{ uri: 'logo_onboarding' }} style={{ width: 32, height: 27 }} />}
onPress={this.joinCommunity} onPress={this.joinCommunity}
testID='join-community-button' testID='join-community-button'
/> />
<Button <Button
type='primary' type='primary'
title={I18n.t('Create_a_new_workspace')} title={I18n.t('Create_a_new_workspace')}
icon={<Image source={require('../../static/images/plusWhite.png')} />} icon={<Image source={{ uri: 'plus_onboarding' }} style={{ width: 24, height: 24 }} />}
onPress={this.createWorkspace} onPress={this.createWorkspace}
testID='create-workspace-button' testID='create-workspace-button'
/> />
</View> </View>
{this.renderClose()}
</SafeAreaView> </SafeAreaView>
); );
} }

View File

@ -25,7 +25,9 @@ export default StyleSheet.create({
marginTop: verticalScale(30), marginTop: verticalScale(30),
marginBottom: verticalScale(35), marginBottom: verticalScale(35),
maxHeight: verticalScale(250), maxHeight: verticalScale(250),
resizeMode: 'contain' resizeMode: 'contain',
width: 309,
height: 250
}, },
title: { title: {
alignSelf: 'center', alignSelf: 'center',
@ -96,5 +98,9 @@ export default StyleSheet.create({
}, },
button_text_secondary: { button_text_secondary: {
color: colors.textColorSecondary color: colors.textColorSecondary
},
closeModal: {
position: 'absolute',
left: 15
} }
}); });

View File

@ -2,6 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { FlatList, View, Vibration, SafeAreaView } from 'react-native'; import { FlatList, View, Vibration, SafeAreaView } from 'react-native';
import ActionSheet from 'react-native-actionsheet'; import ActionSheet from 'react-native-actionsheet';
import { connect } from 'react-redux';
import LoggedView from '../View'; import LoggedView from '../View';
import styles from './styles'; import styles from './styles';
@ -14,6 +15,9 @@ import log from '../../utils/log';
import I18n from '../../i18n'; import I18n from '../../i18n';
import SearchBox from '../../containers/SearchBox'; import SearchBox from '../../containers/SearchBox';
@connect(state => ({
baseUrl: state.settings.Site_Url || state.server ? state.server.server : ''
}))
/** @extends React.Component */ /** @extends React.Component */
export default class RoomMembersView extends LoggedView { export default class RoomMembersView extends LoggedView {
static navigatorButtons = { static navigatorButtons = {
@ -27,7 +31,8 @@ export default class RoomMembersView extends LoggedView {
static propTypes = { static propTypes = {
navigator: PropTypes.object, navigator: PropTypes.object,
rid: PropTypes.string, rid: PropTypes.string,
members: PropTypes.array members: PropTypes.array,
baseUrl: PropTypes.string
} }
constructor(props) { constructor(props) {
@ -134,11 +139,7 @@ export default class RoomMembersView extends LoggedView {
screen: 'RoomView', screen: 'RoomView',
title: name, title: name,
backButtonTitle: '', backButtonTitle: '',
passProps: { passProps: { rid }
room: { rid, name },
rid,
name
}
}); });
}, 1000); }, 1000);
} }
@ -175,6 +176,7 @@ export default class RoomMembersView extends LoggedView {
username={item.username} username={item.username}
onPress={() => this.onPressUser(item)} onPress={() => this.onPressUser(item)}
onLongPress={() => this.onLongPressUser(item)} onLongPress={() => this.onLongPressUser(item)}
baseUrl={this.props.baseUrl}
testID={`room-members-view-item-${ item.username }`} testID={`room-members-view-item-${ item.username }`}
/> />
) )

View File

@ -171,7 +171,7 @@ export class ListView extends OldList2 {
onKeyboardDidHide: undefined onKeyboardDidHide: undefined
}); });
const image = data.length === 0 ? require('../../static/images/message_empty.png') : null; const image = data.length === 0 ? { uri: 'message_empty' } : null;
return ( return (
[ [
<ImageBackground key='listview-background' source={image} style={styles.imageBackground} />, <ImageBackground key='listview-background' source={image} style={styles.imageBackground} />,

View File

@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import { Text, View, LayoutAnimation, ActivityIndicator, SafeAreaView } from 'react-native'; import { Text, View, LayoutAnimation, ActivityIndicator, SafeAreaView } from 'react-native';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import equal from 'deep-equal'; import equal from 'deep-equal';
import { RectButton } from 'react-native-gesture-handler';
import LoggedView from '../View'; import LoggedView from '../View';
import { List } from './ListView'; import { List } from './ListView';
@ -60,11 +61,11 @@ export default class RoomView extends LoggedView {
constructor(props) { constructor(props) {
super('RoomView', props); super('RoomView', props);
this.rid = props.rid; this.rid = this.props.rid;
this.rooms = database.objects('subscriptions').filtered('rid = $0', this.rid); this.rooms = database.objects('subscriptions').filtered('rid = $0', this.rid);
this.state = { this.state = {
loaded: false, loaded: false,
joined: typeof props.rid === 'undefined', joined: this.rooms.length > 0,
room: {}, room: {},
end: false end: false
}; };
@ -95,6 +96,7 @@ export default class RoomView extends LoggedView {
}); });
this.setState({ loaded: true }); this.setState({ loaded: true });
} }
shouldComponentUpdate(nextProps, nextState) { shouldComponentUpdate(nextProps, nextState) {
return !(equal(this.props, nextProps) && equal(this.state, nextState) && this.state.room.ro === nextState.room.ro); return !(equal(this.props, nextProps) && equal(this.state, nextState) && this.state.room.ro === nextState.room.ro);
} }
@ -191,6 +193,9 @@ export default class RoomView extends LoggedView {
this.props.setLastOpen(null); this.props.setLastOpen(null);
} }
} }
} else {
this.props.openRoom({ rid: this.rid });
this.setState({ joined: false });
} }
} }
@ -204,9 +209,7 @@ export default class RoomView extends LoggedView {
joinRoom = async() => { joinRoom = async() => {
try { try {
await RocketChat.joinRoom(this.props.rid); await RocketChat.joinRoom(this.props.rid);
this.setState({ this.setState({ joined: true });
joined: true
});
} catch (e) { } catch (e) {
log('joinRoom', e); log('joinRoom', e);
} }
@ -245,15 +248,21 @@ export default class RoomView extends LoggedView {
); );
renderFooter = () => { renderFooter = () => {
// TODO: fix it if (!this.state.joined) {
// if (!this.state.joined) { return (
// return ( <View style={styles.joinRoomContainer} key='room-view-join'>
// <View> <Text style={styles.previewMode}>{I18n.t('You_are_in_preview_mode')}</Text>
// <Text>{I18n.t('You_are_in_preview_mode')}</Text> <RectButton
// <Button title='Join' onPress={this.joinRoom} /> onPress={this.joinRoom}
// </View> style={styles.joinRoomButton}
// ); activeOpacity={0.5}
// } underlayColor='#fff'
>
<Text style={styles.joinRoomText}>{I18n.t('Join')}</Text>
</RectButton>
</View>
);
}
if (this.state.room.archived || this.isReadOnly()) { if (this.state.room.archived || this.isReadOnly()) {
return ( return (
<View style={styles.readOnly}> <View style={styles.readOnly}>

View File

@ -53,5 +53,30 @@ export default StyleSheet.create({
width: '100%', width: '100%',
height: '100%', height: '100%',
position: 'absolute' position: 'absolute'
},
joinRoomContainer: {
justifyContent: 'flex-end',
alignItems: 'center',
marginVertical: 15
},
joinRoomButton: {
width: 107,
height: 44,
marginTop: 15,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#1d74f5',
borderRadius: 4
},
joinRoomText: {
color: '#fff',
fontSize: 14,
fontWeight: '500'
},
previewMode: {
fontSize: 16,
fontWeight: '500',
color: '#0C0D0F'
} }
}); });

View File

@ -23,12 +23,13 @@ const styles = StyleSheet.create({
}, },
disclosure: { disclosure: {
marginLeft: 3, marginLeft: 3,
marginTop: 2, marginTop: 1,
width: 12, width: 12,
height: 9 height: 9
}, },
upsideDown: { upsideDown: {
transform: [{ scaleY: -1 }] transform: [{ scaleY: -1 }],
marginTop: 4
} }
}); });

View File

@ -82,17 +82,13 @@ export default class ServerDropdown extends Component {
this.close(); this.close();
setTimeout(() => { setTimeout(() => {
this.props.navigator.showModal({ this.props.navigator.showModal({
screen: 'NewServerView', screen: 'OnboardingView',
title: I18n.t('Add_Server'),
passProps: { passProps: {
previousServer: this.props.server previousServer: this.props.server
}, },
navigatorButtons: { navigatorStyle: {
leftButtons: [{ navBarHidden: true,
id: 'cancel', orientation: 'portrait'
testID: 'new-server-close',
title: I18n.t('Close')
}]
} }
}); });
}, ANIMATION_DURATION); }, ANIMATION_DURATION);

View File

@ -327,11 +327,7 @@ export default class RoomsListView extends LoggedView {
screen: 'RoomView', screen: 'RoomView',
title: name, title: name,
backButtonTitle: '', backButtonTitle: '',
passProps: { passProps: { rid }
room: { rid, name },
rid,
name
}
}); });
this.cancelSearchingAndroid(); this.cancelSearchingAndroid();
} }

View File

@ -118,7 +118,8 @@ export default StyleSheet.create({
color: isIOS() ? '#1D74F5' : '#FFF', color: isIOS() ? '#1D74F5' : '#FFF',
fontSize: 15, fontSize: 15,
fontWeight: 'normal', fontWeight: 'normal',
marginRight: 15 marginRight: 15,
paddingVertical: 10
}, },
serverItem: { serverItem: {
height: 68 height: 68

View File

@ -1,5 +1,6 @@
import { Navigation } from 'react-native-navigation'; import { Navigation } from 'react-native-navigation';
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
import { gestureHandlerRootHOC } from 'react-native-gesture-handler';
import CreateChannelView from './CreateChannelView'; import CreateChannelView from './CreateChannelView';
import ForgotPasswordView from './ForgotPasswordView'; import ForgotPasswordView from './ForgotPasswordView';
@ -36,29 +37,29 @@ export const registerScreens = (store) => {
Navigation.registerComponent('ForgotPasswordView', () => ForgotPasswordView, store, Provider); Navigation.registerComponent('ForgotPasswordView', () => ForgotPasswordView, store, Provider);
Navigation.registerComponent('LoginSignupView', () => LoginSignupView, store, Provider); Navigation.registerComponent('LoginSignupView', () => LoginSignupView, store, Provider);
Navigation.registerComponent('LoginView', () => LoginView, store, Provider); Navigation.registerComponent('LoginView', () => LoginView, store, Provider);
Navigation.registerComponent('MentionedMessagesView', () => MentionedMessagesView, store, Provider); Navigation.registerComponent('MentionedMessagesView', () => gestureHandlerRootHOC(MentionedMessagesView), store, Provider);
Navigation.registerComponent('NewMessageView', () => NewMessageView, store, Provider); Navigation.registerComponent('NewMessageView', () => NewMessageView, store, Provider);
Navigation.registerComponent('NewServerView', () => NewServerView, store, Provider); Navigation.registerComponent('NewServerView', () => NewServerView, store, Provider);
Navigation.registerComponent('OAuthView', () => OAuthView, store, Provider); Navigation.registerComponent('OAuthView', () => OAuthView, store, Provider);
Navigation.registerComponent('OnboardingView', () => OnboardingView, store, Provider); Navigation.registerComponent('OnboardingView', () => OnboardingView, store, Provider);
Navigation.registerComponent('PinnedMessagesView', () => PinnedMessagesView, store, Provider); Navigation.registerComponent('PinnedMessagesView', () => gestureHandlerRootHOC(PinnedMessagesView), store, Provider);
Navigation.registerComponent('PrivacyPolicyView', () => PrivacyPolicyView, store, Provider); Navigation.registerComponent('PrivacyPolicyView', () => PrivacyPolicyView, store, Provider);
Navigation.registerComponent('ProfileView', () => ProfileView, store, Provider); Navigation.registerComponent('ProfileView', () => ProfileView, store, Provider);
Navigation.registerComponent('RegisterView', () => RegisterView, store, Provider); Navigation.registerComponent('RegisterView', () => RegisterView, store, Provider);
Navigation.registerComponent('RoomActionsView', () => RoomActionsView, store, Provider); Navigation.registerComponent('RoomActionsView', () => RoomActionsView, store, Provider);
Navigation.registerComponent('RoomFilesView', () => RoomFilesView, store, Provider); Navigation.registerComponent('RoomFilesView', () => gestureHandlerRootHOC(RoomFilesView), store, Provider);
Navigation.registerComponent('RoomInfoEditView', () => RoomInfoEditView, store, Provider); Navigation.registerComponent('RoomInfoEditView', () => RoomInfoEditView, store, Provider);
Navigation.registerComponent('RoomInfoView', () => RoomInfoView, store, Provider); Navigation.registerComponent('RoomInfoView', () => RoomInfoView, store, Provider);
Navigation.registerComponent('RoomMembersView', () => RoomMembersView, store, Provider); Navigation.registerComponent('RoomMembersView', () => RoomMembersView, store, Provider);
Navigation.registerComponent('RoomsListHeaderView', () => RoomsListHeaderView, store, Provider); Navigation.registerComponent('RoomsListHeaderView', () => RoomsListHeaderView, store, Provider);
Navigation.registerComponent('RoomsListSearchView', () => RoomsListSearchView, store, Provider); Navigation.registerComponent('RoomsListSearchView', () => RoomsListSearchView, store, Provider);
Navigation.registerComponent('RoomsListView', () => RoomsListView, store, Provider); Navigation.registerComponent('RoomsListView', () => gestureHandlerRootHOC(RoomsListView), store, Provider);
Navigation.registerComponent('RoomView', () => RoomView, store, Provider); Navigation.registerComponent('RoomView', () => gestureHandlerRootHOC(RoomView), store, Provider);
Navigation.registerComponent('SearchMessagesView', () => SearchMessagesView, store, Provider); Navigation.registerComponent('SearchMessagesView', () => gestureHandlerRootHOC(SearchMessagesView), store, Provider);
Navigation.registerComponent('SelectedUsersView', () => SelectedUsersView, store, Provider); Navigation.registerComponent('SelectedUsersView', () => SelectedUsersView, store, Provider);
Navigation.registerComponent('SettingsView', () => SettingsView, store, Provider); Navigation.registerComponent('SettingsView', () => SettingsView, store, Provider);
Navigation.registerComponent('Sidebar', () => Sidebar, store, Provider); Navigation.registerComponent('Sidebar', () => Sidebar, store, Provider);
Navigation.registerComponent('SnippetedMessagesView', () => SnippetedMessagesView, store, Provider); Navigation.registerComponent('SnippetedMessagesView', () => gestureHandlerRootHOC(SnippetedMessagesView), store, Provider);
Navigation.registerComponent('StarredMessagesView', () => StarredMessagesView, store, Provider); Navigation.registerComponent('StarredMessagesView', () => gestureHandlerRootHOC(StarredMessagesView), store, Provider);
Navigation.registerComponent('TermsServiceView', () => TermsServiceView, store, Provider); Navigation.registerComponent('TermsServiceView', () => TermsServiceView, store, Provider);
}; };

View File

@ -24,6 +24,8 @@ target 'RocketChatRN' do
] ]
pod 'RNImageCropPicker', :path => '../node_modules/react-native-image-crop-picker' pod 'RNImageCropPicker', :path => '../node_modules/react-native-image-crop-picker'
pod 'RNDeviceInfo', :path => '../node_modules/react-native-device-info'
end end
post_install do |installer| post_install do |installer|

View File

@ -1,5 +1,7 @@
PODS: PODS:
- QBImagePickerController (3.4.0) - QBImagePickerController (3.4.0)
- React (0.56.0):
- React/Core (= 0.56.0)
- React/Core (0.56.0): - React/Core (0.56.0):
- yoga (= 0.56.0.React) - yoga (= 0.56.0.React)
- React/fishhook (0.56.0) - React/fishhook (0.56.0)
@ -28,11 +30,13 @@ PODS:
- React/Core - React/Core
- React/fishhook - React/fishhook
- React/RCTBlob - React/RCTBlob
- RNImageCropPicker (0.20.3): - RNDeviceInfo (0.21.5):
- React
- RNImageCropPicker (0.21.1):
- QBImagePickerController - QBImagePickerController
- React/Core - React/Core
- RSKImageCropper - RSKImageCropper
- RSKImageCropper (2.0.0) - RSKImageCropper (2.1.0)
- yoga (0.56.0.React) - yoga (0.56.0.React)
DEPENDENCIES: DEPENDENCIES:
@ -47,12 +51,15 @@ DEPENDENCIES:
- React/RCTText (from `../node_modules/react-native`) - React/RCTText (from `../node_modules/react-native`)
- React/RCTVibration (from `../node_modules/react-native`) - React/RCTVibration (from `../node_modules/react-native`)
- React/RCTWebSocket (from `../node_modules/react-native`) - React/RCTWebSocket (from `../node_modules/react-native`)
- RNDeviceInfo (from `../node_modules/react-native-device-info`)
- RNImageCropPicker (from `../node_modules/react-native-image-crop-picker`) - RNImageCropPicker (from `../node_modules/react-native-image-crop-picker`)
- yoga (from `../node_modules/react-native/ReactCommon/yoga/yoga.podspec`) - yoga (from `../node_modules/react-native/ReactCommon/yoga/yoga.podspec`)
EXTERNAL SOURCES: EXTERNAL SOURCES:
React: React:
:path: ../node_modules/react-native :path: ../node_modules/react-native
RNDeviceInfo:
:path: ../node_modules/react-native-device-info
RNImageCropPicker: RNImageCropPicker:
:path: ../node_modules/react-native-image-crop-picker :path: ../node_modules/react-native-image-crop-picker
yoga: yoga:
@ -61,10 +68,11 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS: SPEC CHECKSUMS:
QBImagePickerController: d54cf93db6decf26baf6ed3472f336ef35cae022 QBImagePickerController: d54cf93db6decf26baf6ed3472f336ef35cae022
React: 1fe0eb13d90b625d94c3b117c274dcfd2e760e11 React: 1fe0eb13d90b625d94c3b117c274dcfd2e760e11
RNDeviceInfo: 568c5641057313b4912d08a7742ff0b2f753ed5c
RNImageCropPicker: 32ca4b9fef4e1b7b85ba69494242122948117e06 RNImageCropPicker: 32ca4b9fef4e1b7b85ba69494242122948117e06
RSKImageCropper: d9a1acbc0600bf8decc8f0d21895872c99a9e4cf RSKImageCropper: 0d0c6d8525a2381f03fde32a47c6703817a2feed
yoga: b1ce48b6cf950b98deae82838f5173ea7cf89e85 yoga: b1ce48b6cf950b98deae82838f5173ea7cf89e85
PODFILE CHECKSUM: 61f93deba99bd7e36384c5bceba5b92c6b96009e PODFILE CHECKSUM: da5e520837501713de2c32adbff219ab7fc5c0fa
COCOAPODS: 1.4.0 COCOAPODS: 1.4.0

View File

@ -0,0 +1 @@
../../../../../node_modules/react-native-device-info/ios/RNDeviceInfo/DeviceUID.h

View File

@ -0,0 +1 @@
../../../../../node_modules/react-native-device-info/ios/RNDeviceInfo/RNDeviceInfo.h

View File

@ -0,0 +1 @@
../../../../../node_modules/react-native-device-info/ios/RNDeviceInfo/DeviceUID.h

View File

@ -0,0 +1 @@
../../../../../node_modules/react-native-device-info/ios/RNDeviceInfo/RNDeviceInfo.h

View File

@ -0,0 +1,23 @@
{
"name": "RNDeviceInfo",
"version": "0.21.5",
"summary": "Device Information for react-native",
"homepage": "https://github.com/rebeccahughes/react-native-device-info",
"license": "MIT",
"authors": {
"Rebecca Hughes": "rebecca@learnium.net"
},
"platforms": {
"ios": "8.0",
"tvos": "10.0"
},
"source": {
"git": "https://github.com/rebeccahughes/react-native-device-info.git"
},
"source_files": "ios/RNDeviceInfo/*.{h,m}",
"dependencies": {
"React": [
]
}
}

View File

@ -1,6 +1,6 @@
{ {
"name": "RNImageCropPicker", "name": "RNImageCropPicker",
"version": "0.20.3", "version": "0.21.1",
"summary": "Select single or multiple images, with cropping option", "summary": "Select single or multiple images, with cropping option",
"requires_arc": true, "requires_arc": true,
"license": "MIT", "license": "MIT",

16
ios/Pods/Manifest.lock generated
View File

@ -1,5 +1,7 @@
PODS: PODS:
- QBImagePickerController (3.4.0) - QBImagePickerController (3.4.0)
- React (0.56.0):
- React/Core (= 0.56.0)
- React/Core (0.56.0): - React/Core (0.56.0):
- yoga (= 0.56.0.React) - yoga (= 0.56.0.React)
- React/fishhook (0.56.0) - React/fishhook (0.56.0)
@ -28,11 +30,13 @@ PODS:
- React/Core - React/Core
- React/fishhook - React/fishhook
- React/RCTBlob - React/RCTBlob
- RNImageCropPicker (0.20.3): - RNDeviceInfo (0.21.5):
- React
- RNImageCropPicker (0.21.1):
- QBImagePickerController - QBImagePickerController
- React/Core - React/Core
- RSKImageCropper - RSKImageCropper
- RSKImageCropper (2.0.0) - RSKImageCropper (2.1.0)
- yoga (0.56.0.React) - yoga (0.56.0.React)
DEPENDENCIES: DEPENDENCIES:
@ -47,12 +51,15 @@ DEPENDENCIES:
- React/RCTText (from `../node_modules/react-native`) - React/RCTText (from `../node_modules/react-native`)
- React/RCTVibration (from `../node_modules/react-native`) - React/RCTVibration (from `../node_modules/react-native`)
- React/RCTWebSocket (from `../node_modules/react-native`) - React/RCTWebSocket (from `../node_modules/react-native`)
- RNDeviceInfo (from `../node_modules/react-native-device-info`)
- RNImageCropPicker (from `../node_modules/react-native-image-crop-picker`) - RNImageCropPicker (from `../node_modules/react-native-image-crop-picker`)
- yoga (from `../node_modules/react-native/ReactCommon/yoga/yoga.podspec`) - yoga (from `../node_modules/react-native/ReactCommon/yoga/yoga.podspec`)
EXTERNAL SOURCES: EXTERNAL SOURCES:
React: React:
:path: ../node_modules/react-native :path: ../node_modules/react-native
RNDeviceInfo:
:path: ../node_modules/react-native-device-info
RNImageCropPicker: RNImageCropPicker:
:path: ../node_modules/react-native-image-crop-picker :path: ../node_modules/react-native-image-crop-picker
yoga: yoga:
@ -61,10 +68,11 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS: SPEC CHECKSUMS:
QBImagePickerController: d54cf93db6decf26baf6ed3472f336ef35cae022 QBImagePickerController: d54cf93db6decf26baf6ed3472f336ef35cae022
React: 1fe0eb13d90b625d94c3b117c274dcfd2e760e11 React: 1fe0eb13d90b625d94c3b117c274dcfd2e760e11
RNDeviceInfo: 568c5641057313b4912d08a7742ff0b2f753ed5c
RNImageCropPicker: 32ca4b9fef4e1b7b85ba69494242122948117e06 RNImageCropPicker: 32ca4b9fef4e1b7b85ba69494242122948117e06
RSKImageCropper: d9a1acbc0600bf8decc8f0d21895872c99a9e4cf RSKImageCropper: 0d0c6d8525a2381f03fde32a47c6703817a2feed
yoga: b1ce48b6cf950b98deae82838f5173ea7cf89e85 yoga: b1ce48b6cf950b98deae82838f5173ea7cf89e85
PODFILE CHECKSUM: 61f93deba99bd7e36384c5bceba5b92c6b96009e PODFILE CHECKSUM: da5e520837501713de2c32adbff219ab7fc5c0fa
COCOAPODS: 1.4.0 COCOAPODS: 1.4.0

File diff suppressed because it is too large Load Diff

View File

@ -99,16 +99,27 @@ Then implement the data source functions.
// Returns a custom rect for the mask. // Returns a custom rect for the mask.
- (CGRect)imageCropViewControllerCustomMaskRect:(RSKImageCropViewController *)controller - (CGRect)imageCropViewControllerCustomMaskRect:(RSKImageCropViewController *)controller
{ {
CGSize maskSize; CGSize aspectRatio = CGSizeMake(16.0f, 9.0f);
if ([controller isPortraitInterfaceOrientation]) {
maskSize = CGSizeMake(250, 250);
} else {
maskSize = CGSizeMake(220, 220);
}
CGFloat viewWidth = CGRectGetWidth(controller.view.frame); CGFloat viewWidth = CGRectGetWidth(controller.view.frame);
CGFloat viewHeight = CGRectGetHeight(controller.view.frame); CGFloat viewHeight = CGRectGetHeight(controller.view.frame);
CGFloat maskWidth;
if ([controller isPortraitInterfaceOrientation]) {
maskWidth = viewWidth;
} else {
maskWidth = viewHeight;
}
CGFloat maskHeight;
do {
maskHeight = maskWidth * aspectRatio.height / aspectRatio.width;
maskWidth -= 1.0f;
} while (maskHeight != floor(maskHeight));
maskWidth += 1.0f;
CGSize maskSize = CGSizeMake(maskWidth, maskHeight);
CGRect maskRect = CGRectMake((viewWidth - maskSize.width) * 0.5f, CGRect maskRect = CGRectMake((viewWidth - maskSize.width) * 0.5f,
(viewHeight - maskSize.height) * 0.5f, (viewHeight - maskSize.height) * 0.5f,
maskSize.width, maskSize.width,
@ -123,23 +134,42 @@ Then implement the data source functions.
CGRect rect = controller.maskRect; CGRect rect = controller.maskRect;
CGPoint point1 = CGPointMake(CGRectGetMinX(rect), CGRectGetMaxY(rect)); CGPoint point1 = CGPointMake(CGRectGetMinX(rect), CGRectGetMaxY(rect));
CGPoint point2 = CGPointMake(CGRectGetMaxX(rect), CGRectGetMaxY(rect)); CGPoint point2 = CGPointMake(CGRectGetMaxX(rect), CGRectGetMaxY(rect));
CGPoint point3 = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect)); CGPoint point3 = CGPointMake(CGRectGetMaxX(rect), CGRectGetMinY(rect));
CGPoint point4 = CGPointMake(CGRectGetMinX(rect), CGRectGetMinY(rect));
UIBezierPath *triangle = [UIBezierPath bezierPath]; UIBezierPath *rectangle = [UIBezierPath bezierPath];
[triangle moveToPoint:point1]; [rectangle moveToPoint:point1];
[triangle addLineToPoint:point2]; [rectangle addLineToPoint:point2];
[triangle addLineToPoint:point3]; [rectangle addLineToPoint:point3];
[triangle closePath]; [rectangle addLineToPoint:point4];
[rectangle closePath];
return triangle; return rectangle;
} }
// Returns a custom rect in which the image can be moved. // Returns a custom rect in which the image can be moved.
- (CGRect)imageCropViewControllerCustomMovementRect:(RSKImageCropViewController *)controller - (CGRect)imageCropViewControllerCustomMovementRect:(RSKImageCropViewController *)controller
{ {
// If the image is not rotated, then the movement rect coincides with the mask rect, if (controller.rotationAngle == 0) {
// otherwise it is calculated individually for each custom mask.
return controller.maskRect; return controller.maskRect;
} else {
CGRect maskRect = controller.maskRect;
CGFloat rotationAngle = controller.rotationAngle;
CGRect movementRect = CGRectZero;
movementRect.size.width = CGRectGetWidth(maskRect) * fabs(cos(rotationAngle)) + CGRectGetHeight(maskRect) * fabs(sin(rotationAngle));
movementRect.size.height = CGRectGetHeight(maskRect) * fabs(cos(rotationAngle)) + CGRectGetWidth(maskRect) * fabs(sin(rotationAngle));
movementRect.origin.x = CGRectGetMinX(maskRect) + (CGRectGetWidth(maskRect) - CGRectGetWidth(movementRect)) * 0.5f;
movementRect.origin.y = CGRectGetMinY(maskRect) + (CGRectGetHeight(maskRect) - CGRectGetHeight(movementRect)) * 0.5f;
movementRect.origin.x = floor(CGRectGetMinX(movementRect));
movementRect.origin.y = floor(CGRectGetMinY(movementRect));
movementRect = CGRectIntegral(movementRect);
return movementRect;
}
} }
``` ```

View File

@ -81,6 +81,9 @@ CG_EXTERN const CGPoint RSKPointNull;
// Returns the exact center point of the given rectangle. // Returns the exact center point of the given rectangle.
CGPoint RSKRectCenterPoint(CGRect rect); CGPoint RSKRectCenterPoint(CGRect rect);
// Returns the `rect` with normalized values.
CGRect RSKRectNormalize(CGRect rect);
// Returns the `rect` scaled around the `point` by `sx` and `sy`. // Returns the `rect` scaled around the `point` by `sx` and `sy`.
CGRect RSKRectScaleAroundPoint(CGRect rect, CGPoint point, CGFloat sx, CGFloat sy); CGRect RSKRectScaleAroundPoint(CGRect rect, CGPoint point, CGFloat sx, CGFloat sy);

View File

@ -24,6 +24,13 @@
#import "CGGeometry+RSKImageCropper.h" #import "CGGeometry+RSKImageCropper.h"
// K is a constant such that the accumulated error of our floating-point computations is definitely bounded by K units in the last place.
#ifdef CGFLOAT_IS_DOUBLE
static const CGFloat kK = 9;
#else
static const CGFloat kK = 0;
#endif
const CGPoint RSKPointNull = { INFINITY, INFINITY }; const CGPoint RSKPointNull = { INFINITY, INFINITY };
CGPoint RSKRectCenterPoint(CGRect rect) CGPoint RSKRectCenterPoint(CGRect rect)
@ -32,6 +39,45 @@ CGPoint RSKRectCenterPoint(CGRect rect)
CGRectGetMinY(rect) + CGRectGetHeight(rect) / 2); CGRectGetMinY(rect) + CGRectGetHeight(rect) / 2);
} }
CGRect RSKRectNormalize(CGRect rect)
{
CGPoint origin = rect.origin;
CGFloat x = origin.x;
CGFloat y = origin.y;
CGFloat ceilX = ceil(x);
CGFloat ceilY = ceil(y);
if (fabs(ceilX - x) < pow(10, kK) * RSK_EPSILON * fabs(ceilX + x) || fabs(ceilX - x) < RSK_MIN ||
fabs(ceilY - y) < pow(10, kK) * RSK_EPSILON * fabs(ceilY + y) || fabs(ceilY - y) < RSK_MIN) {
origin.x = ceilX;
origin.y = ceilY;
} else {
origin.x = floor(x);
origin.y = floor(y);
}
CGSize size = rect.size;
CGFloat width = size.width;
CGFloat height = size.height;
CGFloat ceilWidth = ceil(width);
CGFloat ceilHeight = ceil(height);
if (fabs(ceilWidth - width) < pow(10, kK) * RSK_EPSILON * fabs(ceilWidth + width) || fabs(ceilWidth - width) < RSK_MIN ||
fabs(ceilHeight - height) < pow(10, kK) * RSK_EPSILON * fabs(ceilHeight + height) || fabs(ceilHeight - height) < RSK_MIN) {
size.width = ceilWidth;
size.height = ceilHeight;
} else {
size.width = floor(width);
size.height = floor(height);
}
return CGRectMake(origin.x, origin.y, size.width, size.height);
}
CGRect RSKRectScaleAroundPoint(CGRect rect, CGPoint point, CGFloat sx, CGFloat sy) CGRect RSKRectScaleAroundPoint(CGRect rect, CGPoint point, CGFloat sx, CGFloat sy)
{ {
CGAffineTransform translationTransform, scaleTransform; CGAffineTransform translationTransform, scaleTransform;

View File

@ -55,6 +55,14 @@ typedef NS_ENUM(NSUInteger, RSKImageCropMode) {
*/ */
- (instancetype)initWithImage:(UIImage *)originalImage cropMode:(RSKImageCropMode)cropMode; - (instancetype)initWithImage:(UIImage *)originalImage cropMode:(RSKImageCropMode)cropMode;
/**
Zooms to a specific area of the image so that it is visible.
@param rect A rectangle defining an area of the image.
@param animated YES if the scrolling should be animated, NO if it should be immediate.
*/
- (void)zoomToRect:(CGRect)rect animated:(BOOL)animated;
///----------------------------- ///-----------------------------
/// @name Accessing the Delegate /// @name Accessing the Delegate
///----------------------------- ///-----------------------------
@ -329,6 +337,11 @@ typedef NS_ENUM(NSUInteger, RSKImageCropMode) {
@optional @optional
/**
Tells the delegate that the image has been displayed.
*/
- (void)imageCropViewControllerDidDisplayImage:(RSKImageCropViewController *)controller;
/** /**
Tells the delegate that the original image will be cropped. Tells the delegate that the original image will be cropped.
*/ */

View File

@ -33,13 +33,6 @@
static const CGFloat kResetAnimationDuration = 0.4; static const CGFloat kResetAnimationDuration = 0.4;
static const CGFloat kLayoutImageScrollViewAnimationDuration = 0.25; static const CGFloat kLayoutImageScrollViewAnimationDuration = 0.25;
// K is a constant such that the accumulated error of our floating-point computations is definitely bounded by K units in the last place.
#ifdef CGFLOAT_IS_DOUBLE
static const CGFloat kK = 9;
#else
static const CGFloat kK = 0;
#endif
@interface RSKImageCropViewController () <UIGestureRecognizerDelegate> @interface RSKImageCropViewController () <UIGestureRecognizerDelegate>
@property (assign, nonatomic) BOOL originalNavigationControllerNavigationBarHidden; @property (assign, nonatomic) BOOL originalNavigationControllerNavigationBarHidden;
@ -57,6 +50,8 @@ static const CGFloat kLayoutImageScrollViewAnimationDuration = 0.25;
@property (readonly, nonatomic) CGRect rectForMaskPath; @property (readonly, nonatomic) CGRect rectForMaskPath;
@property (readonly, nonatomic) CGRect rectForClipPath; @property (readonly, nonatomic) CGRect rectForClipPath;
@property (readonly, nonatomic) CGRect imageRect;
@property (strong, nonatomic) UILabel *moveAndScaleLabel; @property (strong, nonatomic) UILabel *moveAndScaleLabel;
@property (strong, nonatomic) UIButton *cancelButton; @property (strong, nonatomic) UIButton *cancelButton;
@property (strong, nonatomic) UIButton *chooseButton; @property (strong, nonatomic) UIButton *chooseButton;
@ -136,7 +131,16 @@ static const CGFloat kLayoutImageScrollViewAnimationDuration = 0.25;
[super viewDidLoad]; [super viewDidLoad];
if ([self respondsToSelector:@selector(edgesForExtendedLayout)]) { if ([self respondsToSelector:@selector(edgesForExtendedLayout)]) {
self.edgesForExtendedLayout = UIRectEdgeNone; self.edgesForExtendedLayout = UIRectEdgeNone;
}
if (@available(iOS 11.0, *)) {
self.imageScrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
else if ([self respondsToSelector:@selector(automaticallyAdjustsScrollViewInsets)] == YES) {
self.automaticallyAdjustsScrollViewInsets = NO; self.automaticallyAdjustsScrollViewInsets = NO;
} }
@ -157,11 +161,15 @@ static const CGFloat kLayoutImageScrollViewAnimationDuration = 0.25;
{ {
[super viewWillAppear:animated]; [super viewWillAppear:animated];
if ([self respondsToSelector:@selector(prefersStatusBarHidden)] == NO) {
UIApplication *application = [UIApplication rsk_sharedApplication]; UIApplication *application = [UIApplication rsk_sharedApplication];
if (application) { if (application) {
self.originalStatusBarHidden = application.statusBarHidden; self.originalStatusBarHidden = application.statusBarHidden;
[application setStatusBarHidden:YES]; [application setStatusBarHidden:YES];
} }
}
self.originalNavigationControllerNavigationBarHidden = self.navigationController.navigationBarHidden; self.originalNavigationControllerNavigationBarHidden = self.navigationController.navigationBarHidden;
[self.navigationController setNavigationBarHidden:YES animated:NO]; [self.navigationController setNavigationBarHidden:YES animated:NO];
@ -182,10 +190,14 @@ static const CGFloat kLayoutImageScrollViewAnimationDuration = 0.25;
{ {
[super viewWillDisappear:animated]; [super viewWillDisappear:animated];
if ([self respondsToSelector:@selector(prefersStatusBarHidden)] == NO) {
UIApplication *application = [UIApplication rsk_sharedApplication]; UIApplication *application = [UIApplication rsk_sharedApplication];
if (application) { if (application) {
[application setStatusBarHidden:self.originalStatusBarHidden]; [application setStatusBarHidden:self.originalStatusBarHidden];
} }
}
[self.navigationController setNavigationBarHidden:self.originalNavigationControllerNavigationBarHidden animated:animated]; [self.navigationController setNavigationBarHidden:self.originalNavigationControllerNavigationBarHidden animated:animated];
self.navigationController.navigationBar.shadowImage = self.originalNavigationControllerNavigationBarShadowImage; self.navigationController.navigationBar.shadowImage = self.originalNavigationControllerNavigationBarShadowImage;
@ -385,31 +397,96 @@ static const CGFloat kLayoutImageScrollViewAnimationDuration = 0.25;
return _rotationGestureRecognizer; return _rotationGestureRecognizer;
} }
- (CGRect)cropRect - (CGRect)imageRect
{ {
CGRect cropRect = CGRectZero;
float zoomScale = 1.0 / self.imageScrollView.zoomScale; float zoomScale = 1.0 / self.imageScrollView.zoomScale;
cropRect.origin.x = floor(self.imageScrollView.contentOffset.x * zoomScale); CGRect imageRect = CGRectZero;
cropRect.origin.y = floor(self.imageScrollView.contentOffset.y * zoomScale);
cropRect.size.width = CGRectGetWidth(self.imageScrollView.bounds) * zoomScale;
cropRect.size.height = CGRectGetHeight(self.imageScrollView.bounds) * zoomScale;
CGFloat width = CGRectGetWidth(cropRect); imageRect.origin.x = self.imageScrollView.contentOffset.x * zoomScale;
CGFloat height = CGRectGetHeight(cropRect); imageRect.origin.y = self.imageScrollView.contentOffset.y * zoomScale;
CGFloat ceilWidth = ceil(width); imageRect.size.width = CGRectGetWidth(self.imageScrollView.bounds) * zoomScale;
CGFloat ceilHeight = ceil(height); imageRect.size.height = CGRectGetHeight(self.imageScrollView.bounds) * zoomScale;
if (fabs(ceilWidth - width) < pow(10, kK) * RSK_EPSILON * fabs(ceilWidth + width) || fabs(ceilWidth - width) < RSK_MIN || imageRect = RSKRectNormalize(imageRect);
fabs(ceilHeight - height) < pow(10, kK) * RSK_EPSILON * fabs(ceilHeight + height) || fabs(ceilHeight - height) < RSK_MIN) {
cropRect.size.width = ceilWidth; CGSize imageSize = self.originalImage.size;
cropRect.size.height = ceilHeight; CGFloat x = CGRectGetMinX(imageRect);
} else { CGFloat y = CGRectGetMinY(imageRect);
cropRect.size.width = floor(width); CGFloat width = CGRectGetWidth(imageRect);
cropRect.size.height = floor(height); CGFloat height = CGRectGetHeight(imageRect);
UIImageOrientation imageOrientation = self.originalImage.imageOrientation;
if (imageOrientation == UIImageOrientationRight || imageOrientation == UIImageOrientationRightMirrored) {
imageRect.origin.x = y;
imageRect.origin.y = floor(imageSize.width - CGRectGetWidth(imageRect) - x);
imageRect.size.width = height;
imageRect.size.height = width;
} else if (imageOrientation == UIImageOrientationLeft || imageOrientation == UIImageOrientationLeftMirrored) {
imageRect.origin.x = floor(imageSize.height - CGRectGetHeight(imageRect) - y);
imageRect.origin.y = x;
imageRect.size.width = height;
imageRect.size.height = width;
} else if (imageOrientation == UIImageOrientationDown || imageOrientation == UIImageOrientationDownMirrored) {
imageRect.origin.x = floor(imageSize.width - CGRectGetWidth(imageRect) - x);
imageRect.origin.y = floor(imageSize.height - CGRectGetHeight(imageRect) - y);
} }
CGFloat imageScale = self.originalImage.scale;
imageRect = CGRectApplyAffineTransform(imageRect, CGAffineTransformMakeScale(imageScale, imageScale));
return imageRect;
}
- (CGRect)cropRect
{
CGRect maskRect = self.maskRect;
CGFloat rotationAngle = self.rotationAngle;
CGRect rotatedImageScrollViewFrame = self.imageScrollView.frame;
float zoomScale = 1.0 / self.imageScrollView.zoomScale;
CGAffineTransform imageScrollViewTransform = self.imageScrollView.transform;
self.imageScrollView.transform = CGAffineTransformIdentity;
CGRect imageScrollViewFrame = self.imageScrollView.frame;
self.imageScrollView.frame = self.maskRect;
CGRect imageFrame = CGRectZero;
imageFrame.origin.x = CGRectGetMinX(maskRect) - self.imageScrollView.contentOffset.x;
imageFrame.origin.y = CGRectGetMinY(maskRect) - self.imageScrollView.contentOffset.y;
imageFrame.size = self.imageScrollView.contentSize;
CGFloat tx = CGRectGetMinX(imageFrame) + self.imageScrollView.contentOffset.x + CGRectGetWidth(maskRect) * 0.5f;
CGFloat ty = CGRectGetMinY(imageFrame) + self.imageScrollView.contentOffset.y + CGRectGetHeight(maskRect) * 0.5f;
CGFloat sx = CGRectGetWidth(rotatedImageScrollViewFrame) / CGRectGetWidth(imageScrollViewFrame);
CGFloat sy = CGRectGetHeight(rotatedImageScrollViewFrame) / CGRectGetHeight(imageScrollViewFrame);
CGAffineTransform t1 = CGAffineTransformMakeTranslation(-tx, -ty);
CGAffineTransform t2 = CGAffineTransformMakeRotation(rotationAngle);
CGAffineTransform t3 = CGAffineTransformMakeScale(sx, sy);
CGAffineTransform t4 = CGAffineTransformMakeTranslation(tx, ty);
CGAffineTransform t1t2 = CGAffineTransformConcat(t1, t2);
CGAffineTransform t1t2t3 = CGAffineTransformConcat(t1t2, t3);
CGAffineTransform t1t2t3t4 = CGAffineTransformConcat(t1t2t3, t4);
imageFrame = CGRectApplyAffineTransform(imageFrame, t1t2t3t4);
CGRect cropRect = CGRectMake(0.0, 0.0, CGRectGetWidth(maskRect), CGRectGetHeight(maskRect));
cropRect.origin.x = -CGRectGetMinX(imageFrame) + CGRectGetMinX(maskRect);
cropRect.origin.y = -CGRectGetMinY(imageFrame) + CGRectGetMinY(maskRect);
cropRect = CGRectApplyAffineTransform(cropRect, CGAffineTransformMakeScale(zoomScale, zoomScale));
cropRect = RSKRectNormalize(cropRect);
CGFloat imageScale = self.originalImage.scale;
cropRect = CGRectApplyAffineTransform(cropRect, CGAffineTransformMakeScale(imageScale, imageScale));
self.imageScrollView.frame = imageScrollViewFrame;
self.imageScrollView.transform = imageScrollViewTransform;
return cropRect; return cropRect;
} }
@ -567,6 +644,11 @@ static const CGFloat kLayoutImageScrollViewAnimationDuration = 0.25;
} }
} }
- (void)zoomToRect:(CGRect)rect animated:(BOOL)animated
{
[self.imageScrollView zoomToRect:rect animated:animated];
}
#pragma mark - Public #pragma mark - Public
- (BOOL)isPortraitInterfaceOrientation - (BOOL)isPortraitInterfaceOrientation
@ -677,6 +759,10 @@ static const CGFloat kLayoutImageScrollViewAnimationDuration = 0.25;
if (self.originalImage) { if (self.originalImage) {
[self.imageScrollView displayImage:self.originalImage]; [self.imageScrollView displayImage:self.originalImage];
[self reset:NO]; [self reset:NO];
if ([self.delegate respondsToSelector:@selector(imageCropViewControllerDidDisplayImage:)]) {
[self.delegate imageCropViewControllerDidDisplayImage:self];
}
} }
} }
@ -832,106 +918,79 @@ static const CGFloat kLayoutImageScrollViewAnimationDuration = 0.25;
} }
} }
- (UIImage *)croppedImage:(UIImage *)image cropRect:(CGRect)cropRect scale:(CGFloat)imageScale orientation:(UIImageOrientation)imageOrientation - (UIImage *)imageWithImage:(UIImage *)image inRect:(CGRect)rect scale:(CGFloat)scale imageOrientation:(UIImageOrientation)imageOrientation
{ {
if (!image.images) { if (!image.images) {
CGImageRef croppedCGImage = CGImageCreateWithImageInRect(image.CGImage, cropRect); CGImageRef cgImage = CGImageCreateWithImageInRect(image.CGImage, rect);
UIImage *croppedImage = [UIImage imageWithCGImage:croppedCGImage scale:imageScale orientation:imageOrientation]; UIImage *image = [UIImage imageWithCGImage:cgImage scale:scale orientation:imageOrientation];
CGImageRelease(croppedCGImage); CGImageRelease(cgImage);
return croppedImage; return image;
} else { } else {
UIImage *animatedImage = image; UIImage *animatedImage = image;
NSMutableArray *croppedImages = [NSMutableArray array]; NSMutableArray *images = [NSMutableArray array];
for (UIImage *image in animatedImage.images) { for (UIImage *animatedImageImage in animatedImage.images) {
UIImage *croppedImage = [self croppedImage:image cropRect:cropRect scale:imageScale orientation:imageOrientation]; UIImage *image = [self imageWithImage:animatedImageImage inRect:rect scale:scale imageOrientation:imageOrientation];
[croppedImages addObject:croppedImage]; [images addObject:image];
} }
return [UIImage animatedImageWithImages:croppedImages duration:image.duration]; return [UIImage animatedImageWithImages:images duration:image.duration];
} }
} }
- (UIImage *)croppedImage:(UIImage *)image cropMode:(RSKImageCropMode)cropMode cropRect:(CGRect)cropRect rotationAngle:(CGFloat)rotationAngle zoomScale:(CGFloat)zoomScale maskPath:(UIBezierPath *)maskPath applyMaskToCroppedImage:(BOOL)applyMaskToCroppedImage - (UIImage *)croppedImage:(UIImage *)originalImage cropMode:(RSKImageCropMode)cropMode cropRect:(CGRect)cropRect imageRect:(CGRect)imageRect rotationAngle:(CGFloat)rotationAngle zoomScale:(CGFloat)zoomScale maskPath:(UIBezierPath *)maskPath applyMaskToCroppedImage:(BOOL)applyMaskToCroppedImage
{ {
// Step 1: check and correct the crop rect. // Step 1: create an image using the data contained within the specified rect.
CGSize imageSize = image.size; UIImage *image = [self imageWithImage:originalImage inRect:imageRect scale:originalImage.scale imageOrientation:originalImage.imageOrientation];
CGFloat x = CGRectGetMinX(cropRect);
CGFloat y = CGRectGetMinY(cropRect);
CGFloat width = CGRectGetWidth(cropRect);
CGFloat height = CGRectGetHeight(cropRect);
UIImageOrientation imageOrientation = image.imageOrientation; // Step 2: fix orientation of the image.
if (imageOrientation == UIImageOrientationRight || imageOrientation == UIImageOrientationRightMirrored) { image = [image fixOrientation];
cropRect.origin.x = y;
cropRect.origin.y = floor(imageSize.width - CGRectGetWidth(cropRect) - x);
cropRect.size.width = height;
cropRect.size.height = width;
} else if (imageOrientation == UIImageOrientationLeft || imageOrientation == UIImageOrientationLeftMirrored) {
cropRect.origin.x = floor(imageSize.height - CGRectGetHeight(cropRect) - y);
cropRect.origin.y = x;
cropRect.size.width = height;
cropRect.size.height = width;
} else if (imageOrientation == UIImageOrientationDown || imageOrientation == UIImageOrientationDownMirrored) {
cropRect.origin.x = floor(imageSize.width - CGRectGetWidth(cropRect) - x);
cropRect.origin.y = floor(imageSize.height - CGRectGetHeight(cropRect) - y);
}
CGFloat imageScale = image.scale; // Step 3: If current mode is `RSKImageCropModeSquare` and the original image is not rotated
cropRect = CGRectApplyAffineTransform(cropRect, CGAffineTransformMakeScale(imageScale, imageScale)); // or mask should not be applied to the image after cropping and the original image is not rotated,
// we can return the image immediately.
// Step 2: create an image using the data contained within the specified rect.
UIImage *croppedImage = [self croppedImage:image cropRect:cropRect scale:imageScale orientation:imageOrientation];
// Step 3: fix orientation of the cropped image.
croppedImage = [croppedImage fixOrientation];
imageOrientation = croppedImage.imageOrientation;
// Step 4: If current mode is `RSKImageCropModeSquare` and the image is not rotated
// or mask should not be applied to the image after cropping and the image is not rotated,
// we can return the cropped image immediately.
// Otherwise, we must further process the image. // Otherwise, we must further process the image.
if ((cropMode == RSKImageCropModeSquare || !applyMaskToCroppedImage) && rotationAngle == 0.0) { if ((cropMode == RSKImageCropModeSquare || !applyMaskToCroppedImage) && rotationAngle == 0.0) {
// Step 5: return the cropped image immediately. // Step 4: return the image immediately.
return croppedImage; return image;
} else { } else {
// Step 5: create a new context. // Step 4: create a new context.
CGSize contextSize = cropRect.size; CGSize contextSize = cropRect.size;
UIGraphicsBeginImageContextWithOptions(contextSize, NO, imageScale); UIGraphicsBeginImageContextWithOptions(contextSize, NO, originalImage.scale);
// Step 6: apply the mask if needed. // Step 5: apply the mask if needed.
if (applyMaskToCroppedImage) { if (applyMaskToCroppedImage) {
// 6a: scale the mask to the size of the crop rect. // 5a: scale the mask to the size of the crop rect.
UIBezierPath *maskPathCopy = [maskPath copy]; UIBezierPath *maskPathCopy = [maskPath copy];
CGFloat scale = 1.0 / zoomScale; CGFloat scale = 1.0 / zoomScale;
[maskPathCopy applyTransform:CGAffineTransformMakeScale(scale, scale)]; [maskPathCopy applyTransform:CGAffineTransformMakeScale(scale, scale)];
// 6b: move the mask to the top-left. // 5b: move the mask to the top-left.
CGPoint translation = CGPointMake(-CGRectGetMinX(maskPathCopy.bounds), CGPoint translation = CGPointMake(-CGRectGetMinX(maskPathCopy.bounds),
-CGRectGetMinY(maskPathCopy.bounds)); -CGRectGetMinY(maskPathCopy.bounds));
[maskPathCopy applyTransform:CGAffineTransformMakeTranslation(translation.x, translation.y)]; [maskPathCopy applyTransform:CGAffineTransformMakeTranslation(translation.x, translation.y)];
// 6c: apply the mask. // 5c: apply the mask.
[maskPathCopy addClip]; [maskPathCopy addClip];
} }
// Step 7: rotate the cropped image if needed. // Step 6: rotate the image if needed.
if (rotationAngle != 0) { if (rotationAngle != 0) {
croppedImage = [croppedImage rotateByAngle:rotationAngle]; image = [image rotateByAngle:rotationAngle];
} }
// Step 8: draw the cropped image. // Step 7: draw the image.
CGPoint point = CGPointMake(floor((contextSize.width - croppedImage.size.width) * 0.5f), CGPoint point = CGPointMake(floor((contextSize.width - image.size.width) * 0.5f),
floor((contextSize.height - croppedImage.size.height) * 0.5f)); floor((contextSize.height - image.size.height) * 0.5f));
[croppedImage drawAtPoint:point]; [image drawAtPoint:point];
// Step 9: get the cropped image affter processing from the context. // Step 8: get the cropped image affter processing from the context.
croppedImage = UIGraphicsGetImageFromCurrentImageContext(); UIImage *croppedImage = UIGraphicsGetImageFromCurrentImageContext();
// Step 10: remove the context. // Step 9: remove the context.
UIGraphicsEndImageContext(); UIGraphicsEndImageContext();
croppedImage = [UIImage imageWithCGImage:croppedImage.CGImage scale:imageScale orientation:imageOrientation]; croppedImage = [UIImage imageWithCGImage:croppedImage.CGImage scale:originalImage.scale orientation:image.imageOrientation];
// Step 11: return the cropped image affter processing. // Step 10: return the cropped image affter processing.
return croppedImage; return croppedImage;
} }
} }
@ -945,6 +1004,7 @@ static const CGFloat kLayoutImageScrollViewAnimationDuration = 0.25;
UIImage *originalImage = self.originalImage; UIImage *originalImage = self.originalImage;
RSKImageCropMode cropMode = self.cropMode; RSKImageCropMode cropMode = self.cropMode;
CGRect cropRect = self.cropRect; CGRect cropRect = self.cropRect;
CGRect imageRect = self.imageRect;
CGFloat rotationAngle = self.rotationAngle; CGFloat rotationAngle = self.rotationAngle;
CGFloat zoomScale = self.imageScrollView.zoomScale; CGFloat zoomScale = self.imageScrollView.zoomScale;
UIBezierPath *maskPath = self.maskPath; UIBezierPath *maskPath = self.maskPath;
@ -952,7 +1012,7 @@ static const CGFloat kLayoutImageScrollViewAnimationDuration = 0.25;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UIImage *croppedImage = [self croppedImage:originalImage cropMode:cropMode cropRect:cropRect rotationAngle:rotationAngle zoomScale:zoomScale maskPath:maskPath applyMaskToCroppedImage:applyMaskToCroppedImage]; UIImage *croppedImage = [self croppedImage:originalImage cropMode:cropMode cropRect:cropRect imageRect:imageRect rotationAngle:rotationAngle zoomScale:zoomScale maskPath:maskPath applyMaskToCroppedImage:applyMaskToCroppedImage];
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate imageCropViewController:self didCropImage:croppedImage usingCropRect:cropRect rotationAngle:rotationAngle]; [self.delegate imageCropViewController:self didCropImage:croppedImage usingCropRect:cropRect rotationAngle:rotationAngle];

View File

@ -1,9 +1,25 @@
// //
// RSKInternalUtility.h // RSKInternalUtility.h
// RSKImageCropperExample
// //
// Created by Ruslan Skorb on 9/5/15. // Copyright (c) 2015-present Ruslan Skorb, http://ruslanskorb.com/
// Copyright (c) 2015 Ruslan Skorb. All rights reserved. //
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>

View File

@ -1,9 +1,25 @@
// //
// RSKInternalUtility.m // RSKInternalUtility.m
// RSKImageCropperExample
// //
// Created by Ruslan Skorb on 9/5/15. // Copyright (c) 2015-present Ruslan Skorb, http://ruslanskorb.com/
// Copyright (c) 2015 Ruslan Skorb. All rights reserved. //
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// //
#import "RSKInternalUtility.h" #import "RSKInternalUtility.h"

View File

@ -12,6 +12,31 @@ The above copyright notice and this permission notice shall be included in all c
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
## RNDeviceInfo
The MIT License (MIT)
Copyright (c) 2015 Rebecca Hughes
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
## RNImageCropPicker ## RNImageCropPicker
MIT License MIT License

View File

@ -29,6 +29,37 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
<key>Type</key> <key>Type</key>
<string>PSGroupSpecifier</string> <string>PSGroupSpecifier</string>
</dict> </dict>
<dict>
<key>FooterText</key>
<string>The MIT License (MIT)
Copyright (c) 2015 Rebecca Hughes
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
</string>
<key>License</key>
<string>MIT</string>
<key>Title</key>
<string>RNDeviceInfo</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict> <dict>
<key>FooterText</key> <key>FooterText</key>
<string>MIT License <string>MIT License

View File

@ -1,8 +1,8 @@
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/QBImagePickerController" "${PODS_ROOT}/Headers/Public/RNImageCropPicker" "${PODS_ROOT}/Headers/Public/RSKImageCropper" "${PODS_ROOT}/Headers/Public/React" "${PODS_ROOT}/Headers/Public/yoga" HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/QBImagePickerController" "${PODS_ROOT}/Headers/Public/RNDeviceInfo" "${PODS_ROOT}/Headers/Public/RNImageCropPicker" "${PODS_ROOT}/Headers/Public/RSKImageCropper" "${PODS_ROOT}/Headers/Public/React" "${PODS_ROOT}/Headers/Public/yoga"
LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/QBImagePickerController" "${PODS_CONFIGURATION_BUILD_DIR}/RNImageCropPicker" "${PODS_CONFIGURATION_BUILD_DIR}/RSKImageCropper" "${PODS_CONFIGURATION_BUILD_DIR}/React" "${PODS_CONFIGURATION_BUILD_DIR}/yoga" LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/QBImagePickerController" "${PODS_CONFIGURATION_BUILD_DIR}/RNDeviceInfo" "${PODS_CONFIGURATION_BUILD_DIR}/RNImageCropPicker" "${PODS_CONFIGURATION_BUILD_DIR}/RSKImageCropper" "${PODS_CONFIGURATION_BUILD_DIR}/React" "${PODS_CONFIGURATION_BUILD_DIR}/yoga"
OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/QBImagePickerController" -isystem "${PODS_ROOT}/Headers/Public/RNImageCropPicker" -isystem "${PODS_ROOT}/Headers/Public/RSKImageCropper" -isystem "${PODS_ROOT}/Headers/Public/React" -isystem "${PODS_ROOT}/Headers/Public/yoga" OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/QBImagePickerController" -isystem "${PODS_ROOT}/Headers/Public/RNDeviceInfo" -isystem "${PODS_ROOT}/Headers/Public/RNImageCropPicker" -isystem "${PODS_ROOT}/Headers/Public/RSKImageCropper" -isystem "${PODS_ROOT}/Headers/Public/React" -isystem "${PODS_ROOT}/Headers/Public/yoga"
OTHER_LDFLAGS = $(inherited) -ObjC -l"QBImagePickerController" -l"RNImageCropPicker" -l"RSKImageCropper" -l"React" -l"stdc++" -l"yoga" -framework "JavaScriptCore" -framework "Photos" -framework "QuartzCore" -framework "UIKit" OTHER_LDFLAGS = $(inherited) -ObjC -l"QBImagePickerController" -l"RNDeviceInfo" -l"RNImageCropPicker" -l"RSKImageCropper" -l"React" -l"stdc++" -l"yoga" -framework "JavaScriptCore" -framework "Photos" -framework "QuartzCore" -framework "UIKit"
PODS_BUILD_DIR = ${BUILD_DIR} PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/. PODS_PODFILE_DIR_PATH = ${SRCROOT}/.

View File

@ -1,8 +1,8 @@
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/QBImagePickerController" "${PODS_ROOT}/Headers/Public/RNImageCropPicker" "${PODS_ROOT}/Headers/Public/RSKImageCropper" "${PODS_ROOT}/Headers/Public/React" "${PODS_ROOT}/Headers/Public/yoga" HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/QBImagePickerController" "${PODS_ROOT}/Headers/Public/RNDeviceInfo" "${PODS_ROOT}/Headers/Public/RNImageCropPicker" "${PODS_ROOT}/Headers/Public/RSKImageCropper" "${PODS_ROOT}/Headers/Public/React" "${PODS_ROOT}/Headers/Public/yoga"
LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/QBImagePickerController" "${PODS_CONFIGURATION_BUILD_DIR}/RNImageCropPicker" "${PODS_CONFIGURATION_BUILD_DIR}/RSKImageCropper" "${PODS_CONFIGURATION_BUILD_DIR}/React" "${PODS_CONFIGURATION_BUILD_DIR}/yoga" LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/QBImagePickerController" "${PODS_CONFIGURATION_BUILD_DIR}/RNDeviceInfo" "${PODS_CONFIGURATION_BUILD_DIR}/RNImageCropPicker" "${PODS_CONFIGURATION_BUILD_DIR}/RSKImageCropper" "${PODS_CONFIGURATION_BUILD_DIR}/React" "${PODS_CONFIGURATION_BUILD_DIR}/yoga"
OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/QBImagePickerController" -isystem "${PODS_ROOT}/Headers/Public/RNImageCropPicker" -isystem "${PODS_ROOT}/Headers/Public/RSKImageCropper" -isystem "${PODS_ROOT}/Headers/Public/React" -isystem "${PODS_ROOT}/Headers/Public/yoga" OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/QBImagePickerController" -isystem "${PODS_ROOT}/Headers/Public/RNDeviceInfo" -isystem "${PODS_ROOT}/Headers/Public/RNImageCropPicker" -isystem "${PODS_ROOT}/Headers/Public/RSKImageCropper" -isystem "${PODS_ROOT}/Headers/Public/React" -isystem "${PODS_ROOT}/Headers/Public/yoga"
OTHER_LDFLAGS = $(inherited) -ObjC -l"QBImagePickerController" -l"RNImageCropPicker" -l"RSKImageCropper" -l"React" -l"stdc++" -l"yoga" -framework "JavaScriptCore" -framework "Photos" -framework "QuartzCore" -framework "UIKit" OTHER_LDFLAGS = $(inherited) -ObjC -l"QBImagePickerController" -l"RNDeviceInfo" -l"RNImageCropPicker" -l"RSKImageCropper" -l"React" -l"stdc++" -l"yoga" -framework "JavaScriptCore" -framework "Photos" -framework "QuartzCore" -framework "UIKit"
PODS_BUILD_DIR = ${BUILD_DIR} PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/. PODS_PODFILE_DIR_PATH = ${SRCROOT}/.

View File

@ -1,6 +1,6 @@
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/QBImagePickerController CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/QBImagePickerController
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/QBImagePickerController" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/QBImagePickerController" "${PODS_ROOT}/Headers/Public/RNImageCropPicker" "${PODS_ROOT}/Headers/Public/RSKImageCropper" "${PODS_ROOT}/Headers/Public/React" "${PODS_ROOT}/Headers/Public/yoga" HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/QBImagePickerController" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/QBImagePickerController" "${PODS_ROOT}/Headers/Public/RNDeviceInfo" "${PODS_ROOT}/Headers/Public/RNImageCropPicker" "${PODS_ROOT}/Headers/Public/RSKImageCropper" "${PODS_ROOT}/Headers/Public/React" "${PODS_ROOT}/Headers/Public/yoga"
OTHER_LDFLAGS = -framework "Photos" OTHER_LDFLAGS = -framework "Photos"
PODS_BUILD_DIR = ${BUILD_DIR} PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)

View File

@ -0,0 +1,5 @@
#import <Foundation/Foundation.h>
@interface PodsDummy_RNDeviceInfo : NSObject
@end
@implementation PodsDummy_RNDeviceInfo
@end

View File

@ -0,0 +1,12 @@
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif

View File

@ -0,0 +1,10 @@
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/RNDeviceInfo
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/RNDeviceInfo" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/QBImagePickerController" "${PODS_ROOT}/Headers/Public/RNDeviceInfo" "${PODS_ROOT}/Headers/Public/RNImageCropPicker" "${PODS_ROOT}/Headers/Public/RSKImageCropper" "${PODS_ROOT}/Headers/Public/React" "${PODS_ROOT}/Headers/Public/yoga"
LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/React" "${PODS_CONFIGURATION_BUILD_DIR}/yoga"
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_ROOT = ${SRCROOT}
PODS_TARGET_SRCROOT = ${PODS_ROOT}/../../node_modules/react-native-device-info
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
SKIP_INSTALL = YES

View File

@ -1,6 +1,6 @@
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/RNImageCropPicker CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/RNImageCropPicker
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/RNImageCropPicker" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/QBImagePickerController" "${PODS_ROOT}/Headers/Public/RNImageCropPicker" "${PODS_ROOT}/Headers/Public/RSKImageCropper" "${PODS_ROOT}/Headers/Public/React" "${PODS_ROOT}/Headers/Public/yoga" HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/RNImageCropPicker" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/QBImagePickerController" "${PODS_ROOT}/Headers/Public/RNDeviceInfo" "${PODS_ROOT}/Headers/Public/RNImageCropPicker" "${PODS_ROOT}/Headers/Public/RSKImageCropper" "${PODS_ROOT}/Headers/Public/React" "${PODS_ROOT}/Headers/Public/yoga"
LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/QBImagePickerController" "${PODS_CONFIGURATION_BUILD_DIR}/RSKImageCropper" "${PODS_CONFIGURATION_BUILD_DIR}/React" "${PODS_CONFIGURATION_BUILD_DIR}/yoga" LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/QBImagePickerController" "${PODS_CONFIGURATION_BUILD_DIR}/RSKImageCropper" "${PODS_CONFIGURATION_BUILD_DIR}/React" "${PODS_CONFIGURATION_BUILD_DIR}/yoga"
PODS_BUILD_DIR = ${BUILD_DIR} PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)

View File

@ -1,6 +1,6 @@
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/RSKImageCropper CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/RSKImageCropper
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/RSKImageCropper" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/QBImagePickerController" "${PODS_ROOT}/Headers/Public/RNImageCropPicker" "${PODS_ROOT}/Headers/Public/RSKImageCropper" "${PODS_ROOT}/Headers/Public/React" "${PODS_ROOT}/Headers/Public/yoga" HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/RSKImageCropper" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/QBImagePickerController" "${PODS_ROOT}/Headers/Public/RNDeviceInfo" "${PODS_ROOT}/Headers/Public/RNImageCropPicker" "${PODS_ROOT}/Headers/Public/RSKImageCropper" "${PODS_ROOT}/Headers/Public/React" "${PODS_ROOT}/Headers/Public/yoga"
OTHER_LDFLAGS = -framework "QuartzCore" -framework "UIKit" OTHER_LDFLAGS = -framework "QuartzCore" -framework "UIKit"
PODS_BUILD_DIR = ${BUILD_DIR} PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)

View File

@ -1,7 +1,7 @@
CLANG_CXX_LANGUAGE_STANDARD = c++14 CLANG_CXX_LANGUAGE_STANDARD = c++14
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/React CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/React
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/React" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/QBImagePickerController" "${PODS_ROOT}/Headers/Public/RNImageCropPicker" "${PODS_ROOT}/Headers/Public/RSKImageCropper" "${PODS_ROOT}/Headers/Public/React" "${PODS_ROOT}/Headers/Public/yoga" "$(PODS_TARGET_SRCROOT)/ReactCommon" HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/React" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/QBImagePickerController" "${PODS_ROOT}/Headers/Public/RNDeviceInfo" "${PODS_ROOT}/Headers/Public/RNImageCropPicker" "${PODS_ROOT}/Headers/Public/RSKImageCropper" "${PODS_ROOT}/Headers/Public/React" "${PODS_ROOT}/Headers/Public/yoga" "$(PODS_TARGET_SRCROOT)/ReactCommon"
LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/yoga" LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/yoga"
OTHER_LDFLAGS = -l"stdc++" -framework "JavaScriptCore" OTHER_LDFLAGS = -l"stdc++" -framework "JavaScriptCore"
PODS_BUILD_DIR = ${BUILD_DIR} PODS_BUILD_DIR = ${BUILD_DIR}

View File

@ -1,6 +1,6 @@
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/yoga CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/yoga
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/yoga" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/QBImagePickerController" "${PODS_ROOT}/Headers/Public/RNImageCropPicker" "${PODS_ROOT}/Headers/Public/RSKImageCropper" "${PODS_ROOT}/Headers/Public/React" "${PODS_ROOT}/Headers/Public/yoga" HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/yoga" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/QBImagePickerController" "${PODS_ROOT}/Headers/Public/RNDeviceInfo" "${PODS_ROOT}/Headers/Public/RNImageCropPicker" "${PODS_ROOT}/Headers/Public/RSKImageCropper" "${PODS_ROOT}/Headers/Public/React" "${PODS_ROOT}/Headers/Public/yoga"
PODS_BUILD_DIR = ${BUILD_DIR} PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_ROOT = ${SRCROOT} PODS_ROOT = ${SRCROOT}

View File

@ -62,6 +62,7 @@
832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
8A159EDB97C44E52AF62D69C /* libRNSVG.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA50CE47374C4C35BE6D9D58 /* libRNSVG.a */; }; 8A159EDB97C44E52AF62D69C /* libRNSVG.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA50CE47374C4C35BE6D9D58 /* libRNSVG.a */; };
8ECBD927DDAC4987B98E102E /* libRCTVideo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 20CE3E407E0D4D9E8C9885F2 /* libRCTVideo.a */; }; 8ECBD927DDAC4987B98E102E /* libRCTVideo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 20CE3E407E0D4D9E8C9885F2 /* libRCTVideo.a */; };
95E57ADEB9A0487791D2C50E /* libRNGestureHandler.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58E5009FCA8D40E59303C3DD /* libRNGestureHandler.a */; };
AE5D35882AE04CC29630FB3D /* Entypo.ttf in Resources */ = {isa = PBXBuildFile; fileRef = DC6EE17B5550465E98C70FF0 /* Entypo.ttf */; }; AE5D35882AE04CC29630FB3D /* Entypo.ttf in Resources */ = {isa = PBXBuildFile; fileRef = DC6EE17B5550465E98C70FF0 /* Entypo.ttf */; };
B88F586F1FBF57F600B352B8 /* libRCTPushNotification.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88F58461FBF55E200B352B8 /* libRCTPushNotification.a */; }; B88F586F1FBF57F600B352B8 /* libRCTPushNotification.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88F58461FBF55E200B352B8 /* libRCTPushNotification.a */; };
B8971BB2202A093B0000D245 /* libKeyboardTrackingView.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B8971BB1202A091D0000D245 /* libKeyboardTrackingView.a */; }; B8971BB2202A093B0000D245 /* libKeyboardTrackingView.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B8971BB1202A091D0000D245 /* libKeyboardTrackingView.a */; };
@ -380,6 +381,13 @@
remoteGlobalIDString = 134814201AA4EA6300B7C361; remoteGlobalIDString = 134814201AA4EA6300B7C361;
remoteInfo = RNNotifications; remoteInfo = RNNotifications;
}; };
7AD44CF421518C610099D147 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = B1A58A7ACB0E4453A44AEC38 /* RNGestureHandler.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 134814201AA4EA6300B7C361;
remoteInfo = RNGestureHandler;
};
7AFB804B205AE63100D004E7 /* PBXContainerItemProxy */ = { 7AFB804B205AE63100D004E7 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy; isa = PBXContainerItemProxy;
containerPortal = 7AFB8035205AE63000D004E7 /* RCTToast.xcodeproj */; containerPortal = 7AFB8035205AE63000D004E7 /* RCTToast.xcodeproj */;
@ -544,6 +552,7 @@
3B696712EE2345A59F007A88 /* libRNImagePicker.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNImagePicker.a; sourceTree = "<group>"; }; 3B696712EE2345A59F007A88 /* libRNImagePicker.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNImagePicker.a; sourceTree = "<group>"; };
4019A5E1911B4C61944FBCEC /* SafariViewManager.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = SafariViewManager.xcodeproj; path = "../node_modules/react-native-safari-view/SafariViewManager.xcodeproj"; sourceTree = "<group>"; }; 4019A5E1911B4C61944FBCEC /* SafariViewManager.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = SafariViewManager.xcodeproj; path = "../node_modules/react-native-safari-view/SafariViewManager.xcodeproj"; sourceTree = "<group>"; };
41FE03CD3B554249859F01BA /* RNZeroconf.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNZeroconf.xcodeproj; path = "../node_modules/react-native-zeroconf/ios/RNZeroconf.xcodeproj"; sourceTree = "<group>"; }; 41FE03CD3B554249859F01BA /* RNZeroconf.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNZeroconf.xcodeproj; path = "../node_modules/react-native-zeroconf/ios/RNZeroconf.xcodeproj"; sourceTree = "<group>"; };
58E5009FCA8D40E59303C3DD /* libRNGestureHandler.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNGestureHandler.a; sourceTree = "<group>"; };
5A0EEFAF8AB14F5B9E796CDD /* libRNVectorIcons.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNVectorIcons.a; sourceTree = "<group>"; }; 5A0EEFAF8AB14F5B9E796CDD /* libRNVectorIcons.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNVectorIcons.a; sourceTree = "<group>"; };
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 = "<group>"; }; 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 = "<group>"; };
5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = "<group>"; }; 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = "<group>"; };
@ -568,6 +577,7 @@
A18EFC3B0CFE40E0918A8F0C /* EvilIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = EvilIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/EvilIcons.ttf"; sourceTree = "<group>"; }; A18EFC3B0CFE40E0918A8F0C /* EvilIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = EvilIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/EvilIcons.ttf"; sourceTree = "<group>"; };
ACD75701AFD1CB848CAB0CB3 /* Pods-RocketChatRN.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RocketChatRN.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RocketChatRN/Pods-RocketChatRN.debug.xcconfig"; sourceTree = "<group>"; }; ACD75701AFD1CB848CAB0CB3 /* Pods-RocketChatRN.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RocketChatRN.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RocketChatRN/Pods-RocketChatRN.debug.xcconfig"; sourceTree = "<group>"; };
AD0379F2BCE84C968538CDAF /* RCTVideo.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RCTVideo.xcodeproj; path = "../node_modules/react-native-video/ios/RCTVideo.xcodeproj"; sourceTree = "<group>"; }; AD0379F2BCE84C968538CDAF /* RCTVideo.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RCTVideo.xcodeproj; path = "../node_modules/react-native-video/ios/RCTVideo.xcodeproj"; sourceTree = "<group>"; };
B1A58A7ACB0E4453A44AEC38 /* RNGestureHandler.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNGestureHandler.xcodeproj; path = "../node_modules/react-native-gesture-handler/ios/RNGestureHandler.xcodeproj"; sourceTree = "<group>"; };
B2607FA180F14E6584301101 /* libSplashScreen.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libSplashScreen.a; sourceTree = "<group>"; }; B2607FA180F14E6584301101 /* libSplashScreen.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libSplashScreen.a; sourceTree = "<group>"; };
B37C79D9BD0742CE936B6982 /* libc++.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; }; B37C79D9BD0742CE936B6982 /* libc++.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
B88F58361FBF55E200B352B8 /* RCTPushNotification.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTPushNotification.xcodeproj; path = "../node_modules/react-native/Libraries/PushNotificationIOS/RCTPushNotification.xcodeproj"; sourceTree = "<group>"; }; B88F58361FBF55E200B352B8 /* RCTPushNotification.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTPushNotification.xcodeproj; path = "../node_modules/react-native/Libraries/PushNotificationIOS/RCTPushNotification.xcodeproj"; sourceTree = "<group>"; };
@ -632,6 +642,7 @@
BAB7DC22804246F3923A1833 /* libFastImage.a in Frameworks */, BAB7DC22804246F3923A1833 /* libFastImage.a in Frameworks */,
F5BF54DC78E1411B8343933B /* libRNI18n.a in Frameworks */, F5BF54DC78E1411B8343933B /* libRNI18n.a in Frameworks */,
50046CB6BDA69B9232CF66D9 /* libPods-RocketChatRN.a in Frameworks */, 50046CB6BDA69B9232CF66D9 /* libPods-RocketChatRN.a in Frameworks */,
95E57ADEB9A0487791D2C50E /* libRNGestureHandler.a in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -889,6 +900,14 @@
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
7AD44CF121518C610099D147 /* Products */ = {
isa = PBXGroup;
children = (
7AD44CF521518C610099D147 /* libRNGestureHandler.a */,
);
name = Products;
sourceTree = "<group>";
};
7AFB8036205AE63000D004E7 /* Products */ = { 7AFB8036205AE63000D004E7 /* Products */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -928,6 +947,7 @@
1845C223DA364898A8400573 /* FastImage.xcodeproj */, 1845C223DA364898A8400573 /* FastImage.xcodeproj */,
22D3971EAF2E4660B4FAB3DD /* RNI18n.xcodeproj */, 22D3971EAF2E4660B4FAB3DD /* RNI18n.xcodeproj */,
0B82BCC462E84F308C5B5CD1 /* RNFetchBlob.xcodeproj */, 0B82BCC462E84F308C5B5CD1 /* RNFetchBlob.xcodeproj */,
B1A58A7ACB0E4453A44AEC38 /* RNGestureHandler.xcodeproj */,
); );
name = Libraries; name = Libraries;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1039,6 +1059,7 @@
921481B47B50490CA761932E /* libRNI18n.a */, 921481B47B50490CA761932E /* libRNI18n.a */,
C01CD6D4653143EEB5100C3A /* libRNI18n-tvOS.a */, C01CD6D4653143EEB5100C3A /* libRNI18n-tvOS.a */,
1A34D902CC074FF1BCC7DB48 /* libimageCropPicker.a */, 1A34D902CC074FF1BCC7DB48 /* libimageCropPicker.a */,
58E5009FCA8D40E59303C3DD /* libRNGestureHandler.a */,
); );
name = "Recovered References"; name = "Recovered References";
sourceTree = "<group>"; sourceTree = "<group>";
@ -1281,6 +1302,10 @@
ProductGroup = 7A8C912120F39A8000C8F5EE /* Products */; ProductGroup = 7A8C912120F39A8000C8F5EE /* Products */;
ProjectRef = 0B82BCC462E84F308C5B5CD1 /* RNFetchBlob.xcodeproj */; ProjectRef = 0B82BCC462E84F308C5B5CD1 /* RNFetchBlob.xcodeproj */;
}, },
{
ProductGroup = 7AD44CF121518C610099D147 /* Products */;
ProjectRef = B1A58A7ACB0E4453A44AEC38 /* RNGestureHandler.xcodeproj */;
},
{ {
ProductGroup = 7A770EBC20BECDC7001AD51A /* Products */; ProductGroup = 7A770EBC20BECDC7001AD51A /* Products */;
ProjectRef = 22D3971EAF2E4660B4FAB3DD /* RNI18n.xcodeproj */; ProjectRef = 22D3971EAF2E4660B4FAB3DD /* RNI18n.xcodeproj */;
@ -1608,6 +1633,13 @@
remoteRef = 7A8DEB5120ED0BDE00C5DCE4 /* PBXContainerItemProxy */; remoteRef = 7A8DEB5120ED0BDE00C5DCE4 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR; sourceTree = BUILT_PRODUCTS_DIR;
}; };
7AD44CF521518C610099D147 /* libRNGestureHandler.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRNGestureHandler.a;
remoteRef = 7AD44CF421518C610099D147 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
7AFB804C205AE63100D004E7 /* libRCTToast.a */ = { 7AFB804C205AE63100D004E7 /* libRCTToast.a */ = {
isa = PBXReferenceProxy; isa = PBXReferenceProxy;
fileType = archive.ar; fileType = archive.ar;
@ -1944,6 +1976,7 @@
"$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**", "$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**",
"$(SRCROOT)/../node_modules/react-native-i18n/ios", "$(SRCROOT)/../node_modules/react-native-i18n/ios",
"$(SRCROOT)/../node_modules/rn-fetch-blob/ios/**", "$(SRCROOT)/../node_modules/rn-fetch-blob/ios/**",
"$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**",
); );
INFOPLIST_FILE = RocketChatRNTests/Info.plist; INFOPLIST_FILE = RocketChatRNTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0; IPHONEOS_DEPLOYMENT_TARGET = 8.0;
@ -1961,6 +1994,7 @@
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
); );
OTHER_LDFLAGS = ( OTHER_LDFLAGS = (
"-ObjC", "-ObjC",
@ -1992,6 +2026,7 @@
"$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**", "$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**",
"$(SRCROOT)/../node_modules/react-native-i18n/ios", "$(SRCROOT)/../node_modules/react-native-i18n/ios",
"$(SRCROOT)/../node_modules/rn-fetch-blob/ios/**", "$(SRCROOT)/../node_modules/rn-fetch-blob/ios/**",
"$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**",
); );
INFOPLIST_FILE = RocketChatRNTests/Info.plist; INFOPLIST_FILE = RocketChatRNTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0; IPHONEOS_DEPLOYMENT_TARGET = 8.0;
@ -2009,6 +2044,7 @@
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
); );
OTHER_LDFLAGS = ( OTHER_LDFLAGS = (
"-ObjC", "-ObjC",
@ -2053,6 +2089,7 @@
"$(SRCROOT)/../node_modules/react-native-i18n/ios", "$(SRCROOT)/../node_modules/react-native-i18n/ios",
"$(SRCROOT)/../node_modules/react-native-notifications/RNNotifications", "$(SRCROOT)/../node_modules/react-native-notifications/RNNotifications",
"$(SRCROOT)/../node_modules/rn-fetch-blob/ios/**", "$(SRCROOT)/../node_modules/rn-fetch-blob/ios/**",
"$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**",
); );
INFOPLIST_FILE = RocketChatRN/Info.plist; INFOPLIST_FILE = RocketChatRN/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
@ -2102,6 +2139,7 @@
"$(SRCROOT)/../node_modules/react-native-i18n/ios", "$(SRCROOT)/../node_modules/react-native-i18n/ios",
"$(SRCROOT)/../node_modules/react-native-notifications/RNNotifications", "$(SRCROOT)/../node_modules/react-native-notifications/RNNotifications",
"$(SRCROOT)/../node_modules/rn-fetch-blob/ios/**", "$(SRCROOT)/../node_modules/rn-fetch-blob/ios/**",
"$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**",
); );
INFOPLIST_FILE = RocketChatRN/Info.plist; INFOPLIST_FILE = RocketChatRN/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
@ -2146,6 +2184,7 @@
"$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**", "$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**",
"$(SRCROOT)/../node_modules/react-native-i18n/ios", "$(SRCROOT)/../node_modules/react-native-i18n/ios",
"$(SRCROOT)/../node_modules/rn-fetch-blob/ios/**", "$(SRCROOT)/../node_modules/rn-fetch-blob/ios/**",
"$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**",
); );
INFOPLIST_FILE = "RocketChatRN-tvOS/Info.plist"; INFOPLIST_FILE = "RocketChatRN-tvOS/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
@ -2162,6 +2201,7 @@
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
); );
OTHER_LDFLAGS = ( OTHER_LDFLAGS = (
"-ObjC", "-ObjC",
@ -2203,6 +2243,7 @@
"$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**", "$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**",
"$(SRCROOT)/../node_modules/react-native-i18n/ios", "$(SRCROOT)/../node_modules/react-native-i18n/ios",
"$(SRCROOT)/../node_modules/rn-fetch-blob/ios/**", "$(SRCROOT)/../node_modules/rn-fetch-blob/ios/**",
"$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**",
); );
INFOPLIST_FILE = "RocketChatRN-tvOS/Info.plist"; INFOPLIST_FILE = "RocketChatRN-tvOS/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
@ -2219,6 +2260,7 @@
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
); );
OTHER_LDFLAGS = ( OTHER_LDFLAGS = (
"-ObjC", "-ObjC",
@ -2259,6 +2301,7 @@
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
); );
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.RocketChatRN-tvOSTests"; PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.RocketChatRN-tvOSTests";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
@ -2295,6 +2338,7 @@
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
); );
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.RocketChatRN-tvOSTests"; PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.RocketChatRN-tvOSTests";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";

Some files were not shown because too many files have changed in this diff Show More