Skip to content

Commit

Permalink
Merge pull request #134 from sendbird/feat/voice-message/qa
Browse files Browse the repository at this point in the history
fix(UIKIT-4417): voice message qa
  • Loading branch information
bang9 authored Sep 30, 2023
2 parents 00f322e + 8401a32 commit ebe70d4
Show file tree
Hide file tree
Showing 32 changed files with 443 additions and 216 deletions.
85 changes: 54 additions & 31 deletions docs-validation/1_introduction/NativeModules.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ import {
createExpoFileService,
createExpoMediaService,
createExpoNotificationService,
createExpoPlayerService,
createExpoRecorderService,
createNativeClipboardService,
createNativeFileService,
createNativeMediaService,
createNativeNotificationService,
createNativePlayerService,
createNativeRecorderService,
} from '@sendbird/uikit-react-native';

/**
Expand All @@ -23,24 +27,35 @@ import * as ImagePicker from 'react-native-image-picker';
import * as Permissions from 'react-native-permissions';
import * as CreateThumbnail from 'react-native-create-thumbnail';
import * as ImageResizer from '@bam.tech/react-native-image-resizer';
import * as AudioRecorderPlayer from 'react-native-audio-recorder-player';

const NativeClipboardService = createNativeClipboardService(Clipboard);
const NativeNotificationService = createNativeNotificationService({
messagingModule: RNFBMessaging,
permissionModule: Permissions,
});
const NativeFileService = createNativeFileService({
fsModule: FileAccess,
permissionModule: Permissions,
imagePickerModule: ImagePicker,
mediaLibraryModule: CameraRoll,
documentPickerModule: DocumentPicker,
});
const NativeMediaService = createNativeMediaService({
VideoComponent: Video,
thumbnailModule: CreateThumbnail,
imageResizerModule: ImageResizer,
});
const nativePlatformServices = {
clipboard: createNativeClipboardService(Clipboard),
notification: createNativeNotificationService({
messagingModule: RNFBMessaging,
permissionModule: Permissions,
}),
file: createNativeFileService({
imagePickerModule: ImagePicker,
documentPickerModule: DocumentPicker,
permissionModule: Permissions,
fsModule: FileAccess,
mediaLibraryModule: CameraRoll,
}),
media: createNativeMediaService({
VideoComponent: Video,
thumbnailModule: CreateThumbnail,
imageResizerModule: ImageResizer,
}),
player: createNativePlayerService({
audioRecorderModule: AudioRecorderPlayer,
permissionModule: Permissions,
}),
recorder: createNativeRecorderService({
audioRecorderModule: AudioRecorderPlayer,
permissionModule: Permissions,
}),
};
/** ------------------ **/

/**
Expand All @@ -57,18 +72,26 @@ import * as ExpoAV from 'expo-av';
import * as ExpoVideoThumbnail from 'expo-video-thumbnails';
import * as ExpoImageManipulator from 'expo-image-manipulator';

const ExpoNotificationService = createExpoNotificationService(ExpoNotifications);
const ExpoClipboardService = createExpoClipboardService(ExpoClipboard);
const ExpoFileService = createExpoFileService({
fsModule: ExpoFS,
imagePickerModule: ExpoImagePicker,
mediaLibraryModule: ExpoMediaLibrary,
documentPickerModule: ExpoDocumentPicker,
});
const ExpoMediaService = createExpoMediaService({
avModule: ExpoAV,
thumbnailModule: ExpoVideoThumbnail,
imageManipulator: ExpoImageManipulator,
fsModule: ExpoFS,
})
const expoPlatformServices = {
clipboard: createExpoClipboardService(ExpoClipboard),
notification: createExpoNotificationService(ExpoNotifications),
file: createExpoFileService({
fsModule: ExpoFS,
imagePickerModule: ExpoImagePicker,
mediaLibraryModule: ExpoMediaLibrary,
documentPickerModule: ExpoDocumentPicker,
}),
media: createExpoMediaService({
avModule: ExpoAV,
thumbnailModule: ExpoVideoThumbnail,
imageManipulator: ExpoImageManipulator,
fsModule: ExpoFS,
}),
player: createExpoPlayerService({
avModule: ExpoAV,
}),
recorder: createExpoRecorderService({
avModule: ExpoAV,
}),
};
/** ------------------ **/
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ const Modal = ({
<KeyboardAvoidingView
// NOTE: This is trick for Android.
// When orientation is changed on Android, the offset that to avoid soft-keyboard is not updated normally.
key={`${width}-${height}`}
key={Platform.OS === 'android' && enableKeyboardAvoid ? `${width}-${height}` : undefined}
enabled={enableKeyboardAvoid}
style={styles.background}
behavior={Platform.select({ ios: 'padding', default: 'height' })}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React, { ReactNode, useEffect, useRef } from 'react';
import { Animated, Easing, StyleSheet, ViewStyle } from 'react-native';

import { NOOP } from '@sendbird/uikit-utils';

import useUIKitTheme from '../../theme/useUIKitTheme';
import Box from '../Box';

Expand All @@ -22,23 +24,22 @@ const ProgressBar = ({ current = 100, total = 100, trackColor, barColor, overlay

const progress = useRef(new Animated.Value(0)).current;
const percent = current / total;
const stopped = percent === 0;

useEffect(() => {
if (Number.isNaN(percent)) return;

const animation = Animated.timing(progress, {
toValue: percent,
duration: 100,
useNativeDriver: false,
easing: Easing.linear,
});
if (!Number.isNaN(percent)) {
const animation = Animated.timing(progress, {
toValue: stopped ? 0 : percent,
duration: stopped ? 0 : 100,
useNativeDriver: false,
easing: Easing.linear,
});

animation.start();
return () => {
if (Number.isNaN(percent)) return;
animation.start();
return () => animation.stop();
}

animation.stop();
};
return NOOP;
}, [percent]);

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';

import type { SendbirdFileMessage } from '@sendbird/uikit-utils';
import { millsToMSS } from '@sendbird/uikit-utils';
Expand All @@ -24,6 +24,7 @@ type Props = GroupChannelMessageProps<
SendbirdFileMessage,
{
durationMetaArrayKey?: string;
onUnmount: () => void;
}
>;
const VoiceFileMessage = (props: Props) => {
Expand All @@ -33,6 +34,7 @@ const VoiceFileMessage = (props: Props) => {
onToggleVoiceMessage,
message,
durationMetaArrayKey = 'KEY_VOICE_MESSAGE_DURATION',
onUnmount,
} = props;

const { colors } = useUIKitTheme();
Expand All @@ -48,7 +50,14 @@ const VoiceFileMessage = (props: Props) => {
};
});

useEffect(() => {
return () => {
onUnmount();
};
}, []);

const uiColors = colors.ui.groupChannelMessage[variant];
const remainingTime = state.duration - state.currentTime;

return (
<MessageContainer {...props}>
Expand Down Expand Up @@ -85,7 +94,7 @@ const VoiceFileMessage = (props: Props) => {
style={{ lineHeight: undefined, marginLeft: 6, opacity: 0.88 }}
color={uiColors.enabled.textVoicePlaytime}
>
{millsToMSS(state.currentTime === 0 ? state.duration : state.currentTime)}
{millsToMSS(state.currentTime === 0 ? state.duration : remainingTime)}
</Text>
</Box>
}
Expand Down
103 changes: 64 additions & 39 deletions packages/uikit-react-native/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ Add the following permissions to your `android/app/src/main/AndroidManifest.xml`
package="com.your.app">

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
Expand Down Expand Up @@ -123,6 +124,8 @@ const App = () => {
notification: NotificationService,
clipboard: ClipboardService,
media: MediaService,
recorder: RecorderService,
player: PlayerService,
}}
>
{/* ... */}
Expand All @@ -147,6 +150,7 @@ npm install react-native-video \
react-native-image-picker \
react-native-document-picker \
react-native-create-thumbnail \
react-native-audio-recorder-player \
@react-native-clipboard/clipboard \
@react-native-camera-roll/camera-roll \
@react-native-firebase/app \
Expand All @@ -157,34 +161,45 @@ npx pod-install
```

```ts
import * as ImageResizer from '@bam.tech/react-native-image-resizer';
import { CameraRoll } from '@react-native-camera-roll/camera-roll';
import Clipboard from '@react-native-clipboard/clipboard';
import { CameraRoll } from '@react-native-camera-roll/camera-roll';
import RNFBMessaging from '@react-native-firebase/messaging';
import * as CreateThumbnail from 'react-native-create-thumbnail';
import Video from 'react-native-video';
import * as DocumentPicker from 'react-native-document-picker';
import * as FileAccess from 'react-native-file-access';
import * as ImagePicker from 'react-native-image-picker';
import * as Permissions from 'react-native-permissions';
import Video from 'react-native-video';

const NativeClipboardService = createNativeClipboardService(Clipboard);
const NativeNotificationService = createNativeNotificationService({
messagingModule: RNFBMessaging,
permissionModule: Permissions,
});
const NativeFileService = createNativeFileService({
fsModule: FileAccess,
permissionModule: Permissions,
imagePickerModule: ImagePicker,
mediaLibraryModule: CameraRoll,
documentPickerModule: DocumentPicker,
});
const NativeMediaService = createNativeMediaService({
VideoComponent: Video,
thumbnailModule: CreateThumbnail,
imageResizerModule: ImageResizer,
});
import * as CreateThumbnail from 'react-native-create-thumbnail';
import * as ImageResizer from '@bam.tech/react-native-image-resizer';
import * as AudioRecorderPlayer from 'react-native-audio-recorder-player';

const nativePlatformServices = {
clipboard: createNativeClipboardService(Clipboard),
notification: createNativeNotificationService({
messagingModule: RNFBMessaging,
permissionModule: Permissions,
}),
file: createNativeFileService({
imagePickerModule: ImagePicker,
documentPickerModule: DocumentPicker,
permissionModule: Permissions,
fsModule: FileAccess,
mediaLibraryModule: CameraRoll,
}),
media: createNativeMediaService({
VideoComponent: Video,
thumbnailModule: CreateThumbnail,
imageResizerModule: ImageResizer,
}),
player: createNativePlayerService({
audioRecorderModule: AudioRecorderPlayer,
permissionModule: Permissions,
}),
recorder: createNativeRecorderService({
audioRecorderModule: AudioRecorderPlayer,
permissionModule: Permissions,
}),
};
```

**Using Expo CLI**
Expand All @@ -204,30 +219,38 @@ expo install expo-image-picker \
```

```ts
import * as ExpoAV from 'expo-av';
import * as ExpoClipboard from 'expo-clipboard';
import * as ExpoDocumentPicker from 'expo-document-picker';
import * as ExpoFS from 'expo-file-system';
import * as ExpoImageManipulator from 'expo-image-manipulator';
import * as ExpoImagePicker from 'expo-image-picker';
import * as ExpoMediaLibrary from 'expo-media-library';
import * as ExpoNotifications from 'expo-notifications';
import * as ExpoAV from 'expo-av';
import * as ExpoVideoThumbnail from 'expo-video-thumbnails';
import * as ExpoImageManipulator from 'expo-image-manipulator';

const ExpoNotificationService = createExpoNotificationService(ExpoNotifications);
const ExpoClipboardService = createExpoClipboardService(ExpoClipboard);
const ExpoFileService = createExpoFileService({
fsModule: ExpoFS,
imagePickerModule: ExpoImagePicker,
mediaLibraryModule: ExpoMediaLibrary,
documentPickerModule: ExpoDocumentPicker,
});
const ExpoMediaService = createExpoMediaService({
avModule: ExpoAV,
thumbnailModule: ExpoVideoThumbnail,
imageManipulator: ExpoImageManipulator,
fsModule: ExpoFS,
});
const expoPlatformServices = {
clipboard: createExpoClipboardService(ExpoClipboard),
notification: createExpoNotificationService(ExpoNotifications),
file: createExpoFileService({
fsModule: ExpoFS,
imagePickerModule: ExpoImagePicker,
mediaLibraryModule: ExpoMediaLibrary,
documentPickerModule: ExpoDocumentPicker,
}),
media: createExpoMediaService({
avModule: ExpoAV,
thumbnailModule: ExpoVideoThumbnail,
imageManipulator: ExpoImageManipulator,
fsModule: ExpoFS,
}),
player: createExpoPlayerService({
avModule: ExpoAV,
}),
recorder: createExpoRecorderService({
avModule: ExpoAV,
}),
};
```

### Local caching (required)
Expand All @@ -236,7 +259,7 @@ You can implement Local caching easily.

```shell
npm i @react-native-async-storage/async-storage
npx pod-isntall
npx pod-install
```

```tsx
Expand Down Expand Up @@ -420,6 +443,8 @@ const App = () => {
notification: NotificationService,
clipboard: ClipboardService,
media: MediaService,
recorder: RecorderService,
player: PlayerService,
}}
>
<Navigation />
Expand Down
4 changes: 2 additions & 2 deletions packages/uikit-react-native/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
"js-convert-case": "^4.2.0",
"react": "17.0.2",
"react-native": "0.67.5",
"react-native-audio-recorder-player": "^3.5.4",
"react-native-audio-recorder-player": "^3.6.0",
"react-native-builder-bob": "^0.18.0",
"react-native-create-thumbnail": "^1.5.1",
"react-native-document-picker": "^8.0.0",
Expand Down Expand Up @@ -120,7 +120,7 @@
"expo-video-thumbnails": ">=6.4.0",
"react": ">=17.0.2",
"react-native": ">=0.65.0",
"react-native-audio-recorder-player": ">=3.5.4",
"react-native-audio-recorder-player": ">=3.6.0",
"react-native-create-thumbnail": ">=1.5.1",
"react-native-document-picker": ">=8.0.0",
"react-native-file-access": ">=2.4.3",
Expand Down
Loading

0 comments on commit ebe70d4

Please sign in to comment.