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 24 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2aa24a9
feat: added new check for isAudio and added the supported mime types
panoramix360 Mar 19, 2024
04651eb
feat: adding the progress and audio on the audio file message
panoramix360 Apr 8, 2024
30da764
feat: finishing the layout of the audio_file
panoramix360 Apr 8, 2024
012467a
feat: play and pause audio
panoramix360 Apr 10, 2024
b029481
feat: update the progress bar when audio is playing
panoramix360 Apr 10, 2024
01180e6
feat: update the timeframe of the audio
panoramix360 Apr 10, 2024
0b2ddf8
feat: update with the new design
panoramix360 May 1, 2024
6455466
feat: adding download and preview
panoramix360 May 7, 2024
256af5e
feat: creates a hook for the file download and preview
panoramix360 May 15, 2024
405bd5f
feat: adding useCallback to make the return stable
panoramix360 May 22, 2024
bf67960
fix: iOS issue when playing in loop
panoramix360 May 28, 2024
cb31369
feat: adding localization for the error
panoramix360 May 28, 2024
ec6a404
fix: removing code tha was inserted for debug
panoramix360 May 28, 2024
c4f9055
feat: add a new line on the en.json
panoramix360 Jun 10, 2024
8b47feb
fix: fixing types
panoramix360 Aug 5, 2024
f6800a0
feat: adding the onSeek method inside the progress bar
panoramix360 Aug 26, 2024
cfc5744
feat: changing progress value to animated value
panoramix360 Aug 26, 2024
7988700
feat: changing to GestureDetector and making the seek method work
panoramix360 Aug 28, 2024
d68aaae
feat: adding a touchable without feedback to prevent the audio to tri…
panoramix360 Aug 28, 2024
396633c
feat: adding the drag on the seek method
panoramix360 Sep 5, 2024
e3b80d5
feat: making the download button more gray
panoramix360 Sep 5, 2024
5658fa0
fix: fix tests
panoramix360 Sep 5, 2024
a440f87
fix: prevent onProgress from clearing the seconds when the audio is p…
panoramix360 Oct 2, 2024
7121f40
feat: clamping the position of the cursor to never be dragged offscreen
panoramix360 Oct 2, 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