Skip to content

Commit

Permalink
Merge pull request #4736 from akshayasalvi/attachment-view-in-comments
Browse files Browse the repository at this point in the history
Change UI view for Attachments in Chat
  • Loading branch information
thienlnam authored Aug 23, 2021
2 parents 234b35f + 1929de1 commit 90bff75
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 50 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import React from 'react';
import {StyleSheet} from 'react-native';
import {Pressable, StyleSheet} from 'react-native';
import lodashGet from 'lodash/get';
import Text from '../../Text';
import {propTypes, defaultProps} from '../anchorForCommentsOnlyPropTypes';
import PressableWithSecondaryInteraction from '../../PressableWithSecondaryInteraction';
import {showContextMenu} from '../../../pages/home/report/ContextMenu/ReportActionContextMenu';
import {CONTEXT_MENU_TYPES} from '../../../pages/home/report/ContextMenu/ContextMenuActions';
import AttachmentView from '../../AttachmentView';
import fileDownload from '../../../libs/fileDownload';


/*
Expand All @@ -17,34 +19,52 @@ const BaseAnchorForCommentsOnly = ({
target,
children,
style,
fileName,
...props
}) => {
let linkRef;
return (
<PressableWithSecondaryInteraction
onSecondaryInteraction={
(event) => {
showContextMenu(
CONTEXT_MENU_TYPES.LINK,
event,
href,
lodashGet(linkRef, 'current'),
);
}
}
>
<Text
ref={el => linkRef = el}
style={StyleSheet.flatten(style)}
accessibilityRole="link"
href={href}
hrefAttrs={{rel, target}}

props.isAttachment
? (
<Pressable onPress={() => {
fileDownload(href);
}}
>
<AttachmentView
sourceURL={href}
file={{name: fileName}}
shouldShowDownloadIcon
/>
</Pressable>
)
: (
<PressableWithSecondaryInteraction
onSecondaryInteraction={
(event) => {
showContextMenu(
CONTEXT_MENU_TYPES.LINK,
event,
href,
lodashGet(linkRef, 'current'),
);
}
}
>
<Text
ref={el => linkRef = el}
style={StyleSheet.flatten(style)}
accessibilityRole="link"
href={href}
hrefAttrs={{rel, target}}
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
>
{children}
</Text>
</PressableWithSecondaryInteraction>
{...props}
>
{children}
</Text>
</PressableWithSecondaryInteraction>
)

);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React from 'react';
import lodashGet from 'lodash/get';
import {Linking, StyleSheet} from 'react-native';
import {Linking, StyleSheet, Pressable} from 'react-native';
import {propTypes, defaultProps} from '../anchorForCommentsOnlyPropTypes';
import fileDownload from '../../../libs/fileDownload';
import Text from '../../Text';
import PressableWithSecondaryInteraction from '../../PressableWithSecondaryInteraction';
import {showContextMenu} from '../../../pages/home/report/ContextMenu/ReportActionContextMenu';
import {CONTEXT_MENU_TYPES} from '../../../pages/home/report/ContextMenu/ContextMenuActions';
import AttachmentView from '../../AttachmentView';

/*
* This is a default anchor component for regular links.
Expand All @@ -15,13 +16,28 @@ const BaseAnchorForCommentsOnly = ({
href,
children,
style,
shouldDownloadFile,
isAttachment,
fileName,
...props
}) => {
let linkRef;
return (
<PressableWithSecondaryInteraction
onSecondaryInteraction={
isAttachment
? (
<Pressable onPress={() => {
fileDownload(href);
}}
>
<AttachmentView
sourceURL={href}
file={{name: fileName}}
shouldShowDownloadIcon
/>
</Pressable>
)
: (
<PressableWithSecondaryInteraction
onSecondaryInteraction={
(event) => {
showContextMenu(
CONTEXT_MENU_TYPES.LINK,
Expand All @@ -31,17 +47,18 @@ const BaseAnchorForCommentsOnly = ({
);
}
}
onPress={() => (shouldDownloadFile ? fileDownload(href) : Linking.openURL(href))}
>
<Text
ref={el => linkRef = el}
style={StyleSheet.flatten(style)}
onPress={() => Linking.openURL(href)}
>
<Text
ref={el => linkRef = el}
style={StyleSheet.flatten(style)}
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
>
{children}
</Text>
</PressableWithSecondaryInteraction>
{...props}
>
{children}
</Text>
</PressableWithSecondaryInteraction>
)
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,29 @@ const propTypes = {
This is unused in native, but is here for parity with web */
target: PropTypes.string,

/** Should the link be treated as a file download or a regular hyperlink? (relevant to native platforms only) */
shouldDownloadFile: PropTypes.bool,
/** Flag to differentiate attachments and hyperlink. Base on flag link will be treated as a file download or a regular hyperlink */
isAttachment: PropTypes.bool,

/** Any children to display */
children: PropTypes.node,

/** Display label in case of attachments */
fileName: PropTypes.string,

/** Any additional styles to apply */
// eslint-disable-next-line react/forbid-prop-types
style: PropTypes.any,

};

const defaultProps = {
href: '',
rel: '',
target: '',
shouldDownloadFile: false,
isAttachment: false,
children: null,
style: {},
fileName: '',
};

export {propTypes, defaultProps};
2 changes: 1 addition & 1 deletion src/components/AnchorForCommentsOnly/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const AnchorForCommentsOnly = (props) => {
const propsToPass = _.omit(props, 'isAuthTokenRequired');
if (props.isAuthTokenRequired) {
propsToPass.href = addEncryptedAuthTokenToURL(props.href);
propsToPass.shouldDownloadFile = true;
propsToPass.isAttachment = true;
}
// eslint-disable-next-line react/jsx-props-no-spreading
return <BaseAnchorForCommentsOnly {...propsToPass} />;
Expand Down
11 changes: 10 additions & 1 deletion src/components/AttachmentView.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import styles from '../styles/styles';
import PDFView from './PDFView';
import ImageView from './ImageView';
import Icon from './Icon';
import {Paperclip} from './Icon/Expensicons';
import {Paperclip, Download} from './Icon/Expensicons';
import withLocalize, {withLocalizePropTypes} from './withLocalize';
import compose from '../libs/compose';
import Text from './Text';
Expand All @@ -20,13 +20,17 @@ const propTypes = {
name: PropTypes.string,
}),

/** Flag to show/hide download icon */
shouldShowDownloadIcon: PropTypes.bool,

...withLocalizePropTypes,
};

const defaultProps = {
file: {
name: '',
},
shouldShowDownloadIcon: false,
};

const AttachmentView = (props) => {
Expand Down Expand Up @@ -58,6 +62,11 @@ const AttachmentView = (props) => {
<Icon src={Paperclip} />
</View>
<Text style={[styles.textStrong]}>{props.file && props.file.name}</Text>
{props.shouldShowDownloadIcon && (
<View style={styles.ml2}>
<Icon src={Download} />
</View>
)}
</View>
);
};
Expand Down
4 changes: 4 additions & 0 deletions src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
splitBoxModelStyle,
} from 'react-native-render-html';
import PropTypes from 'prop-types';
import lodashGet from 'lodash/get';
import Config from '../../CONFIG';
import styles, {webViewStyles, getFontFamilyMonospace} from '../../styles/styles';
import fontFamily from '../../styles/fontFamily';
Expand Down Expand Up @@ -67,6 +68,8 @@ function AnchorRenderer({tnode, key, style}) {

// An auth token is needed to download Expensify chat attachments
const isAttachment = Boolean(htmlAttribs['data-expensify-source']);
const fileName = lodashGet(tnode, 'domNode.children[0].data', '');

return (
<AnchorForCommentsOnly
href={htmlAttribs.href}
Expand All @@ -81,6 +84,7 @@ function AnchorRenderer({tnode, key, style}) {
rel={htmlAttribs.rel || 'noopener noreferrer'}
style={style}
key={key}
fileName={fileName}
>
<TNodeChildrenRenderer tnode={tnode} />
</AnchorForCommentsOnly>
Expand Down
5 changes: 3 additions & 2 deletions src/libs/fileDownload/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import getAttachmentName from './getAttachmentName';
/**
* Downloading attachment in web, desktop
* @param {String} url
* @param {String} fileName
*/
export default function fileDownload(url) {
export default function fileDownload(url, fileName) {
fetch(url)
.then(response => response.blob())
.then((blob) => {
Expand All @@ -22,7 +23,7 @@ export default function fileDownload(url) {
link.style.display = 'none';
link.setAttribute(
'download',
getAttachmentName(url), // generating the file name
fileName ?? getAttachmentName(url), // generating the file name
);

// Append to html link element page
Expand Down
12 changes: 7 additions & 5 deletions src/libs/fileDownload/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,15 @@ function showAlert(content) {
/**
* Handling the download
* @param {String} url
* @param {String} fileName
*/
function handleDownload(url) {
function handleDownload(url, fileName) {
const dirs = RNFetchBlob.fs.dirs;

// android files will download to Download directory
// ios files will download to documents directory
const path = getPlatform() === 'android' ? dirs.DownloadDir : dirs.DocumentDir;
const attachmentName = getAttachmentName(url);
const attachmentName = fileName ?? getAttachmentName(url);

// fetching the attachment
const fetchedAttachment = RNFetchBlob.config({
Expand Down Expand Up @@ -104,8 +105,9 @@ function handleDownload(url) {
/**
* Platform specifically check download
* @param {String} url
* @param {String} fileName
*/
export default function fileDownload(url) {
export default function fileDownload(url, fileName) {
const permissionError = {
title: 'Access Needed',
// eslint-disable-next-line max-len
Expand All @@ -126,7 +128,7 @@ export default function fileDownload(url) {
if (getPlatform() === 'android') {
hasAndroidPermission().then((hasPermission) => {
if (hasPermission) {
handleDownload(url);
handleDownload(url, fileName);
return;
}

Expand All @@ -135,6 +137,6 @@ export default function fileDownload(url) {
showAlert(permissionError);
});
} else {
handleDownload(url);
handleDownload(url, fileName);
}
}

0 comments on commit 90bff75

Please sign in to comment.