PLT-6033 Add loading spinner to image previewer (#387)
This commit is contained in:
parent
c049cb0f9d
commit
f37c308ab8
17 changed files with 211 additions and 71 deletions
11
app/actions/views/file_preview.js
Normal file
11
app/actions/views/file_preview.js
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {ViewTypes} from 'app/constants';
|
||||
|
||||
export function addFileToFetchCache(url) {
|
||||
return {
|
||||
type: ViewTypes.ADD_FILE_TO_FETCH_CACHE,
|
||||
url
|
||||
};
|
||||
}
|
||||
|
|
@ -16,12 +16,15 @@ export function handleUploadFiles(files, rootId, requestId) {
|
|||
const teamId = state.entities.teams.currentTeamId;
|
||||
const channelId = state.entities.channels.currentChannelId;
|
||||
const formData = new FormData();
|
||||
const clientIds = [];
|
||||
|
||||
files.forEach((file) => {
|
||||
const name = file.path.split('/').pop();
|
||||
const mimeType = lookupMimeType(name);
|
||||
const clientId = generateId();
|
||||
|
||||
clientIds.push(clientId);
|
||||
|
||||
const fileData = {
|
||||
uri: file.path,
|
||||
name,
|
||||
|
|
@ -38,6 +41,13 @@ export function handleUploadFiles(files, rootId, requestId) {
|
|||
formBoundary = '--mobile.client.file.upload';
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: ViewTypes.SET_TEMP_UPLOAD_FILES_FOR_POST_DRAFT,
|
||||
clientIds,
|
||||
channelId,
|
||||
rootId
|
||||
});
|
||||
|
||||
await uploadFile(teamId, channelId, formData, formBoundary, rootId, requestId)(dispatch, getState);
|
||||
};
|
||||
}
|
||||
|
|
@ -50,10 +60,10 @@ export function handleClearFiles(channelId, rootId) {
|
|||
};
|
||||
}
|
||||
|
||||
export function handleRemoveFile(fileId, channelId, rootId) {
|
||||
export function handleRemoveFile(clientId, channelId, rootId) {
|
||||
return {
|
||||
type: ViewTypes.REMOVE_FILE_FROM_POST_DRAFT,
|
||||
fileId,
|
||||
clientId,
|
||||
channelId,
|
||||
rootId
|
||||
};
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ import FileAttachmentPreview from './file_attachment_preview';
|
|||
|
||||
export default class FileAttachment extends PureComponent {
|
||||
static propTypes = {
|
||||
addFileToFetchCache: PropTypes.func.isRequired,
|
||||
fetchCache: PropTypes.object.isRequired,
|
||||
file: PropTypes.object.isRequired,
|
||||
theme: PropTypes.object.isRequired
|
||||
};
|
||||
|
|
@ -60,6 +62,8 @@ export default class FileAttachment extends PureComponent {
|
|||
if (file.has_preview_image) {
|
||||
fileAttachmentComponent = (
|
||||
<FileAttachmentPreview
|
||||
addFileToFetchCache={this.props.addFileToFetchCache}
|
||||
fetchCache={this.props.fetchCache}
|
||||
file={file}
|
||||
theme={theme}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import FileAttachment from './file_attachment';
|
|||
export default class FileAttachmentList extends Component {
|
||||
static propTypes = {
|
||||
actions: PropTypes.object.isRequired,
|
||||
fetchCache: PropTypes.object.isRequired,
|
||||
files: PropTypes.array.isRequired,
|
||||
hideOptionsContext: PropTypes.func.isRequired,
|
||||
onLongPress: PropTypes.func,
|
||||
|
|
@ -44,6 +45,8 @@ export default class FileAttachmentList extends Component {
|
|||
onPressOut={() => this.props.toggleSelected(false)}
|
||||
>
|
||||
<FileAttachment
|
||||
addFileToFetchCache={this.props.actions.addFileToFetchCache}
|
||||
fetchCache={this.props.fetchCache}
|
||||
file={file}
|
||||
theme={this.props.theme}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import {connect} from 'react-redux';
|
|||
|
||||
import {makeGetFilesForPost} from 'mattermost-redux/selectors/entities/files';
|
||||
import {loadFilesForPostIfNecessary} from 'app/actions/views/channel';
|
||||
import {addFileToFetchCache} from 'app/actions/views/file_preview';
|
||||
import {getTheme} from 'app/selectors/preferences';
|
||||
import {goToImagePreviewModal} from 'app/actions/navigation';
|
||||
|
||||
|
|
@ -16,6 +17,7 @@ function makeMapStateToProps() {
|
|||
return function mapStateToProps(state, ownProps) {
|
||||
return {
|
||||
...ownProps,
|
||||
fetchCache: state.views.fetchCache,
|
||||
files: getFilesForPost(state, ownProps.post),
|
||||
theme: getTheme(state)
|
||||
};
|
||||
|
|
@ -25,6 +27,7 @@ function makeMapStateToProps() {
|
|||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
addFileToFetchCache,
|
||||
goToImagePreviewModal,
|
||||
loadFilesForPostIfNecessary
|
||||
}, dispatch)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import React, {
|
|||
PureComponent
|
||||
} from 'react';
|
||||
import {
|
||||
ActivityIndicator,
|
||||
Animated,
|
||||
View,
|
||||
Image,
|
||||
StyleSheet
|
||||
|
|
@ -13,67 +15,110 @@ import {
|
|||
|
||||
import Client from 'mattermost-redux/client';
|
||||
|
||||
import genericIcon from 'assets/images/icons/generic.png';
|
||||
const {View: AnimatedView} = Animated;
|
||||
|
||||
export default class FileAttachmentPreview extends PureComponent {
|
||||
static propTypes = {
|
||||
file: PropTypes.object.isRequired,
|
||||
addFileToFetchCache: PropTypes.func.isRequired,
|
||||
fetchCache: PropTypes.object.isRequired,
|
||||
file: PropTypes.object,
|
||||
imageHeight: PropTypes.number,
|
||||
imageWidth: PropTypes.number,
|
||||
resizeMode: PropTypes.string,
|
||||
resizeMethod: PropTypes.string,
|
||||
wrapperBackgroundColor: PropTypes.string,
|
||||
wrapperHeight: PropTypes.number,
|
||||
wrapperWidth: PropTypes.number
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
fadeInOnLoad: false,
|
||||
imageHeight: 100,
|
||||
imageWidth: 100,
|
||||
loading: false,
|
||||
resizeMode: 'cover',
|
||||
resizeMethod: 'resize',
|
||||
wrapperBackgroundColor: '#fff',
|
||||
wrapperHeigh: 100,
|
||||
wrapperWidth: 100
|
||||
};
|
||||
|
||||
state = {
|
||||
opacity: new Animated.Value(0),
|
||||
requesting: true,
|
||||
retry: 0
|
||||
}
|
||||
|
||||
// Sometimes the request after a file upload errors out.
|
||||
// We'll up to three times to get the image.
|
||||
// We have to add a timestamp so fetch will retry the call.
|
||||
handleError = () => {
|
||||
handleLoadError = () => {
|
||||
if (this.state.retry < 3) {
|
||||
setTimeout(() => this.setState({
|
||||
this.setState({
|
||||
retry: this.state.retry++,
|
||||
timestamp: Date.now()
|
||||
}), 100);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleLoad = () => {
|
||||
this.setState({
|
||||
requesting: false
|
||||
});
|
||||
|
||||
Animated.timing(this.state.opacity, {
|
||||
toValue: 1,
|
||||
duration: 300
|
||||
}).start(() => {
|
||||
this.props.addFileToFetchCache(Client.getFilePreviewUrl(this.props.file.id, this.state.timestamp));
|
||||
});
|
||||
}
|
||||
|
||||
handleLoadStart = () => {
|
||||
this.setState({
|
||||
requesting: true
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
fetchCache,
|
||||
file,
|
||||
imageHeight,
|
||||
imageWidth,
|
||||
resizeMethod,
|
||||
resizeMode,
|
||||
wrapperBackgroundColor,
|
||||
wrapperHeight,
|
||||
wrapperWidth
|
||||
} = this.props;
|
||||
|
||||
const source = {uri: Client.getFilePreviewUrl(file.id, this.state.timestamp)};
|
||||
const source = file.id ? {uri: Client.getFilePreviewUrl(file.id, this.state.timestamp)} : {};
|
||||
|
||||
const isInFetchCache = fetchCache[source.uri];
|
||||
const imageComponentLoaders = {
|
||||
onError: isInFetchCache ? null : this.handleLoadError,
|
||||
onLoadStart: isInFetchCache ? null : this.handleLoadStart,
|
||||
onLoad: isInFetchCache ? null : this.handleLoad
|
||||
};
|
||||
const opacity = isInFetchCache ? 1 : this.state.opacity;
|
||||
|
||||
return (
|
||||
<View style={[style.fileImageWrapper, {height: wrapperHeight, width: wrapperWidth}]}>
|
||||
<Image
|
||||
style={{height: imageHeight, width: imageWidth}}
|
||||
source={source}
|
||||
defaultSource={genericIcon}
|
||||
resizeMode={resizeMode}
|
||||
resizeMethod={resizeMethod}
|
||||
onError={this.handleError}
|
||||
/>
|
||||
<View style={[style.fileImageWrapper, {backgroundColor: wrapperBackgroundColor, height: wrapperHeight, width: wrapperWidth}]}>
|
||||
<AnimatedView style={{height: imageHeight, width: imageWidth, backgroundColor: wrapperBackgroundColor, opacity}}>
|
||||
<Image
|
||||
style={{height: imageHeight, width: imageWidth}}
|
||||
source={source}
|
||||
resizeMode={resizeMode}
|
||||
resizeMethod={resizeMethod}
|
||||
{...imageComponentLoaders}
|
||||
/>
|
||||
</AnimatedView>
|
||||
{(!isInFetchCache && (file.loading || this.state.requesting)) &&
|
||||
<View style={style.loaderContainer}>
|
||||
<ActivityIndicator size='small'/>
|
||||
</View>
|
||||
}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
|
@ -83,5 +128,13 @@ const style = StyleSheet.create({
|
|||
fileImageWrapper: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
},
|
||||
loaderContainer: {
|
||||
position: 'absolute',
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: '#fff'
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,10 +4,8 @@
|
|||
import React, {PropTypes, PureComponent} from 'react';
|
||||
import {
|
||||
Dimensions,
|
||||
KeyboardAvoidingView,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View
|
||||
} from 'react-native';
|
||||
|
|
@ -15,22 +13,23 @@ import Font from 'react-native-vector-icons/FontAwesome';
|
|||
import {RequestStatus} from 'mattermost-redux/constants';
|
||||
|
||||
import FileAttachmentPreview from 'app/components/file_attachment_list/file_attachment_preview';
|
||||
import KeyboardLayout from 'app/components/layout/keyboard_layout';
|
||||
|
||||
const {height: deviceHeight} = Dimensions.get('window');
|
||||
|
||||
export default class FileUploadPreview extends PureComponent {
|
||||
static propTypes = {
|
||||
actions: PropTypes.shape({
|
||||
cancelUploadFileRequest: PropTypes.func.isRequired,
|
||||
addFileToFetchCache: PropTypes.func.isRequired,
|
||||
handleClearFiles: PropTypes.func.isRequired,
|
||||
handleRemoveFile: PropTypes.func.isRequired
|
||||
}).isRequired,
|
||||
channelId: PropTypes.string.isRequired,
|
||||
createPostRequestStatus: PropTypes.string.isRequired,
|
||||
fetchCache: PropTypes.object.isRequired,
|
||||
files: PropTypes.array.isRequired,
|
||||
rootId: PropTypes.string,
|
||||
uploadFileRequestStatus: PropTypes.string.isRequired,
|
||||
uploadFileRequestId: PropTypes.number
|
||||
uploadFileRequestStatus: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
|
|
@ -43,13 +42,17 @@ export default class FileUploadPreview extends PureComponent {
|
|||
return this.props.files.map((file) => {
|
||||
return (
|
||||
<View
|
||||
key={file.id}
|
||||
key={file.clientId}
|
||||
style={style.preview}
|
||||
>
|
||||
<FileAttachmentPreview file={file}/>
|
||||
<FileAttachmentPreview
|
||||
addFileToFetchCache={this.props.actions.addFileToFetchCache}
|
||||
fetchCache={this.props.fetchCache}
|
||||
file={file}
|
||||
/>
|
||||
<TouchableOpacity
|
||||
style={style.removeButton}
|
||||
onPress={() => this.props.actions.handleRemoveFile(file.id, this.props.channelId, this.props.rootId)}
|
||||
onPress={() => this.props.actions.handleRemoveFile(file.clientId, this.props.channelId, this.props.rootId)}
|
||||
>
|
||||
<Font
|
||||
name='times'
|
||||
|
|
@ -62,27 +65,13 @@ export default class FileUploadPreview extends PureComponent {
|
|||
});
|
||||
}
|
||||
|
||||
handleCancelUpload = () => {
|
||||
this.props.actions.cancelUploadFileRequest(this.props.uploadFileRequestId);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.props.files.length && this.props.uploadFileRequestStatus !== RequestStatus.STARTED) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let component;
|
||||
if (this.props.uploadFileRequestStatus === RequestStatus.STARTED) {
|
||||
component = (
|
||||
<View style={style.loader}>
|
||||
<Text style={style.loaderText}>{'Loading...'}</Text>
|
||||
<TouchableOpacity onPress={this.handleCancelUpload}>
|
||||
<Text style={style.cancelText}>{'Cancel'}</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
} else {
|
||||
component = (
|
||||
return (
|
||||
<KeyboardLayout style={style.container}>
|
||||
<ScrollView
|
||||
horizontal={true}
|
||||
style={style.scrollView}
|
||||
|
|
@ -90,13 +79,7 @@ export default class FileUploadPreview extends PureComponent {
|
|||
>
|
||||
{this.buildFilePreviews()}
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<KeyboardAvoidingView style={style.container}>
|
||||
{component}
|
||||
</KeyboardAvoidingView>
|
||||
</KeyboardLayout>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -132,7 +115,7 @@ const style = StyleSheet.create({
|
|||
alignItems: 'center',
|
||||
height: 115,
|
||||
justifyContent: 'center',
|
||||
marginLeft: 24,
|
||||
marginRight: 5,
|
||||
width: 115
|
||||
},
|
||||
removeButton: {
|
||||
|
|
@ -151,6 +134,7 @@ const style = StyleSheet.create({
|
|||
marginBottom: 24
|
||||
},
|
||||
scrollViewContent: {
|
||||
alignItems: 'flex-end'
|
||||
alignItems: 'flex-end',
|
||||
marginLeft: 10
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,9 +3,10 @@
|
|||
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {connect} from 'react-redux';
|
||||
import {cancelUploadFileRequest} from 'mattermost-redux/actions/files';
|
||||
|
||||
import {handleClearFiles, handleRemoveFile} from 'app/actions/views/file_upload';
|
||||
import {addFileToFetchCache} from 'app/actions/views/file_preview';
|
||||
import {getTheme} from 'app/selectors/preferences';
|
||||
|
||||
import FileUploadPreview from './file_upload_preview';
|
||||
|
||||
|
|
@ -13,14 +14,16 @@ function mapStateToProps(state, ownProps) {
|
|||
return {
|
||||
...ownProps,
|
||||
createPostRequestStatus: state.requests.posts.createPost.status,
|
||||
uploadFileRequestStatus: state.requests.files.uploadFiles.status
|
||||
fetchCache: state.views.fetchCache,
|
||||
uploadFileRequestStatus: state.requests.files.uploadFiles.status,
|
||||
theme: getTheme(state)
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
cancelUploadFileRequest,
|
||||
addFileToFetchCache,
|
||||
handleClearFiles,
|
||||
handleRemoveFile
|
||||
}, dispatch)
|
||||
|
|
|
|||
|
|
@ -135,11 +135,7 @@ export default class PostTextbox extends PureComponent {
|
|||
}
|
||||
|
||||
uploadFiles = (images) => {
|
||||
const uploadFileRequestId = Date.now();
|
||||
this.setState({
|
||||
uploadFileRequestId
|
||||
});
|
||||
this.props.actions.handleUploadFiles(images, this.props.rootId, uploadFileRequestId);
|
||||
this.props.actions.handleUploadFiles(images, this.props.rootId);
|
||||
}
|
||||
|
||||
showFileAttachmentOptions = () => {
|
||||
|
|
@ -225,7 +221,6 @@ export default class PostTextbox extends PureComponent {
|
|||
channelId={this.props.channelId}
|
||||
files={this.props.files}
|
||||
rootId={this.props.rootId}
|
||||
uploadFileRequestId={this.state.uploadFileRequestId}
|
||||
/>
|
||||
<Autocomplete
|
||||
ref={this.attachAutocomplete}
|
||||
|
|
|
|||
|
|
@ -19,9 +19,14 @@ const ViewTypes = keyMirror({
|
|||
SET_POST_DRAFT: null,
|
||||
SET_COMMENT_DRAFT: null,
|
||||
|
||||
SET_TEMP_UPLOAD_FILES_FOR_POST_DRAFT: null,
|
||||
|
||||
CLEAR_FILES_FOR_POST_DRAFT: null,
|
||||
|
||||
REMOVE_FILE_FROM_POST_DRAFT: null
|
||||
REMOVE_FILE_FROM_POST_DRAFT: null,
|
||||
REMOVE_LAST_FILE_FROM_POST_DRAFT: null,
|
||||
|
||||
ADD_FILE_TO_FETCH_CACHE: null
|
||||
});
|
||||
|
||||
export default ViewTypes;
|
||||
|
|
|
|||
|
|
@ -279,6 +279,7 @@ const state = {
|
|||
channel: {
|
||||
drafts: {}
|
||||
},
|
||||
fetchCache: {},
|
||||
i18n: {
|
||||
locale: ''
|
||||
},
|
||||
|
|
|
|||
|
|
@ -37,14 +37,15 @@ function drafts(state = {}, action) {
|
|||
|
||||
return data;
|
||||
}
|
||||
case FilesTypes.RECEIVED_UPLOAD_FILES: {
|
||||
case ViewTypes.SET_TEMP_UPLOAD_FILES_FOR_POST_DRAFT: {
|
||||
if (action.rootId) {
|
||||
return state;
|
||||
}
|
||||
|
||||
const tempFiles = action.clientIds.map((id) => ({clientId: id, loading: true}));
|
||||
const files = [
|
||||
...state[action.channelId].files,
|
||||
...action.data
|
||||
...tempFiles
|
||||
];
|
||||
|
||||
return {
|
||||
|
|
@ -52,6 +53,26 @@ function drafts(state = {}, action) {
|
|||
[action.channelId]: Object.assign({}, state[action.channelId], {files})
|
||||
};
|
||||
}
|
||||
case FilesTypes.RECEIVED_UPLOAD_FILES: {
|
||||
if (action.rootId || !state[action.channelId].files) {
|
||||
return state;
|
||||
}
|
||||
|
||||
// Reconcile tempFiles with the received uploaded files
|
||||
const files = state[action.channelId].files.map((tempFile) => {
|
||||
const file = action.data.find((f) => f.clientId === tempFile.clientId);
|
||||
if (file) {
|
||||
return file;
|
||||
}
|
||||
|
||||
return tempFile;
|
||||
});
|
||||
|
||||
return {
|
||||
...state,
|
||||
[action.channelId]: Object.assign({}, state[action.channelId], {files})
|
||||
};
|
||||
}
|
||||
case ViewTypes.CLEAR_FILES_FOR_POST_DRAFT: {
|
||||
if (action.rootId) {
|
||||
return state;
|
||||
|
|
@ -67,7 +88,7 @@ function drafts(state = {}, action) {
|
|||
return state;
|
||||
}
|
||||
|
||||
const files = state[action.channelId].files.filter((file) => file.id !== action.fileId);
|
||||
const files = state[action.channelId].files.filter((file) => (file.clientId !== action.clientId));
|
||||
|
||||
return {
|
||||
...state,
|
||||
|
|
|
|||
16
app/reducers/views/fetch_cache.js
Normal file
16
app/reducers/views/fetch_cache.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {ViewTypes} from 'app/constants';
|
||||
|
||||
export default function fetchCache(state = {}, action) {
|
||||
switch (action.type) {
|
||||
case ViewTypes.ADD_FILE_TO_FETCH_CACHE:
|
||||
return {
|
||||
...state,
|
||||
[action.url]: true
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
import {combineReducers} from 'redux';
|
||||
|
||||
import channel from './channel';
|
||||
import fetchCache from './fetch_cache';
|
||||
import i18n from './i18n';
|
||||
import login from './login';
|
||||
import notification from './notification';
|
||||
|
|
@ -13,6 +14,7 @@ import thread from './thread';
|
|||
|
||||
export default combineReducers({
|
||||
channel,
|
||||
fetchCache,
|
||||
i18n,
|
||||
login,
|
||||
notification,
|
||||
|
|
|
|||
|
|
@ -36,15 +36,36 @@ function drafts(state = {}, action) {
|
|||
|
||||
return data;
|
||||
}
|
||||
case ViewTypes.SET_TEMP_UPLOAD_FILES_FOR_POST_DRAFT: {
|
||||
if (!action.rootId) {
|
||||
return state;
|
||||
}
|
||||
|
||||
const tempFiles = action.clientIds.map((id) => ({clientId: id, loading: true}));
|
||||
const files = [
|
||||
...state[action.rootId].files,
|
||||
...tempFiles
|
||||
];
|
||||
|
||||
return {
|
||||
...state,
|
||||
[action.rootId]: Object.assign({}, state[action.rootId], {files})
|
||||
};
|
||||
}
|
||||
case FilesTypes.RECEIVED_UPLOAD_FILES: {
|
||||
if (!action.rootId) {
|
||||
return state;
|
||||
}
|
||||
|
||||
const files = [
|
||||
...state[action.rootId].files,
|
||||
...action.data
|
||||
];
|
||||
// Reconcile tempFiles with the received uploaded files
|
||||
const files = state[action.rootId].files.map((tempFile) => {
|
||||
const file = action.data.find((f) => f.clientId === tempFile.clientId);
|
||||
if (file) {
|
||||
return file;
|
||||
}
|
||||
|
||||
return tempFile;
|
||||
});
|
||||
|
||||
return {
|
||||
...state,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import {
|
|||
TouchableWithoutFeedback,
|
||||
View
|
||||
} from 'react-native';
|
||||
import Icon from 'react-native-vector-icons/FontAwesome';
|
||||
import Icon from 'react-native-vector-icons/Ionicons';
|
||||
import LinearGradient from 'react-native-linear-gradient';
|
||||
|
||||
import FileAttachmentIcon from 'app/components/file_attachment_list/file_attachment_icon';
|
||||
|
|
@ -32,8 +32,10 @@ const STATUS_BAR_HEIGHT = Platform.OS === 'android' ? 25 : 0; // Used to account
|
|||
export default class ImagePreview extends PureComponent {
|
||||
static propTypes = {
|
||||
actions: PropTypes.shape({
|
||||
addFileToFetchCache: PropTypes.func.isRequired,
|
||||
goBack: PropTypes.func.isRequired
|
||||
}),
|
||||
fetchCache: PropTypes.object.isRequired,
|
||||
fileId: PropTypes.string.isRequired,
|
||||
files: PropTypes.array.isRequired,
|
||||
theme: PropTypes.object.isRequired
|
||||
|
|
@ -163,8 +165,8 @@ export default class ImagePreview extends PureComponent {
|
|||
style={style.headerIcon}
|
||||
>
|
||||
<Icon
|
||||
name='close'
|
||||
size={15}
|
||||
name='md-close'
|
||||
size={26}
|
||||
color='#fff'
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
|
|
@ -199,11 +201,14 @@ export default class ImagePreview extends PureComponent {
|
|||
if (file.has_preview_image) {
|
||||
component = (
|
||||
<FileAttachmentPreview
|
||||
addFileToFetchCache={this.props.actions.addFileToFetchCache}
|
||||
fetchCache={this.props.fetchCache}
|
||||
file={file}
|
||||
theme={this.props.theme}
|
||||
imageHeight={Math.min(maxImageHeight, file.height)}
|
||||
imageWidth={Math.min(this.state.deviceWidth, file.width)}
|
||||
resizeMode='contain'
|
||||
wrapperBackgroundColor='#000'
|
||||
wrapperHeight={maxImageHeight}
|
||||
wrapperWidth={this.state.deviceWidth}
|
||||
/>
|
||||
|
|
@ -281,7 +286,7 @@ const style = StyleSheet.create({
|
|||
flexDirection: 'row',
|
||||
...Platform.select({
|
||||
ios: {
|
||||
marginTop: 30
|
||||
marginTop: 20
|
||||
},
|
||||
android: {
|
||||
marginTop: 10
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
import {bindActionCreators} from 'redux';
|
||||
|
||||
import {goBack} from 'app/actions/navigation';
|
||||
import {addFileToFetchCache} from 'app/actions/views/file_preview';
|
||||
import {getTheme} from 'app/selectors/preferences';
|
||||
import {makeGetFilesForPost} from 'mattermost-redux/selectors/entities/files';
|
||||
|
||||
|
|
@ -16,6 +17,7 @@ function makeMapStateToProps() {
|
|||
return function mapStateToProps(state, ownProps) {
|
||||
return {
|
||||
...ownProps,
|
||||
fetchCache: state.views.fetchCache,
|
||||
files: getFilesForPost(state, ownProps.post),
|
||||
theme: getTheme(state)
|
||||
};
|
||||
|
|
@ -25,6 +27,7 @@ function makeMapStateToProps() {
|
|||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
addFileToFetchCache,
|
||||
goBack
|
||||
}, dispatch)
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue