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

feat: app sounds #31055

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
594d0c8
feat: add animated splash screen
lauridskern Dec 6, 2023
67923f1
fix: indents
lauridskern Dec 6, 2023
087ca99
feat: select random video each time
lauridskern Dec 19, 2023
5b9a1ff
feat: randomize video and show last shown splash video in dev settings
lauridskern Dec 19, 2023
1adb767
Add MenuItemWithTopDescription component to TestToolMenu
lauridskern Dec 20, 2023
d2fa21f
remove old splashscreen hider component
lauridskern Jan 8, 2024
71d23b8
Merge remote-tracking branch 'upstream/main' into origin/feat/update-…
lauridskern Jan 8, 2024
4a3a23a
fix: eslint errors, use the new useThemeStyles hook
lauridskern Jan 8, 2024
83c640f
Merge remote-tracking branch 'upstream/main' into origin/feat/update-…
lauridskern Jan 8, 2024
8ec87c7
Merge remote-tracking branch 'upstream/main' into origin/feat/update-…
lauridskern Jan 8, 2024
35fc53a
wip: install next version of react-native-video for proper opacity su…
hannojg Jan 9, 2024
e3a8071
wip(android): migrate to new v6 rn-video api
hannojg Jan 9, 2024
bd1be47
ios: pod install rn-video installation
hannojg Jan 9, 2024
c1cea21
fix: splash screen video restarting midway
hannojg Jan 9, 2024
c643469
fix: add rn-video patch to support opacity
hannojg Jan 9, 2024
270511d
remove windowIsTranslucent for splash screen
hannojg Jan 9, 2024
37d573c
android: fix splash screen opacity fade out looking odd
hannojg Jan 9, 2024
67d191b
Merge branch 'main' of github.com:Expensify/App into origin/feat/upda…
hannojg Jan 9, 2024
e7bddc1
add comments to explain new splash screen
hannojg Jan 9, 2024
6f16784
add mock for react-native-video
hannojg Jan 9, 2024
38073a4
better explain
hannojg Jan 10, 2024
d7cc842
Merge branch 'main' of github.com:Expensify/App into origin/feat/upda…
hannojg Jan 10, 2024
a55c062
fix: animated splash screen different implementations ios android
hannojg Jan 10, 2024
bf889b3
TEMP: add workaround for not found on adhoc builds
hannojg Jan 11, 2024
a7eafea
add android workaround
hannojg Jan 11, 2024
9b081f5
Merge branch 'main' into origin/feat/update-loading-screen-to-play-an…
kirillzyusko Jan 19, 2024
11477c9
chore: update Podfile.lock after merge
kirillzyusko Jan 19, 2024
3f27579
feat: audio player
kirillzyusko Jan 19, 2024
203a441
feat: sound on message send
kirillzyusko Jan 19, 2024
e3ab465
feat: mute settings management
kirillzyusko Jan 19, 2024
a46900b
fix: XCode build issues (null references in project.pbxproj)
kirillzyusko Jan 19, 2024
27a972f
fix: simplify implementation
kirillzyusko Jan 19, 2024
7796a09
feat: play different sounds for different messages
kirillzyusko Jan 19, 2024
ed5b09b
fix: play sound when you send message from '+' menu
kirillzyusko Jan 22, 2024
eaaaafb
fix: sound for task completion
kirillzyusko Jan 22, 2024
a57272e
refactor: better fs structure
kirillzyusko Jan 22, 2024
e393ec4
refactor: remove console.log statements
kirillzyusko Jan 22, 2024
598cd11
fix: silent push on web since we play own sound when message arrives
kirillzyusko Jan 22, 2024
fc79b63
Merge branch 'main' into origin/feat/update-loading-screen-to-play-an…
kirillzyusko Jan 23, 2024
2dd1515
fix: use modern way for importing React modules in ObjC
kirillzyusko Jan 23, 2024
e9c4a55
chore: remove patch since it seems like the problem with iOS builds w…
kirillzyusko Jan 23, 2024
5979ab3
fix: play sound when user completes a task
kirillzyusko Jan 24, 2024
334f187
fix: play when someone sends @here
kirillzyusko Jan 24, 2024
80dba50
fix: exclude undefined to execute all if-statements
kirillzyusko Jan 24, 2024
3b56e55
Merge branch 'main' into origin/feat/update-loading-screen-to-play-an…
kirillzyusko Jan 30, 2024
c383046
Merge branch 'main' into origin/feat/update-loading-screen-to-play-an…
kirillzyusko Jan 30, 2024
890da12
revert: animated splash screen
kirillzyusko Jan 30, 2024
d0a7e35
revert: animated splash screen (part 2)
kirillzyusko Jan 30, 2024
a35955e
fix: assure minimimal execution sound play
kirillzyusko Jan 30, 2024
cb310a8
chore: move patch back since it's needed
kirillzyusko Jan 30, 2024
330dd8d
Merge branch 'main' into origin/feat/update-loading-screen-to-play-an…
kirillzyusko Jan 31, 2024
2224618
chore: reorganize imports
kirillzyusko Feb 1, 2024
2447423
chore: use fs platform specific code separation
kirillzyusko Feb 1, 2024
9f3bc13
chore: combine if-statements in single loops
kirillzyusko Feb 1, 2024
8566418
fix: ts errors
kirillzyusko Feb 1, 2024
92960b3
refactor: optimize performance
kirillzyusko Feb 1, 2024
8f58872
fix: use marketing team wording
kirillzyusko Feb 2, 2024
231aaef
fix: update wording
kirillzyusko Feb 2, 2024
8478839
Merge branch 'main' into origin/feat/update-loading-screen-to-play-an…
kirillzyusko Feb 5, 2024
35a28ce
Merge branch 'main' into origin/feat/update-loading-screen-to-play-an…
kirillzyusko Feb 6, 2024
a20c54b
fix: do not play sound if channel is muted
kirillzyusko Feb 6, 2024
d29768b
chore: added jest mock
kirillzyusko Feb 7, 2024
3be083b
Merge branch 'main' into origin/feat/update-loading-screen-to-play-an…
kirillzyusko Feb 8, 2024
339133e
Merge branch 'main' into origin/feat/update-loading-screen-to-play-an…
kirillzyusko Feb 8, 2024
a69cadb
fix: prettier
kirillzyusko Feb 8, 2024
1e828f6
refactor: added dictionary for playing a sound
kirillzyusko Feb 12, 2024
7ed56ec
fix: changes after code review
kirillzyusko Feb 12, 2024
748d554
Merge branch 'main' into origin/feat/update-loading-screen-to-play-an…
kirillzyusko Feb 12, 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
Binary file added android/app/src/main/res/raw/attention.mp3
Binary file not shown.
Binary file added android/app/src/main/res/raw/done.mp3
Binary file not shown.
Binary file added android/app/src/main/res/raw/receive.mp3
Binary file not shown.
Binary file added android/app/src/main/res/raw/success.mp3
Binary file not shown.
Binary file added assets/sounds/attention.mp3
Binary file not shown.
Binary file added assets/sounds/done.mp3
Binary file not shown.
Binary file added assets/sounds/receive.mp3
Binary file not shown.
Binary file added assets/sounds/success.mp3
Binary file not shown.
4 changes: 3 additions & 1 deletion config/webpack/webpack.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ const webpackConfig = ({envFile = '.env', platform = 'web'}) => ({
{from: 'web/manifest.json'},
{from: 'assets/css', to: 'css'},
{from: 'assets/fonts/web', to: 'fonts'},
{from: 'assets/sounds', to: 'sounds'},
{from: 'node_modules/react-pdf/dist/esm/Page/AnnotationLayer.css', to: 'css/AnnotationLayer.css'},
{from: 'node_modules/react-pdf/dist/esm/Page/TextLayer.css', to: 'css/TextLayer.css'},
{from: 'assets/images/shadow.png', to: 'images/shadow.png'},
Expand Down Expand Up @@ -200,7 +201,7 @@ const webpackConfig = ({envFile = '.env', platform = 'web'}) => ({
alias: {
'react-native-config': 'react-web-config',
'react-native$': 'react-native-web',

'react-native-sound': 'react-native-web-sound',
// Module alias for web & desktop
// https://webpack.js.org/configuration/resolve/#resolvealias
'@assets': path.resolve(__dirname, '../../assets'),
Expand Down Expand Up @@ -239,6 +240,7 @@ const webpackConfig = ({envFile = '.env', platform = 'web'}) => ({
'process/browser': require.resolve('process/browser'),
},
},

optimization: {
runtimeChunk: 'single',
splitChunks: {
Expand Down
16 changes: 16 additions & 0 deletions ios/NewExpensify.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@

/* Begin PBXBuildFile section */
059DC4EFD39EF39437E6823D /* libPods-NotificationServiceExtension.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A997AA8204EA3D90907FA80 /* libPods-NotificationServiceExtension.a */; };
083353EB2B5AB22A00C603C0 /* attention.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 083353E72B5AB22900C603C0 /* attention.mp3 */; };
083353EC2B5AB22A00C603C0 /* done.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 083353E82B5AB22900C603C0 /* done.mp3 */; };
083353ED2B5AB22A00C603C0 /* receive.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 083353E92B5AB22900C603C0 /* receive.mp3 */; };
083353EE2B5AB22A00C603C0 /* success.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 083353EA2B5AB22900C603C0 /* success.mp3 */; };
0C7C65547D7346EB923BE808 /* ExpensifyMono-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = E704648954784DDFBAADF568 /* ExpensifyMono-Regular.otf */; };
0CDA8E34287DD650004ECBEC /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0CDA8E33287DD650004ECBEC /* AppDelegate.mm */; };
0CDA8E35287DD650004ECBEC /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0CDA8E33287DD650004ECBEC /* AppDelegate.mm */; };
Expand Down Expand Up @@ -79,6 +83,10 @@
00E356EE1AD99517003FC87E /* NewExpensifyTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NewExpensifyTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
076FD9E41E08971BBF51D580 /* libPods-NewExpensify-NewExpensifyTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-NewExpensify-NewExpensifyTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
083353E72B5AB22900C603C0 /* attention.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = attention.mp3; path = ../assets/sounds/attention.mp3; sourceTree = "<group>"; };
083353E82B5AB22900C603C0 /* done.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = done.mp3; path = ../assets/sounds/done.mp3; sourceTree = "<group>"; };
083353E92B5AB22900C603C0 /* receive.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = receive.mp3; path = ../assets/sounds/receive.mp3; sourceTree = "<group>"; };
083353EA2B5AB22900C603C0 /* success.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = success.mp3; path = ../assets/sounds/success.mp3; sourceTree = "<group>"; };
0CDA8E33287DD650004ECBEC /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = NewExpensify/AppDelegate.mm; sourceTree = "<group>"; };
0CDA8E36287DD6A0004ECBEC /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = NewExpensify/Images.xcassets; sourceTree = "<group>"; };
0F5BE0CD252686320097D869 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -311,6 +319,10 @@
A9EA265D209D4558995C9BD4 /* Resources */ = {
isa = PBXGroup;
children = (
083353E72B5AB22900C603C0 /* attention.mp3 */,
083353E82B5AB22900C603C0 /* done.mp3 */,
083353E92B5AB22900C603C0 /* receive.mp3 */,
083353EA2B5AB22900C603C0 /* success.mp3 */,
44BF435285B94E5B95F90994 /* ExpensifyNewKansas-Medium.otf */,
D2AFB39EC1D44BF9B91D3227 /* ExpensifyNewKansas-MediumItalic.otf */,
DCF33E34FFEC48128CDD41D4 /* ExpensifyMono-Bold.otf */,
Expand Down Expand Up @@ -496,13 +508,17 @@
0F5BE0CE252686330097D869 /* GoogleService-Info.plist in Resources */,
E9DF872D2525201700607FDC /* AirshipConfig.plist in Resources */,
F0C450EA2705020500FD2970 /* colors.json in Resources */,
083353EB2B5AB22A00C603C0 /* attention.mp3 in Resources */,
0CDA8E37287DD6A0004ECBEC /* Images.xcassets in Resources */,
70CF6E82262E297300711ADC /* BootSplash.storyboard in Resources */,
FF941A8D48F849269AB85C9A /* ExpensifyNewKansas-Medium.otf in Resources */,
BDB853621F354EBB84E619C2 /* ExpensifyNewKansas-MediumItalic.otf in Resources */,
26AF3C3540374A9FACB6C19E /* ExpensifyMono-Bold.otf in Resources */,
083353EE2B5AB22A00C603C0 /* success.mp3 in Resources */,
0C7C65547D7346EB923BE808 /* ExpensifyMono-Regular.otf in Resources */,
2A9F8CDA983746B0B9204209 /* ExpensifyNeue-Bold.otf in Resources */,
083353EC2B5AB22A00C603C0 /* done.mp3 in Resources */,
083353ED2B5AB22A00C603C0 /* receive.mp3 in Resources */,
ED222ED90E074A5481A854FA /* ExpensifyNeue-BoldItalic.otf in Resources */,
30581EA8AAFD4FCE88C5D191 /* ExpensifyNeue-Italic.otf in Resources */,
1246A3EF20E54E7A9494C8B9 /* ExpensifyNeue-Regular.otf in Resources */,
Expand Down
9 changes: 9 additions & 0 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1438,6 +1438,11 @@ PODS:
- glog
- RCT-Folly (= 2022.05.16.00)
- React-Core
- RNSound (0.11.2):
- React-Core
- RNSound/Core (= 0.11.2)
- RNSound/Core (0.11.2):
- React-Core
- RNSVG (14.0.0):
- React-Core
- SDWebImage (5.17.0):
Expand Down Expand Up @@ -1580,6 +1585,7 @@ DEPENDENCIES:
- RNReactNativeHapticFeedback (from `../node_modules/react-native-haptic-feedback`)
- RNReanimated (from `../node_modules/react-native-reanimated`)
- RNScreens (from `../node_modules/react-native-screens`)
- RNSound (from `../node_modules/react-native-sound`)
- RNSVG (from `../node_modules/react-native-svg`)
- VisionCamera (from `../node_modules/react-native-vision-camera`)
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
Expand Down Expand Up @@ -1827,6 +1833,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-reanimated"
RNScreens:
:path: "../node_modules/react-native-screens"
RNSound:
:path: "../node_modules/react-native-sound"
RNSVG:
:path: "../node_modules/react-native-svg"
VisionCamera:
Expand Down Expand Up @@ -1973,6 +1981,7 @@ SPEC CHECKSUMS:
RNReactNativeHapticFeedback: 1e3efeca9628ff9876ee7cdd9edec1b336913f8c
RNReanimated: 57f436e7aa3d277fbfed05e003230b43428157c0
RNScreens: b582cb834dc4133307562e930e8fa914b8c04ef2
RNSound: 6c156f925295bdc83e8e422e7d8b38d33bc71852
RNSVG: 255767813dac22db1ec2062c8b7e7b856d4e5ae6
SDWebImage: 750adf017a315a280c60fde706ab1e552a3ae4e9
SDWebImageAVIFCoder: 8348fef6d0ec69e129c66c9fe4d74fbfbf366112
Expand Down
8 changes: 8 additions & 0 deletions jest/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,11 @@ jest.mock('react-native-fs', () => ({
unlink: jest.fn(() => new Promise<void>((res) => res())),
CachesDirectoryPath: jest.fn(),
}));

jest.mock('react-native-sound', () => {
class SoundMock {
play = jest.fn();
}

return SoundMock;
});
26 changes: 26 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -157,13 +157,15 @@
"react-native-render-html": "6.3.1",
"react-native-safe-area-context": "4.7.4",
"react-native-screens": "3.29.0",
"react-native-sound": "^0.11.2",
"react-native-svg": "14.1.0",
"react-native-tab-view": "^3.5.2",
"react-native-url-polyfill": "^2.0.0",
"react-native-view-shot": "3.8.0",
"react-native-vision-camera": "2.16.8",
"react-native-web": "^0.19.9",
"react-native-web-linear-gradient": "^1.1.2",
"react-native-web-sound": "^0.1.3",
"react-native-webview": "13.6.3",
"react-pdf": "7.3.3",
"react-plaid-link": "3.3.2",
Expand Down
38 changes: 38 additions & 0 deletions patches/react-native-sound+0.11.2.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
diff --git a/node_modules/react-native-sound/RNSound/RNSound.h b/node_modules/react-native-sound/RNSound/RNSound.h
index 7f5b97b..1a3c840 100644
--- a/node_modules/react-native-sound/RNSound/RNSound.h
+++ b/node_modules/react-native-sound/RNSound/RNSound.h
@@ -1,17 +1,7 @@
-#if __has_include(<React/RCTBridgeModule.h>)
#import <React/RCTBridgeModule.h>
-#else
-#import "RCTBridgeModule.h"
-#endif
-
#import <AVFoundation/AVFoundation.h>
-
-#if __has_include(<React/RCTEventEmitter.h>)
#import <React/RCTEventEmitter.h>
-#else
-#import "RCTEventEmitter.h"
-#endif

@interface RNSound : RCTEventEmitter <RCTBridgeModule, AVAudioPlayerDelegate>
-@property (nonatomic, weak) NSNumber *_key;
+@property(nonatomic, weak) NSNumber *_key;
@end
diff --git a/node_modules/react-native-sound/RNSound/RNSound.m b/node_modules/react-native-sound/RNSound/RNSound.m
index df3784e..d34ac01 100644
--- a/node_modules/react-native-sound/RNSound/RNSound.m
+++ b/node_modules/react-native-sound/RNSound/RNSound.m
@@ -1,10 +1,6 @@
#import "RNSound.h"

-#if __has_include("RCTUtils.h")
-#import "RCTUtils.h"
-#else
#import <React/RCTUtils.h>
-#endif

@implementation RNSound {
NSMutableDictionary *_playerPool;
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import * as OptionsListUtils from '@libs/OptionsListUtils';
import * as PolicyUtils from '@libs/PolicyUtils';
import * as ReceiptUtils from '@libs/ReceiptUtils';
import * as ReportUtils from '@libs/ReportUtils';
import playSound, {SOUNDS} from '@libs/Sound';
import * as TransactionUtils from '@libs/TransactionUtils';
import * as IOU from '@userActions/IOU';
import CONST from '@src/CONST';
Expand Down Expand Up @@ -549,6 +550,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({
return;
}

playSound(SOUNDS.DONE);
setDidConfirm(true);
onConfirm(selectedParticipants);
}
Expand Down
2 changes: 2 additions & 0 deletions src/components/SettlementButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {withOnyx} from 'react-native-onyx';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import * as ReportUtils from '@libs/ReportUtils';
import playSound, {SOUNDS} from '@libs/Sound';
import * as BankAccounts from '@userActions/BankAccounts';
import * as IOU from '@userActions/IOU';
import * as PaymentMethods from '@userActions/PaymentMethods';
Expand Down Expand Up @@ -201,6 +202,7 @@ function SettlementButton({
return;
}

playSound(SOUNDS.DONE);
onPress(iouPaymentType);
};

Expand Down
1 change: 1 addition & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1053,6 +1053,7 @@ export default {
},
preferencesPage: {
receiveRelevantFeatureUpdatesAndExpensifyNews: 'Receive relevant feature updates and Expensify news',
muteAllSounds: 'Mute all sounds from Expensify',
},
priorityModePage: {
priorityMode: 'Priority mode',
Expand Down
1 change: 1 addition & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1050,6 +1050,7 @@ export default {
},
preferencesPage: {
receiveRelevantFeatureUpdatesAndExpensifyNews: 'Recibir noticias sobre Expensify y actualizaciones del producto',
muteAllSounds: 'Silenciar todos los sonidos de Expensify',
},
priorityModePage: {
priorityMode: 'Modo prioridad',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ function canUseBrowserNotifications(): Promise<boolean> {
* @param icon Path to icon
* @param data extra data to attach to the notification
*/
function push(title: string, body = '', icon: string | ImageSourcePropType = '', data: LocalNotificationData = {}, onClick: LocalNotificationClickHandler = () => {}) {
function push(title: string, body = '', icon: string | ImageSourcePropType = '', data: LocalNotificationData = {}, onClick: LocalNotificationClickHandler = () => {}, silent = false) {
canUseBrowserNotifications().then((canUseNotifications) => {
if (!canUseNotifications) {
return;
Expand All @@ -54,6 +54,7 @@ function push(title: string, body = '', icon: string | ImageSourcePropType = '',
body,
icon: String(icon),
data,
silent,
});
notificationCache[notificationID].onclick = () => {
onClick();
Expand Down Expand Up @@ -104,7 +105,7 @@ export default {
reportID: report.reportID,
};

push(title, body, icon, data, onClick);
push(title, body, icon, data, onClick, true);
},

pushModifiedExpenseNotification(report: Report, reportAction: ReportAction, onClick: LocalNotificationClickHandler, usesIcon = false) {
Expand Down
3 changes: 3 additions & 0 deletions src/libs/Sound/config/index.native.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const config = {prefix: ''};

export default config;
3 changes: 3 additions & 0 deletions src/libs/Sound/config/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const config = {prefix: '/sounds/'};

export default config;
71 changes: 71 additions & 0 deletions src/libs/Sound/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
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<F extends (...args: Parameters<F>) => ReturnType<F>>(func: F, minExecutionTime: number) {
const queue: Array<[() => ReturnType<F>, (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<F>) {
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<typeof SOUNDS>) => {
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);
Loading
Loading