Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion app/(storybook)/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ComponentType } from 'react';
import { Text, View } from 'react-native';

import { FeatureFlag, logError } from '@/utils';
import { FeatureFlag, logError } from '@/utils/log';

const StorybookEnabled = process.env.EXPO_PUBLIC_STORYBOOK_ENABLED === 'true';

Expand Down
30 changes: 14 additions & 16 deletions app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,21 @@ import {
import { useTheme, useThemeStore } from '@/theme';
import { FeatureFlag, logError } from '@/utils';

const StorybookEnabled = process.env.EXPO_PUBLIC_STORYBOOK_ENABLED === 'true';

// Prevent the splash screen from auto-hiding before initialization completes
SplashScreen.preventAutoHideAsync();

// Register Android foreground service early (async, fire-and-forget)
if (Platform.OS === 'android') {
if (Platform.OS === 'android' && !StorybookEnabled) {
registerForegroundService();
}

declare const global: {
ErrorUtils?: {
getGlobalHandler: () => (error: Error, isFatal?: boolean) => void;
setGlobalHandler: (
handler: (error: Error, isFatal?: boolean) => void
handler: (error: Error, isFatal?: boolean) => void,
) => void;
};
};
Expand All @@ -68,8 +70,6 @@ function installGlobalErrorHandler() {
});
}

const StorybookEnabled = process.env.EXPO_PUBLIC_STORYBOOK_ENABLED === 'true';

export const unstable_settings = {
initialRouteName: StorybookEnabled ? '(storybook)/index' : '(pages)/index',
};
Expand Down Expand Up @@ -247,25 +247,23 @@ export default function RootLayout() {
useEffect(() => {
async function initializeApp() {
try {
// Initialize in parallel where possible
await Promise.all([
initTheme(),
initializeSettingsStore(),
initializeSessionStore(),
storageService.processPendingDeletes(),
]);

// Initialize transcription store (depends on session store being ready)
await initializeTranscriptionStore();
await initTheme();

if (!StorybookEnabled) {
await Promise.all([
initializeSettingsStore(),
initializeSessionStore(),
storageService.processPendingDeletes(),
]);
await initializeTranscriptionStore();
}

setAppReady(true);
} catch (error) {
logError(error, {
flag: FeatureFlag.general,
message: 'Failed to initialize app',
});
// Still mark as ready to allow the app to render
// Individual stores handle their own error states
setAppReady(true);
}
}
Expand Down
152 changes: 0 additions & 152 deletions components/shared/recording-controls/RecordingControlsView.stories.tsx

This file was deleted.

7 changes: 6 additions & 1 deletion services/AudioService.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { EventEmitter } from 'events';

import AudioRecord from '@fugood/react-native-audio-pcm-stream';
import {
AudioModule,
AudioRecorder,
Expand All @@ -22,6 +21,12 @@ import {

import { permissionService } from './PermissionService';

let AudioRecord: any;
try {
// eslint-disable-next-line @typescript-eslint/no-require-imports
AudioRecord = require('@fugood/react-native-audio-pcm-stream').default;
} catch {}

const RECORDING_OPTIONS: RecordingOptions = {
extension: '.wav',
sampleRate: AppConstants.AUDIO_SAMPLE_RATE,
Expand Down
13 changes: 9 additions & 4 deletions services/EncryptionService.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { fromByteArray } from 'base64-js';
import * as Crypto from 'expo-crypto';
import * as SecureStore from 'expo-secure-store';
import AesGcmCrypto from 'react-native-aes-gcm-crypto';

let AesGcmCrypto: any;
try {
// eslint-disable-next-line @typescript-eslint/no-require-imports
AesGcmCrypto = require('react-native-aes-gcm-crypto').default;
} catch {}

const KEY_STORAGE_KEY = 'aes_data_key';

Expand All @@ -20,7 +25,7 @@ const createEncryptionService = () => {
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
throw new Error(
`Failed to retrieve or generate encryption key: ${message}`
`Failed to retrieve or generate encryption key: ${message}`,
);
}
};
Expand All @@ -43,7 +48,7 @@ const createEncryptionService = () => {

if (parts.length !== 2) {
throw new Error(
'Invalid cipher text format. Expected format: iv:contenttag'
'Invalid cipher text format. Expected format: iv:contenttag',
);
}

Expand All @@ -58,7 +63,7 @@ const createEncryptionService = () => {
key,
iv,
tag,
false
false,
);

return decrypted;
Expand Down
Loading