mirror of
https://github.com/Boof2015/astra-mobile.git
synced 2026-08-19 12:14:47 +02:00
android auto support
This commit is contained in:
+25
-5
@@ -1,4 +1,4 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Stack } from 'expo-router';
|
||||
import { StatusBar } from 'expo-status-bar';
|
||||
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
||||
@@ -27,6 +27,14 @@ import { useNormalizationSync } from '@/audio/useNormalizationSync';
|
||||
import { useLastFmScrobbler } from '@/audio/useLastFmScrobbler';
|
||||
import { colors } from '@/theme';
|
||||
|
||||
// Anchor the root stack at the tabs so a deep link straight to a top-level route (the
|
||||
// widget/notification opening `now-playing`, or `recently-played`) builds `[(tabs), route]`
|
||||
// instead of just `[route]`. Without this, dismissing the now-playing modal pops to an empty
|
||||
// stack → blank screen. Only affects deep-link/launch ordering; normal nav is unchanged.
|
||||
export const unstable_settings = {
|
||||
initialRouteName: '(tabs)',
|
||||
};
|
||||
|
||||
SplashScreen.preventAutoHideAsync();
|
||||
|
||||
/** Mirrors RNTP state into the player store. Renders nothing. */
|
||||
@@ -63,11 +71,23 @@ export default function RootLayout() {
|
||||
JetBrainsMono_500Medium,
|
||||
});
|
||||
|
||||
// Failsafe so the splash can never hang the UI blank. `preventAutoHideAsync` runs at
|
||||
// module scope — including in the headless JS context Android Auto spins up — so when
|
||||
// the process is started from the car first and the app is opened later, the normal
|
||||
// "hide once fonts load" path can get stuck. Render (and hide the splash) anyway after
|
||||
// a short timeout even if fonts haven't reported in.
|
||||
const [splashTimedOut, setSplashTimedOut] = useState(false);
|
||||
useEffect(() => {
|
||||
if (fontsLoaded) {
|
||||
void SplashScreen.hideAsync();
|
||||
const timer = setTimeout(() => setSplashTimedOut(true), 2000);
|
||||
return () => clearTimeout(timer);
|
||||
}, []);
|
||||
const ready = fontsLoaded || splashTimedOut;
|
||||
|
||||
useEffect(() => {
|
||||
if (ready) {
|
||||
void SplashScreen.hideAsync().catch(() => {});
|
||||
}
|
||||
}, [fontsLoaded]);
|
||||
}, [ready]);
|
||||
|
||||
// Eager library init: SQLite open + initial reads are tens of ms, and the
|
||||
// Library tab + playback adapters get data immediately. EQ + audio settings load
|
||||
@@ -99,7 +119,7 @@ export default function RootLayout() {
|
||||
.catch((err) => console.error('[lastfm] init failed', err));
|
||||
}, []);
|
||||
|
||||
if (!fontsLoaded) return null;
|
||||
if (!ready) return null;
|
||||
|
||||
return (
|
||||
<GestureHandlerRootView style={styles.root}>
|
||||
|
||||
@@ -265,7 +265,14 @@ export default function NowPlayingScreen() {
|
||||
// a second native modal animation after release.
|
||||
const translateY = useSharedValue(0);
|
||||
const menuProgress = useSharedValue(0);
|
||||
const dismiss = () => router.back();
|
||||
// Belt-and-suspenders for deep-link entry (widget/notification → now-playing with no
|
||||
// history): `(tabs)` is the stack anchor (see root _layout unstable_settings), so back()
|
||||
// returns there; if somehow there's nothing to go back to, replace to the tabs home so
|
||||
// dismissing can never land on a blank screen.
|
||||
const dismiss = () => {
|
||||
if (router.canGoBack()) router.back();
|
||||
else router.replace('/');
|
||||
};
|
||||
const finishCloseMenu = () => setMenuOpen(false);
|
||||
|
||||
function openMenu() {
|
||||
|
||||
Reference in New Issue
Block a user