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",