From b136de4ebaa32cc0651ee9a66f9598454d8adac2 Mon Sep 17 00:00:00 2001 From: bang9 Date: Mon, 21 Aug 2023 19:23:08 +0900 Subject: [PATCH] feat: implement cli player service --- packages/uikit-react-native/package.json | 2 + .../platform/createPlayerService.native.tsx | 91 +++++++++++++++++++ .../uikit-react-native/src/platform/types.ts | 12 +++ yarn.lock | 15 ++- 4 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 packages/uikit-react-native/src/platform/createPlayerService.native.tsx diff --git a/packages/uikit-react-native/package.json b/packages/uikit-react-native/package.json index 8e8c84d70..7cb1e3702 100644 --- a/packages/uikit-react-native/package.json +++ b/packages/uikit-react-native/package.json @@ -89,6 +89,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-builder-bob": "^0.18.0", "react-native-create-thumbnail": "^1.5.1", "react-native-document-picker": "^8.0.0", @@ -118,6 +119,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-create-thumbnail": ">=1.5.1", "react-native-document-picker": ">=8.0.0", "react-native-file-access": ">=2.4.3", diff --git a/packages/uikit-react-native/src/platform/createPlayerService.native.tsx b/packages/uikit-react-native/src/platform/createPlayerService.native.tsx new file mode 100644 index 000000000..cff97df9f --- /dev/null +++ b/packages/uikit-react-native/src/platform/createPlayerService.native.tsx @@ -0,0 +1,91 @@ +import { Platform } from 'react-native'; +import type * as RNAudioRecorder from 'react-native-audio-recorder-player'; +import * as Permissions from 'react-native-permissions'; + +import type { PlayerServiceInterface, Unsubscribe } from './types'; + +type Modules = { + audioRecorderModule: typeof RNAudioRecorder; + permissionModule: typeof Permissions; +}; + +const createNativePlayerService = ({ audioRecorderModule, permissionModule }: Modules): PlayerServiceInterface => { + const module = new audioRecorderModule.default(); + + class Player implements PlayerServiceInterface { + state: PlayerServiceInterface['state'] = 'idle'; + subscribers = new Set<(currentTime: number, duration: number) => void>(); + + constructor() { + this.state = 'idle'; + + module.setSubscriptionDuration(1); + module.addPlayBackListener((data) => { + this.subscribers.forEach((callback) => { + callback(data.currentPosition, data.duration); + }); + }); + } + + async requestPermission(): Promise { + if (Platform.OS === 'android') { + const { READ_MEDIA_AUDIO, READ_EXTERNAL_STORAGE } = permissionModule.PERMISSIONS.ANDROID; + const permission = Platform.Version > 32 ? READ_MEDIA_AUDIO : READ_EXTERNAL_STORAGE; + + const status = await permissionModule.check(permission); + if (status === 'granted') { + return true; + } else { + const status = await permissionModule.request(permission); + return status === 'granted'; + } + } else { + return true; + } + } + + async play(uri: string, headers?: Record): Promise { + if (this.state === 'playing') return; + + await module.startPlayer(uri, headers); + this.state = 'playing'; + } + + async seek(time: number): Promise { + if (this.state !== 'playing') return; + + await module.seekToPlayer(time); + } + + async pause(): Promise { + if (this.state === 'paused' || this.state === 'stopped') return; + + await module.pausePlayer(); + this.state = 'paused'; + } + + async stop(): Promise { + if (this.state === 'stopped') return; + + await module.stopPlayer(); + this.state = 'stopped'; + } + + async reset(): Promise { + await this.stop(); + this.state = 'idle'; + this.subscribers.clear(); + } + + addListener(callback: (currentTime: number, duration: number) => void): Unsubscribe { + this.subscribers.add(callback); + return () => { + this.subscribers.delete(callback); + }; + } + } + + return new Player(); +}; + +export default createNativePlayerService; diff --git a/packages/uikit-react-native/src/platform/types.ts b/packages/uikit-react-native/src/platform/types.ts index 91fdb68d5..f0c0b60c2 100644 --- a/packages/uikit-react-native/src/platform/types.ts +++ b/packages/uikit-react-native/src/platform/types.ts @@ -105,3 +105,15 @@ export interface MediaServiceInterface { getVideoThumbnail(options: GetVideoThumbnailOptions): GetVideoThumbnailResult; compressImage(options: CompressImageOptions): CompressImageResult; } + +// ---------- PlayerService ---------- // +export interface PlayerServiceInterface { + state: 'idle' | 'prepared' | 'playing' | 'paused' | 'stopped'; + requestPermission(): Promise; + play(uri: string, headers?: Record): Promise; + seek(time: number): Promise; + pause(): Promise; + stop(): Promise; + reset(): Promise; + addListener(callback: (currentTime: number, duration: number) => void): Unsubscribe; +} diff --git a/yarn.lock b/yarn.lock index b9fcec25e..5bbd8cd12 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3372,7 +3372,7 @@ dependencies: nanoid "^3.1.23" -"@sendbird/chat@4.9.8", "@sendbird/chat@^4.9.8": +"@sendbird/chat@^4.9.8": version "4.9.8" resolved "https://registry.yarnpkg.com/@sendbird/chat/-/chat-4.9.8.tgz#c70378fc1da684ea0c532b2e55bd8b1f3939838c" integrity sha512-tRTr/5iXl4Fhxon6T8yO2xaRxvyO2KctFjqdEHVLW9JuhWEAWiWZsY/5Lbxivi/Pt+ebiQuBhl/af3V1WOJDCg== @@ -6801,6 +6801,11 @@ domexception@^2.0.1: dependencies: webidl-conversions "^5.0.0" +dooboolab-welcome@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/dooboolab-welcome/-/dooboolab-welcome-1.3.2.tgz#4928595312f0429b4ea1b485ba8767bae6acdab7" + integrity sha512-2NbMaIIURElxEf/UAoVUFlXrO+7n/FRhLCiQlk4fkbGRh9cJ3/f8VEMPveR9m4Ug2l2Zey+UCXjd6EcBqHJ5bw== + dot-prop@^5.1.0: version "5.3.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" @@ -12911,6 +12916,14 @@ react-is@^17.0.1, react-is@^17.0.2: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== +react-native-audio-recorder-player@^3.5.1, react-native-audio-recorder-player@^3.5.4: + version "3.5.4" + resolved "https://registry.yarnpkg.com/react-native-audio-recorder-player/-/react-native-audio-recorder-player-3.5.4.tgz#b40383a330c203accecd357069c5fc1ee36a1286" + integrity sha512-aYGUTcswbIkvA729xysW19Onnd6DlNEnR+34m3F/8LpiQg+LfaPiP0aWRhS+7hmm5r19Sb5LEM+Ik3baoc6STA== + dependencies: + dooboolab-welcome "^1.3.2" + react-native-audio-recorder-player "^3.5.1" + react-native-builder-bob@^0.18.0, react-native-builder-bob@^0.18.2: version "0.18.3" resolved "https://registry.yarnpkg.com/react-native-builder-bob/-/react-native-builder-bob-0.18.3.tgz#fb4d3e50a3b2290db3c88de6d40403ac7eb9f85f"