Skip to content

Commit

Permalink
refactor: remove isQuoted prop from Attachment and QuotedAudioRecordi…
Browse files Browse the repository at this point in the history
…ng component
  • Loading branch information
MartinCupela committed Mar 24, 2023
1 parent 3f0c693 commit 664487d
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 228 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,5 @@ client/dist
/.virtualgo
.vscode/
coverage.out

docusaurus/shared
Original file line number Diff line number Diff line change
Expand Up @@ -19,34 +19,38 @@ import QuotedAudioRecording from "../../assets/audio-recording-quoted.png";
import QuotedAudioRecordingFileSizeFallback from "../../assets/audio-recording-quoted-file-size-fallback.png";
import QuotedAudioRecordingFallbackTitle from "../../assets/audio-recording-quoted-fallback-title.png";

Audio attachments recorded directly from the chat UI are called audio recordings. The SDK provides a default implementation called <GHComponentLink text='AudioRecording' path='/Attachment/AudioRecording.tsx'/>. The default component renders or <GHComponentLink text='AudioRecordingPlayer component' path='/Attachment/AudioRecording.tsx'/> or <GHComponentLink text='QuotedAudioRecording' path='/Attachment/AudioRecording.tsx'/>.
Audio attachments recorded directly from the chat UI are called audio recordings. The SDK provides a default implementation called <GHComponentLink text='AudioRecording' path='/Attachment/AudioRecording.tsx'/>.

The `AudioRecordingPlayer` component is displayed in the message attachment list and is used to reproduce the audio.
The `AudioRecording` component is displayed in the message attachment list and is used to reproduce the audio.

<ImageShowcase
border
items={[
{
image: AudioRecordingPlayer,
caption: <span>AudioRecordingPlayer component</span>,
alt: 'Image of the AudioRecordingPlayer component',
caption: <span>AudioRecording playercomponent</span>,
alt: 'Image of the AudioRecording playercomponent',
},
]}
/>

Whereas `QuotedAudioRecording` is used to display basic information about the audio recording in quoted message reply.
But it can be also rendered in a quoted message reply and display basic information about the audio recording .

<ImageShowcase
border
items={[
{
image: QuotedAudioRecording,
caption: <span>QuotedAudioRecording component</span>,
alt: 'Image of the QuotedAudioRecording component',
caption: <span>Quoted AudioRecording component</span>,
alt: 'Image of the quoted AudioRecording component',
},
]}
/>

:::note
The `stream-chat-react` does not currently support audio recording capability. The recording is supported by other our SDKs. The React SDK then displays the attachment.
:::

## Attachment payload

The response payload for the audio recording attachment comes with the following properties:
Expand All @@ -72,7 +76,7 @@ These properties serve the following purpose:
- **type** - the value will always be `"audio_recording"`
- **waveList** - the array of fractional number values between 0 and 1. These values represent the amplitudes later reflected in the <GHComponentLink text='WaveProgressBar' path='/Attachment/components/WaveProgressBar.tsx'/>

## AudioRecordingPlayer
## AudioRecording player

### Navigation

Expand All @@ -83,8 +87,8 @@ By clicking in the space of wave progress bar a user can navigate to a specific
items={[
{
image: AudioRecordingPlayerStoppedRepro,
caption: <span>AudioRecordingPlayer navigation</span>,
alt: 'Image of the AudioRecordingPlayer stopped in the middle of the reproduction',
caption: <span>AudioRecording player navigation</span>,
alt: 'Image of the AudioRecording player stopped in the middle of the reproduction',
},
]}
/>
Expand All @@ -98,8 +102,8 @@ The playback speed can be changed by clicking the <GHComponentLink text='Playba
items={[
{
image: AudioRecordingPlayerInProgress,
caption: <span>AudioRecordingPlayer playing the audio</span>,
alt: 'Image of the AudioRecordingPlayer playing the audio',
caption: <span>AudioRecording player playing the audio</span>,
alt: 'Image of the AudioRecording player playing the audio',
},
]}
/>
Expand All @@ -108,20 +112,20 @@ The playback speed can be changed by clicking the <GHComponentLink text='Playba

### Missing duration

If the duration is not available in the [attachment object payload](./#attachment-payload), `AudioRecordingPlayer` as well as `QuotedAudioRecording` component will display the attachment size instead.
If the duration is not available in the [attachment object payload](./#attachment-payload). The component will display the attachment size instead.

<ImageShowcase
border
items={[
{
image: AudioRecordingPlayerFileSizeFallback,
caption: <span>AudioRecordingPlayer displaying file size instead of audio duration</span>,
alt: 'Image of the AudioRecordingPlayer displaying file size instead of audio duration',
caption: <span>AudioRecording player displaying file size instead of audio duration</span>,
alt: 'Image of the AudioRecording player displaying file size instead of audio duration',
},
{
image: QuotedAudioRecordingFileSizeFallback,
caption: <span>QuotedAudioRecording displaying file size instead of audio duration</span>,
alt: 'Image of the QuotedAudioRecording displaying file size instead of audio duration',
caption: <span>Quoted AudioRecording displaying file size instead of audio duration</span>,
alt: 'Image of the AudioRecording in quoted reply displaying the file size instead of audio duration',
},
]}
/>
Expand All @@ -136,13 +140,13 @@ If the audio recording does not come with title, a fallback title is provided.
items={[
{
image: AudioRecordingPlayerFallbackTitle,
caption: <span>AudioRecordingPlayer displaying the fallback title</span>,
alt: 'Image of the AudioRecordingPlayer displaying the fallback title',
caption: <span>AudioRecording player displaying the fallback title</span>,
alt: 'Image of the AudioRecording player displaying the fallback title',
},
{
image: QuotedAudioRecordingFallbackTitle,
caption: <span>QuotedAudioRecording displaying the fallback title</span>,
alt: 'Image of the QuotedAudioRecording displaying the fallback title',
caption: <span>Quoted AudioRecording displaying the fallback title</span>,
alt: 'Image of the AudioRecording in quoted reply displaying the fallback title',
},
]}
/>
Expand All @@ -156,22 +160,22 @@ If the `waveList` is an empty array, then no progress bar is rendered.
items={[
{
image: AudioRecordingPlayerMissingWaveList,
caption: <span>AudioRecordingPlayer without progress bar</span>,
alt: 'Image of the AudioRecordingPlayer missing progress bar',
caption: <span>AudioRecording player without progress bar</span>,
alt: 'Image of the AudioRecording player missing progress bar',
},
]}
/>


## Audio player controller

The API to control the audio recording player is provided by <GHComponentLink text='useAudioController' path='/Attachment/hooks/useAudioController.tsx'/>. The `AudioRecordingPlayer` makes use of the following memoized functions:
The API to control the audio recording player is provided by <GHComponentLink text='useAudioController' path='/Attachment/hooks/useAudioController.tsx'/>. The `AudioRecording` makes use of the following memoized functions:

1. `togglePlay` - to start and stop playing the record
2. `seek` - to change audio progress
3. `increasePlaybackRate` - to change the playback rate in the round-robin manner

Besides the above actions, the controller maintains state in the following form:
Besides the above actions, the controller maintains the state in the following form:

1. `isPlaying` - boolean flag informing the UI, whether the reproduction is in flight
2. `progress` - numeric fractional value between 0 and 100 representing the progress of the audio reproduction
Expand All @@ -182,7 +186,7 @@ Besides the above actions, the controller maintains state in the following form:

The pattern of customization applied to the default `AudioRecording` component will be the same:

1. Create a custom audio recording component (e.g. `CustomAudioRecording`). It will serve as a wrapper component that renders `AudioRecordingPlayer` resp. `QuotedAudioRecording`. Pass props to these components.
1. Create a custom audio recording component (e.g. `CustomAudioRecording`). It will serve as a wrapper component that renders `AudioRecording` and override the props.

2. Create a custom attachment component (e.g. `CustomAttachment`), that will be again a wrapper around the SDK's `Attachment` component. Pass the custom audio recording component to the `Attachment` component via prop `AudioRecording`.

Expand All @@ -196,20 +200,16 @@ Example:
import {
Attachment,
AttachmentProps,
AudioRecordingPlayer,
AudioRecording,
AudioRecordingProps,
...
Channel,
...
QuotedAudioRecording,
} from 'stream-chat-react';

const CustomAudioRecording = ({ attachment, isQuoted }: AudioRecordingProps) =>
isQuoted ? (
<QuotedAudioRecording attachment={attachment} />
) : (
<AudioRecordingPlayer attachment={attachment} playbackRates={[2.0, 3.0]} />
);
const CustomAudioRecording = ({ attachment }: AudioRecordingProps) => (
<AudioRecording attachment={attachment} playbackRates={[2.0, 3.0]} />
);

const CustomAttachment = (props: AttachmentProps) => (
<Attachment {...props} AudioRecording={CustomAudioRecording}/>
Expand All @@ -236,9 +236,7 @@ This could be solved by customizing the styles. You can stop displaying the reco
### Customize the fallback title
If you do not like our fallback title, you can change it by changing the translation.
// todo: add the translation customization guide
If you do not like our fallback title, you can change it by [overriding the default translation](../../../guides/theming/translations/#override-default-translations).
### Other customizations
Expand All @@ -249,9 +247,9 @@ If you would like to perform the following customizations:
We recommend you to assemble your own components, that serve to display audio recording data and allow for reproduction. Then you can pass those components to the custom attachment component as described above.
The reason is, that `AudioRecordingPlayer` and `QuotedAudioRecording` are considerably small components. Addition of props for file icon components and progress bars, etc. would lead problems with their maintainability.
The reason is, that `AudioRecording` is quite a small component. Addition of props for file icon components and progress bars, etc. would lead problems with their maintainability.
You can always take an inspiration from the default implementation.
You can always take the inspiration from the default implementation.
## Props reference
Expand All @@ -265,24 +263,6 @@ The attachment object from the message's attachment list.
|------------|
| Attachment |
#### isQuoted
A boolean flag to signal whether the audio recording will be rendered inside the quoted reply.
| Type |
|---------|
| boolean |
### AudioRecordingPlayer
#### attachment
The attachment object from the message's attachment list.
| Type |
|------------|
| Attachment |
### playbackRates
An array of fractional numeric values of playback speed to override the defaults (1.0, 1.5, 2.0).
Expand Down Expand Up @@ -324,13 +304,3 @@ The array of fractional number values between 0 and 1 representing the height of
| Type |
|----------|
| number[] |
### QuotedAudioRecording
#### attachment
The attachment object from the message's attachment list.
| Type |
|------------|
| Attachment |
4 changes: 1 addition & 3 deletions src/components/Attachment/Attachment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export type AttachmentProps<
AttachmentActions?: React.ComponentType<AttachmentActionsProps<StreamChatGenerics>>;
/** Custom UI component for displaying an audio type attachment, defaults to and accepts same props as: [Audio](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Attachment/Audio.tsx) */
Audio?: React.ComponentType<AudioProps<StreamChatGenerics>>;
/** Custom UI component for displaying an audio recording attachment, defaults to and accepts same props as: [AudioRecordingProps](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Attachment/AudioRecording.tsx) */
/** Custom UI component for displaying an audio recording attachment, defaults to and accepts same props as: [AudioRecording](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Attachment/AudioRecording.tsx) */
AudioRecording?: React.ComponentType<AudioRecordingProps<StreamChatGenerics>>;
/** Custom UI component for displaying a card type attachment, defaults to and accepts same props as: [Card](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Attachment/Card.tsx) */
Card?: React.ComponentType<CardProps>;
Expand All @@ -75,8 +75,6 @@ export type AttachmentProps<
Gallery?: React.ComponentType<GalleryProps<StreamChatGenerics>>;
/** Custom UI component for displaying an image type attachment, defaults to and accepts same props as: [Image](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Gallery/Image.tsx) */
Image?: React.ComponentType<ImageProps>;
/** Optional flag to signal that an attachment is a displayed as a part of a quoted message */
isQuoted?: boolean;
/** Custom UI component for displaying a media type attachment, defaults to `ReactPlayer` from 'react-player' */
Media?: React.ComponentType<ReactPlayerProps>;
/** Custom UI component for displaying unsupported attachment types, defaults to NullComponent */
Expand Down
3 changes: 1 addition & 2 deletions src/components/Attachment/AttachmentContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -243,11 +243,10 @@ export const AudioRecordingContainer = <
>({
attachment,
AudioRecording = DefaultAudioRecording,
isQuoted,
}: RenderAttachmentProps<StreamChatGenerics>) => (
<AttachmentWithinContainer attachment={attachment} componentType='audioRecording'>
<div className='str-chat__attachment'>
<AudioRecording attachment={attachment} isQuoted={isQuoted} />
<AudioRecording attachment={attachment} />
</div>
</AttachmentWithinContainer>
);
Expand Down
60 changes: 6 additions & 54 deletions src/components/Attachment/AudioRecording.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ import { useTranslationContext } from '../../context';

import type { DefaultStreamChatGenerics } from '../../types/types';

type AudioRecordingPlayerProps<
export type AudioRecordingProps<
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics
> = Pick<AudioRecordingProps<StreamChatGenerics>, 'attachment'> & {
> = {
/** The attachment object from the message's attachment list. */
attachment: Attachment<StreamChatGenerics>;
/** An array of fractional numeric values of playback speed to override the defaults (1.0, 1.5, 2.0) */
playbackRates?: number[];
};

export const AudioRecordingPlayer = ({ attachment, playbackRates }: AudioRecordingPlayerProps) => {
export const AudioRecordingPlayer = ({ attachment, playbackRates }: AudioRecordingProps) => {
const { t } = useTranslationContext('AudioRecording');
const {
asset_url,
Expand Down Expand Up @@ -85,54 +87,4 @@ export const AudioRecordingPlayer = ({ attachment, playbackRates }: AudioRecordi
);
};

export type QuotedAudioRecordingProps<
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics
> = Pick<AudioRecordingProps<StreamChatGenerics>, 'attachment'>;

export const QuotedAudioRecording = ({ attachment }: QuotedAudioRecordingProps) => {
const { t } = useTranslationContext();
const title = attachment.title || t<string>('Voice message');
return (
<div
className='str-chat__message-attachment__quoted-audio-recording-widget'
data-testid='quoted-audio-recording-widget'
>
<div className='str-chat__message-attachment__quoted-audio-recording-widget__info'>
<div
className='str-chat__message-attachment__quoted-audio-recording-widget__title'
title={title}
>
{title}
</div>
<div className='str-chat__message-attachment__quoted-audio-recording-widget__timer'>
{attachment.duration ? (
secondsToTime(attachment.duration / 1000)
) : (
<FileSizeIndicator fileSize={attachment.file_size} maximumFractionDigits={0} />
)}
</div>
</div>
<FileIcon big={true} mimeType={attachment.mime_type} size={34} version={'2'} />
</div>
);
};

export type AudioRecordingProps<
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics
> = {
/** The attachment object from the message's attachment list. */
attachment: Attachment<StreamChatGenerics>;
/** A boolean flag to signal whether the attachment will be rendered inside the quoted reply. */
isQuoted?: boolean;
};

const UnMemoizedAudioRecording = ({ attachment, isQuoted }: AudioRecordingProps) =>
isQuoted ? (
<QuotedAudioRecording attachment={attachment} />
) : (
<AudioRecordingPlayer attachment={attachment} />
);

export const AudioRecording = React.memo(
UnMemoizedAudioRecording,
) as typeof UnMemoizedAudioRecording;
export const AudioRecording = React.memo(AudioRecordingPlayer) as typeof AudioRecordingPlayer;
Loading

0 comments on commit 664487d

Please sign in to comment.