diff --git a/app.json b/app.json index 7d59077..5fe8807 100644 --- a/app.json +++ b/app.json @@ -29,7 +29,8 @@ }, "scheme": "burmalda", "plugins": [ - "expo-router" + "expo-router", + "react-native-track-player" ], "updates": { "enabled": false diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index 056c7d5..b23949e 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -60,9 +60,9 @@ export default function HomeScreen() { load(); }, []); - useFocusEffect(() => { + useFocusEffect(useCallback(() => { loadDownloadedTracks(); - }); + }, [loadDownloadedTracks])); const onRefresh = async () => { setRefresh(true); diff --git a/app/_layout.tsx b/app/_layout.tsx index db49d61..7e5246b 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -5,21 +5,7 @@ import { StatusBar } from 'expo-status-bar'; import { useBootAuth } from '../hooks/useAuth'; import { Colors } from '../constants/theme'; -export default function RootLayout() { - useBootAuth(); - useOTAUpdates(); - - return ( - - - - - - - - ); -} - +// Must be defined before use — hooks are not hoisted function useOTAUpdates() { useEffect(() => { if (__DEV__) return; @@ -38,3 +24,18 @@ function useOTAUpdates() { })(); }, []); } + +export default function RootLayout() { + useBootAuth(); + useOTAUpdates(); + + return ( + + + + + + + + ); +} diff --git a/hooks/useAudio.ts b/hooks/useAudio.ts index 024962b..6e719f4 100644 --- a/hooks/useAudio.ts +++ b/hooks/useAudio.ts @@ -14,15 +14,11 @@ let _lastLoadedId: number | null = null; async function ensureSetup() { if (_setupDone) return; - _setupDone = true; try { await TrackPlayer.setupPlayer({ minBuffer: 15, maxBuffer: 50, playBuffer: 2.5, - // iOS: show full artwork on lock screen - iosCategory: 'playback' as any, - iosCategoryMode: 'default' as any, }); await TrackPlayer.updateOptions({ android: { @@ -42,7 +38,6 @@ async function ensureSetup() { Capability.Pause, Capability.SkipToNext, ], - // iOS lock screen: larger artwork notificationCapabilities: [ Capability.Play, Capability.Pause, @@ -51,12 +46,14 @@ async function ensureSetup() { Capability.SeekTo, ], }); + _setupDone = true; } catch (e: any) { + // "already" means player was set up before (e.g. hot reload) if (e?.message?.toLowerCase().includes('already')) { _setupDone = true; return; } - _setupDone = false; + // Other errors — allow retry next call throw e; } } diff --git a/index.js b/index.js index 95f0204..7b8e08b 100644 --- a/index.js +++ b/index.js @@ -3,9 +3,12 @@ import 'expo-router/entry'; // Register TrackPlayer background service safely // Must be wrapped — if native module isn't ready, app would white-screen otherwise try { - const TrackPlayer = require('react-native-track-player').default; + const TP = require('react-native-track-player'); + const TrackPlayer = TP.default ?? TP; const { PlaybackService } = require('./hooks/PlaybackService'); - TrackPlayer.registerPlaybackService(() => PlaybackService); + if (TrackPlayer?.registerPlaybackService && typeof PlaybackService === 'function') { + TrackPlayer.registerPlaybackService(() => PlaybackService); + } } catch (e) { // TrackPlayer native module not ready yet — skip service registration // Music playback via TrackPlayer will still work, just no remote controls diff --git a/package.json b/package.json index 694ec0f..601b835 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "expo-image": "~1.12.15", "expo-linear-gradient": "~13.0.2", "expo-linking": "~6.3.1", - "expo-network": "^55.0.13", + "expo-network": "~4.0.0", "expo-router": "~3.5.23", "expo-secure-store": "~13.0.2", "expo-status-bar": "~1.12.1",