fix mobile pwa header video startup and slide overflow
This commit is contained in:
parent
e8f47993a9
commit
95e60594e8
@ -619,7 +619,7 @@
|
||||
scroll-snap-type: x mandatory;
|
||||
scroll-behavior: smooth;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
touch-action: pan-x pinch-zoom;
|
||||
touch-action: pan-x pan-y pinch-zoom;
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
gap: 1rem;
|
||||
@ -643,6 +643,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
padding-bottom: calc(env(safe-area-inset-bottom) + 7.25rem);
|
||||
overflow: visible;
|
||||
}
|
||||
}
|
||||
|
||||
@ -309,14 +309,19 @@ export function UnifiedQuitPlanCard({
|
||||
if (!showNicotine && !showWeed) return null;
|
||||
|
||||
return (
|
||||
<Card className="backdrop-blur-2xl shadow-2xl border-white/10 overflow-hidden bg-white/5">
|
||||
<Card
|
||||
className={cn(
|
||||
"backdrop-blur-2xl shadow-2xl border-white/10 overflow-hidden bg-white/5",
|
||||
!isDesktopVariant && "max-h-[calc(100dvh-13.5rem)]"
|
||||
)}
|
||||
>
|
||||
<CardHeader className="pb-1 pt-6 px-4 sm:px-6">
|
||||
<CardTitle className="flex items-center gap-2 text-sm sm:text-base font-black uppercase tracking-widest opacity-60">
|
||||
<TrendingDown className="h-4 w-4 text-primary" />
|
||||
Quit Journey Plan
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="pt-2 p-2 sm:p-4">
|
||||
<CardContent className={cn("pt-2 p-2 sm:p-4", !isDesktopVariant && "overflow-y-auto overscroll-contain pr-1")}>
|
||||
{showNicotine && (
|
||||
<SubstancePlanSection
|
||||
substance="nicotine"
|
||||
|
||||
@ -140,6 +140,7 @@ export function UserHeader({ user, preferences, onModalStateChange }: UserHeader
|
||||
const { theme } = useTheme();
|
||||
const { isSupported, permission, requestPermission } = useNotifications(reminderSettings);
|
||||
const videoRef = useRef<HTMLVideoElement>(null);
|
||||
const videoRetryTimeoutRef = useRef<number | null>(null);
|
||||
const [isVideoLoaded, setIsVideoLoaded] = useState(false);
|
||||
const [isVideoPlaying, setIsVideoPlaying] = useState(false);
|
||||
|
||||
@ -160,6 +161,35 @@ export function UserHeader({ user, preferences, onModalStateChange }: UserHeader
|
||||
checkMobile();
|
||||
}, []);
|
||||
|
||||
const clearVideoRetryTimeout = () => {
|
||||
if (videoRetryTimeoutRef.current !== null) {
|
||||
window.clearTimeout(videoRetryTimeoutRef.current);
|
||||
videoRetryTimeoutRef.current = null;
|
||||
}
|
||||
};
|
||||
|
||||
const scheduleVideoRetry = () => {
|
||||
clearVideoRetryTimeout();
|
||||
videoRetryTimeoutRef.current = window.setTimeout(() => {
|
||||
const video = videoRef.current;
|
||||
if (!video) return;
|
||||
|
||||
if (video.readyState < 2) {
|
||||
video.load();
|
||||
}
|
||||
|
||||
video.play().catch(() => {
|
||||
// Ignore autoplay retries that still fail.
|
||||
});
|
||||
}, 900);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
clearVideoRetryTimeout();
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Force play background video
|
||||
useEffect(() => {
|
||||
if (videoRef.current) {
|
||||
@ -176,12 +206,15 @@ export function UserHeader({ user, preferences, onModalStateChange }: UserHeader
|
||||
video.playsInline = true;
|
||||
video.setAttribute('playsinline', 'true'); // Explicit attribute for some older browsers
|
||||
video.setAttribute('webkit-playsinline', 'true');
|
||||
video.preload = 'metadata';
|
||||
} else {
|
||||
video.preload = 'auto';
|
||||
}
|
||||
|
||||
video.loop = true;
|
||||
|
||||
// If already ready, set loaded immediately
|
||||
if (video.readyState >= 3) {
|
||||
if (video.readyState >= 2) {
|
||||
setIsVideoLoaded(true);
|
||||
}
|
||||
|
||||
@ -190,10 +223,20 @@ export function UserHeader({ user, preferences, onModalStateChange }: UserHeader
|
||||
if (playPromise !== undefined) {
|
||||
playPromise.catch((err) => {
|
||||
console.warn("Autoplay failed, user interaction might be needed:", err);
|
||||
// If PWA, we might want to show the poster as fallback silently without error spam
|
||||
if (isMobile || isPWA) {
|
||||
scheduleVideoRetry();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (isMobile || isPWA) {
|
||||
scheduleVideoRetry();
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
clearVideoRetryTimeout();
|
||||
};
|
||||
}, [isMobile, isPWA]);
|
||||
|
||||
useEffect(() => {
|
||||
@ -366,18 +409,49 @@ export function UserHeader({ user, preferences, onModalStateChange }: UserHeader
|
||||
"x-webkit-airplay": "deny",
|
||||
"disableRemotePlayback": true
|
||||
} as any)}
|
||||
preload="auto"
|
||||
preload={isMobile || isPWA ? 'metadata' : 'auto'}
|
||||
controls={false}
|
||||
disablePictureInPicture
|
||||
onContextMenu={(e) => e.preventDefault()}
|
||||
onLoadedData={() => setIsVideoLoaded(true)}
|
||||
onPlay={() => setIsVideoPlaying(true)}
|
||||
onPlaying={() => setIsVideoPlaying(true)}
|
||||
onTimeUpdate={() => {
|
||||
if (!isVideoPlaying && videoRef.current && videoRef.current.currentTime > 0) {
|
||||
onCanPlay={() => {
|
||||
setIsVideoLoaded(true);
|
||||
if (videoRef.current?.paused) {
|
||||
videoRef.current.play().catch(() => {
|
||||
if (isMobile || isPWA) {
|
||||
scheduleVideoRetry();
|
||||
}
|
||||
});
|
||||
}
|
||||
}}
|
||||
onPlaying={() => {
|
||||
if (videoRef.current && videoRef.current.currentTime > 0.06) {
|
||||
setIsVideoPlaying(true);
|
||||
}
|
||||
}}
|
||||
onTimeUpdate={() => {
|
||||
if (!isVideoPlaying && videoRef.current && videoRef.current.currentTime > 0.06) {
|
||||
setIsVideoPlaying(true);
|
||||
}
|
||||
}}
|
||||
onWaiting={() => {
|
||||
setIsVideoPlaying(false);
|
||||
if (isMobile || isPWA) {
|
||||
scheduleVideoRetry();
|
||||
}
|
||||
}}
|
||||
onStalled={() => {
|
||||
setIsVideoPlaying(false);
|
||||
if (isMobile || isPWA) {
|
||||
scheduleVideoRetry();
|
||||
}
|
||||
}}
|
||||
onPause={() => {
|
||||
setIsVideoPlaying(false);
|
||||
}}
|
||||
onError={() => {
|
||||
setIsVideoPlaying(false);
|
||||
}}
|
||||
className={cn(
|
||||
"absolute inset-0 w-full h-full object-cover transition-opacity duration-[1500ms] ease-in-out",
|
||||
isMobile ? "scale-105" : "scale-110",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user