diff --git a/App.tsx b/App.tsx
index 206b593..4fe3dc6 100644
--- a/App.tsx
+++ b/App.tsx
@@ -35,6 +35,7 @@ import * as Sentry from '@sentry/react-native';
import UpdateService from './src/services/updateService';
import { memoryMonitorService } from './src/services/memoryMonitorService';
import { aiService } from './src/services/aiService';
+import { AccountProvider, useAccount } from './src/contexts/AccountContext';
Sentry.init({
dsn: 'https://1a58bf436454d346e5852b7bfd3c95e8@o4509536317276160.ingest.de.sentry.io/4509536317734992',
@@ -143,21 +144,18 @@ const ThemedApp = () => {
const shouldShowApp = isAppReady && hasCompletedOnboarding !== null;
const initialRouteName = hasCompletedOnboarding ? 'MainTabs' : 'Onboarding';
- return (
-
+ const NavigationWithRef = () => {
+ const { navigationRef } = useAccount() as any;
+ return (
-
+
{!isAppReady && }
{shouldShowApp && }
-
- {/* Update Popup */}
{Platform.OS === 'ios' && (
{
)}
-
+ );
+ };
+
+ return (
+
+
+
+
+
);
}
diff --git a/src/components/icons/PluginIcon.tsx b/src/components/icons/PluginIcon.tsx
new file mode 100644
index 0000000..e056e0d
--- /dev/null
+++ b/src/components/icons/PluginIcon.tsx
@@ -0,0 +1,65 @@
+import React from 'react';
+import { View } from 'react-native';
+import Svg, { Path, Line } from 'react-native-svg';
+
+interface PluginIconProps {
+ size?: number;
+ color?: string;
+}
+
+const PluginIcon: React.FC = ({ size = 24, color = '#FFFFFF' }) => {
+ return (
+
+
+
+ );
+};
+
+export default PluginIcon;
diff --git a/src/components/icons/ProfileIcon.tsx b/src/components/icons/ProfileIcon.tsx
new file mode 100644
index 0000000..db5aaec
--- /dev/null
+++ b/src/components/icons/ProfileIcon.tsx
@@ -0,0 +1,35 @@
+import React from 'react';
+import { View } from 'react-native';
+import Svg, { Path } from 'react-native-svg';
+
+interface ProfileIconProps {
+ size?: number;
+ color?: string;
+}
+
+const ProfileIcon: React.FC = ({ size = 24, color = '#FFFFFF' }) => {
+ return (
+
+
+
+ );
+};
+
+export default ProfileIcon;
diff --git a/src/contexts/AccountContext.tsx b/src/contexts/AccountContext.tsx
index 0359d3e..85c4cfb 100644
--- a/src/contexts/AccountContext.tsx
+++ b/src/contexts/AccountContext.tsx
@@ -49,20 +49,32 @@ export const AccountProvider: React.FC<{ children: React.ReactNode }> = ({ child
// Auth state listener
const { data: subscription } = supabase.auth.onAuthStateChange(async (_event, session) => {
+ // Do not block UI on auth transitions
setLoading(true);
try {
const fullUser = session?.user ? await accountService.getCurrentUser() : null;
setUser(fullUser);
+ // Immediately clear loading so UI can transition to MainTabs/Auth
+ setLoading(false);
if (fullUser) {
- await syncService.migrateLocalScopeToUser();
- await syncService.subscribeRealtime();
- // Pull first to hydrate local state, then push to avoid wiping server with empty local
- await syncService.fullPull();
- await syncService.fullPush();
+ // Run sync in background without blocking UI
+ setTimeout(async () => {
+ try {
+ await syncService.migrateLocalScopeToUser();
+ await new Promise(r => setTimeout(r, 0));
+ await syncService.subscribeRealtime();
+ await new Promise(r => setTimeout(r, 0));
+ await syncService.fullPull();
+ await new Promise(r => setTimeout(r, 0));
+ await syncService.fullPush();
+ } catch (error) {
+ console.warn('[AccountContext] Background sync failed:', error);
+ }
+ }, 0);
} else {
syncService.unsubscribeRealtime();
}
- } finally {
+ } catch (e) {
setLoading(false);
}
});
diff --git a/src/navigation/AppNavigator.tsx b/src/navigation/AppNavigator.tsx
index 7a9df57..40c6687 100644
--- a/src/navigation/AppNavigator.tsx
+++ b/src/navigation/AppNavigator.tsx
@@ -44,7 +44,7 @@ import ThemeScreen from '../screens/ThemeScreen';
import OnboardingScreen from '../screens/OnboardingScreen';
import AuthScreen from '../screens/AuthScreen';
import AccountManageScreen from '../screens/AccountManageScreen';
-import { AccountProvider, useAccount } from '../contexts/AccountContext';
+import { useAccount } from '../contexts/AccountContext';
import { LoadingProvider, useLoading } from '../contexts/LoadingContext';
import PluginsScreen from '../screens/PluginsScreen';
import CastMoviesScreen from '../screens/CastMoviesScreen';
@@ -1336,11 +1336,9 @@ const AppNavigator = ({ initialRouteName }: { initialRouteName?: keyof RootStack
host: "https://us.i.posthog.com",
}}
>
-
-
-
-
-
+
+
+
);
diff --git a/src/screens/OnboardingScreen.tsx b/src/screens/OnboardingScreen.tsx
index 967eaea..3b445dd 100644
--- a/src/screens/OnboardingScreen.tsx
+++ b/src/screens/OnboardingScreen.tsx
@@ -74,14 +74,6 @@ const onboardingData: OnboardingSlide[] = [
icon: 'library-books',
gradient: ['#43e97b', '#38f9d7'],
},
- {
- id: '5',
- title: 'Plugins',
- subtitle: 'Stream Sources Only',
- description: 'Plugins add streaming sources to Nuvio.',
- icon: 'widgets',
- gradient: ['#ff9a9e', '#fad0c4'],
- },
];
const OnboardingScreen = () => {
diff --git a/src/screens/SettingsScreen.tsx b/src/screens/SettingsScreen.tsx
index 9c0022e..8cf773e 100644
--- a/src/screens/SettingsScreen.tsx
+++ b/src/screens/SettingsScreen.tsx
@@ -31,6 +31,8 @@ import { catalogService } from '../services/catalogService';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import * as Sentry from '@sentry/react-native';
import CustomAlert from '../components/CustomAlert';
+import ProfileIcon from '../components/icons/ProfileIcon';
+import PluginIcon from '../components/icons/PluginIcon';
const { width, height } = Dimensions.get('window');
const isTablet = width >= 768;
@@ -91,7 +93,8 @@ const SettingsCard: React.FC = ({ children, title, isTablet =
interface SettingItemProps {
title: string;
description?: string;
- icon: keyof typeof MaterialIcons.glyphMap;
+ icon?: keyof typeof MaterialIcons.glyphMap;
+ customIcon?: React.ReactNode;
renderControl?: () => React.ReactNode;
isLast?: boolean;
onPress?: () => void;
@@ -103,6 +106,7 @@ const SettingItem: React.FC = ({
title,
description,
icon,
+ customIcon,
renderControl,
isLast = false,
onPress,
@@ -124,14 +128,22 @@ const SettingItem: React.FC = ({
>
-
+ {customIcon ? (
+ customIcon
+ ) : (
+
+ )}
@@ -426,7 +438,7 @@ const SettingsScreen: React.FC = () => {
}
onPress={() => navigation.navigate('AccountManage')}
isTablet={isTablet}
/>
@@ -473,7 +485,7 @@ const SettingsScreen: React.FC = () => {
}
renderControl={ChevronRight}
onPress={() => navigation.navigate('ScraperSettings')}
isTablet={isTablet}