From bf4463b866db2c9c991908e782a62906c856c77d Mon Sep 17 00:00:00 2001 From: enahum Date: Mon, 4 Dec 2017 12:20:10 -0300 Subject: [PATCH] Previewer (#1246) * Fix heic * Change previwer to use the swiper instead a simple ScrollView --- app/actions/views/file_upload.js | 5 +- app/components/swiper.js | 24 ++- app/screens/image_preview/image_preview.js | 238 +++++++++++---------- app/screens/image_preview/previewer.js | 2 +- 4 files changed, 141 insertions(+), 128 deletions(-) diff --git a/app/actions/views/file_upload.js b/app/actions/views/file_upload.js index 14753182f..aada24b93 100644 --- a/app/actions/views/file_upload.js +++ b/app/actions/views/file_upload.js @@ -16,6 +16,7 @@ export function handleUploadFiles(files, rootId) { const channelId = state.entities.channels.currentChannelId; const formData = new FormData(); const clientIds = []; + const re = /heic/i; files.forEach((file) => { let name = file.fileName; @@ -24,9 +25,9 @@ export function handleUploadFiles(files, rootId) { const uri = file.uri; const clientId = generateId(); - if (extension === 'HEIC') { + if (re.test(extension)) { extension = 'JPG'; - name = name.replace(/HEIC/, 'jpg'); + name = name.replace(re, 'jpg'); mimeType = 'image/jpeg'; } diff --git a/app/components/swiper.js b/app/components/swiper.js index a06ab2847..5da1e52ba 100644 --- a/app/components/swiper.js +++ b/app/components/swiper.js @@ -4,7 +4,6 @@ import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; import { - InteractionManager, View, ScrollView, ViewPagerAndroid, @@ -30,7 +29,8 @@ export default class Swiper extends PureComponent { PropTypes.object, PropTypes.number ]), - width: PropTypes.number + width: PropTypes.number, + onScrollBegin: PropTypes.func }; static defaultProps = { @@ -38,7 +38,8 @@ export default class Swiper extends PureComponent { keyboardShouldPersistTaps: 'handled', onIndexChanged: () => null, scrollEnabled: true, - showsPagination: true + showsPagination: true, + onScrollBegin: () => true }; constructor(props) { @@ -84,6 +85,7 @@ export default class Swiper extends PureComponent { onScrollBegin = () => { this.isScrolling = true; + this.props.onScrollBegin(); }; onScrollEnd = (e) => { @@ -98,11 +100,15 @@ export default class Swiper extends PureComponent { this.updateIndex(e.nativeEvent.contentOffset.x); }; - scrollToStart = () => { - if (Platform.OS === 'ios') { - InteractionManager.runAfterInteractions(() => { - this.scrollView.scrollTo({x: 0, animated: false}); - }); + onPageScrollStateChanged = (e) => { + switch (e) { + case 'idle': + this.isScrolling = false; + break; + case 'dragging': + this.isScrolling = true; + this.props.onScrollBegin(); + break; } }; @@ -141,8 +147,8 @@ export default class Swiper extends PureComponent { { - if (this.scrollView) { - this.scrollView.scrollTo({x: (this.state.currentFile) * this.props.deviceWidth, animated: false}); - } - Animated.timing(this.state.wrapperViewOpacity, { toValue: 1, duration: 100 @@ -113,12 +110,6 @@ export default class ImagePreview extends PureComponent { } componentWillReceiveProps(nextProps) { - if (this.props.deviceWidth !== nextProps.deviceWidth) { - if (this.scrollView) { - this.scrollView.scrollTo({x: (this.state.currentFile * nextProps.deviceWidth), animated: true}); - } - } - if (!nextProps.files.length) { this.showDeletedFilesAlert(); } @@ -130,14 +121,40 @@ export default class ImagePreview extends PureComponent { } } - attachScrollView = (c) => { - this.scrollView = c; - }; - close = () => { this.props.navigator.dismissModal({animationType: 'none'}); }; + getPreviews = () => { + return this.state.files.map((file, index) => { + let mime = file.mime_type; + if (mime && mime.includes(';')) { + mime = mime.split(';')[0]; + } + + let component; + + if (file.has_preview_image || file.mime_type === 'image/gif') { + component = this.renderPreviewer(file, index); + } else if (SUPPORTED_DOCS_FORMAT.includes(mime)) { + component = this.renderAttachmentDocument(file); + } else if (SUPPORTED_VIDEO_FORMAT.includes(file.mime_type)) { + component = this.renderVideoPreview(file); + } else { + component = this.renderAttachmentIcon(file); + } + + return ( + + {component} + + ); + }); + }; + handleClose = () => { if (this.state.showFileInfo) { this.close(); @@ -151,6 +168,12 @@ export default class ImagePreview extends PureComponent { } }; + handleLayout = () => { + if (this.refs.swiper) { + this.refs.swiper.runOnLayout = true; + } + }; + handleImageDoubleTap = (x, y) => { this.zoomableImages[this.state.currentFile].toggleZoom(x, y); }; @@ -160,25 +183,17 @@ export default class ImagePreview extends PureComponent { this.setHeaderAndFileInfoVisible(!this.state.showFileInfo); }; - handleScroll = (event) => { - const offset = event.nativeEvent.contentOffset.x / this.props.deviceWidth; - const wholeNumber = Number((offset).toFixed(0)); - - if (Math.abs(offset - wholeNumber) < 0.01) { - this.setState({ - currentFile: wholeNumber, - pagingEnabled: true, - shouldShrinkImages: false - }); - } else if (!this.state.shouldShrinkImages && !this.state.isZooming) { - this.setState({ - shouldShrinkImages: true - }); + handleIndexChanged = (currentFile) => { + if (Number.isInteger(currentFile)) { + this.setState({currentFile, limitOpacity: new Animated.Value(0)}); } }; - handleScrollStopped = () => { - EventEmitter.emit('stop-video-playback'); + handleScroll = () => { + Animated.timing(this.state.limitOpacity, { + toValue: 1, + duration: 100 + }).start(); }; handleVideoSeek = (seeking) => { @@ -399,42 +414,46 @@ export default class ImagePreview extends PureComponent { renderDownloadButton = () => { const {canDownloadFiles} = this.props; - const {files} = this.state; + const {currentFile, files} = this.state; - const file = files[this.state.currentFile]; + const file = files[currentFile]; - let icon; - let action = emptyFunction; - if (canDownloadFiles) { - if (Platform.OS === 'android') { - action = this.showDownloadOptions; - icon = ( - - ); - } else if (file.has_preview_image || SUPPORTED_VIDEO_FORMAT.includes(file.mime_type)) { - action = this.showDownloadOptions; - icon = ( - - ); + if (file) { + let icon; + let action = emptyFunction; + if (canDownloadFiles) { + if (Platform.OS === 'android') { + action = this.showDownloadOptions; + icon = ( + + ); + } else if (file.has_preview_image || SUPPORTED_VIDEO_FORMAT.includes(file.mime_type)) { + action = this.showDownloadOptions; + icon = ( + + ); + } } + + return ( + + {icon} + + ); } - return ( - - {icon} - - ); + return null; }; renderPreviewer = (file, index) => { @@ -476,56 +495,48 @@ export default class ImagePreview extends PureComponent { ); }; + renderSwiper = () => { + return ( + + {this.getPreviews()} + + ); + }; + render() { + const {currentFile, files} = this.state; + const file = files[currentFile]; + + if (!file) { + return null; + } + + const fileName = file ? file.name : ''; + return ( - + - - {this.state.files.map((file, index) => { - let mime = file.mime_type; - if (mime && mime.includes(';')) { - mime = mime.split(';')[0]; - } - - let component; - if (file.has_preview_image || file.mime_type === 'image/gif') { - component = this.renderPreviewer(file, index); - } else if (SUPPORTED_DOCS_FORMAT.includes(mime)) { - component = this.renderAttachmentDocument(file); - } else if (SUPPORTED_VIDEO_FORMAT.includes(file.mime_type)) { - component = this.renderVideoPreview(file); - } else { - component = this.renderAttachmentIcon(file); - } - - return ( - - {component} - - ); - })} - + {this.renderSwiper()} @@ -540,7 +551,7 @@ export default class ImagePreview extends PureComponent { /> - {`${this.state.currentFile + 1}/${this.state.files.length}`} + {`${currentFile + 1}/${files.length}`} {this.renderDownloadButton()} @@ -555,7 +566,7 @@ export default class ImagePreview extends PureComponent { pointerEvents='none' > - {this.state.files[this.state.currentFile].name} + {fileName} @@ -563,7 +574,7 @@ export default class ImagePreview extends PureComponent { - +