fix: add error boundary, harden player setup, catch init errors
This commit is contained in:
1 parent
2327778136
commit
a65a3eeb5b
2 files changed
+48
-10
No files matched your search
+43
-3
@@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState, Component } from 'react';
|
||||||
import { View, StatusBar } from 'react-native';
|
import { View, StatusBar, Text, ScrollView } from 'react-native';
|
||||||
import { NavigationContainer } from '@react-navigation/native';
|
import { NavigationContainer } from '@react-navigation/native';
|
||||||
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
|
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
|
||||||
import { createStackNavigator } from '@react-navigation/stack';
|
import { createStackNavigator } from '@react-navigation/stack';
|
||||||
@@ -19,6 +19,30 @@ import LoginScreen from './src/screens/Login';
|
|||||||
import NowPlayingScreen from './src/screens/NowPlaying';
|
import NowPlayingScreen from './src/screens/NowPlaying';
|
||||||
import PlayerBar from './src/components/PlayerBar';
|
import PlayerBar from './src/components/PlayerBar';
|
||||||
|
|
||||||
|
// ─── ERROR BOUNDARY ───
|
||||||
|
class ErrorBoundary extends Component {
|
||||||
|
state = { error: null };
|
||||||
|
static getDerivedStateFromError(e) { return { error: e }; }
|
||||||
|
render() {
|
||||||
|
if (this.state.error) {
|
||||||
|
return (
|
||||||
|
<ScrollView style={{ flex: 1, backgroundColor: '#121212', padding: 24, paddingTop: 60 }}>
|
||||||
|
<Text style={{ color: '#e05252', fontSize: 16, fontWeight: '700', marginBottom: 12 }}>
|
||||||
|
Fehler beim Starten
|
||||||
|
</Text>
|
||||||
|
<Text style={{ color: '#fff', fontSize: 13, fontFamily: 'monospace' }}>
|
||||||
|
{this.state.error?.message || String(this.state.error)}
|
||||||
|
</Text>
|
||||||
|
<Text style={{ color: '#aaa', fontSize: 12, marginTop: 16 }}>
|
||||||
|
{this.state.error?.stack}
|
||||||
|
</Text>
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return this.props.children;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const Tab = createBottomTabNavigator();
|
const Tab = createBottomTabNavigator();
|
||||||
const Stack = createStackNavigator();
|
const Stack = createStackNavigator();
|
||||||
|
|
||||||
@@ -63,11 +87,16 @@ function RootNavigator() {
|
|||||||
export default function App() {
|
export default function App() {
|
||||||
const { loadConfig } = useStore();
|
const { loadConfig } = useStore();
|
||||||
const [ready, setReady] = useState(false);
|
const [ready, setReady] = useState(false);
|
||||||
|
const [initError, setInitError] = useState(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
|
try {
|
||||||
await loadConfig();
|
await loadConfig();
|
||||||
await setupPlayer();
|
await setupPlayer();
|
||||||
|
} catch (e) {
|
||||||
|
setInitError(e?.message || String(e));
|
||||||
|
}
|
||||||
setReady(true);
|
setReady(true);
|
||||||
})();
|
})();
|
||||||
}, []);
|
}, []);
|
||||||
@@ -82,9 +111,19 @@ export default function App() {
|
|||||||
return () => { sub1.remove(); sub2.remove(); };
|
return () => { sub1.remove(); sub2.remove(); };
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (!ready) return null;
|
if (!ready) return (
|
||||||
|
<View style={{ flex: 1, backgroundColor: '#121212' }} />
|
||||||
|
);
|
||||||
|
|
||||||
|
if (initError) return (
|
||||||
|
<ScrollView style={{ flex: 1, backgroundColor: '#121212', padding: 24, paddingTop: 60 }}>
|
||||||
|
<Text style={{ color: '#e05252', fontSize: 16, fontWeight: '700', marginBottom: 12 }}>Init-Fehler</Text>
|
||||||
|
<Text style={{ color: '#fff', fontSize: 13 }}>{initError}</Text>
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<ErrorBoundary>
|
||||||
<GestureHandlerRootView style={{ flex: 1 }}>
|
<GestureHandlerRootView style={{ flex: 1 }}>
|
||||||
<SafeAreaProvider>
|
<SafeAreaProvider>
|
||||||
<StatusBar barStyle="light-content" backgroundColor="#121212" />
|
<StatusBar barStyle="light-content" backgroundColor="#121212" />
|
||||||
@@ -103,5 +142,6 @@ export default function App() {
|
|||||||
</NavigationContainer>
|
</NavigationContainer>
|
||||||
</SafeAreaProvider>
|
</SafeAreaProvider>
|
||||||
</GestureHandlerRootView>
|
</GestureHandlerRootView>
|
||||||
|
</ErrorBoundary>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,8 @@ let _setupDone = false;
|
|||||||
|
|
||||||
export async function setupPlayer() {
|
export async function setupPlayer() {
|
||||||
if (_setupDone) return;
|
if (_setupDone) return;
|
||||||
await TrackPlayer.setupPlayer({ autoHandleInterruptions: true });
|
try {
|
||||||
|
await TrackPlayer.setupPlayer();
|
||||||
await TrackPlayer.updateOptions({
|
await TrackPlayer.updateOptions({
|
||||||
capabilities: [
|
capabilities: [
|
||||||
Capability.Play,
|
Capability.Play,
|
||||||
@@ -17,14 +18,11 @@ export async function setupPlayer() {
|
|||||||
Capability.Stop,
|
Capability.Stop,
|
||||||
],
|
],
|
||||||
compactCapabilities: [Capability.Play, Capability.Pause, Capability.SkipToNext, Capability.SkipToPrevious],
|
compactCapabilities: [Capability.Play, Capability.Pause, Capability.SkipToNext, Capability.SkipToPrevious],
|
||||||
notificationCapabilities: [
|
|
||||||
Capability.Play,
|
|
||||||
Capability.Pause,
|
|
||||||
Capability.SkipToNext,
|
|
||||||
Capability.SkipToPrevious,
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
_setupDone = true;
|
_setupDone = true;
|
||||||
|
} catch (e) {
|
||||||
|
console.error('TrackPlayer setup failed:', e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert a Navidrome song object to a react-native-track-player track object
|
// Convert a Navidrome song object to a react-native-track-player track object
|
||||||
|
|||||||
Reference in new issue
Block a user