From 33baf35de6169bbc05c7f6c661150bfef86d804c Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Mon, 7 May 2018 17:41:36 -0300 Subject: [PATCH] Better image cache component (#292) * react-native-img-cache removed * Improve list render * Support inside markdown --- __tests__/__snapshots__/RoomItem.js.snap | 132 +++- .../__snapshots__/Storyshots.test.js.snap | 660 +++++++++++++++++- android/app/build.gradle | 6 +- .../reactnative}/CustomTabsAndroid.java | 0 .../reactnative}/CustomTabsHelper.java | 0 .../rocketchat/reactnative}/MainActivity.java | 0 .../reactnative}/MainApplication.java | 4 +- .../reactnative}/RocketChatNativePackage.java | 0 android/build.gradle | 3 + android/settings.gradle | 2 + app/containers/Avatar.js | 21 +- app/containers/EmojiPicker/CustomEmoji.js | 4 +- app/containers/message/Image.js | 8 +- app/containers/message/Markdown.js | 10 +- app/containers/message/PhotoModal.js | 4 +- app/containers/message/Reply.js | 9 +- app/views/Photo.js | 36 - app/views/RoomView/ListView.js | 13 +- app/views/RoomsListView/Header/index.js | 4 +- ios/RocketChatRN.xcodeproj/project.pbxproj | 18 +- package-lock.json | 16 +- package.json | 2 +- 22 files changed, 854 insertions(+), 98 deletions(-) rename android/app/src/main/java/{com/rocketchatrn => chat/rocketchat/reactnative}/CustomTabsAndroid.java (100%) rename android/app/src/main/java/{com/rocketchatrn => chat/rocketchat/reactnative}/CustomTabsHelper.java (100%) rename android/app/src/main/java/{com/rocketchatrn => chat/rocketchat/reactnative}/MainActivity.java (100%) rename android/app/src/main/java/{com/rocketchatrn => chat/rocketchat/reactnative}/MainApplication.java (94%) rename android/app/src/main/java/{com/rocketchatrn => chat/rocketchat/reactnative}/RocketChatNativePackage.java (100%) delete mode 100644 app/views/Photo.js diff --git a/__tests__/__snapshots__/RoomItem.js.snap b/__tests__/__snapshots__/RoomItem.js.snap index 7322a46b6..9d388e323 100644 --- a/__tests__/__snapshots__/RoomItem.js.snap +++ b/__tests__/__snapshots__/RoomItem.js.snap @@ -546,7 +546,49 @@ exports[`render unread +999 1`] = ` > NA - + + + NA - + + + NA - + + + TE - + + + AA - + + + BB - + + + TE - + + + @@ -223,7 +391,49 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = ` > RC - + + + RC - + + + RC - + + + LC - + + + LC - + + + LC - + + + LC - + + + LC - + + + W - + + + WW - + + + - + + + ); return ( - {initials} + {this.state.showInitials && + + {initials} + + } {image} {this.props.children} ); diff --git a/app/containers/EmojiPicker/CustomEmoji.js b/app/containers/EmojiPicker/CustomEmoji.js index 8215f0ea6..2f10cb771 100644 --- a/app/containers/EmojiPicker/CustomEmoji.js +++ b/app/containers/EmojiPicker/CustomEmoji.js @@ -1,7 +1,7 @@ import React from 'react'; import { ViewPropTypes } from 'react-native'; import PropTypes from 'prop-types'; -import { CachedImage } from 'react-native-img-cache'; +import FastImage from 'react-native-fast-image'; import { connect } from 'react-redux'; @connect(state => ({ @@ -19,7 +19,7 @@ export default class CustomEmoji extends React.Component { render() { const { baseUrl, emoji, style } = this.props; return ( - diff --git a/app/containers/message/Image.js b/app/containers/message/Image.js index 2bf78435c..7724edbef 100644 --- a/app/containers/message/Image.js +++ b/app/containers/message/Image.js @@ -1,6 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; -import { CachedImage } from 'react-native-img-cache'; +import FastImage from 'react-native-fast-image'; import { TouchableOpacity, StyleSheet } from 'react-native'; import { connect } from 'react-redux'; import PhotoModal from './PhotoModal'; @@ -13,8 +13,8 @@ const styles = StyleSheet.create({ }, image: { width: 320, - height: 200, - resizeMode: 'cover' + height: 200 + // resizeMode: 'cover' }, labelContainer: { alignItems: 'flex-start' @@ -56,7 +56,7 @@ export default class extends React.PureComponent { onPress={() => this._onPressButton()} style={styles.button} > - diff --git a/app/containers/message/Markdown.js b/app/containers/message/Markdown.js index 3c88b09d5..1dc11b8ff 100644 --- a/app/containers/message/Markdown.js +++ b/app/containers/message/Markdown.js @@ -94,6 +94,13 @@ const defaultRules = { const codeStyle = StyleSheet.flatten(styles.codeStyle); +// Support +const formatText = text => + text.replace( + new RegExp('(?:<|<)((?:https|http):\\/\\/[^\\|]+)\\|(.+?)(?=>|>)(?:>|>)', 'gm'), + (match, url, title) => `[${ title }](${ url })` + ); + @connect(state => ({ customEmojis: state.customEmojis })) @@ -108,7 +115,8 @@ export default class Markdown extends React.Component { if (!msg) { return null; } - const m = emojify(msg, { output: 'unicode' }); + let m = formatText(msg); + m = emojify(m, { output: 'unicode' }); const s = StyleSheet.flatten(style); return ( diff --git a/app/containers/message/PhotoModal.js b/app/containers/message/PhotoModal.js index 7d378794e..0bb21888e 100644 --- a/app/containers/message/PhotoModal.js +++ b/app/containers/message/PhotoModal.js @@ -1,6 +1,6 @@ import React from 'react'; import { ScrollView, View, Text, TouchableWithoutFeedback } from 'react-native'; -import { CachedImage } from 'react-native-img-cache'; +import FastImage from 'react-native-fast-image'; import PropTypes from 'prop-types'; import Modal from 'react-native-modal'; @@ -50,7 +50,7 @@ export default class PhotoModal extends React.PureComponent { - { openLink(attachment.title_link || attachment.author_link); }; -// Support -const formatText = text => - text.replace( - new RegExp('(?:<|<)((?:https|http):\\/\\/[^\\|]+)\\|(.+?)(?=>|>)(?:>|>)', 'gm'), - (match, url, title) => `[${ title }](${ url })` - ); - const Reply = ({ attachment, timeFormat }) => { if (!attachment) { return null; @@ -113,7 +106,7 @@ const Reply = ({ attachment, timeFormat }) => { }; const renderText = () => ( - attachment.text ? : null + attachment.text ? : null ); const renderFields = () => { diff --git a/app/views/Photo.js b/app/views/Photo.js deleted file mode 100644 index a13dd4adb..000000000 --- a/app/views/Photo.js +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react'; -import { ScrollView, View } from 'react-native'; -import { CachedImage } from 'react-native-img-cache'; -import PropTypes from 'prop-types'; - -const styles = { - imageWrapper: { - flex: 1, - alignItems: 'stretch', - backgroundColor: '#000' - }, - image: { - flex: 1 - } -}; - -export default class Photo extends React.PureComponent { - static propTypes = { - navigation: PropTypes.object.isRequired - } - render() { - const { image } = this.props.navigation.state.params; - return ( - - - - - - ); - } -} diff --git a/app/views/RoomView/ListView.js b/app/views/RoomView/ListView.js index 0c0d587b8..3dd10fbea 100644 --- a/app/views/RoomView/ListView.js +++ b/app/views/RoomView/ListView.js @@ -9,7 +9,6 @@ import PropTypes from 'prop-types'; import DateSeparator from './DateSeparator'; import UnreadSeparator from './UnreadSeparator'; import styles from './styles'; -import throttle from '../../utils/throttle'; import Typing from '../../containers/Typing'; import database from '../../lib/realm'; import scrollPersistTaps from '../../utils/scrollPersistTaps'; @@ -52,17 +51,16 @@ export class List extends React.Component { return this.props.end !== nextProps.end; } componentWillUnmount() { - this.date.removeListener(this.updateState); - this.date.removeAllListeners(); + this.data.removeAllListeners(); this.updateState.stop(); } - updateState = throttle(() => { + updateState = () => { // this.setState({ this.dataSource = this.dataSource.cloneWithRows(this.data); LayoutAnimation.easeInEaseOut(); this.forceUpdate(); // }); - }, 2500); + }; render() { return ( item._id} - onEndReachedThreshold={0.5} + onEndReachedThreshold={100} renderFooter={this.props.renderFooter} renderHeader={() => } onEndReached={() => this.props.onEndReached(this.data)} dataSource={this.dataSource} renderRow={(item, previousItem) => this.props.renderRow(item, previousItem)} - initialListSize={10} + initialListSize={20} + pageSize={20} {...scrollPersistTaps} />); } diff --git a/app/views/RoomsListView/Header/index.js b/app/views/RoomsListView/Header/index.js index 3850acb72..e07b3dc37 100644 --- a/app/views/RoomsListView/Header/index.js +++ b/app/views/RoomsListView/Header/index.js @@ -4,7 +4,7 @@ import Icon from 'react-native-vector-icons/Ionicons'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import Modal from 'react-native-modal'; -import { CachedImage } from 'react-native-img-cache'; +import FastImage from 'react-native-fast-image'; import { HeaderBackButton } from 'react-navigation'; import Avatar from '../../../containers/Avatar'; @@ -118,7 +118,7 @@ export default class RoomsListHeaderView extends React.PureComponent { style={styles.headerButton} onPress={() => this.props.navigation.navigate({ key: 'DrawerOpen', routeName: 'DrawerOpen' })} > - diff --git a/ios/RocketChatRN.xcodeproj/project.pbxproj b/ios/RocketChatRN.xcodeproj/project.pbxproj index 0bf4d04e1..800e7e1a1 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 */; }; @@ -71,6 +70,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 */; }; + BAB7DC22804246F3923A1833 /* libFastImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FD2E2837F110483CA29EE0D4 /* libFastImage.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -535,6 +535,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 = ""; }; + 1845C223DA364898A8400573 /* FastImage.xcodeproj */ = {isa = PBXFileReference; name = "FastImage.xcodeproj"; path = "../node_modules/react-native-fast-image/ios/FastImage.xcodeproj"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; }; + FD2E2837F110483CA29EE0D4 /* libFastImage.a */ = {isa = PBXFileReference; name = "libFastImage.a"; path = "libFastImage.a"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -580,6 +582,7 @@ 0F026E58B8A6427D9A204D89 /* libSplashScreen.a in Frameworks */, 2C800DF680F8451599E80AF1 /* libSafariViewManager.a in Frameworks */, 74815BBCB91147C08C8F7B3D /* libRNAudio.a in Frameworks */, + BAB7DC22804246F3923A1833 /* libFastImage.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -839,6 +842,7 @@ 30FCE1B6376C423E94C9FBB0 /* SplashScreen.xcodeproj */, 4019A5E1911B4C61944FBCEC /* SafariViewManager.xcodeproj */, C21010507E5B4B37BA0E4C9D /* RNAudio.xcodeproj */, + 1845C223DA364898A8400573 /* FastImage.xcodeproj */, ); name = Libraries; sourceTree = ""; @@ -1768,6 +1772,7 @@ "$(SRCROOT)/../node_modules/react-native-splash-screen/ios", "$(SRCROOT)/../node_modules/react-native-safari-view", "$(SRCROOT)/../node_modules/react-native-audio/ios", + "$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**", ); INFOPLIST_FILE = RocketChatRNTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; @@ -1781,6 +1786,7 @@ "\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", ); OTHER_LDFLAGS = ( "-ObjC", @@ -1811,6 +1817,7 @@ "$(SRCROOT)/../node_modules/react-native-splash-screen/ios", "$(SRCROOT)/../node_modules/react-native-safari-view", "$(SRCROOT)/../node_modules/react-native-audio/ios", + "$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**", ); INFOPLIST_FILE = RocketChatRNTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; @@ -1824,6 +1831,7 @@ "\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", ); OTHER_LDFLAGS = ( "-ObjC", @@ -1864,6 +1872,7 @@ "$(SRCROOT)/../node_modules/react-native-safari-view", "$(SRCROOT)/../node_modules/react-native-audio/ios", "$(SRCROOT)/../../../react-native/React/**", + "$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**", ); INFOPLIST_FILE = RocketChatRN/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -1909,6 +1918,7 @@ "$(SRCROOT)/../node_modules/react-native-safari-view", "$(SRCROOT)/../node_modules/react-native-audio/ios", "$(SRCROOT)/../../../react-native/React/**", + "$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**", ); INFOPLIST_FILE = RocketChatRN/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -1952,6 +1962,7 @@ "$(SRCROOT)/../node_modules/react-native-splash-screen/ios", "$(SRCROOT)/../node_modules/react-native-safari-view", "$(SRCROOT)/../node_modules/react-native-audio/ios", + "$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**", ); INFOPLIST_FILE = "RocketChatRN-tvOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -1964,6 +1975,7 @@ "\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", ); OTHER_LDFLAGS = ( "-ObjC", @@ -2004,6 +2016,7 @@ "$(SRCROOT)/../node_modules/react-native-splash-screen/ios", "$(SRCROOT)/../node_modules/react-native-safari-view", "$(SRCROOT)/../node_modules/react-native-audio/ios", + "$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**", ); INFOPLIST_FILE = "RocketChatRN-tvOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -2016,6 +2029,7 @@ "\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", ); OTHER_LDFLAGS = ( "-ObjC", @@ -2052,6 +2066,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)"; @@ -2084,6 +2099,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)"; diff --git a/package-lock.json b/package-lock.json index af04587d6..3cb4700d2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15869,6 +15869,14 @@ "resolved": "https://registry.npmjs.org/react-native-fabric/-/react-native-fabric-0.5.1.tgz", "integrity": "sha512-NKYXiH8w/DjNXoozko1twjAd5F8shL/UiTVx/PQ8QNaasWpbxlXgeJ5exhDSIcDXao0AUdcPWJunYdSCjq208g==" }, + "react-native-fast-image": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/react-native-fast-image/-/react-native-fast-image-4.0.8.tgz", + "integrity": "sha512-/FC2M3ZDqmQRERQpYlyMhyr7eX5euvi9bXkowNY5A7t/bRB09LSsfQbk8FtI2stgSgA6d0YUXHt3ll7m/ZB0SQ==", + "requires": { + "prop-types": "15.6.1" + } + }, "react-native-fetch-blob": { "version": "0.10.8", "resolved": "https://registry.npmjs.org/react-native-fetch-blob/-/react-native-fetch-blob-0.10.8.tgz", @@ -15898,14 +15906,6 @@ "resolved": "https://registry.npmjs.org/react-native-image-picker/-/react-native-image-picker-0.26.7.tgz", "integrity": "sha1-rS7pV/f2zAE5aJPqA9hMsq2y43Y=" }, - "react-native-img-cache": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/react-native-img-cache/-/react-native-img-cache-1.5.3.tgz", - "integrity": "sha1-zP+6hmAwd9C+T53Aiv9Z4/VRCQs=", - "requires": { - "crypto-js": "3.1.9-1" - } - }, "react-native-iphone-x-helper": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.0.2.tgz", diff --git a/package.json b/package.json index 53125930e..949dfa320 100644 --- a/package.json +++ b/package.json @@ -46,9 +46,9 @@ "react-native-cached-image": "^1.4.3", "react-native-easy-markdown": "git+https://github.com/diegolmello/react-native-easy-markdown.git", "react-native-fabric": "^0.5.1", + "react-native-fast-image": "^4.0.8", "react-native-fetch-blob": "^0.10.8", "react-native-image-picker": "^0.26.7", - "react-native-img-cache": "^1.5.2", "react-native-keyboard-aware-scroll-view": "^0.5.0", "react-native-keyboard-input": "git+https://github.com/RocketChat/react-native-keyboard-input.git", "react-native-keyboard-tracking-view": "git+https://github.com/RocketChat/react-native-keyboard-tracking-view.git",