From a9539ce68760fa3128b70acb66fbbaba9d88bdf8 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 3 Oct 2024 09:38:44 +0700 Subject: [PATCH 01/12] create platform specific code for sound --- src/libs/Sound/BaseSound.ts | 60 +++++++++++++++++ src/libs/Sound/index.native.ts | 19 ++++++ src/libs/Sound/index.ts | 118 ++++++++++++++++++--------------- 3 files changed, 142 insertions(+), 55 deletions(-) create mode 100644 src/libs/Sound/BaseSound.ts create mode 100644 src/libs/Sound/index.native.ts diff --git a/src/libs/Sound/BaseSound.ts b/src/libs/Sound/BaseSound.ts new file mode 100644 index 000000000000..ae0561ca4b6d --- /dev/null +++ b/src/libs/Sound/BaseSound.ts @@ -0,0 +1,60 @@ +import Onyx from 'react-native-onyx'; +import Sound from 'react-native-sound'; +import type {ValueOf} from 'type-fest'; +import ONYXKEYS from '@src/ONYXKEYS'; +import config from './config'; + +let isMuted = false; + +Onyx.connect({ + key: ONYXKEYS.USER, + callback: (val) => (isMuted = !!val?.isMutedAllSounds), +}); + +const SOUNDS = { + DONE: 'done', + SUCCESS: 'success', + ATTENTION: 'attention', + RECEIVE: 'receive', +} as const; + +/** + * Creates a version of the given function that, when called, queues the execution and ensures that + * calls are spaced out by at least the specified `minExecutionTime`, even if called more frequently. This allows + * for throttling frequent calls to a function, ensuring each is executed with a minimum `minExecutionTime` between calls. + * Each call returns a promise that resolves when the function call is executed, allowing for asynchronous handling. + */ +function withMinimalExecutionTime) => ReturnType>(func: F, minExecutionTime: number) { + const queue: Array<[() => ReturnType, (value?: unknown) => void]> = []; + let timerId: NodeJS.Timeout | null = null; + + function processQueue() { + if (queue.length > 0) { + const next = queue.shift(); + + if (!next) { + return; + } + + const [nextFunc, resolve] = next; + nextFunc(); + resolve(); + timerId = setTimeout(processQueue, minExecutionTime); + } else { + timerId = null; + } + } + + return function (...args: Parameters) { + return new Promise((resolve) => { + queue.push([() => func(...args), resolve]); + + if (!timerId) { + // If the timer isn't running, start processing the queue + processQueue(); + } + }); + }; +} + +export {SOUNDS, withMinimalExecutionTime, isMuted}; diff --git a/src/libs/Sound/index.native.ts b/src/libs/Sound/index.native.ts new file mode 100644 index 000000000000..e2f779d83d48 --- /dev/null +++ b/src/libs/Sound/index.native.ts @@ -0,0 +1,19 @@ +import Onyx from 'react-native-onyx'; +import Sound from 'react-native-sound'; +import type {ValueOf} from 'type-fest'; +import ONYXKEYS from '@src/ONYXKEYS'; +import config from './config'; +import { SOUNDS, isMuted, withMinimalExecutionTime } from './BaseSound' + +const playSound = (soundFile: ValueOf) => { + const sound = new Sound(`${config.prefix}${soundFile}.mp3`, Sound.MAIN_BUNDLE, (error) => { + if (error || isMuted) { + return; + } + + sound.play(); + }); +}; + +export {SOUNDS}; +export default withMinimalExecutionTime(playSound, 300); diff --git a/src/libs/Sound/index.ts b/src/libs/Sound/index.ts index 4639887e831c..e968f1704c9b 100644 --- a/src/libs/Sound/index.ts +++ b/src/libs/Sound/index.ts @@ -1,71 +1,79 @@ -import Onyx from 'react-native-onyx'; -import Sound from 'react-native-sound'; -import type {ValueOf} from 'type-fest'; -import ONYXKEYS from '@src/ONYXKEYS'; + +import { Howl } from 'howler'; +import type { ValueOf } from 'type-fest'; import config from './config'; +import { SOUNDS, isMuted, withMinimalExecutionTime } from './BaseSound' -let isMuted = false; +async function cacheSoundAssets() { + if ('caches' in window) { + const cache = await caches.open('sound-assets'); + const soundFiles = Object.values(SOUNDS).map(sound => `${config.prefix}${sound}.mp3`); + + const cachePromises = soundFiles.map(async (soundFile) => { + const response = await cache.match(soundFile); + if (!response) { + await cache.add(soundFile); + console.log('[wildebug] Sound asset cached:', soundFile); + } else { + console.log('[wildebug] Sound asset already cached:', soundFile); + } + }); -Onyx.connect({ - key: ONYXKEYS.USER, - callback: (val) => (isMuted = !!val?.isMutedAllSounds), -}); + await Promise.all(cachePromises); + console.log('[wildebug] Sound assets caching completed'); + } +} +const playSound = async (soundFile: ValueOf) => { + if (isMuted) { + console.log('[wildebug] Sound is muted'); + return; + } -const SOUNDS = { - DONE: 'done', - SUCCESS: 'success', - ATTENTION: 'attention', - RECEIVE: 'receive', -} as const; + const soundSrc = `${config.prefix}${soundFile}.mp3`; + console.log('[wildebug] Playing sound:', soundSrc); -/** - * Creates a version of the given function that, when called, queues the execution and ensures that - * calls are spaced out by at least the specified `minExecutionTime`, even if called more frequently. This allows - * for throttling frequent calls to a function, ensuring each is executed with a minimum `minExecutionTime` between calls. - * Each call returns a promise that resolves when the function call is executed, allowing for asynchronous handling. - */ -function withMinimalExecutionTime) => ReturnType>(func: F, minExecutionTime: number) { - const queue: Array<[() => ReturnType, (value?: unknown) => void]> = []; - let timerId: NodeJS.Timeout | null = null; + if ('caches' in window) { + const cache = await caches.open('sound-assets'); + const response = await cache.match(soundSrc); - function processQueue() { - if (queue.length > 0) { - const next = queue.shift(); + if (response) { + const soundBlob = await response.blob(); + const soundUrl = URL.createObjectURL(soundBlob); + console.log('[wildebug] Sound fetched from cache:', soundUrl); - if (!next) { - return; - } + const sound = new Howl({ + src: [soundUrl], + format: ['mp3'], + onloaderror: (id, error) => { + console.error('[wildebug] Load error:', error); + }, + onplayerror: (id, error) => { + console.error('[wildebug] Play error:', error); + }, + }); - const [nextFunc, resolve] = next; - nextFunc(); - resolve(); - timerId = setTimeout(processQueue, minExecutionTime); + sound.play(); + return; } else { - timerId = null; + console.log('[wildebug] Sound not found in cache, fetching from network'); } } - return function (...args: Parameters) { - return new Promise((resolve) => { - queue.push([() => func(...args), resolve]); - - if (!timerId) { - // If the timer isn't running, start processing the queue - processQueue(); - } - }); - }; -} - -const playSound = (soundFile: ValueOf) => { - const sound = new Sound(`${config.prefix}${soundFile}.mp3`, Sound.MAIN_BUNDLE, (error) => { - if (error || isMuted) { - return; - } - - sound.play(); + // Fallback to fetching from network if not in cache + const sound = new Howl({ + src: [soundSrc], + onloaderror: (id, error) => { + console.error('[wildebug] Load error:', error); + }, + onplayerror: (id, error) => { + console.error('[wildebug] Play error:', error); + }, }); + + sound.play(); }; +// Cache sound assets on load +cacheSoundAssets(); -export {SOUNDS}; +export { SOUNDS }; export default withMinimalExecutionTime(playSound, 300); From 802531349828c01d5588a52a0655c117950b5dbb Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 3 Oct 2024 09:42:05 +0700 Subject: [PATCH 02/12] Install howler --- package-lock.json | 11 ++++++++++- package.json | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index d14689a59ae4..b7748cbf002a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -57,6 +57,7 @@ "expo-image-manipulator": "12.0.5", "fast-equals": "^4.0.3", "focus-trap-react": "^10.2.3", + "howler": "^2.2.4", "htmlparser2": "^7.2.0", "idb-keyval": "^6.2.1", "lodash-es": "4.17.21", @@ -174,6 +175,7 @@ "@types/base-64": "^1.0.2", "@types/canvas-size": "^1.2.2", "@types/concurrently": "^7.0.0", + "@types/howler": "^2.2.12", "@types/jest": "^29.5.2", "@types/jest-when": "^3.5.2", "@types/js-yaml": "^4.0.5", @@ -15764,6 +15766,12 @@ "hoist-non-react-statics": "^3.3.0" } }, + "node_modules/@types/howler": { + "version": "2.2.12", + "resolved": "https://registry.npmjs.org/@types/howler/-/howler-2.2.12.tgz", + "integrity": "sha512-hy769UICzOSdK0Kn1FBk4gN+lswcj1EKRkmiDtMkUGvFfYJzgaDXmVXkSShS2m89ERAatGIPnTUlp2HhfkVo5g==", + "dev": true + }, "node_modules/@types/html-minifier-terser": { "version": "6.1.0", "dev": true, @@ -25966,7 +25974,8 @@ }, "node_modules/howler": { "version": "2.2.4", - "license": "MIT" + "resolved": "https://registry.npmjs.org/howler/-/howler-2.2.4.tgz", + "integrity": "sha512-iARIBPgcQrwtEr+tALF+rapJ8qSc+Set2GJQl7xT1MQzWaVkFebdJhR3alVlSiUf5U7nAANKuj3aWpwerocD5w==" }, "node_modules/hpack.js": { "version": "2.1.6", diff --git a/package.json b/package.json index dba6c39a5dff..9b2c59321324 100644 --- a/package.json +++ b/package.json @@ -114,6 +114,7 @@ "expo-image-manipulator": "12.0.5", "fast-equals": "^4.0.3", "focus-trap-react": "^10.2.3", + "howler": "^2.2.4", "htmlparser2": "^7.2.0", "idb-keyval": "^6.2.1", "lodash-es": "4.17.21", @@ -231,6 +232,7 @@ "@types/base-64": "^1.0.2", "@types/canvas-size": "^1.2.2", "@types/concurrently": "^7.0.0", + "@types/howler": "^2.2.12", "@types/jest": "^29.5.2", "@types/jest-when": "^3.5.2", "@types/js-yaml": "^4.0.5", From 3aa759d085c986f62f266f79c1047399f153d191 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 3 Oct 2024 09:56:53 +0700 Subject: [PATCH 03/12] wrap error message --- src/libs/Sound/index.ts | 114 +++++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 53 deletions(-) diff --git a/src/libs/Sound/index.ts b/src/libs/Sound/index.ts index e968f1704c9b..b9183b64407d 100644 --- a/src/libs/Sound/index.ts +++ b/src/libs/Sound/index.ts @@ -1,79 +1,87 @@ - import { Howl } from 'howler'; import type { ValueOf } from 'type-fest'; import config from './config'; import { SOUNDS, isMuted, withMinimalExecutionTime } from './BaseSound' +import Log from '@libs/Log'; -async function cacheSoundAssets() { +function cacheSoundAssets() { if ('caches' in window) { - const cache = await caches.open('sound-assets'); - const soundFiles = Object.values(SOUNDS).map(sound => `${config.prefix}${sound}.mp3`); - - const cachePromises = soundFiles.map(async (soundFile) => { - const response = await cache.match(soundFile); - if (!response) { - await cache.add(soundFile); - console.log('[wildebug] Sound asset cached:', soundFile); - } else { - console.log('[wildebug] Sound asset already cached:', soundFile); - } - }); + caches.open('sound-assets').then(cache => { + const soundFiles = Object.values(SOUNDS).map(sound => `${config.prefix}${sound}.mp3`); + + const cachePromises = soundFiles.map(soundFile => { + return cache.match(soundFile).then(response => { + if (!response) { + return cache.add(soundFile); + } + }); + }); - await Promise.all(cachePromises); - console.log('[wildebug] Sound assets caching completed'); + return Promise.all(cachePromises); + }); } } -const playSound = async (soundFile: ValueOf) => { + +const playSound = (soundFile: ValueOf) => { if (isMuted) { - console.log('[wildebug] Sound is muted'); return; } const soundSrc = `${config.prefix}${soundFile}.mp3`; - console.log('[wildebug] Playing sound:', soundSrc); if ('caches' in window) { - const cache = await caches.open('sound-assets'); - const response = await cache.match(soundSrc); + caches.open('sound-assets').then(cache => { + cache.match(soundSrc).then(response => { + if (response) { + response.blob().then(soundBlob => { + const soundUrl = URL.createObjectURL(soundBlob); + + const sound = new Howl({ + src: [soundUrl], + format: ['mp3'], + onloaderror: (id, error) => { + Log.hmmm('[sound] Load error:', { message: (error as Error).message }); + }, + onplayerror: (id, error) => { + Log.hmmm('[sound] Play error:', { message: (error as Error).message }); + }, + }); - if (response) { - const soundBlob = await response.blob(); - const soundUrl = URL.createObjectURL(soundBlob); - console.log('[wildebug] Sound fetched from cache:', soundUrl); + sound.play(); + }); + } else { + const sound = new Howl({ + src: [soundSrc], + onloaderror: (id, error) => { + Log.hmmm('[sound] Load error:', { message: (error as Error).message }); + }, + onplayerror: (id, error) => { + Log.hmmm('[sound] Play error:', { message: (error as Error).message }); + }, + }); - const sound = new Howl({ - src: [soundUrl], - format: ['mp3'], - onloaderror: (id, error) => { - console.error('[wildebug] Load error:', error); - }, - onplayerror: (id, error) => { - console.error('[wildebug] Play error:', error); - }, + sound.play(); + } }); + }); + } else { + // Fallback to fetching from network if not in cache + const sound = new Howl({ + src: [soundSrc], + onloaderror: (id, error) => { + Log.hmmm('[sound] Load error:', { message: (error as Error).message }); + }, + onplayerror: (id, error) => { + Log.hmmm('[sound] Play error:', { message: (error as Error).message }); + }, + }); - sound.play(); - return; - } else { - console.log('[wildebug] Sound not found in cache, fetching from network'); - } + sound.play(); } - - // Fallback to fetching from network if not in cache - const sound = new Howl({ - src: [soundSrc], - onloaderror: (id, error) => { - console.error('[wildebug] Load error:', error); - }, - onplayerror: (id, error) => { - console.error('[wildebug] Play error:', error); - }, - }); - - sound.play(); }; + // Cache sound assets on load cacheSoundAssets(); export { SOUNDS }; -export default withMinimalExecutionTime(playSound, 300); +export default withMinimalExecutionTime(playSound, 300); \ No newline at end of file From a8074951b610937888f231c7eeb69537f62cce5d Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 3 Oct 2024 09:58:54 +0700 Subject: [PATCH 04/12] DRY --- src/libs/Sound/index.ts | 54 ++++++++++++++--------------------------- 1 file changed, 18 insertions(+), 36 deletions(-) diff --git a/src/libs/Sound/index.ts b/src/libs/Sound/index.ts index b9183b64407d..359bc56892dc 100644 --- a/src/libs/Sound/index.ts +++ b/src/libs/Sound/index.ts @@ -22,6 +22,21 @@ function cacheSoundAssets() { } } +const initializeAndPlaySound = (src: string) => { + const sound = new Howl({ + src: [src], + format: ['mp3'], + onloaderror: (id, error) => { + Log.hmmm('[sound] Load error:', { message: (error as Error).message }); + }, + onplayerror: (id, error) => { + Log.hmmm('[sound] Play error:', { message: (error as Error).message }); + }, + }); + + sound.play(); +}; + const playSound = (soundFile: ValueOf) => { if (isMuted) { return; @@ -35,51 +50,18 @@ const playSound = (soundFile: ValueOf) => { if (response) { response.blob().then(soundBlob => { const soundUrl = URL.createObjectURL(soundBlob); - - const sound = new Howl({ - src: [soundUrl], - format: ['mp3'], - onloaderror: (id, error) => { - Log.hmmm('[sound] Load error:', { message: (error as Error).message }); - }, - onplayerror: (id, error) => { - Log.hmmm('[sound] Play error:', { message: (error as Error).message }); - }, - }); - - sound.play(); + initializeAndPlaySound(soundUrl); }); } else { - const sound = new Howl({ - src: [soundSrc], - onloaderror: (id, error) => { - Log.hmmm('[sound] Load error:', { message: (error as Error).message }); - }, - onplayerror: (id, error) => { - Log.hmmm('[sound] Play error:', { message: (error as Error).message }); - }, - }); - - sound.play(); + initializeAndPlaySound(soundSrc); } }); }); } else { // Fallback to fetching from network if not in cache - const sound = new Howl({ - src: [soundSrc], - onloaderror: (id, error) => { - Log.hmmm('[sound] Load error:', { message: (error as Error).message }); - }, - onplayerror: (id, error) => { - Log.hmmm('[sound] Play error:', { message: (error as Error).message }); - }, - }); - - sound.play(); + initializeAndPlaySound(soundSrc); } }; - // Cache sound assets on load cacheSoundAssets(); From d646ce928f9d2b020a852f4f862528e4084721e5 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 3 Oct 2024 10:03:19 +0700 Subject: [PATCH 05/12] change to early return style --- src/libs/Sound/index.ts | 58 ++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/src/libs/Sound/index.ts b/src/libs/Sound/index.ts index 359bc56892dc..f773328fc0ae 100644 --- a/src/libs/Sound/index.ts +++ b/src/libs/Sound/index.ts @@ -5,21 +5,23 @@ import { SOUNDS, isMuted, withMinimalExecutionTime } from './BaseSound' import Log from '@libs/Log'; function cacheSoundAssets() { - if ('caches' in window) { - caches.open('sound-assets').then(cache => { - const soundFiles = Object.values(SOUNDS).map(sound => `${config.prefix}${sound}.mp3`); - - const cachePromises = soundFiles.map(soundFile => { - return cache.match(soundFile).then(response => { - if (!response) { - return cache.add(soundFile); - } - }); - }); + if (!('caches' in window)) { + return; + } - return Promise.all(cachePromises); + caches.open('sound-assets').then(cache => { + const soundFiles = Object.values(SOUNDS).map(sound => `${config.prefix}${sound}.mp3`); + + const cachePromises = soundFiles.map(soundFile => { + return cache.match(soundFile).then(response => { + if (!response) { + return cache.add(soundFile); + } + }); }); - } + + return Promise.all(cachePromises); + }); } const initializeAndPlaySound = (src: string) => { @@ -44,24 +46,26 @@ const playSound = (soundFile: ValueOf) => { const soundSrc = `${config.prefix}${soundFile}.mp3`; - if ('caches' in window) { - caches.open('sound-assets').then(cache => { - cache.match(soundSrc).then(response => { - if (response) { - response.blob().then(soundBlob => { - const soundUrl = URL.createObjectURL(soundBlob); - initializeAndPlaySound(soundUrl); - }); - } else { - initializeAndPlaySound(soundSrc); - } - }); - }); - } else { + if (!('caches' in window)) { // Fallback to fetching from network if not in cache initializeAndPlaySound(soundSrc); + return; } + + caches.open('sound-assets').then(cache => { + cache.match(soundSrc).then(response => { + if (response) { + response.blob().then(soundBlob => { + const soundUrl = URL.createObjectURL(soundBlob); + initializeAndPlaySound(soundUrl); + }); + return; + } + initializeAndPlaySound(soundSrc); + }); + }); }; + // Cache sound assets on load cacheSoundAssets(); From 6256f9b4a83ce266a88ac60c8e19c167c9f4aca2 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 3 Oct 2024 10:17:44 +0700 Subject: [PATCH 06/12] Lint, prettier, add comment --- src/libs/Sound/BaseSound.ts | 7 +++--- src/libs/Sound/index.native.ts | 6 ++--- src/libs/Sound/index.ts | 42 ++++++++++++++++++---------------- 3 files changed, 27 insertions(+), 28 deletions(-) diff --git a/src/libs/Sound/BaseSound.ts b/src/libs/Sound/BaseSound.ts index ae0561ca4b6d..e7fc5fadd259 100644 --- a/src/libs/Sound/BaseSound.ts +++ b/src/libs/Sound/BaseSound.ts @@ -1,8 +1,5 @@ import Onyx from 'react-native-onyx'; -import Sound from 'react-native-sound'; -import type {ValueOf} from 'type-fest'; import ONYXKEYS from '@src/ONYXKEYS'; -import config from './config'; let isMuted = false; @@ -18,6 +15,8 @@ const SOUNDS = { RECEIVE: 'receive', } as const; +const getIsMuted = () => isMuted; + /** * Creates a version of the given function that, when called, queues the execution and ensures that * calls are spaced out by at least the specified `minExecutionTime`, even if called more frequently. This allows @@ -57,4 +56,4 @@ function withMinimalExecutionTime) => ReturnTy }; } -export {SOUNDS, withMinimalExecutionTime, isMuted}; +export {SOUNDS, withMinimalExecutionTime, getIsMuted}; diff --git a/src/libs/Sound/index.native.ts b/src/libs/Sound/index.native.ts index e2f779d83d48..262d061a61ef 100644 --- a/src/libs/Sound/index.native.ts +++ b/src/libs/Sound/index.native.ts @@ -1,13 +1,11 @@ -import Onyx from 'react-native-onyx'; import Sound from 'react-native-sound'; import type {ValueOf} from 'type-fest'; -import ONYXKEYS from '@src/ONYXKEYS'; +import {getIsMuted, SOUNDS, withMinimalExecutionTime} from './BaseSound'; import config from './config'; -import { SOUNDS, isMuted, withMinimalExecutionTime } from './BaseSound' const playSound = (soundFile: ValueOf) => { const sound = new Sound(`${config.prefix}${soundFile}.mp3`, Sound.MAIN_BUNDLE, (error) => { - if (error || isMuted) { + if (error || getIsMuted()) { return; } diff --git a/src/libs/Sound/index.ts b/src/libs/Sound/index.ts index f773328fc0ae..b350ee2c95a2 100644 --- a/src/libs/Sound/index.ts +++ b/src/libs/Sound/index.ts @@ -1,38 +1,40 @@ -import { Howl } from 'howler'; -import type { ValueOf } from 'type-fest'; -import config from './config'; -import { SOUNDS, isMuted, withMinimalExecutionTime } from './BaseSound' +import {Howl} from 'howler'; +import type {ValueOf} from 'type-fest'; import Log from '@libs/Log'; +import {getIsMuted, SOUNDS, withMinimalExecutionTime} from './BaseSound'; +import config from './config'; function cacheSoundAssets() { + // Exit early if the Cache API is not available in the current browser. if (!('caches' in window)) { return; } - caches.open('sound-assets').then(cache => { - const soundFiles = Object.values(SOUNDS).map(sound => `${config.prefix}${sound}.mp3`); - - const cachePromises = soundFiles.map(soundFile => { - return cache.match(soundFile).then(response => { - if (!response) { - return cache.add(soundFile); + caches.open('sound-assets').then((cache) => { + const soundFiles = Object.values(SOUNDS).map((sound) => `${config.prefix}${sound}.mp3`); + + // Cache each sound file if it's not already cached. + const cachePromises = soundFiles.map((soundFile) => { + return cache.match(soundFile).then((response) => { + if (response) { + return; } + return cache.add(soundFile); }); }); return Promise.all(cachePromises); }); } - const initializeAndPlaySound = (src: string) => { const sound = new Howl({ src: [src], format: ['mp3'], onloaderror: (id, error) => { - Log.hmmm('[sound] Load error:', { message: (error as Error).message }); + Log.hmmm('[sound] Load error:', {message: (error as Error).message}); }, onplayerror: (id, error) => { - Log.hmmm('[sound] Play error:', { message: (error as Error).message }); + Log.hmmm('[sound] Play error:', {message: (error as Error).message}); }, }); @@ -40,7 +42,7 @@ const initializeAndPlaySound = (src: string) => { }; const playSound = (soundFile: ValueOf) => { - if (isMuted) { + if (getIsMuted()) { return; } @@ -52,10 +54,10 @@ const playSound = (soundFile: ValueOf) => { return; } - caches.open('sound-assets').then(cache => { - cache.match(soundSrc).then(response => { + caches.open('sound-assets').then((cache) => { + cache.match(soundSrc).then((response) => { if (response) { - response.blob().then(soundBlob => { + response.blob().then((soundBlob) => { const soundUrl = URL.createObjectURL(soundBlob); initializeAndPlaySound(soundUrl); }); @@ -69,5 +71,5 @@ const playSound = (soundFile: ValueOf) => { // Cache sound assets on load cacheSoundAssets(); -export { SOUNDS }; -export default withMinimalExecutionTime(playSound, 300); \ No newline at end of file +export {SOUNDS}; +export default withMinimalExecutionTime(playSound, 300); From d01aa837d2e1f71210a8a4f81a64884508003551 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 3 Oct 2024 10:19:44 +0700 Subject: [PATCH 07/12] Remove unnecessary plugin --- config/webpack/webpack.common.ts | 2 -- package-lock.json | 11 ----------- package.json | 1 - 3 files changed, 14 deletions(-) diff --git a/config/webpack/webpack.common.ts b/config/webpack/webpack.common.ts index 91fc4b1bf528..2d8e27fd453e 100644 --- a/config/webpack/webpack.common.ts +++ b/config/webpack/webpack.common.ts @@ -227,8 +227,6 @@ const getCommonConfiguration = ({file = '.env', platform = 'web'}: Environment): 'react-native-config': 'react-web-config', // eslint-disable-next-line @typescript-eslint/naming-convention 'react-native$': 'react-native-web', - // eslint-disable-next-line @typescript-eslint/naming-convention - 'react-native-sound': 'react-native-web-sound', // Module alias for web & desktop // https://webpack.js.org/configuration/resolve/#resolvealias // eslint-disable-next-line @typescript-eslint/naming-convention diff --git a/package-lock.json b/package-lock.json index b7748cbf002a..64a68659fdb9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -117,7 +117,6 @@ "react-native-view-shot": "3.8.0", "react-native-vision-camera": "4.0.0-beta.13", "react-native-web": "^0.19.12", - "react-native-web-sound": "^0.1.3", "react-native-webview": "13.8.6", "react-plaid-link": "3.3.2", "react-web-config": "^1.0.0", @@ -35738,16 +35737,6 @@ "react-dom": "^18.0.0" } }, - "node_modules/react-native-web-sound": { - "version": "0.1.3", - "license": "MIT", - "dependencies": { - "howler": "^2.2.1" - }, - "peerDependencies": { - "react-native-web": "*" - } - }, "node_modules/react-native-web/node_modules/memoize-one": { "version": "6.0.0", "license": "MIT" diff --git a/package.json b/package.json index 9b2c59321324..767819c43167 100644 --- a/package.json +++ b/package.json @@ -174,7 +174,6 @@ "react-native-view-shot": "3.8.0", "react-native-vision-camera": "4.0.0-beta.13", "react-native-web": "^0.19.12", - "react-native-web-sound": "^0.1.3", "react-native-webview": "13.8.6", "react-plaid-link": "3.3.2", "react-web-config": "^1.0.0", From 0e38cb230931d2117a9224688d5da0580c9b54b3 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Fri, 4 Oct 2024 08:20:40 +0700 Subject: [PATCH 08/12] Update src/libs/Sound/index.ts Co-authored-by: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> --- src/libs/Sound/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Sound/index.ts b/src/libs/Sound/index.ts index b350ee2c95a2..af8665403706 100644 --- a/src/libs/Sound/index.ts +++ b/src/libs/Sound/index.ts @@ -31,7 +31,7 @@ const initializeAndPlaySound = (src: string) => { src: [src], format: ['mp3'], onloaderror: (id, error) => { - Log.hmmm('[sound] Load error:', {message: (error as Error).message}); + Log.alert('[sound] Load error:', {message: (error as Error).message}); }, onplayerror: (id, error) => { Log.hmmm('[sound] Play error:', {message: (error as Error).message}); From ac311c5aaada93168bf8511af61883ee8044483e Mon Sep 17 00:00:00 2001 From: Wildan M Date: Fri, 4 Oct 2024 08:20:52 +0700 Subject: [PATCH 09/12] Update src/libs/Sound/index.ts Co-authored-by: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> --- src/libs/Sound/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Sound/index.ts b/src/libs/Sound/index.ts index af8665403706..baa4ccfe3ca8 100644 --- a/src/libs/Sound/index.ts +++ b/src/libs/Sound/index.ts @@ -34,7 +34,7 @@ const initializeAndPlaySound = (src: string) => { Log.alert('[sound] Load error:', {message: (error as Error).message}); }, onplayerror: (id, error) => { - Log.hmmm('[sound] Play error:', {message: (error as Error).message}); + Log.alert('[sound] Play error:', {message: (error as Error).message}); }, }); From 4523e5c24936857367a12e228397761a98f699db Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Fri, 4 Oct 2024 08:41:24 +0700 Subject: [PATCH 10/12] lint fix --- src/libs/Sound/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/Sound/index.ts b/src/libs/Sound/index.ts index baa4ccfe3ca8..9e6109cb6892 100644 --- a/src/libs/Sound/index.ts +++ b/src/libs/Sound/index.ts @@ -26,18 +26,18 @@ function cacheSoundAssets() { return Promise.all(cachePromises); }); } + const initializeAndPlaySound = (src: string) => { const sound = new Howl({ src: [src], format: ['mp3'], - onloaderror: (id, error) => { + onloaderror: (_id: number, error: unknown) => { Log.alert('[sound] Load error:', {message: (error as Error).message}); }, - onplayerror: (id, error) => { + onplayerror: (_id: number, error: unknown) => { Log.alert('[sound] Play error:', {message: (error as Error).message}); }, }); - sound.play(); }; From 3988d410a258853ca1a7db39ca7a8bf74c3b653f Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Mon, 7 Oct 2024 07:53:54 +0700 Subject: [PATCH 11/12] create clearSoundAssetsCache, use when logout and reset app --- src/libs/Sound/index.ts | 21 ++++++++++++++++++++- src/libs/actions/App.ts | 2 ++ src/libs/actions/Session/index.ts | 2 ++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/libs/Sound/index.ts b/src/libs/Sound/index.ts index 9e6109cb6892..39ff567df68e 100644 --- a/src/libs/Sound/index.ts +++ b/src/libs/Sound/index.ts @@ -68,8 +68,27 @@ const playSound = (soundFile: ValueOf) => { }); }; +function clearSoundAssetsCache() { + // Exit early if the Cache API is not available in the current browser. + if (!('caches' in window)) { + return; + } + + caches + .delete('sound-assets') + .then((success) => { + if (success) { + return; + } + Log.alert('[sound] Failed to clear sound assets cache.'); + }) + .catch((error) => { + Log.alert('[sound] Error clearing sound assets cache:', {message: (error as Error).message}); + }); +} + // Cache sound assets on load cacheSoundAssets(); -export {SOUNDS}; +export {SOUNDS, clearSoundAssetsCache}; export default withMinimalExecutionTime(playSound, 300); diff --git a/src/libs/actions/App.ts b/src/libs/actions/App.ts index d69bcf0e5761..44bdc55c90fc 100644 --- a/src/libs/actions/App.ts +++ b/src/libs/actions/App.ts @@ -17,6 +17,7 @@ import Navigation from '@libs/Navigation/Navigation'; import Performance from '@libs/Performance'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as SessionUtils from '@libs/SessionUtils'; +import {clearSoundAssetsCache} from '@libs/Sound'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {OnyxKey} from '@src/ONYXKEYS'; @@ -559,6 +560,7 @@ function clearOnyxAndResetApp(shouldNavigateToHomepage?: boolean) { }); }); }); + clearSoundAssetsCache(); } export { diff --git a/src/libs/actions/Session/index.ts b/src/libs/actions/Session/index.ts index 4d6ba6cfa774..37488442525d 100644 --- a/src/libs/actions/Session/index.ts +++ b/src/libs/actions/Session/index.ts @@ -36,6 +36,7 @@ import NetworkConnection from '@libs/NetworkConnection'; import * as Pusher from '@libs/Pusher/pusher'; import * as ReportUtils from '@libs/ReportUtils'; import * as SessionUtils from '@libs/SessionUtils'; +import {clearSoundAssetsCache} from '@libs/Sound'; import Timers from '@libs/Timers'; import {hideContextMenu} from '@pages/home/report/ContextMenu/ReportActionContextMenu'; import {KEYS_TO_PRESERVE, openApp} from '@userActions/App'; @@ -761,6 +762,7 @@ function cleanupSession() { clearCache().then(() => { Log.info('Cleared all cache data', true, {}, true); }); + clearSoundAssetsCache(); Timing.clearData(); } From aa7bcd43d3ebc6f8baff87a5a62d954689cf2d7f Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 10 Oct 2024 17:22:13 +0700 Subject: [PATCH 12/12] Fix possible undefined function on native --- src/libs/Sound/index.native.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libs/Sound/index.native.ts b/src/libs/Sound/index.native.ts index 262d061a61ef..f9e0db31b9b0 100644 --- a/src/libs/Sound/index.native.ts +++ b/src/libs/Sound/index.native.ts @@ -13,5 +13,7 @@ const playSound = (soundFile: ValueOf) => { }); }; -export {SOUNDS}; +function clearSoundAssetsCache() {} + +export {SOUNDS, clearSoundAssetsCache}; export default withMinimalExecutionTime(playSound, 300);