This commit is contained in:
2026-05-18 15:59:46 +02:00
parent 2658c37453
commit 26713b13b1
21 changed files with 894 additions and 97 deletions

View File

@@ -1,7 +1,6 @@
import React, { useEffect, useState } from 'react';
import { Text, View } from 'react-native';
import { Redirect, Stack, usePathname, useRouter } from 'expo-router';
import { useShareIntent } from 'expo-share-intent';
import { Redirect, Stack, usePathname } from 'expo-router';
import { StatusBar } from 'expo-status-bar';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { AppProvider, useApp } from '../context/AppContext';
@@ -11,7 +10,6 @@ import { useColors } from '../constants/Colors';
import { initDatabase, AppMetaDb } from '../services/database';
import * as SecureStore from 'expo-secure-store';
import * as SplashScreen from 'expo-splash-screen';
import * as ExpoLinking from 'expo-linking';
import { AuthService } from '../services/authService';
import { AnimatedSplashScreen } from '../components/AnimatedSplashScreen';
@@ -19,7 +17,8 @@ import { AnimatedSplashScreen } from '../components/AnimatedSplashScreen';
SplashScreen.preventAutoHideAsync().catch(() => { });
const SECURE_INSTALL_MARKER = 'greenlens_install_v1';
const isShareIntentUrl = (url: string | null | undefined) => Boolean(url?.includes('://dataUrl='));
const SHARE_INTENT_CALLBACK_PATH = '/dataUrl=greenlensShareKey';
const isShareIntentCallbackPath = (path: string | null | undefined) => path === SHARE_INTENT_CALLBACK_PATH;
const toStartupErrorMessage = (error: unknown): string => {
if (!error) return 'Unknown startup error';
@@ -105,35 +104,9 @@ function RootLayoutInner() {
} = useApp();
const colors = useColors(isDarkMode, colorPalette);
const pathname = usePathname();
const router = useRouter();
const [shareIntentEnabled, setShareIntentEnabled] = useState(false);
const { hasShareIntent, shareIntent, resetShareIntent } = useShareIntent({ disabled: !shareIntentEnabled });
const [installCheckDone, setInstallCheckDone] = useState(false);
const [splashAnimationComplete, setSplashAnimationComplete] = useState(false);
useEffect(() => {
let mounted = true;
ExpoLinking.getInitialURL()
.then((url) => {
if (mounted && isShareIntentUrl(url)) {
setShareIntentEnabled(true);
}
})
.catch(() => {});
const subscription = ExpoLinking.addEventListener('url', ({ url }) => {
if (isShareIntentUrl(url)) {
setShareIntentEnabled(true);
}
});
return () => {
mounted = false;
subscription.remove();
};
}, []);
useEffect(() => {
(async () => {
const didResetSessionForFreshInstall = await ensureInstallConsistency();
@@ -145,35 +118,18 @@ function RootLayoutInner() {
}, [signOut]);
const isAppReady = installCheckDone && !isInitializing && !isLoadingPlants;
useEffect(() => {
if (!hasShareIntent || !isAppReady) return;
const sharedImage = shareIntent.files?.find((file) => file.mimeType?.startsWith('image/'));
if (!sharedImage) {
resetShareIntent();
return;
}
const uri = sharedImage.path;
if (!uri) {
resetShareIntent();
return;
}
resetShareIntent();
router.push({
pathname: '/scanner',
params: { sharedImageUri: uri },
});
}, [hasShareIntent, shareIntent, resetShareIntent, router, isAppReady]);
const hasActiveEntitlement = isActivatingEntitlement
|| (billingSummary?.entitlement?.plan === 'pro'
&& billingSummary?.entitlement?.status === 'active');
const isAllowedWithoutSession = pathname.includes('onboarding')
|| pathname.includes('auth/')
|| pathname.includes('scanner')
|| isShareIntentCallbackPath(pathname)
|| pathname.includes('profile/billing');
const isAllowedWithoutEntitlement = pathname.includes('auth/')
|| pathname.includes('onboarding')
|| pathname.includes('scanner')
|| isShareIntentCallbackPath(pathname)
|| pathname.includes('profile/billing');
let content = null;
@@ -202,6 +158,7 @@ function RootLayoutInner() {
name="scanner"
options={{ presentation: 'fullScreenModal', animation: 'slide_from_bottom' }}
/>
<Stack.Screen name="dataUrl=greenlensShareKey" options={{ animation: 'none' }} />
<Stack.Screen
name="profile/billing"
options={{ presentation: 'card', animation: 'slide_from_right' }}
@@ -232,6 +189,7 @@ function RootLayoutInner() {
name="scanner"
options={{ presentation: 'fullScreenModal', animation: 'slide_from_bottom' }}
/>
<Stack.Screen name="dataUrl=greenlensShareKey" options={{ animation: 'none' }} />
<Stack.Screen
name="plant/[id]"
options={{ presentation: 'card', animation: 'slide_from_right' }}