-
Notifications
You must be signed in to change notification settings - Fork 1.5k
[NEW] Preview or download attachments #3470
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 16 commits
b4a394a
27e4ab1
c631493
299b203
6c36321
19794c3
81a8c3c
d5c07dc
7f7dc3a
20b9a1a
0a4e4f7
0befc81
7c7e20d
64675d7
febb261
182ebab
4df0524
b6e7a38
da32e38
dd6fdbf
0e105c6
554df95
d707d39
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| import RNFetchBlob from 'rn-fetch-blob'; | ||
|
|
||
| export const DOCUMENTS_PATH = `${RNFetchBlob.fs.dirs.DocumentDir}/`; | ||
| export const DOWNLOAD_PATH = `${RNFetchBlob.fs.dirs.DownloadDir}/`; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,15 +1,19 @@ | ||
| import React, { useContext } from 'react'; | ||
| import React, { useContext, useState } from 'react'; | ||
| import { StyleSheet } from 'react-native'; | ||
| import { dequal } from 'dequal'; | ||
|
|
||
| import Touchable from './Touchable'; | ||
| import Markdown from '../markdown'; | ||
| import openLink from '../../utils/openLink'; | ||
| import { isIOS } from '../../utils/deviceInfo'; | ||
| import { CustomIcon } from '../../lib/Icons'; | ||
| import { formatAttachmentUrl } from '../../lib/utils'; | ||
| import { themes } from '../../constants/colors'; | ||
| import MessageContext from './Context'; | ||
| import { fileDownload } from '../../utils/fileDownload'; | ||
| import EventEmitter from '../../utils/events'; | ||
| import { LISTENER } from '../Toast'; | ||
| import I18n from '../../i18n'; | ||
| import RCActivityIndicator from '../ActivityIndicator'; | ||
|
|
||
| const SUPPORTED_TYPES = ['video/quicktime', 'video/mp4', ...(isIOS ? [] : ['video/3gp', 'video/mkv'])]; | ||
| const isTypeSupported = (type: any) => SUPPORTED_TYPES.indexOf(type) !== -1; | ||
|
|
@@ -27,6 +31,9 @@ const styles = StyleSheet.create({ | |
|
|
||
| interface IMessageVideo { | ||
| file: { | ||
| title: string; | ||
| title_link: string; | ||
| type: string; | ||
| video_type: string; | ||
| video_url: string; | ||
| description: string; | ||
|
|
@@ -39,15 +46,34 @@ interface IMessageVideo { | |
| const Video = React.memo( | ||
| ({ file, showAttachment, getCustomEmoji, theme }: IMessageVideo) => { | ||
| const { baseUrl, user } = useContext(MessageContext); | ||
| const [loading, setLoading] = useState(false); | ||
|
|
||
| if (!baseUrl) { | ||
| return null; | ||
| } | ||
| const onPress = () => { | ||
| const onPress = async () => { | ||
| if (isTypeSupported(file.video_type)) { | ||
| return showAttachment(file); | ||
| } | ||
| const uri = formatAttachmentUrl(file.video_url, user.id, user.token, baseUrl); | ||
| openLink(uri, theme); | ||
|
|
||
| if (!isIOS) { | ||
| const uri = formatAttachmentUrl(file.video_url, user.id, user.token, baseUrl); | ||
| await downloadVideo(uri); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On my Android, it's just showing
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In this case I didn't want to redirect the user, because is not all android has a default app to reproduce .WEB videos, so as we cant insurence that, I preferred just download the file to downloads folder. |
||
| return; | ||
| } | ||
| EventEmitter.emit(LISTENER, { message: I18n.t('Unsupported_format') }); | ||
| }; | ||
|
|
||
| const downloadVideo = async (uri: string) => { | ||
| setLoading(true); | ||
| const fileDownloaded = await fileDownload(uri, file); | ||
| setLoading(false); | ||
|
|
||
| if (fileDownloaded) { | ||
| EventEmitter.emit(LISTENER, { message: I18n.t('saved_to_gallery') }); | ||
| return; | ||
| } | ||
| EventEmitter.emit(LISTENER, { message: I18n.t('error-save-video') }); | ||
| }; | ||
|
|
||
| return ( | ||
|
|
@@ -56,7 +82,11 @@ const Video = React.memo( | |
| onPress={onPress} | ||
| style={[styles.button, { backgroundColor: themes[theme].videoBackground }]} | ||
| background={Touchable.Ripple(themes[theme].bannerBackground)}> | ||
| <CustomIcon name='play-filled' size={54} color={themes[theme].buttonText} /> | ||
| {loading ? ( | ||
| <RCActivityIndicator theme={theme} /> | ||
| ) : ( | ||
| <CustomIcon name='play-filled' size={54} color={themes[theme].buttonText} /> | ||
| )} | ||
| </Touchable> | ||
| {/* @ts-ignore*/} | ||
| <Markdown | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| import RNFetchBlob, { FetchBlobResponse } from 'rn-fetch-blob'; | ||
| import FileViewer from 'react-native-file-viewer'; | ||
|
|
||
| import EventEmitter from '../events'; | ||
| import { LISTENER } from '../../containers/Toast'; | ||
| import I18n from '../../i18n'; | ||
| import { DOCUMENTS_PATH, DOWNLOAD_PATH } from '../../constants/localPath'; | ||
|
|
||
| interface IAttachment { | ||
| title: string; | ||
| title_link: string; | ||
| type: string; | ||
| description: string; | ||
| } | ||
|
|
||
| export const getExtensionType = (text: string): string | undefined => text.split('.').pop(); | ||
|
|
||
| export const getLocalFilePathFromFile = (localPath: string, attachment: IAttachment): string => { | ||
| const fileName = attachment.title.split('.')[0]; | ||
| return `${localPath}${fileName}.${getExtensionType(attachment.title_link)}`; | ||
|
diegolmello marked this conversation as resolved.
Outdated
|
||
| }; | ||
|
|
||
| export const fileDownload = (url: string, attachment: IAttachment): Promise<FetchBlobResponse> => { | ||
| const path = getLocalFilePathFromFile(DOWNLOAD_PATH, attachment); | ||
|
|
||
| const options = { | ||
| path, | ||
| timeout: 10000, | ||
| indicator: true, | ||
| overwrite: true, | ||
| addAndroidDownloads: { | ||
| path, | ||
| notification: true, | ||
| useDownloadManager: true | ||
| } | ||
| }; | ||
|
|
||
| return RNFetchBlob.config(options).fetch('GET', url); | ||
| }; | ||
|
|
||
| export const fileDownloadAndPreview = async (url: string, attachment: IAttachment): Promise<void> => { | ||
| const path = getLocalFilePathFromFile(DOCUMENTS_PATH, attachment); | ||
| const file = await RNFetchBlob.config({ | ||
| timeout: 10000, | ||
| indicator: true, | ||
| path | ||
| }).fetch('GET', url); | ||
|
|
||
| if (file) { | ||
|
AlexAlexandre marked this conversation as resolved.
Outdated
|
||
| FileViewer.open(file.data, { | ||
| showOpenWithDialog: true, | ||
| showAppsSuggestions: true | ||
| }) | ||
| .then(res => res) | ||
| .catch(() => { | ||
| EventEmitter.emit(LISTENER, { message: I18n.t('Downloaded_file') }); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On my Android phone, it's only showing this message.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, on my Android tests, when the user don't have a default app installed we redirect to the play store, I forgot to upload the Android prints screens, but I did it right now. I fixed the catch to download the files when the app can't show the preview, it's works now! |
||
| }); | ||
| } | ||
| }; | ||
Uh oh!
There was an error while loading. Please reload this page.