From 3c2fd626af787b9531d5fea8b2dde0c242463ae6 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento Date: Thu, 10 Aug 2017 17:09:54 -0300 Subject: [PATCH] Add basic image upload --- android/app/build.gradle | 1 + .../com/rocketchatrn/MainApplication.java | 2 + android/settings.gradle | 2 + app/components/Message.js | 2 +- app/components/MessageBox.js | 72 ++++++++++++++++++- app/lib/rocketchat.js | 55 +++++++++++++- app/views/room.js | 1 + ios/RocketChatRN.xcodeproj/project.pbxproj | 42 +++-------- ios/RocketChatRN/Info.plist | 6 +- package.json | 1 + 10 files changed, 147 insertions(+), 37 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 10b7da622..cb1425889 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -134,6 +134,7 @@ android { dependencies { compile project(':react-native-svg') + compile project(':react-native-image-picker') compile project(':react-native-vector-icons') compile project(':react-native-fetch-blob') compile project(':react-native-zeroconf') diff --git a/android/app/src/main/java/com/rocketchatrn/MainApplication.java b/android/app/src/main/java/com/rocketchatrn/MainApplication.java index 6926fa93c..f55f4fcc1 100644 --- a/android/app/src/main/java/com/rocketchatrn/MainApplication.java +++ b/android/app/src/main/java/com/rocketchatrn/MainApplication.java @@ -4,6 +4,7 @@ import android.app.Application; import com.facebook.react.ReactApplication; import com.horcrux.svg.SvgPackage; +import com.imagepicker.ImagePickerPackage; import com.oblador.vectoricons.VectorIconsPackage; import com.RNFetchBlob.RNFetchBlobPackage; import com.balthazargronon.RCTZeroconf.ZeroconfReactPackage; @@ -29,6 +30,7 @@ public class MainApplication extends Application implements ReactApplication { return Arrays.asList( new MainReactPackage(), new SvgPackage(), + new ImagePickerPackage(), new VectorIconsPackage(), new RNFetchBlobPackage(), new ZeroconfReactPackage(), diff --git a/android/settings.gradle b/android/settings.gradle index 2b8a47531..fcc9db102 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,6 +1,8 @@ rootProject.name = 'RocketChatRN' include ':react-native-svg' project(':react-native-svg').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-svg/android') +include ':react-native-image-picker' +project(':react-native-image-picker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-image-picker/android') include ':react-native-vector-icons' project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android') include ':react-native-fetch-blob' diff --git a/app/components/Message.js b/app/components/Message.js index 7cc2cf616..bbf3d0cbf 100644 --- a/app/components/Message.js +++ b/app/components/Message.js @@ -59,7 +59,7 @@ export default class Message extends React.PureComponent { extraStyle.opacity = 0.3; } - const msg = emojify(this.props.item.msg || 'asd', { output: 'unicode' }); + const msg = emojify(this.props.item.msg, { output: 'unicode' }); let username = this.props.item.u.username; const position = username.length % colors.length; diff --git a/app/components/MessageBox.js b/app/components/MessageBox.js index 9145ffb5a..8bd34bca7 100644 --- a/app/components/MessageBox.js +++ b/app/components/MessageBox.js @@ -1,22 +1,39 @@ import React from 'react'; import PropTypes from 'prop-types'; import { View, TextInput, StyleSheet } from 'react-native'; +import Icon from 'react-native-vector-icons/MaterialIcons'; +import ImagePicker from 'react-native-image-picker'; +import RNFetchBlob from 'react-native-fetch-blob'; +import RocketChat from '../lib/rocketchat'; const styles = StyleSheet.create({ textBox: { paddingTop: 1, - backgroundColor: '#ccc' + borderTopWidth: 1, + borderTopColor: '#ccc', + backgroundColor: '#fff', + flexDirection: 'row', + alignItems: 'center' }, textBoxInput: { height: 40, backgroundColor: '#fff', - paddingLeft: 15 + flexGrow: 1 + }, + fileButton: { + color: '#aaa', + paddingLeft: 23, + paddingRight: 20, + paddingTop: 10, + paddingBottom: 10, + fontSize: 20 } }); export default class MessageBox extends React.PureComponent { static propTypes = { - onSubmit: PropTypes.func.isRequired + onSubmit: PropTypes.func.isRequired, + rid: PropTypes.string.isRequired } constructor(props) { @@ -36,9 +53,58 @@ export default class MessageBox extends React.PureComponent { this.setState({ text: '' }); }; + addFile = () => { + const options = { + customButtons: [{ + name: 'import', title: 'Import File From' + }] + }; + + ImagePicker.showImagePicker(options, (response) => { + console.log('Response = ', response); + + if (response.didCancel) { + console.log('User cancelled image picker'); + } else if (response.error) { + console.log('ImagePicker Error: ', response.error); + } else if (response.customButton) { + console.log('User tapped custom button: ', response.customButton); + } else { + const fileInfo = { + name: response.fileName, + size: response.fileSize, + type: response.type || 'image/jpeg', + rid: this.props.rid, + // description: '', + store: 'Uploads' + }; + + RocketChat.ufsCreate(fileInfo).then((result) => { + RNFetchBlob.fetch('POST', result.url, { + 'Content-Type': 'application/octet-stream' + }, response.data).then(() => { + RocketChat.ufsComplete(result.fileId, fileInfo.store, result.token) + .then((completeRresult) => { + RocketChat.sendFileMessage(completeRresult.rid, { + _id: completeRresult._id, + type: completeRresult.type, + size: completeRresult.size, + name: completeRresult.name, + url: completeRresult.path + }); + }); + }).catch((err) => { + console.log({ err }); + }); + }); + } + }); + } + render() { return ( + { - console.log('changed', ddbMessage); + // console.log('changed', ddbMessage); if (ddbMessage.collection === 'stream-room-messages') { realm.write(() => { const message = ddbMessage.fields.args[0]; @@ -187,6 +187,59 @@ const RocketChat = { return resolve(result); }); }); + }, + + + /* + "name":"yXfExLErmNR5eNPx7.png" + "size":961 + "type":"image/png" + "rid":"GENERAL" + "description":"" + "store":"fileSystem" + */ + ufsCreate(fileInfo) { + return new Promise((resolve, reject) => { + Meteor.call('ufsCreate', fileInfo, (error, result) => { + if (error) { + return reject(error); + } + return resolve(result); + }); + }); + }, + + // ["ZTE8CKHJt7LATv7Me","fileSystem","e8E96b2819" + ufsComplete(fileId, store, token) { + return new Promise((resolve, reject) => { + Meteor.call('ufsComplete', fileId, store, token, (error, result) => { + if (error) { + return reject(error); + } + return resolve(result); + }); + }); + }, + + /* + - "GENERAL" + - { + "type":"image/png", + "size":961, + "name":"yXfExLErmNR5eNPx7.png", + "description":"", + "url":"/ufs/fileSystem/ZTE8CKHJt7LATv7Me/yXfExLErmNR5eNPx7.png" + } + */ + sendFileMessage(rid, message) { + return new Promise((resolve, reject) => { + Meteor.call('sendFileMessage', rid, null, message, (error, result) => { + if (error) { + return reject(error); + } + return resolve(result); + }); + }); } }; diff --git a/app/views/room.js b/app/views/room.js index 3fa23fa71..b3058f01f 100644 --- a/app/views/room.js +++ b/app/views/room.js @@ -124,6 +124,7 @@ export default class RoomView extends React.Component { return ( ); } diff --git a/ios/RocketChatRN.xcodeproj/project.pbxproj b/ios/RocketChatRN.xcodeproj/project.pbxproj index 692e55f7d..960d9faf5 100644 --- a/ios/RocketChatRN.xcodeproj/project.pbxproj +++ b/ios/RocketChatRN.xcodeproj/project.pbxproj @@ -5,7 +5,6 @@ }; objectVersion = 46; objects = { - /* Begin PBXBuildFile section */ 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; }; 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; }; @@ -54,6 +53,7 @@ CBD0E0A35B174C4DBFED3B31 /* Zocial.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E528DE3A405E43B4A37ABA68 /* Zocial.ttf */; }; D6408D9E4A864FF6BA986857 /* SimpleLineIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 8A2DD67ADD954AD9873F45FC /* SimpleLineIcons.ttf */; }; EF736EF520A64AE8820E684A /* libRealmReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DF26CC845883492D8AC8869B /* libRealmReact.a */; }; + C758F0BD5C3244E2BA073E61 /* libRNImagePicker.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B696712EE2345A59F007A88 /* libRNImagePicker.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -365,6 +365,8 @@ DF26CC845883492D8AC8869B /* libRealmReact.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRealmReact.a; sourceTree = ""; }; E528DE3A405E43B4A37ABA68 /* Zocial.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Zocial.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Zocial.ttf"; sourceTree = ""; }; F88C6541BD764BEEABB87272 /* Octicons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Octicons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Octicons.ttf"; sourceTree = ""; }; + 4B38C7E37A8748E0BC665078 /* RNImagePicker.xcodeproj */ = {isa = PBXFileReference; name = "RNImagePicker.xcodeproj"; path = "../node_modules/react-native-image-picker/ios/RNImagePicker.xcodeproj"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; }; + 3B696712EE2345A59F007A88 /* libRNImagePicker.a */ = {isa = PBXFileReference; name = "libRNImagePicker.a"; path = "libRNImagePicker.a"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -398,6 +400,7 @@ BED2B77AA660460E8BC9F8E0 /* libRNFetchBlob.a in Frameworks */, 77C35F50C01C43668188886C /* libRNVectorIcons.a in Frameworks */, 8A159EDB97C44E52AF62D69C /* libRNSVG.a in Frameworks */, + C758F0BD5C3244E2BA073E61 /* libRNImagePicker.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -589,6 +592,7 @@ 4CD38E4891ED4601B7481448 /* RNFetchBlob.xcodeproj */, 22A8B76C8EBA443BB97CE82D /* RNVectorIcons.xcodeproj */, C23AEF1D9EBE4A38A1A6B97B /* RNSVG.xcodeproj */, + 4B38C7E37A8748E0BC665078 /* RNImagePicker.xcodeproj */, ); name = Libraries; sourceTree = ""; @@ -1287,17 +1291,13 @@ "$(SRCROOT)/../node_modules/react-native-fetch-blob/ios/**", "$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager", "$(SRCROOT)/../node_modules/react-native-svg/ios/**", + "$(SRCROOT)/../node_modules/react-native-image-picker/ios", ); INFOPLIST_FILE = RocketChatRNTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", ); OTHER_LDFLAGS = ( "-ObjC", @@ -1321,17 +1321,13 @@ "$(SRCROOT)/../node_modules/react-native-fetch-blob/ios/**", "$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager", "$(SRCROOT)/../node_modules/react-native-svg/ios/**", + "$(SRCROOT)/../node_modules/react-native-image-picker/ios", ); INFOPLIST_FILE = RocketChatRNTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", ); OTHER_LDFLAGS = ( "-ObjC", @@ -1357,6 +1353,7 @@ "$(SRCROOT)/../node_modules/react-native-fetch-blob/ios/**", "$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager", "$(SRCROOT)/../node_modules/react-native-svg/ios/**", + "$(SRCROOT)/../node_modules/react-native-image-picker/ios", ); INFOPLIST_FILE = RocketChatRN/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -1387,6 +1384,7 @@ "$(SRCROOT)/../node_modules/react-native-fetch-blob/ios/**", "$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager", "$(SRCROOT)/../node_modules/react-native-svg/ios/**", + "$(SRCROOT)/../node_modules/react-native-image-picker/ios", ); INFOPLIST_FILE = RocketChatRN/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -1422,16 +1420,12 @@ "$(SRCROOT)/../node_modules/react-native-fetch-blob/ios/**", "$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager", "$(SRCROOT)/../node_modules/react-native-svg/ios/**", + "$(SRCROOT)/../node_modules/react-native-image-picker/ios", ); INFOPLIST_FILE = "RocketChatRN-tvOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", ); OTHER_LDFLAGS = ( "-ObjC", @@ -1465,16 +1459,12 @@ "$(SRCROOT)/../node_modules/react-native-fetch-blob/ios/**", "$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager", "$(SRCROOT)/../node_modules/react-native-svg/ios/**", + "$(SRCROOT)/../node_modules/react-native-image-picker/ios", ); INFOPLIST_FILE = "RocketChatRN-tvOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", ); OTHER_LDFLAGS = ( "-ObjC", @@ -1504,11 +1494,6 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", ); PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.RocketChatRN-tvOSTests"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1534,11 +1519,6 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", ); PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.RocketChatRN-tvOSTests"; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/ios/RocketChatRN/Info.plist b/ios/RocketChatRN/Info.plist index 0d8c0bab9..93710c115 100644 --- a/ios/RocketChatRN/Info.plist +++ b/ios/RocketChatRN/Info.plist @@ -2,6 +2,10 @@ + NSCameraUsageDescription + Upload images from camera + NSPhotoLibraryUsageDescription + Upload images from library CFBundleDevelopmentRegion en CFBundleDisplayName @@ -36,7 +40,7 @@ NSLocationWhenInUseUsageDescription - + UILaunchStoryboardName LaunchScreen UIRequiredDeviceCapabilities diff --git a/package.json b/package.json index c459c63b0..36c730b18 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "react-native-action-button": "^2.7.2", "react-native-easy-markdown": "git+https://github.com/lappalj4/react-native-easy-markdown.git", "react-native-fetch-blob": "^0.10.8", + "react-native-image-picker": "^0.26.3", "react-native-form-generator": "^0.9.9", "react-native-img-cache": "^1.4.0", "react-native-meteor": "^1.1.0",