Harte Paywall

This commit is contained in:
2026-04-29 21:16:16 +02:00
committed by Timo Knuth
parent 0f933da3c9
commit d37b49f1f6
10 changed files with 305 additions and 129 deletions

View File

@@ -230,8 +230,9 @@ export default function HomeScreen() {
lexiconExplored: false,
customizationDone: false,
});
const { registerLayout, startTour } = useCoachMarks();
const { layouts, registerLayout, startTour } = useCoachMarks();
const fabRef = useRef<View>(null);
const tourStartRequestedRef = useRef(false);
const posthog = usePostHog();
useFocusEffect(
@@ -250,49 +251,77 @@ export default function HomeScreen() {
// Tour nach Registrierung starten
useEffect(() => {
const checkTour = async () => {
const flag = await AsyncStorage.getItem('greenlens_show_tour');
if (flag !== 'true') return;
await AsyncStorage.removeItem('greenlens_show_tour');
// 1 Sekunde warten, dann Tour starten
setTimeout(() => {
// Tab-Positionen approximieren (gleichmäßig verteilt)
const tabBarBottom = SCREEN_H - 85;
const tabW = SCREEN_W / 3;
registerLayout('tab_search', { x: tabW, y: tabBarBottom + 8, width: tabW, height: 52 });
registerLayout('tab_profile', { x: tabW * 2, y: tabBarBottom + 8, width: tabW, height: 52 });
startTour([
{
elementKey: 'fab',
title: t.tourFabTitle,
description: t.tourFabDesc,
tooltipSide: 'above',
},
{
elementKey: 'tab_search',
title: t.tourSearchTitle,
description: t.tourSearchDesc,
tooltipSide: 'above',
},
{
elementKey: 'tab_profile',
title: t.tourProfileTitle,
description: t.tourProfileDesc,
tooltipSide: 'above',
},
{
elementKey: 'onboarding_checklist',
title: t.tourChecklistTitle,
description: t.tourChecklistDesc,
tooltipSide: 'below',
},
]);
}, 1000);
let cancelled = false;
let retryTimer: ReturnType<typeof setTimeout> | null = null;
const tourSteps = [
{
elementKey: 'fab',
title: t.tourFabTitle,
description: t.tourFabDesc,
tooltipSide: 'above' as const,
},
{
elementKey: 'tab_search',
title: t.tourSearchTitle,
description: t.tourSearchDesc,
tooltipSide: 'above' as const,
},
{
elementKey: 'tab_profile',
title: t.tourProfileTitle,
description: t.tourProfileDesc,
tooltipSide: 'above' as const,
},
{
elementKey: 'onboarding_checklist',
title: t.tourChecklistTitle,
description: t.tourChecklistDesc,
tooltipSide: 'below' as const,
},
];
const registerTabLayouts = () => {
const tabBarBottom = SCREEN_H - 85;
const tabW = SCREEN_W / 3;
registerLayout('tab_search', { x: tabW, y: tabBarBottom + 8, width: tabW, height: 52 });
registerLayout('tab_profile', { x: tabW * 2, y: tabBarBottom + 8, width: tabW, height: 52 });
};
const checkTour = async () => {
if (tourStartRequestedRef.current) return;
const flag = await AsyncStorage.getItem('greenlens_show_tour');
if (flag !== 'true') return;
tourStartRequestedRef.current = true;
const startWhenReady = async (attempt = 0) => {
if (cancelled) return;
registerTabLayouts();
if (!layouts.fab && attempt < 10) {
retryTimer = setTimeout(() => startWhenReady(attempt + 1), 250);
return;
}
startTour(tourSteps);
await AsyncStorage.removeItem('greenlens_show_tour');
tourStartRequestedRef.current = false;
};
retryTimer = setTimeout(() => startWhenReady(), 1000);
};
checkTour();
}, [registerLayout, startTour, t.tourChecklistDesc, t.tourChecklistTitle, t.tourFabDesc, t.tourFabTitle, t.tourProfileDesc, t.tourProfileTitle, t.tourSearchDesc, t.tourSearchTitle]);
return () => {
cancelled = true;
if (retryTimer) {
clearTimeout(retryTimer);
}
};
}, [layouts, registerLayout, startTour, t.tourChecklistDesc, t.tourChecklistTitle, t.tourFabDesc, t.tourFabTitle, t.tourProfileDesc, t.tourProfileTitle, t.tourSearchDesc, t.tourSearchTitle]);
const copy = t;
const greetingText = useMemo(() => {