<commit_before>// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import React, {useCallback, useEffect, useState} from 'react';
import {StyleProp, StyleSheet, useWindowDimensions, View, ViewStyle} from 'react-native';
import LinearGradient from 'react-native-linear-gradient';

import {buildFilePreviewUrl, buildFileThumbnailUrl} from '@actions/remote/file';
import CompassIcon from '@components/compass_icon';
import ProgressiveImage from '@components/progressive_image';
import {useServerUrl} from '@context/server';
import {useTheme} from '@context/theme';
import {isGif as isGifImage} from '@utils/file';
import {calculateDimensions} from '@utils/images';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';

import FileIcon from './file_icon';

import type {ResizeMode} from 'react-native-fast-image';

type ImageFileProps = {
    backgroundColor?: string;
    file: FileInfo;
    forwardRef: React.RefObject<unknown>;
    inViewPort?: boolean;
    isSingleImage?: boolean;
    resizeMode?: ResizeMode;
    wrapperWidth?: number;
}

const SMALL_IMAGE_MAX_HEIGHT = 48;
const SMALL_IMAGE_MAX_WIDTH = 48;
const GRADIENT_COLORS = ['rgba(0, 0, 0, 0)', 'rgba(0, 0, 0, .32)'];
const GRADIENT_END = {x: 1, y: 1};
const GRADIENT_LOCATIONS = [0.5, 1];
const GRADIENT_START = {x: 0.5, y: 0.5};

const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
    boxPlaceholder: {
        paddingBottom: '100%',
    },
    fileImageWrapper: {
        borderRadius: 5,
        overflow: 'hidden',
    },
    failed: {
        justifyContent: 'center',
        alignItems: 'center',
        borderColor: changeOpacity(theme.centerChannelColor, 0.2),
        borderRadius: 4,
        borderWidth: 1,
    },
    gifContainer: {
        alignItems: 'flex-end',
        justifyContent: 'flex-end',
        padding: 8,
        ...StyleSheet.absoluteFillObject,
    },
    imagePreview: {
        ...StyleSheet.absoluteFillObject,
    },
    smallImageBorder: {
        borderRadius: 5,
    },
    smallImageOverlay: {
        ...StyleSheet.absoluteFillObject,
        justifyContent: 'center',
        alignItems: 'center',
        borderRadius: 4,
    },
    singleSmallImageWrapper: {
        height: SMALL_IMAGE_MAX_HEIGHT,
        width: SMALL_IMAGE_MAX_WIDTH,
        overflow: 'hidden',
    },
}));

const ImageFile = ({
    backgroundColor, file, forwardRef, inViewPort, isSingleImage,
    resizeMode = 'cover', wrapperWidth,
}: ImageFileProps) => {
    const dimensions = useWindowDimensions();
    const theme = useTheme();
    const serverUrl = useServerUrl();
    const [isGif, setIsGif] = useState(isGifImage(file));
    const [failed, setFailed] = useState(false);
    const style = getStyleSheet(theme);
    let image;

    const getImageDimensions = () => {
        if (isSingleImage) {
            const viewPortHeight = Math.max(dimensions.height, dimensions.width) * 0.45;
            return calculateDimensions(file?.height, file?.width, wrapperWidth, viewPortHeight);
        }

        return undefined;
    };

    const handleError = useCallback(() => {
        setFailed(true);
    }, []);

    const imageProps = () => {
        const props: ProgressiveImageProps = {};

        if (file.localPath) {
            props.defaultSource = {uri: file.localPath};
        } else if (file.id) {
            if (file.mini_preview && file.mime_type) {
                props.thumbnailUri = `data:${file.mime_type};base64,${file.mini_preview}`;
            } else {
                props.thumbnailUri = buildFileThumbnailUrl(serverUrl, file.id);
            }
            props.imageUri = buildFilePreviewUrl(serverUrl, file.id);
            props.inViewPort = inViewPort;
        }
        return props;
    };

    useEffect(() => {
        setIsGif(isGifImage(file));
    }, [file]);

    if (file.height <= SMALL_IMAGE_MAX_HEIGHT || file.width <= SMALL_IMAGE_MAX_WIDTH) {
        let wrapperStyle: StyleProp<ViewStyle> = style.fileImageWrapper;
        if (isSingleImage) {
            wrapperStyle = style.singleSmallImageWrapper;

            if (file.width > SMALL_IMAGE_MAX_WIDTH) {
                wrapperStyle = [wrapperStyle, {width: '100%'}];
            }
        }

        image = (
            <ProgressiveImage
                id={file.id!}
                forwardRef={forwardRef}
                style={{height: file.height, width: file.width}}
                tintDefaultSource={!file.localPath && !failed}
                onError={handleError}
                resizeMode={'contain'}
                {...imageProps()}
            />
        );

        if (failed) {
            image = (
                <FileIcon
                    failed={failed}
                    file={file}
                    backgroundColor={backgroundColor}
                /><commit_msg>useMemo function call (#6372)<commit_after>// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import React, {useCallback, useMemo, useState} from 'react';
import {StyleProp, StyleSheet, useWindowDimensions, View, ViewStyle} from 'react-native';
import LinearGradient from 'react-native-linear-gradient';

import {buildFilePreviewUrl, buildFileThumbnailUrl} from '@actions/remote/file';
import CompassIcon from '@components/compass_icon';
import ProgressiveImage from '@components/progressive_image';
import {useServerUrl} from '@context/server';
import {useTheme} from '@context/theme';
import {isGif as isGifImage} from '@utils/file';
import {calculateDimensions} from '@utils/images';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';

import FileIcon from './file_icon';

import type {ResizeMode} from 'react-native-fast-image';

type ImageFileProps = {
    backgroundColor?: string;
    file: FileInfo;
    forwardRef: React.RefObject<unknown>;
    inViewPort?: boolean;
    isSingleImage?: boolean;
    resizeMode?: ResizeMode;
    wrapperWidth?: number;
}

const SMALL_IMAGE_MAX_HEIGHT = 48;
const SMALL_IMAGE_MAX_WIDTH = 48;
const GRADIENT_COLORS = ['rgba(0, 0, 0, 0)', 'rgba(0, 0, 0, .32)'];
const GRADIENT_END = {x: 1, y: 1};
const GRADIENT_LOCATIONS = [0.5, 1];
const GRADIENT_START = {x: 0.5, y: 0.5};

const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
    boxPlaceholder: {
        paddingBottom: '100%',
    },
    fileImageWrapper: {
        borderRadius: 5,
        overflow: 'hidden',
    },
    failed: {
        justifyContent: 'center',
        alignItems: 'center',
        borderColor: changeOpacity(theme.centerChannelColor, 0.2),
        borderRadius: 4,
        borderWidth: 1,
    },
    gifContainer: {
        alignItems: 'flex-end',
        justifyContent: 'flex-end',
        padding: 8,
        ...StyleSheet.absoluteFillObject,
    },
    imagePreview: {
        ...StyleSheet.absoluteFillObject,
    },
    smallImageBorder: {
        borderRadius: 5,
    },
    smallImageOverlay: {
        ...StyleSheet.absoluteFillObject,
        justifyContent: 'center',
        alignItems: 'center',
        borderRadius: 4,
    },
    singleSmallImageWrapper: {
        height: SMALL_IMAGE_MAX_HEIGHT,
        width: SMALL_IMAGE_MAX_WIDTH,
        overflow: 'hidden',
    },
}));

const ImageFile = ({
    backgroundColor, file, forwardRef, inViewPort, isSingleImage,
    resizeMode = 'cover', wrapperWidth,
}: ImageFileProps) => {
    const dimensions = useWindowDimensions();
    const theme = useTheme();
    const serverUrl = useServerUrl();
    const isGif = useMemo(() => isGifImage(file), [file]);
    const [failed, setFailed] = useState(false);
    const style = getStyleSheet(theme);
    let image;

    const getImageDimensions = () => {
        if (isSingleImage) {
            const viewPortHeight = Math.max(dimensions.height, dimensions.width) * 0.45;
            return calculateDimensions(file?.height, file?.width, wrapperWidth, viewPortHeight);
        }

        return undefined;
    };

    const handleError = useCallback(() => {
        setFailed(true);
    }, []);

    const imageProps = () => {
        const props: ProgressiveImageProps = {};

        if (file.localPath) {
            props.defaultSource = {uri: file.localPath};
        } else if (file.id) {
            if (file.mini_preview && file.mime_type) {
                props.thumbnailUri = `data:${file.mime_type};base64,${file.mini_preview}`;
            } else {
                props.thumbnailUri = buildFileThumbnailUrl(serverUrl, file.id);
            }
            props.imageUri = buildFilePreviewUrl(serverUrl, file.id);
            props.inViewPort = inViewPort;
        }
        return props;
    };

    if (file.height <= SMALL_IMAGE_MAX_HEIGHT || file.width <= SMALL_IMAGE_MAX_WIDTH) {
        let wrapperStyle: StyleProp<ViewStyle> = style.fileImageWrapper;
        if (isSingleImage) {
            wrapperStyle = style.singleSmallImageWrapper;

            if (file.width > SMALL_IMAGE_MAX_WIDTH) {
                wrapperStyle = [wrapperStyle, {width: '100%'}];
            }
        }

        image = (
            <ProgressiveImage
                id={file.id!}
                forwardRef={forwardRef}
                style={{height: file.height, width: file.width}}
                tintDefaultSource={!file.localPath && !failed}
                onError={handleError}
                resizeMode={'contain'}
                {...imageProps()}
            />
        );

        if (failed) {
            image = (
                <FileIcon
                    failed={failed}
                    file={file}
                    backgroundColor={backgroundColor}
                />
{'fraction_non_alphanumeric': 0.1225206611570248, 'fraction_numerical': 0.009710743801652892, 'mean_word_length': 2.521644234267006, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3223222', 'n_tokens_mistral': 2912, 'n_tokens_neox': 2769, 'n_words': 607}