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 {
implementation project(':react-native-device-info')
implementation project(':react-native-gesture-handler')
implementation project(':react-native-image-crop-picker')
implementation project(':react-native-i18n')
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.notification.INotificationsApplication;
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.List;
@ -57,6 +59,8 @@ public class MainApplication extends NavigationApplication implements INotificat
public List<ReactPackage> createAdditionalReactPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new RNDeviceInfo(),
new RNGestureHandlerPackage(),
new PickerPackage(),
new SvgPackage(),
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'
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'
project(':@remobile/react-native-toast').projectDir = new File(rootProject.projectDir, '../node_modules/@remobile/react-native-toast/android')
include ':rn-fetch-blob'

View File

@ -266,7 +266,7 @@ export default class MessageBox extends React.PureComponent {
await RocketChat.sendFileMessage(this.props.rid, fileInfo);
} catch (e) {
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);
}

View File

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

View File

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

View File

@ -52,17 +52,13 @@ export default class Markdown extends React.Component {
};
}
return (
<Text
key={key}
onPress={() => alert(`Username ${ content }`)}
style={mentionStyle}
>
<Text style={mentionStyle} key={key}>
&nbsp;{content}&nbsp;
</Text>
);
},
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;
</Text>
),

View File

@ -1,9 +1,10 @@
import React, { PureComponent } from 'react';
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 moment from 'moment';
import { KeyboardUtils } from 'react-native-keyboard-input';
import { State, RectButton, LongPressGestureHandler } from 'react-native-gesture-handler';
import Image from './Image';
import User from './User';
@ -16,7 +17,6 @@ import Reply from './Reply';
import ReactionsModal from './ReactionsModal';
import Emoji from './Emoji';
import styles from './styles';
import Touch from '../../utils/touch';
import I18n from '../../i18n';
import messagesStatus from '../../constants/messagesStatus';
@ -247,15 +247,20 @@ export default class Message extends PureComponent {
renderReaction = (reaction) => {
const reacted = reaction.usernames.findIndex(item => item.value === this.props.user.username) !== -1;
const reactedContainerStyle = reacted && styles.reactedContainer;
const underlayColor = reacted ? '#fff' : '#e1e5e8';
return (
<TouchableOpacity
onPress={() => this.props.onReactionPress(reaction.emoji)}
onLongPress={this.props.onReactionLongPress}
<LongPressGestureHandler
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
content={reaction.emoji}
customEmojis={this.props.customEmojis}
@ -265,7 +270,8 @@ export default class Message extends PureComponent {
/>
<Text style={styles.reactionCount}>{ reaction.usernames.length }</Text>
</View>
</TouchableOpacity>
</RectButton>
</LongPressGestureHandler>
);
}
@ -277,14 +283,18 @@ export default class Message extends PureComponent {
return (
<View style={styles.reactionsContainer}>
{reactions.map(this.renderReaction)}
<TouchableOpacity
<RectButton
onPress={this.props.toggleReactionPicker}
key='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} />
</TouchableOpacity>
</View>
</RectButton>
</View>
);
}
@ -292,15 +302,15 @@ export default class Message extends PureComponent {
renderBroadcastReply() {
if (this.props.broadcast && !this.isOwn()) {
return (
<Touch
<RectButton
onPress={this.props.replyBroadcast}
style={styles.broadcastButton}
activeOpacity={0.5}
underlayColor='#fff'
>
<View style={styles.broadcastButtonContainer}>
<ImageRN source={{ uri: 'reply' }} style={styles.broadcastButtonIcon} />
<Text style={styles.broadcastButtonText}>Reply</Text>
</View>
</Touch>
<Text style={styles.broadcastButtonText}>{I18n.t('Reply')}</Text>
</RectButton>
);
}
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 });
return (
<Touch
onPress={this.onPress}
onLongPress={onLongPress}
disabled={this.isInfoMessage() || this.hasError() || archived}
accessibilityLabel={accessibilityLabel}
style={[styles.container, header && { marginBottom: 10 }]}
<LongPressGestureHandler
onHandlerStateChange={({ nativeEvent }) => nativeEvent.state === State.ACTIVE && onLongPress()}
>
<RectButton
enabled={!(this.isInfoMessage() || this.hasError() || archived)}
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}>
{this.renderError()}
{this.renderAvatar()}
@ -345,7 +361,8 @@ export default class Message extends PureComponent {
: null
}
</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 PropTypes from 'prop-types';
import moment from 'moment';
import { RectButton } from 'react-native-gesture-handler';
import Markdown from './Markdown';
import openLink from '../../utils/openLink';
import Touch from '../../utils/touch';
const styles = StyleSheet.create({
button: {
@ -13,13 +13,13 @@ const styles = StyleSheet.create({
flexDirection: 'row',
alignItems: 'center',
marginTop: 15,
alignSelf: 'flex-end'
alignSelf: 'flex-end',
backgroundColor: '#f3f4f5'
},
attachmentContainer: {
flex: 1,
borderRadius: 4,
flexDirection: 'column',
backgroundColor: '#f3f4f5',
padding: 15
},
authorContainer: {
@ -55,12 +55,15 @@ const styles = StyleSheet.create({
}
});
const onPress = (attachment) => {
const url = attachment.title_link || attachment.author_link;
const onPress = (attachment, baseUrl, user) => {
let url = attachment.title_link || attachment.author_link;
if (!url) {
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 = ({
@ -91,9 +94,19 @@ const Reply = ({
);
};
const renderText = () => (
attachment.text ? <Markdown msg={attachment.text} customEmojis={customEmojis} baseUrl={baseUrl} username={user.username} /> : null
const renderText = () => {
const text = attachment.text || attachment.title;
if (text) {
return (
<Markdown
msg={text}
customEmojis={customEmojis}
baseUrl={baseUrl}
username={user.username}
/>
);
}
};
const renderFields = () => {
if (!attachment.fields) {
@ -113,16 +126,18 @@ const Reply = ({
};
return (
<Touch
onPress={() => onPress(attachment)}
<RectButton
onPress={() => onPress(attachment, baseUrl, user)}
style={[styles.button, index > 0 && styles.marginTop]}
activeOpacity={0.5}
underlayColor='#fff'
>
<View style={styles.attachmentContainer}>
{renderTitle()}
{renderText()}
{renderFields()}
</View>
</Touch>
</RectButton>
);
};

View File

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

View File

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

View File

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

View File

@ -146,7 +146,7 @@ export default class MessageContainer extends React.Component {
item, message, editing, user, style, archived, baseUrl, customEmojis, useRealName, broadcast
} = this.props;
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;
const isEditing = message._id === item._id && editing;
return (
@ -173,6 +173,7 @@ export default class MessageContainer extends React.Component {
customEmojis={customEmojis}
reactionsModal={this.state.reactionsModal}
useRealName={useRealName}
role={role}
closeReactions={this.closeReactions}
onErrorPress={this.onErrorPress}
onLongPress={this.onLongPress}

View File

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

View File

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

View File

@ -6,7 +6,7 @@ import messagesStatus from '../../../constants/messagesStatus';
import log from '../../../utils/log';
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 }/rooms-changed`, 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 [, ev] = ddpMessage.fields.eventName.split('/');
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 tpm = merge(data, rooms[0]);
database.write(() => {
@ -58,6 +70,7 @@ export default async function subscribeRooms(id) {
database.delete(rooms);
});
}
}
if (/rooms/.test(ev)) {
if (type === 'updated') {
const [sub] = database.objects('subscriptions').filtered('rid == $0', data._id);
@ -93,9 +106,8 @@ export default async function subscribeRooms(id) {
}
try {
await subscriptions;
await promises;
} catch (e) {
log('subscribeRooms', e);
}
// console.log(this.ddp.subscriptions);
}

View File

@ -470,9 +470,11 @@ const RocketChat = {
log('rocketchat.logout', e);
}
}
// database.deleteAll();
AsyncStorage.removeItem(TOKEN_KEY);
AsyncStorage.removeItem(`${ TOKEN_KEY }-${ server }`);
setTimeout(() => {
database.deleteAll();
}, 1000);
},
registerPushToken(userId) {
@ -750,7 +752,7 @@ const RocketChat = {
// transform room roles to array
const roomRoles = Array.from(Object.keys(roles), i => roles[i].value);
// 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
const mergedRoles = [...new Set([...roomRoles, ...userRoles])];

View File

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

View File

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

View File

@ -10,6 +10,7 @@ import { messagesRequest, editCancel, replyCancel } from '../actions/messages';
import RocketChat from '../lib/rocketchat';
import database from '../lib/realm';
import log from '../utils/log';
import I18n from '../i18n';
import { NavigationActions } from '../Navigation';
const leaveRoom = rid => RocketChat.leaveRoom(rid);
@ -63,41 +64,40 @@ const handleMessageReceived = function* handleMessageReceived({ message }) {
database.create('messages', message, true);
});
if (room._id) {
RocketChat.readMessages(room.rid);
}
}
} catch (e) {
console.warn('handleMessageReceived', e);
}
};
let opened = false;
const watchRoomOpen = function* watchRoomOpen({ room }) {
try {
yield put(messagesRequest({ ...room }));
// const { open } = yield race({
// messages: take(types.MESSAGES.SUCCESS),
// open: take(types.ROOM.OPEN)
// });
//
// if (open) {
// return;
// }
if (opened) {
return;
}
opened = true;
yield put(messagesRequest({ ...room }));
if (room._id) {
RocketChat.readMessages(room.rid);
}
sub = yield RocketChat.subscribeRoom(room);
// const subscriptions = yield Promise.all([RocketChat.subscribe('stream-room-messages', room.rid, false), RocketChat.subscribe('stream-notify-room', `${ room.rid }/typing`, false)]);
thread = yield fork(usersTyping, { rid: room.rid });
yield race({
open: take(types.ROOM.OPEN),
close: take(types.ROOM.CLOSE)
});
opened = false;
cancel(thread);
sub.stop();
yield put(editCancel());
yield put(replyCancel());
// subscriptions.forEach((sub) => {
// sub.unsubscribe().catch(e => alert(e));
// });
} catch (e) {
log('watchRoomOpen', e);
}
@ -161,9 +161,9 @@ const handleLeaveRoom = function* handleLeaveRoom({ rid }) {
yield goRoomsListAndDelete(rid);
} catch (e) {
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 {
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 goRoomsListAndDelete(rid);
} 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'
},
planetImage: {
width: 200,
height: 162,
width: 210,
height: 171,
marginVertical: 20
}
});
@ -283,10 +283,7 @@ export default class LoginSignupView extends LoggedView {
<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]}>{I18n.t('Welcome_title_pt_2')}</Text>
<Image
style={styles.planetImage}
source={require('../static/images/server.png')}
/>
<Image style={styles.planetImage} source={{ uri: 'new_server' }} />
<Button
title={I18n.t('I_have_an_account')}
type='primary'

View File

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

View File

@ -1,9 +1,10 @@
import React from 'react';
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 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 scrollPersistTaps from '../utils/scrollPersistTaps';
import Button from '../containers/Button';
@ -12,11 +13,14 @@ import LoggedView from './View';
import I18n from '../i18n';
import { scale, verticalScale, moderateScale } from '../utils/scaling';
import KeyboardView from '../presentation/KeyboardView';
import DeviceInfo from '../utils/deviceInfo';
const styles = StyleSheet.create({
image: {
alignSelf: 'center',
marginVertical: verticalScale(20)
marginVertical: verticalScale(20),
width: 210,
height: 171
},
title: {
alignSelf: 'center',
@ -36,6 +40,11 @@ const styles = StyleSheet.create({
paddingTop: 14,
paddingBottom: 14,
paddingHorizontal: 16
},
backButton: {
position: 'absolute',
paddingHorizontal: 9,
left: 15
}
});
@ -43,14 +52,9 @@ const defaultServer = 'https://open.rocket.chat';
@connect(state => ({
connecting: state.server.connecting,
failure: state.server.failure,
currentServer: state.server.server,
adding: state.server.adding
failure: state.server.failure
}), dispatch => ({
initAdd: () => dispatch(serverInitAdd()),
finishAdd: () => dispatch(serverFinishAdd()),
connectServer: server => dispatch(serverRequest(server)),
selectServer: server => dispatch(selectServerRequest(server))
connectServer: server => dispatch(serverRequest(server))
}))
/** @extends React.Component */
export default class NewServerView extends LoggedView {
@ -58,14 +62,8 @@ export default class NewServerView extends LoggedView {
navigator: PropTypes.object,
server: PropTypes.string,
connecting: PropTypes.bool.isRequired,
adding: PropTypes.bool,
failure: PropTypes.bool.isRequired,
connectServer: PropTypes.func.isRequired,
selectServer: PropTypes.func.isRequired,
previousServer: PropTypes.string,
currentServer: PropTypes.string,
initAdd: PropTypes.func,
finishAdd: PropTypes.func
connectServer: PropTypes.func.isRequired
}
constructor(props) {
@ -73,11 +71,10 @@ export default class NewServerView extends LoggedView {
this.state = {
text: ''
};
props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
}
componentDidMount() {
const { server, previousServer } = this.props;
const { server } = this.props;
if (server) {
this.props.connectServer(server);
this.setState({ text: server });
@ -86,9 +83,6 @@ export default class NewServerView extends LoggedView {
this.input.focus();
}, 600);
}
if (previousServer) {
this.props.initAdd();
}
}
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) => {
this.setState({ text });
}
@ -147,6 +121,26 @@ export default class NewServerView extends LoggedView {
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() {
const { connecting } = this.props;
const { text } = this.state;
@ -158,7 +152,7 @@ export default class NewServerView extends LoggedView {
>
<ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}>
<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>
<TextInput
inputRef={e => this.input = e}
@ -182,6 +176,7 @@ export default class NewServerView extends LoggedView {
/>
</SafeAreaView>
</ScrollView>
{this.renderBack()}
</KeyboardView>
);
}

View File

@ -1,23 +1,64 @@
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 Icon from 'react-native-vector-icons/MaterialIcons';
import { connect } from 'react-redux';
import { selectServerRequest, serverInitAdd, serverFinishAdd } from '../../actions/server';
import I18n from '../../i18n';
import openLink from '../../utils/openLink';
import Button from './Button';
import styles from './styles';
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 */
export default class OnboardingView extends LoggedView {
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) {
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 = () => {
this.props.navigator.push({
screen: 'NewServerView',
@ -45,17 +86,39 @@ export default class OnboardingView extends LoggedView {
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() {
return (
<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.subtitle}>{I18n.t('Open_Source_Communication')}</Text>
<View style={styles.buttonsContainer}>
<Button
type='secondary'
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}
testID='connect-server-button'
/>
@ -63,18 +126,19 @@ export default class OnboardingView extends LoggedView {
type='secondary'
title={I18n.t('Join_the_community')}
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}
testID='join-community-button'
/>
<Button
type='primary'
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}
testID='create-workspace-button'
/>
</View>
{this.renderClose()}
</SafeAreaView>
);
}

View File

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

View File

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

View File

@ -171,7 +171,7 @@ export class ListView extends OldList2 {
onKeyboardDidHide: undefined
});
const image = data.length === 0 ? require('../../static/images/message_empty.png') : null;
const image = data.length === 0 ? { uri: 'message_empty' } : null;
return (
[
<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 { connect } from 'react-redux';
import equal from 'deep-equal';
import { RectButton } from 'react-native-gesture-handler';
import LoggedView from '../View';
import { List } from './ListView';
@ -60,11 +61,11 @@ export default class RoomView extends LoggedView {
constructor(props) {
super('RoomView', props);
this.rid = props.rid;
this.rid = this.props.rid;
this.rooms = database.objects('subscriptions').filtered('rid = $0', this.rid);
this.state = {
loaded: false,
joined: typeof props.rid === 'undefined',
joined: this.rooms.length > 0,
room: {},
end: false
};
@ -95,6 +96,7 @@ export default class RoomView extends LoggedView {
});
this.setState({ loaded: true });
}
shouldComponentUpdate(nextProps, nextState) {
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);
}
}
} else {
this.props.openRoom({ rid: this.rid });
this.setState({ joined: false });
}
}
@ -204,9 +209,7 @@ export default class RoomView extends LoggedView {
joinRoom = async() => {
try {
await RocketChat.joinRoom(this.props.rid);
this.setState({
joined: true
});
this.setState({ joined: true });
} catch (e) {
log('joinRoom', e);
}
@ -245,15 +248,21 @@ export default class RoomView extends LoggedView {
);
renderFooter = () => {
// TODO: fix it
// if (!this.state.joined) {
// return (
// <View>
// <Text>{I18n.t('You_are_in_preview_mode')}</Text>
// <Button title='Join' onPress={this.joinRoom} />
// </View>
// );
// }
if (!this.state.joined) {
return (
<View style={styles.joinRoomContainer} key='room-view-join'>
<Text style={styles.previewMode}>{I18n.t('You_are_in_preview_mode')}</Text>
<RectButton
onPress={this.joinRoom}
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()) {
return (
<View style={styles.readOnly}>

View File

@ -53,5 +53,30 @@ export default StyleSheet.create({
width: '100%',
height: '100%',
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: {
marginLeft: 3,
marginTop: 2,
marginTop: 1,
width: 12,
height: 9
},
upsideDown: {
transform: [{ scaleY: -1 }]
transform: [{ scaleY: -1 }],
marginTop: 4
}
});

View File

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

View File

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

View File

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

View File

@ -1,5 +1,6 @@
import { Navigation } from 'react-native-navigation';
import { Provider } from 'react-redux';
import { gestureHandlerRootHOC } from 'react-native-gesture-handler';
import CreateChannelView from './CreateChannelView';
import ForgotPasswordView from './ForgotPasswordView';
@ -36,29 +37,29 @@ export const registerScreens = (store) => {
Navigation.registerComponent('ForgotPasswordView', () => ForgotPasswordView, store, Provider);
Navigation.registerComponent('LoginSignupView', () => LoginSignupView, 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('NewServerView', () => NewServerView, store, Provider);
Navigation.registerComponent('OAuthView', () => OAuthView, 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('ProfileView', () => ProfileView, store, Provider);
Navigation.registerComponent('RegisterView', () => RegisterView, 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('RoomInfoView', () => RoomInfoView, store, Provider);
Navigation.registerComponent('RoomMembersView', () => RoomMembersView, store, Provider);
Navigation.registerComponent('RoomsListHeaderView', () => RoomsListHeaderView, store, Provider);
Navigation.registerComponent('RoomsListSearchView', () => RoomsListSearchView, store, Provider);
Navigation.registerComponent('RoomsListView', () => RoomsListView, store, Provider);
Navigation.registerComponent('RoomView', () => RoomView, store, Provider);
Navigation.registerComponent('SearchMessagesView', () => SearchMessagesView, store, Provider);
Navigation.registerComponent('RoomsListView', () => gestureHandlerRootHOC(RoomsListView), store, Provider);
Navigation.registerComponent('RoomView', () => gestureHandlerRootHOC(RoomView), store, Provider);
Navigation.registerComponent('SearchMessagesView', () => gestureHandlerRootHOC(SearchMessagesView), store, Provider);
Navigation.registerComponent('SelectedUsersView', () => SelectedUsersView, store, Provider);
Navigation.registerComponent('SettingsView', () => SettingsView, store, Provider);
Navigation.registerComponent('Sidebar', () => Sidebar, store, Provider);
Navigation.registerComponent('SnippetedMessagesView', () => SnippetedMessagesView, store, Provider);
Navigation.registerComponent('StarredMessagesView', () => StarredMessagesView, store, Provider);
Navigation.registerComponent('SnippetedMessagesView', () => gestureHandlerRootHOC(SnippetedMessagesView), store, Provider);
Navigation.registerComponent('StarredMessagesView', () => gestureHandlerRootHOC(StarredMessagesView), 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 'RNDeviceInfo', :path => '../node_modules/react-native-device-info'
end
post_install do |installer|

View File

@ -1,5 +1,7 @@
PODS:
- QBImagePickerController (3.4.0)
- React (0.56.0):
- React/Core (= 0.56.0)
- React/Core (0.56.0):
- yoga (= 0.56.0.React)
- React/fishhook (0.56.0)
@ -28,11 +30,13 @@ PODS:
- React/Core
- React/fishhook
- React/RCTBlob
- RNImageCropPicker (0.20.3):
- RNDeviceInfo (0.21.5):
- React
- RNImageCropPicker (0.21.1):
- QBImagePickerController
- React/Core
- RSKImageCropper
- RSKImageCropper (2.0.0)
- RSKImageCropper (2.1.0)
- yoga (0.56.0.React)
DEPENDENCIES:
@ -47,12 +51,15 @@ DEPENDENCIES:
- React/RCTText (from `../node_modules/react-native`)
- React/RCTVibration (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`)
- yoga (from `../node_modules/react-native/ReactCommon/yoga/yoga.podspec`)
EXTERNAL SOURCES:
React:
:path: ../node_modules/react-native
RNDeviceInfo:
:path: ../node_modules/react-native-device-info
RNImageCropPicker:
:path: ../node_modules/react-native-image-crop-picker
yoga:
@ -61,10 +68,11 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
QBImagePickerController: d54cf93db6decf26baf6ed3472f336ef35cae022
React: 1fe0eb13d90b625d94c3b117c274dcfd2e760e11
RNDeviceInfo: 568c5641057313b4912d08a7742ff0b2f753ed5c
RNImageCropPicker: 32ca4b9fef4e1b7b85ba69494242122948117e06
RSKImageCropper: d9a1acbc0600bf8decc8f0d21895872c99a9e4cf
RSKImageCropper: 0d0c6d8525a2381f03fde32a47c6703817a2feed
yoga: b1ce48b6cf950b98deae82838f5173ea7cf89e85
PODFILE CHECKSUM: 61f93deba99bd7e36384c5bceba5b92c6b96009e
PODFILE CHECKSUM: da5e520837501713de2c32adbff219ab7fc5c0fa
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",
"version": "0.20.3",
"version": "0.21.1",
"summary": "Select single or multiple images, with cropping option",
"requires_arc": true,
"license": "MIT",

16
ios/Pods/Manifest.lock generated
View File

@ -1,5 +1,7 @@
PODS:
- QBImagePickerController (3.4.0)
- React (0.56.0):
- React/Core (= 0.56.0)
- React/Core (0.56.0):
- yoga (= 0.56.0.React)
- React/fishhook (0.56.0)
@ -28,11 +30,13 @@ PODS:
- React/Core
- React/fishhook
- React/RCTBlob
- RNImageCropPicker (0.20.3):
- RNDeviceInfo (0.21.5):
- React
- RNImageCropPicker (0.21.1):
- QBImagePickerController
- React/Core
- RSKImageCropper
- RSKImageCropper (2.0.0)
- RSKImageCropper (2.1.0)
- yoga (0.56.0.React)
DEPENDENCIES:
@ -47,12 +51,15 @@ DEPENDENCIES:
- React/RCTText (from `../node_modules/react-native`)
- React/RCTVibration (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`)
- yoga (from `../node_modules/react-native/ReactCommon/yoga/yoga.podspec`)
EXTERNAL SOURCES:
React:
:path: ../node_modules/react-native
RNDeviceInfo:
:path: ../node_modules/react-native-device-info
RNImageCropPicker:
:path: ../node_modules/react-native-image-crop-picker
yoga:
@ -61,10 +68,11 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
QBImagePickerController: d54cf93db6decf26baf6ed3472f336ef35cae022
React: 1fe0eb13d90b625d94c3b117c274dcfd2e760e11
RNDeviceInfo: 568c5641057313b4912d08a7742ff0b2f753ed5c
RNImageCropPicker: 32ca4b9fef4e1b7b85ba69494242122948117e06
RSKImageCropper: d9a1acbc0600bf8decc8f0d21895872c99a9e4cf
RSKImageCropper: 0d0c6d8525a2381f03fde32a47c6703817a2feed
yoga: b1ce48b6cf950b98deae82838f5173ea7cf89e85
PODFILE CHECKSUM: 61f93deba99bd7e36384c5bceba5b92c6b96009e
PODFILE CHECKSUM: da5e520837501713de2c32adbff219ab7fc5c0fa
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.
- (CGRect)imageCropViewControllerCustomMaskRect:(RSKImageCropViewController *)controller
{
CGSize maskSize;
if ([controller isPortraitInterfaceOrientation]) {
maskSize = CGSizeMake(250, 250);
} else {
maskSize = CGSizeMake(220, 220);
}
CGSize aspectRatio = CGSizeMake(16.0f, 9.0f);
CGFloat viewWidth = CGRectGetWidth(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,
(viewHeight - maskSize.height) * 0.5f,
maskSize.width,
@ -123,23 +134,42 @@ Then implement the data source functions.
CGRect rect = controller.maskRect;
CGPoint point1 = CGPointMake(CGRectGetMinX(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];
[triangle moveToPoint:point1];
[triangle addLineToPoint:point2];
[triangle addLineToPoint:point3];
[triangle closePath];
UIBezierPath *rectangle = [UIBezierPath bezierPath];
[rectangle moveToPoint:point1];
[rectangle addLineToPoint:point2];
[rectangle addLineToPoint:point3];
[rectangle addLineToPoint:point4];
[rectangle closePath];
return triangle;
return rectangle;
}
// Returns a custom rect in which the image can be moved.
- (CGRect)imageCropViewControllerCustomMovementRect:(RSKImageCropViewController *)controller
{
// If the image is not rotated, then the movement rect coincides with the mask rect,
// otherwise it is calculated individually for each custom mask.
if (controller.rotationAngle == 0) {
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.
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`.
CGRect RSKRectScaleAroundPoint(CGRect rect, CGPoint point, CGFloat sx, CGFloat sy);

View File

@ -24,6 +24,13 @@
#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 };
CGPoint RSKRectCenterPoint(CGRect rect)
@ -32,6 +39,45 @@ CGPoint RSKRectCenterPoint(CGRect rect)
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)
{
CGAffineTransform translationTransform, scaleTransform;

View File

@ -55,6 +55,14 @@ typedef NS_ENUM(NSUInteger, RSKImageCropMode) {
*/
- (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
///-----------------------------
@ -329,6 +337,11 @@ typedef NS_ENUM(NSUInteger, RSKImageCropMode) {
@optional
/**
Tells the delegate that the image has been displayed.
*/
- (void)imageCropViewControllerDidDisplayImage:(RSKImageCropViewController *)controller;
/**
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 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>
@property (assign, nonatomic) BOOL originalNavigationControllerNavigationBarHidden;
@ -57,6 +50,8 @@ static const CGFloat kLayoutImageScrollViewAnimationDuration = 0.25;
@property (readonly, nonatomic) CGRect rectForMaskPath;
@property (readonly, nonatomic) CGRect rectForClipPath;
@property (readonly, nonatomic) CGRect imageRect;
@property (strong, nonatomic) UILabel *moveAndScaleLabel;
@property (strong, nonatomic) UIButton *cancelButton;
@property (strong, nonatomic) UIButton *chooseButton;
@ -136,7 +131,16 @@ static const CGFloat kLayoutImageScrollViewAnimationDuration = 0.25;
[super viewDidLoad];
if ([self respondsToSelector:@selector(edgesForExtendedLayout)]) {
self.edgesForExtendedLayout = UIRectEdgeNone;
}
if (@available(iOS 11.0, *)) {
self.imageScrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
else if ([self respondsToSelector:@selector(automaticallyAdjustsScrollViewInsets)] == YES) {
self.automaticallyAdjustsScrollViewInsets = NO;
}
@ -157,11 +161,15 @@ static const CGFloat kLayoutImageScrollViewAnimationDuration = 0.25;
{
[super viewWillAppear:animated];
if ([self respondsToSelector:@selector(prefersStatusBarHidden)] == NO) {
UIApplication *application = [UIApplication rsk_sharedApplication];
if (application) {
self.originalStatusBarHidden = application.statusBarHidden;
[application setStatusBarHidden:YES];
}
}
self.originalNavigationControllerNavigationBarHidden = self.navigationController.navigationBarHidden;
[self.navigationController setNavigationBarHidden:YES animated:NO];
@ -182,10 +190,14 @@ static const CGFloat kLayoutImageScrollViewAnimationDuration = 0.25;
{
[super viewWillDisappear:animated];
if ([self respondsToSelector:@selector(prefersStatusBarHidden)] == NO) {
UIApplication *application = [UIApplication rsk_sharedApplication];
if (application) {
[application setStatusBarHidden:self.originalStatusBarHidden];
}
}
[self.navigationController setNavigationBarHidden:self.originalNavigationControllerNavigationBarHidden animated:animated];
self.navigationController.navigationBar.shadowImage = self.originalNavigationControllerNavigationBarShadowImage;
@ -385,31 +397,96 @@ static const CGFloat kLayoutImageScrollViewAnimationDuration = 0.25;
return _rotationGestureRecognizer;
}
- (CGRect)cropRect
- (CGRect)imageRect
{
CGRect cropRect = CGRectZero;
float zoomScale = 1.0 / self.imageScrollView.zoomScale;
cropRect.origin.x = floor(self.imageScrollView.contentOffset.x * zoomScale);
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;
CGRect imageRect = CGRectZero;
CGFloat width = CGRectGetWidth(cropRect);
CGFloat height = CGRectGetHeight(cropRect);
CGFloat ceilWidth = ceil(width);
CGFloat ceilHeight = ceil(height);
imageRect.origin.x = self.imageScrollView.contentOffset.x * zoomScale;
imageRect.origin.y = self.imageScrollView.contentOffset.y * zoomScale;
imageRect.size.width = CGRectGetWidth(self.imageScrollView.bounds) * zoomScale;
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 ||
fabs(ceilHeight - height) < pow(10, kK) * RSK_EPSILON * fabs(ceilHeight + height) || fabs(ceilHeight - height) < RSK_MIN) {
imageRect = RSKRectNormalize(imageRect);
cropRect.size.width = ceilWidth;
cropRect.size.height = ceilHeight;
} else {
cropRect.size.width = floor(width);
cropRect.size.height = floor(height);
CGSize imageSize = self.originalImage.size;
CGFloat x = CGRectGetMinX(imageRect);
CGFloat y = CGRectGetMinY(imageRect);
CGFloat width = CGRectGetWidth(imageRect);
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;
}
@ -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
- (BOOL)isPortraitInterfaceOrientation
@ -677,6 +759,10 @@ static const CGFloat kLayoutImageScrollViewAnimationDuration = 0.25;
if (self.originalImage) {
[self.imageScrollView displayImage:self.originalImage];
[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) {
CGImageRef croppedCGImage = CGImageCreateWithImageInRect(image.CGImage, cropRect);
UIImage *croppedImage = [UIImage imageWithCGImage:croppedCGImage scale:imageScale orientation:imageOrientation];
CGImageRelease(croppedCGImage);
return croppedImage;
CGImageRef cgImage = CGImageCreateWithImageInRect(image.CGImage, rect);
UIImage *image = [UIImage imageWithCGImage:cgImage scale:scale orientation:imageOrientation];
CGImageRelease(cgImage);
return image;
} else {
UIImage *animatedImage = image;
NSMutableArray *croppedImages = [NSMutableArray array];
for (UIImage *image in animatedImage.images) {
UIImage *croppedImage = [self croppedImage:image cropRect:cropRect scale:imageScale orientation:imageOrientation];
[croppedImages addObject:croppedImage];
NSMutableArray *images = [NSMutableArray array];
for (UIImage *animatedImageImage in animatedImage.images) {
UIImage *image = [self imageWithImage:animatedImageImage inRect:rect scale:scale imageOrientation:imageOrientation];
[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.
CGSize imageSize = image.size;
CGFloat x = CGRectGetMinX(cropRect);
CGFloat y = CGRectGetMinY(cropRect);
CGFloat width = CGRectGetWidth(cropRect);
CGFloat height = CGRectGetHeight(cropRect);
// Step 1: create an image using the data contained within the specified rect.
UIImage *image = [self imageWithImage:originalImage inRect:imageRect scale:originalImage.scale imageOrientation:originalImage.imageOrientation];
UIImageOrientation imageOrientation = image.imageOrientation;
if (imageOrientation == UIImageOrientationRight || imageOrientation == UIImageOrientationRightMirrored) {
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);
}
// Step 2: fix orientation of the image.
image = [image fixOrientation];
CGFloat imageScale = image.scale;
cropRect = CGRectApplyAffineTransform(cropRect, CGAffineTransformMakeScale(imageScale, imageScale));
// 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.
// Step 3: If current mode is `RSKImageCropModeSquare` and the original image is not rotated
// or mask should not be applied to the image after cropping and the original image is not rotated,
// we can return the image immediately.
// Otherwise, we must further process the image.
if ((cropMode == RSKImageCropModeSquare || !applyMaskToCroppedImage) && rotationAngle == 0.0) {
// Step 5: return the cropped image immediately.
return croppedImage;
// Step 4: return the image immediately.
return image;
} else {
// Step 5: create a new context.
// Step 4: create a new context.
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) {
// 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];
CGFloat scale = 1.0 / zoomScale;
[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),
-CGRectGetMinY(maskPathCopy.bounds));
[maskPathCopy applyTransform:CGAffineTransformMakeTranslation(translation.x, translation.y)];
// 6c: apply the mask.
// 5c: apply the mask.
[maskPathCopy addClip];
}
// Step 7: rotate the cropped image if needed.
// Step 6: rotate the image if needed.
if (rotationAngle != 0) {
croppedImage = [croppedImage rotateByAngle:rotationAngle];
image = [image rotateByAngle:rotationAngle];
}
// Step 8: draw the cropped image.
CGPoint point = CGPointMake(floor((contextSize.width - croppedImage.size.width) * 0.5f),
floor((contextSize.height - croppedImage.size.height) * 0.5f));
[croppedImage drawAtPoint:point];
// Step 7: draw the image.
CGPoint point = CGPointMake(floor((contextSize.width - image.size.width) * 0.5f),
floor((contextSize.height - image.size.height) * 0.5f));
[image drawAtPoint:point];
// Step 9: get the cropped image affter processing from the context.
croppedImage = UIGraphicsGetImageFromCurrentImageContext();
// Step 8: get the cropped image affter processing from the context.
UIImage *croppedImage = UIGraphicsGetImageFromCurrentImageContext();
// Step 10: remove the context.
// Step 9: remove the context.
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;
}
}
@ -945,6 +1004,7 @@ static const CGFloat kLayoutImageScrollViewAnimationDuration = 0.25;
UIImage *originalImage = self.originalImage;
RSKImageCropMode cropMode = self.cropMode;
CGRect cropRect = self.cropRect;
CGRect imageRect = self.imageRect;
CGFloat rotationAngle = self.rotationAngle;
CGFloat zoomScale = self.imageScrollView.zoomScale;
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), ^{
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(), ^{
[self.delegate imageCropViewController:self didCropImage:croppedImage usingCropRect:cropRect rotationAngle:rotationAngle];

View File

@ -1,9 +1,25 @@
//
// RSKInternalUtility.h
// RSKImageCropperExample
//
// Created by Ruslan Skorb on 9/5/15.
// Copyright (c) 2015 Ruslan Skorb. All rights reserved.
// Copyright (c) 2015-present Ruslan Skorb, http://ruslanskorb.com/
//
// 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>

View File

@ -1,9 +1,25 @@
//
// RSKInternalUtility.m
// RSKImageCropperExample
//
// Created by Ruslan Skorb on 9/5/15.
// Copyright (c) 2015 Ruslan Skorb. All rights reserved.
// Copyright (c) 2015-present Ruslan Skorb, http://ruslanskorb.com/
//
// 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"

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.
## 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
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>
<string>PSGroupSpecifier</string>
</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>
<key>FooterText</key>
<string>MIT License

View File

@ -1,8 +1,8 @@
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"
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"
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_LDFLAGS = $(inherited) -ObjC -l"QBImagePickerController" -l"RNImageCropPicker" -l"RSKImageCropper" -l"React" -l"stdc++" -l"yoga" -framework "JavaScriptCore" -framework "Photos" -framework "QuartzCore" -framework "UIKit"
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}/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/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"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_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.

View File

@ -1,8 +1,8 @@
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"
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"
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_LDFLAGS = $(inherited) -ObjC -l"QBImagePickerController" -l"RNImageCropPicker" -l"RSKImageCropper" -l"React" -l"stdc++" -l"yoga" -framework "JavaScriptCore" -framework "Photos" -framework "QuartzCore" -framework "UIKit"
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}/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/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"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_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.

View File

@ -1,6 +1,6 @@
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/QBImagePickerController
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"
PODS_BUILD_DIR = ${BUILD_DIR}
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
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"
PODS_BUILD_DIR = ${BUILD_DIR}
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
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"
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)

View File

@ -1,7 +1,7 @@
CLANG_CXX_LANGUAGE_STANDARD = c++14
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/React
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"
OTHER_LDFLAGS = -l"stdc++" -framework "JavaScriptCore"
PODS_BUILD_DIR = ${BUILD_DIR}

View File

@ -1,6 +1,6 @@
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/yoga
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_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_ROOT = ${SRCROOT}

View File

@ -62,6 +62,7 @@
832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
8A159EDB97C44E52AF62D69C /* libRNSVG.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA50CE47374C4C35BE6D9D58 /* libRNSVG.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 */; };
B88F586F1FBF57F600B352B8 /* libRCTPushNotification.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88F58461FBF55E200B352B8 /* libRCTPushNotification.a */; };
B8971BB2202A093B0000D245 /* libKeyboardTrackingView.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B8971BB1202A091D0000D245 /* libKeyboardTrackingView.a */; };
@ -380,6 +381,13 @@
remoteGlobalIDString = 134814201AA4EA6300B7C361;
remoteInfo = RNNotifications;
};
7AD44CF421518C610099D147 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = B1A58A7ACB0E4453A44AEC38 /* RNGestureHandler.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 134814201AA4EA6300B7C361;
remoteInfo = RNGestureHandler;
};
7AFB804B205AE63100D004E7 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
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>"; };
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>"; };
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>"; };
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>"; };
@ -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>"; };
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>"; };
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>"; };
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>"; };
@ -632,6 +642,7 @@
BAB7DC22804246F3923A1833 /* libFastImage.a in Frameworks */,
F5BF54DC78E1411B8343933B /* libRNI18n.a in Frameworks */,
50046CB6BDA69B9232CF66D9 /* libPods-RocketChatRN.a in Frameworks */,
95E57ADEB9A0487791D2C50E /* libRNGestureHandler.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -889,6 +900,14 @@
name = Products;
sourceTree = "<group>";
};
7AD44CF121518C610099D147 /* Products */ = {
isa = PBXGroup;
children = (
7AD44CF521518C610099D147 /* libRNGestureHandler.a */,
);
name = Products;
sourceTree = "<group>";
};
7AFB8036205AE63000D004E7 /* Products */ = {
isa = PBXGroup;
children = (
@ -928,6 +947,7 @@
1845C223DA364898A8400573 /* FastImage.xcodeproj */,
22D3971EAF2E4660B4FAB3DD /* RNI18n.xcodeproj */,
0B82BCC462E84F308C5B5CD1 /* RNFetchBlob.xcodeproj */,
B1A58A7ACB0E4453A44AEC38 /* RNGestureHandler.xcodeproj */,
);
name = Libraries;
sourceTree = "<group>";
@ -1039,6 +1059,7 @@
921481B47B50490CA761932E /* libRNI18n.a */,
C01CD6D4653143EEB5100C3A /* libRNI18n-tvOS.a */,
1A34D902CC074FF1BCC7DB48 /* libimageCropPicker.a */,
58E5009FCA8D40E59303C3DD /* libRNGestureHandler.a */,
);
name = "Recovered References";
sourceTree = "<group>";
@ -1281,6 +1302,10 @@
ProductGroup = 7A8C912120F39A8000C8F5EE /* Products */;
ProjectRef = 0B82BCC462E84F308C5B5CD1 /* RNFetchBlob.xcodeproj */;
},
{
ProductGroup = 7AD44CF121518C610099D147 /* Products */;
ProjectRef = B1A58A7ACB0E4453A44AEC38 /* RNGestureHandler.xcodeproj */;
},
{
ProductGroup = 7A770EBC20BECDC7001AD51A /* Products */;
ProjectRef = 22D3971EAF2E4660B4FAB3DD /* RNI18n.xcodeproj */;
@ -1608,6 +1633,13 @@
remoteRef = 7A8DEB5120ED0BDE00C5DCE4 /* PBXContainerItemProxy */;
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 */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
@ -1944,6 +1976,7 @@
"$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**",
"$(SRCROOT)/../node_modules/react-native-i18n/ios",
"$(SRCROOT)/../node_modules/rn-fetch-blob/ios/**",
"$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**",
);
INFOPLIST_FILE = RocketChatRNTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
@ -1961,6 +1994,7 @@
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
);
OTHER_LDFLAGS = (
"-ObjC",
@ -1992,6 +2026,7 @@
"$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**",
"$(SRCROOT)/../node_modules/react-native-i18n/ios",
"$(SRCROOT)/../node_modules/rn-fetch-blob/ios/**",
"$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**",
);
INFOPLIST_FILE = RocketChatRNTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
@ -2009,6 +2044,7 @@
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
);
OTHER_LDFLAGS = (
"-ObjC",
@ -2053,6 +2089,7 @@
"$(SRCROOT)/../node_modules/react-native-i18n/ios",
"$(SRCROOT)/../node_modules/react-native-notifications/RNNotifications",
"$(SRCROOT)/../node_modules/rn-fetch-blob/ios/**",
"$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**",
);
INFOPLIST_FILE = RocketChatRN/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
@ -2102,6 +2139,7 @@
"$(SRCROOT)/../node_modules/react-native-i18n/ios",
"$(SRCROOT)/../node_modules/react-native-notifications/RNNotifications",
"$(SRCROOT)/../node_modules/rn-fetch-blob/ios/**",
"$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**",
);
INFOPLIST_FILE = RocketChatRN/Info.plist;
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-i18n/ios",
"$(SRCROOT)/../node_modules/rn-fetch-blob/ios/**",
"$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**",
);
INFOPLIST_FILE = "RocketChatRN-tvOS/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
@ -2162,6 +2201,7 @@
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
);
OTHER_LDFLAGS = (
"-ObjC",
@ -2203,6 +2243,7 @@
"$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**",
"$(SRCROOT)/../node_modules/react-native-i18n/ios",
"$(SRCROOT)/../node_modules/rn-fetch-blob/ios/**",
"$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**",
);
INFOPLIST_FILE = "RocketChatRN-tvOS/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
@ -2219,6 +2260,7 @@
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
);
OTHER_LDFLAGS = (
"-ObjC",
@ -2259,6 +2301,7 @@
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
);
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.RocketChatRN-tvOSTests";
PRODUCT_NAME = "$(TARGET_NAME)";
@ -2295,6 +2338,7 @@
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
);
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.RocketChatRN-tvOSTests";
PRODUCT_NAME = "$(TARGET_NAME)";

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