[MM-40160] Crt gallery fix (#5833) (#5852)

* Fix Gallery crash

* fix file type icons

* memoize gallery files

(cherry picked from commit 1b285dac49)

Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
This commit is contained in:
Mattermost Build 2021-11-30 11:32:17 +02:00 committed by GitHub
parent 2e71fcc226
commit 456208d223
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 45 additions and 46 deletions

View file

@ -25,21 +25,21 @@ const BLUE_ICON = '#338AFF';
const RED_ICON = '#ED522A';
const GREEN_ICON = '#1CA660';
const GRAY_ICON = '#999999';
const FAILED_ICON_NAME_AND_COLOR = ['jumbo-attachment-image-broken', GRAY_ICON];
const FAILED_ICON_NAME_AND_COLOR = ['file-image-broken-outline-large', GRAY_ICON];
const ICON_NAME_AND_COLOR_FROM_FILE_TYPE: Record<string, string[]> = {
audio: ['jumbo-attachment-audio', BLUE_ICON],
code: ['jumbo-attachment-code', BLUE_ICON],
image: ['jumbo-attachment-image', BLUE_ICON],
audio: ['file-audio-outline-large', BLUE_ICON],
code: ['file-code-outline-large', BLUE_ICON],
image: ['file-image-outline-large', BLUE_ICON],
smallImage: ['image-outline', BLUE_ICON],
other: ['jumbo-attachment-generic', BLUE_ICON],
patch: ['jumbo-attachment-patch', BLUE_ICON],
pdf: ['jumbo-attachment-pdf', RED_ICON],
presentation: ['jumbo-attachment-powerpoint', RED_ICON],
spreadsheet: ['jumbo-attachment-excel', GREEN_ICON],
text: ['jumbo-attachment-text', GRAY_ICON],
video: ['jumbo-attachment-video', BLUE_ICON],
word: ['jumbo-attachment-word', BLUE_ICON],
zip: ['jumbo-attachment-zip', BLUE_ICON],
other: ['file-generic-outline-large', BLUE_ICON],
patch: ['file-patch-outline-large', BLUE_ICON],
pdf: ['file-pdf-outline-large', RED_ICON],
presentation: ['file-powerpoint-outline-large', RED_ICON],
spreadsheet: ['file-excel-outline-large', GREEN_ICON],
text: ['file-text-outline-large', GRAY_ICON],
video: ['file-video-outline-large', BLUE_ICON],
word: ['file-word-outline-large', BLUE_ICON],
zip: ['file-zip-outline-large', BLUE_ICON],
};
const styles = StyleSheet.create({

View file

@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useEffect, useRef, useState} from 'react';
import React, {useEffect, useMemo, useState} from 'react';
import {DeviceEventEmitter, StyleProp, StyleSheet, View, ViewStyle} from 'react-native';
import {Client4} from '@client/rest';
@ -46,10 +46,10 @@ const Files = ({canDownloadFiles, failed, files, isReplyPost, postId, theme}: Fi
const [inViewPort, setInViewPort] = useState(false);
const permanentSidebar = usePermanentSidebar();
const isSplitView = useSplitView();
const imageAttachments = useRef<FileInfo[]>([]).current;
const nonImageAttachments = useRef<FileInfo[]>([]).current;
const {imageAttachments, nonImageAttachments} = useMemo(() => {
const images: FileInfo[] = [];
const nonImages: FileInfo[] = [];
if (!imageAttachments.length && !nonImageAttachments.length) {
files.reduce((info, file) => {
if (isImage(file)) {
let uri;
@ -58,15 +58,17 @@ const Files = ({canDownloadFiles, failed, files, isReplyPost, postId, theme}: Fi
} else {
uri = isGif(file) ? Client4.getFileUrl(file.id, 0) : Client4.getFilePreviewUrl(file.id, 0);
}
info.imageAttachments.push({...file, uri});
info.images.push({...file, uri});
} else {
info.nonImageAttachments.push(file);
info.nonImages.push(file);
}
return info;
}, {imageAttachments, nonImageAttachments});
}
}, {images, nonImages});
const filesForGallery = useRef<FileInfo[]>(imageAttachments.concat(nonImageAttachments)).current;
return {imageAttachments: images, nonImageAttachments: nonImages};
}, [files]);
const filesForGallery = imageAttachments.concat(nonImageAttachments);
const attachmentIndex = (fileId: string) => {
return filesForGallery.findIndex((file) => file.id === fileId) || 0;
};

View file

@ -16,8 +16,6 @@ import GalleryViewer from './gallery_viewer';
export default class Gallery extends PureComponent {
static propTypes = {
componentId: PropTypes.string.isRequired,
deviceHeight: PropTypes.number.isRequired,
deviceWidth: PropTypes.number.isRequired,
files: PropTypes.array,
index: PropTypes.number.isRequired,
theme: PropTypes.object.isRequired,
@ -152,19 +150,15 @@ export default class Gallery extends PureComponent {
};
render() {
const {deviceHeight, deviceWidth, files, theme} = this.props;
const {files, theme} = this.props;
const {index, footerVisible} = this.state;
return (
<>
<GalleryViewer
key={`gallery-${deviceWidth}`}
files={files}
footerVisible={footerVisible}
width={deviceWidth}
height={deviceHeight}
initialIndex={index}
isLandscape={deviceWidth > deviceHeight}
onClose={this.close}
onPageSelected={this.handlePageSelected}
onTap={this.handleTapped}

View file

@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import React, {useEffect, useMemo, useRef, useState} from 'react';
import {Platform, StyleSheet, View} from 'react-native';
import {Platform, StyleSheet, useWindowDimensions, View} from 'react-native';
import {PanGestureHandler, PinchGestureHandler, State, TapGestureHandler, TapGestureHandlerStateChangeEvent} from 'react-native-gesture-handler';
import Animated, {abs, add, and, call, clockRunning, cond, divide, eq, greaterOrEq, greaterThan, multiply, neq, not, onChange, set, sub, useCode, EasingNode, ceil} from 'react-native-reanimated';
import {clamp, snapPoint, timing, useClock, usePanGestureHandler, usePinchGestureHandler, useTapGestureHandler, useValue, vec} from 'react-native-redash/lib/module/v1';
@ -18,34 +18,40 @@ import GalleryVideo from './gallery_video';
import type {GalleryProps} from '@mm-types/screens/gallery';
const itemTopStyle = (props: GalleryProps): number => {
type GalleryStyle = {
count: number;
height: number;
width: number;
}
const itemTopStyle = (footerVisible: boolean, isLandscape: boolean): number => {
if (Platform.OS === 'android') {
if (props.footerVisible) {
return props.isLandscape ? -64 : -99;
if (footerVisible) {
return isLandscape ? -64 : -99;
}
return props.isLandscape ? -6 : -41;
return isLandscape ? -6 : -41;
}
return 0;
};
const getStyles = makeStyleSheetFromTheme((props: GalleryProps) => ({
const getStyles = makeStyleSheetFromTheme(({count, width, height}: GalleryStyle) => ({
container: {
...StyleSheet.absoluteFillObject,
},
items: {
width: (props.width * props.files.length),
height: props.height,
width: (width * count),
height,
flexDirection: 'row',
alignItems: 'center',
},
item: {
alignItems: 'center',
height: props.height,
height,
justifyContent: 'center',
overflow: 'hidden',
width: props.width,
width,
},
center: {
justifyContent: 'center',
@ -53,12 +59,13 @@ const getStyles = makeStyleSheetFromTheme((props: GalleryProps) => ({
}));
const GalleryViewer = (props: GalleryProps) => {
const {files, height, initialIndex, width} = props;
const {files, initialIndex} = props;
const [enabled, setEnabled] = useState(false);
const [tapEnabled, setTapEnabled] = useState(true);
const [currentIndex, setCurrentIndex] = useState(initialIndex);
const styles = getStyles(props);
const topValue = itemTopStyle(props);
const {height, width} = useWindowDimensions();
const styles = getStyles({width, height, count: files.length});
const topValue = itemTopStyle(props.footerVisible, width > height);
const top = useRef(useValue(topValue)).current;
const canvas = useMemo(() => vec.create(width, height), [width]);

View file

@ -4,13 +4,11 @@
import {connect} from 'react-redux';
import {getTheme} from '@mm-redux/selectors/entities/preferences';
import {getDimensions} from '@selectors/device';
import Gallery from './gallery';
function mapStateToProps(state) {
return {
...getDimensions(state),
theme: getTheme(state),
};
}

View file

@ -61,13 +61,11 @@ export interface FooterRef {
export interface GalleryProps {
files: Array<FileInfo>;
footerVisible: boolean;
height: number;
initialIndex: number;
isLandscape: boolean;
onClose: CallbackFunctionWithoutArguments;
onPageSelected: (index: number) => void;
onTap: CallbackFunctionWithoutArguments;
width: number;
theme: Theme;
}