forked from Tadrisino/MathApp_frontend
Splash only appears when the server is slow: no flash of the welcome screen on a fast start
The splash used to stay a fixed 700ms plus a fade, so a fast response still showed it briefly and jumped away. Now only the matching background shows for the first 350ms; the splash content appears only if the response has not arrived by then, and once shown it stays at least 700ms. Not run on a device.
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { AnimatePresence, MotionConfig, motion } from 'motion/react';
|
import { AnimatePresence, MotionConfig, motion } from 'motion/react';
|
||||||
import { api, ApiError, http, type Grade, type UserProfile } from '@/api';
|
import { api, ApiError, http, type Grade, type UserProfile } from '@/api';
|
||||||
import type { Prefetch } from '@/state/AppData';
|
import type { Prefetch } from '@/state/AppData';
|
||||||
@@ -23,7 +23,13 @@ type Flow =
|
|||||||
| { kind: 'setup'; profile: UserProfile; grades: Grade[] }
|
| { kind: 'setup'; profile: UserProfile; grades: Grade[] }
|
||||||
| { kind: 'main'; profile: UserProfile; grades: Grade[]; prefetch?: Prefetch };
|
| { kind: 'main'; profile: UserProfile; grades: Grade[]; prefetch?: Prefetch };
|
||||||
|
|
||||||
/** کمترین زمانِ نمایشِ اسپلش، تا صفحه چشمک نزند. */
|
/**
|
||||||
|
* اسپلش فقط وقتی نشان داده میشود که سرور دیرتر از SPLASH_DELAY_MS جواب بدهد؛ اگر زودتر رسید، کاربر
|
||||||
|
* اسپلش را نمیبیند و مستقیم به صفحهی بعدی میرود (بهجای چند صد میلیثانیه چشمک).
|
||||||
|
* اگر یک بار نشان داده شد، دستکم SPLASH_MIN_MS میماند تا خودش چشمک نزند.
|
||||||
|
* تا آن لحظه فقط پسزمینهی همرنگِ اسپلش دیده میشود، نه صفحهی سفید.
|
||||||
|
*/
|
||||||
|
const SPLASH_DELAY_MS = 350;
|
||||||
const SPLASH_MIN_MS = 700;
|
const SPLASH_MIN_MS = 700;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,6 +38,8 @@ const SPLASH_MIN_MS = 700;
|
|||||||
*/
|
*/
|
||||||
export function App() {
|
export function App() {
|
||||||
const [flow, setFlow] = useState<Flow>({ kind: 'boot' });
|
const [flow, setFlow] = useState<Flow>({ kind: 'boot' });
|
||||||
|
const [splashVisible, setSplashVisible] = useState(false);
|
||||||
|
const splashShownAt = useRef<number | null>(null);
|
||||||
|
|
||||||
/** پروفایل و پایهها را میگیرد و تصمیم میگیرد کاربر کجا برود. */
|
/** پروفایل و پایهها را میگیرد و تصمیم میگیرد کاربر کجا برود. */
|
||||||
const enter = useCallback(async () => {
|
const enter = useCallback(async () => {
|
||||||
@@ -45,7 +53,12 @@ export function App() {
|
|||||||
|
|
||||||
const boot = useCallback(async () => {
|
const boot = useCallback(async () => {
|
||||||
setFlow({ kind: 'boot' });
|
setFlow({ kind: 'boot' });
|
||||||
const started = Date.now();
|
splashShownAt.current = null;
|
||||||
|
setSplashVisible(false);
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
splashShownAt.current = Date.now();
|
||||||
|
setSplashVisible(true);
|
||||||
|
}, SPLASH_DELAY_MS);
|
||||||
let next: Flow | null = null;
|
let next: Flow | null = null;
|
||||||
if (api.auth.isSignedIn()) {
|
if (api.auth.isSignedIn()) {
|
||||||
try {
|
try {
|
||||||
@@ -59,8 +72,13 @@ export function App() {
|
|||||||
} else {
|
} else {
|
||||||
next = store.get(KEYS.onboarded) ? { kind: 'login' } : { kind: 'onboarding' };
|
next = store.get(KEYS.onboarded) ? { kind: 'login' } : { kind: 'onboarding' };
|
||||||
}
|
}
|
||||||
const wait = SPLASH_MIN_MS - (Date.now() - started);
|
clearTimeout(timer);
|
||||||
if (wait > 0) await new Promise((r) => setTimeout(r, wait));
|
// اسپلش دیده شده؟ فقط در آن صورت تا کمینهی زمانش نگه دار.
|
||||||
|
const shownAt = splashShownAt.current;
|
||||||
|
if (shownAt !== null) {
|
||||||
|
const wait = SPLASH_MIN_MS - (Date.now() - shownAt);
|
||||||
|
if (wait > 0) await new Promise((r) => setTimeout(r, wait));
|
||||||
|
}
|
||||||
if (next) setFlow(next);
|
if (next) setFlow(next);
|
||||||
}, [enter]);
|
}, [enter]);
|
||||||
|
|
||||||
@@ -99,9 +117,10 @@ export function App() {
|
|||||||
initial={{ opacity: 0 }}
|
initial={{ opacity: 0 }}
|
||||||
animate={{ opacity: 1 }}
|
animate={{ opacity: 1 }}
|
||||||
exit={{ opacity: 0 }}
|
exit={{ opacity: 0 }}
|
||||||
transition={{ duration: 0.2 }}
|
// اگر اسپلش هرگز دیده نشد، محوشدن هم لازم نیست (وگرنه همان چشمک از راهِ دیگر برمیگردد).
|
||||||
|
transition={{ duration: splashVisible || flow.kind !== 'boot' ? 0.2 : 0 }}
|
||||||
>
|
>
|
||||||
{flow.kind === 'boot' && <SplashScreen />}
|
{flow.kind === 'boot' && <SplashScreen showContent={splashVisible} />}
|
||||||
{flow.kind === 'bootError' && (
|
{flow.kind === 'bootError' && (
|
||||||
<div className="flex h-full flex-col justify-center">
|
<div className="flex h-full flex-col justify-center">
|
||||||
<ErrorState error={flow.error} onRetry={() => void boot()} />
|
<ErrorState error={flow.error} onRetry={() => void boot()} />
|
||||||
|
|||||||
@@ -8,8 +8,12 @@ const GLYPHS = [
|
|||||||
{ c: '÷', x: 64, d: 3.8 }, { c: '∑', x: 80, d: 0.6 }, { c: '×', x: 90, d: 4.6 },
|
{ c: '÷', x: 64, d: 3.8 }, { c: '∑', x: 80, d: 0.6 }, { c: '×', x: 90, d: 4.6 },
|
||||||
];
|
];
|
||||||
|
|
||||||
/** تا وقتی نشستِ قبلی بررسی میشود نمایش داده میشود؛ عمداً تأخیرِ ساختگی ندارد. */
|
/**
|
||||||
export function SplashScreen() {
|
* تا وقتی نشستِ قبلی بررسی میشود نمایش داده میشود. `showContent=false` فقط پسزمینه است؛ App
|
||||||
|
* محتوا را فقط وقتی روشن میکند که پاسخِ سرور دیر کرده باشد.
|
||||||
|
*/
|
||||||
|
export function SplashScreen({ showContent }: { showContent: boolean }) {
|
||||||
|
if (!showContent) return <div className="h-full bg-rose" />;
|
||||||
return (
|
return (
|
||||||
<div className="relative flex h-full flex-col items-center justify-center overflow-hidden bg-rose">
|
<div className="relative flex h-full flex-col items-center justify-center overflow-hidden bg-rose">
|
||||||
<div aria-hidden="true" className="pointer-events-none absolute inset-x-0 bottom-0 h-1/2">
|
<div aria-hidden="true" className="pointer-events-none absolute inset-x-0 bottom-0 h-1/2">
|
||||||
|
|||||||
Reference in New Issue
Block a user