Skip to content
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

Implementing the Audio Playback/Download on the chat #7900

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
5ec1d1f
feat: added new check for isAudio and added the supported mime types
panoramix360 Mar 19, 2024
76941b7
feat: adding the progress and audio on the audio file message
panoramix360 Apr 8, 2024
194f3ba
feat: finishing the layout of the audio_file
panoramix360 Apr 8, 2024
c430e1c
feat: play and pause audio
panoramix360 Apr 10, 2024
4002a3c
feat: update the progress bar when audio is playing
panoramix360 Apr 10, 2024
5d5db18
feat: update the timeframe of the audio
panoramix360 Apr 10, 2024
792a432
feat: update with the new design
panoramix360 May 1, 2024
76f4743
feat: adding download and preview
panoramix360 May 7, 2024
f14ca20
feat: creates a hook for the file download and preview
panoramix360 May 15, 2024
d57b871
feat: adding useCallback to make the return stable
panoramix360 May 22, 2024
219ea98
fix: iOS issue when playing in loop
panoramix360 May 28, 2024
9573d6b
feat: adding localization for the error
panoramix360 May 28, 2024
8384df8
fix: removing code tha was inserted for debug
panoramix360 May 28, 2024
20232d8
feat: add a new line on the en.json
panoramix360 Jun 10, 2024
8ab0e89
fix: fixing types
panoramix360 Aug 5, 2024
6eb636c
feat: adding the onSeek method inside the progress bar
panoramix360 Aug 26, 2024
1be3e66
feat: changing progress value to animated value
panoramix360 Aug 26, 2024
7faadd2
feat: changing to GestureDetector and making the seek method work
panoramix360 Aug 28, 2024
525370c
feat: adding a touchable without feedback to prevent the audio to tri…
panoramix360 Aug 28, 2024
3480f6e
feat: adding the drag on the seek method
panoramix360 Sep 5, 2024
136e2fd
feat: making the download button more gray
panoramix360 Sep 5, 2024
3144559
fix: fix tests
panoramix360 Sep 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
// See LICENSE.txt for license information.

import {Button} from '@rneui/base';
import React, {useCallback, useRef, useState} from 'react';
import React, {useCallback, useRef} from 'react';
import {StyleSheet, View} from 'react-native';

import ProgressBar from '@app/components/progress_bar';
import {useTheme} from '@app/context/theme';
import Document, {type DocumentRef} from '@components/document';
import {useDownloadFileAndPreview} from '@hooks/files';

import BookmarkDetails from './bookmark_details';

Expand All @@ -33,9 +34,9 @@ const styles = StyleSheet.create({
});

const BookmarkDocument = ({bookmark, canDownloadFiles, file, onLongPress}: Props) => {
const [progress, setProgress] = useState(0);
const document = useRef<DocumentRef>(null);
const theme = useTheme();
const {progress, toggleDownloadAndPreview} = useDownloadFileAndPreview();

const handlePress = useCallback(async () => {
if (document.current) {
Expand All @@ -47,7 +48,7 @@ const BookmarkDocument = ({bookmark, canDownloadFiles, file, onLongPress}: Props
<Document
canDownloadFiles={canDownloadFiles}
file={file.toFileInfo(bookmark.ownerId)}
onProgress={setProgress}
downloadAndPreviewFile={toggleDownloadAndPreview}
ref={document}
>
<Button
Expand Down
139 changes: 6 additions & 133 deletions app/components/document/index.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,10 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import {deleteAsync} from 'expo-file-system';
import {forwardRef, useImperativeHandle, useRef, useState, type ReactNode, useCallback} from 'react';
import {forwardRef, useImperativeHandle, type ReactNode, useCallback} from 'react';
import {useIntl} from 'react-intl';
import {Platform, StatusBar, type StatusBarStyle} from 'react-native';
import FileViewer from 'react-native-file-viewer';
import tinyColor from 'tinycolor2';

import {downloadFile} from '@actions/remote/file';
import {useServerUrl} from '@context/server';
import {useTheme} from '@context/theme';
import {alertDownloadDocumentDisabled, alertDownloadFailed, alertFailedToOpenDocument} from '@utils/document';
import {getFullErrorMessage, isErrorWithMessage} from '@utils/errors';
import {fileExists, getLocalFilePathFromFile} from '@utils/file';
import {logDebug} from '@utils/log';

import type {ClientResponse, ProgressPromise} from '@mattermost/react-native-network-client';
import {alertDownloadDocumentDisabled} from '@utils/document';

export type DocumentRef = {
handlePreviewPress: () => void;
Expand All @@ -26,135 +14,20 @@ type DocumentProps = {
canDownloadFiles: boolean;
file: FileInfo;
children: ReactNode;
onProgress: (progress: number) => void;
downloadAndPreviewFile: (file: FileInfo) => void;
}

const Document = forwardRef<DocumentRef, DocumentProps>(({canDownloadFiles, children, onProgress, file}: DocumentProps, ref) => {
const Document = forwardRef<DocumentRef, DocumentProps>(({canDownloadFiles, children, downloadAndPreviewFile, file}: DocumentProps, ref) => {
const intl = useIntl();
const serverUrl = useServerUrl();
const theme = useTheme();
const [didCancel, setDidCancel] = useState(false);
const [downloading, setDownloading] = useState(false);
const [preview, setPreview] = useState(false);
const downloadTask = useRef<ProgressPromise<ClientResponse>>();

const cancelDownload = () => {
setDidCancel(true);
if (downloadTask.current?.cancel) {
downloadTask.current.cancel();
}
};

const downloadAndPreviewFile = useCallback(async () => {
setDidCancel(false);
let path;
let exists = false;

try {
path = decodeURIComponent(file.localPath || '');
if (path) {
exists = await fileExists(path);
}

if (!exists) {
path = getLocalFilePathFromFile(serverUrl, file);
exists = await fileExists(path);
}

if (exists) {
openDocument();
} else {
setDownloading(true);
downloadTask.current = downloadFile(serverUrl, file.id!, path!);
downloadTask.current?.progress?.(onProgress);

await downloadTask.current;
onProgress(1);
openDocument();
}
} catch (error) {
if (path) {
deleteAsync(path, {idempotent: true});
}
setDownloading(false);
onProgress(0);

if (!isErrorWithMessage(error) || error.message !== 'cancelled') {
logDebug('error on downloadAndPreviewFile', getFullErrorMessage(error));
alertDownloadFailed(intl);
}
}
}, [file, onProgress]);

const setStatusBarColor = useCallback((style: StatusBarStyle = 'light-content') => {
if (Platform.OS === 'ios') {
if (style) {
StatusBar.setBarStyle(style, true);
} else {
const headerColor = tinyColor(theme.sidebarHeaderBg);
let barStyle: StatusBarStyle = 'light-content';
if (headerColor.isLight() && Platform.OS === 'ios') {
barStyle = 'dark-content';
}
StatusBar.setBarStyle(barStyle, true);
}
}
}, [theme]);

const openDocument = useCallback(async () => {
if (!didCancel && !preview) {
let path = decodeURIComponent(file.localPath || '');
let exists = false;
if (path) {
exists = await fileExists(path);
}

if (!exists) {
path = getLocalFilePathFromFile(serverUrl, file);
}

setPreview(true);
setStatusBarColor('dark-content');
FileViewer.open(path!.replace('file://', ''), {
displayName: decodeURIComponent(file.name),
onDismiss: onDonePreviewingFile,
showOpenWithDialog: true,
showAppsSuggestions: true,
}).then(() => {
setDownloading(false);
onProgress(0);
}).catch(() => {
alertFailedToOpenDocument(file, intl);
onDonePreviewingFile();

if (path) {
deleteAsync(path, {idempotent: true});
}
});
}
}, [didCancel, preview, file, onProgress, setStatusBarColor]);

const handlePreviewPress = useCallback(async () => {
if (!canDownloadFiles) {
alertDownloadDocumentDisabled(intl);
return;
}

if (downloading) {
onProgress(0);
cancelDownload();
setDownloading(false);
} else {
downloadAndPreviewFile();
}
}, [canDownloadFiles, downloadAndPreviewFile, downloading, intl, onProgress, openDocument]);

const onDonePreviewingFile = () => {
onProgress(0);
setDownloading(false);
setPreview(false);
setStatusBarColor();
};
downloadAndPreviewFile(file);
}, [canDownloadFiles, downloadAndPreviewFile, intl]);

useImperativeHandle(ref, () => ({
handlePreviewPress,
Expand Down
Loading
Loading