import 'dart:async'; import 'package:flutter/widgets.dart'; /// Renders [whileDelayed] only after [isLoading] has been true /// continuously for [delay], then renders [whenReady] once loading /// completes. Mirrors the web `useDelayed` hook: a brief loading flash /// doesn't trigger a skeleton; sustained loading does. /// /// Once [isLoading] flips back to false, the timer resets. class DelayedLoading extends StatefulWidget { const DelayedLoading({ super.key, required this.isLoading, required this.whileDelayed, required this.whenReady, this.delay = const Duration(milliseconds: 200), }); final bool isLoading; final Widget whileDelayed; final Widget whenReady; final Duration delay; @override State createState() => _DelayedLoadingState(); } class _DelayedLoadingState extends State { Timer? _timer; bool _delayPassed = false; @override void initState() { super.initState(); _maybeStart(); } @override void didUpdateWidget(DelayedLoading old) { super.didUpdateWidget(old); if (widget.isLoading != old.isLoading) { _timer?.cancel(); _delayPassed = false; _maybeStart(); } } void _maybeStart() { if (!widget.isLoading) return; _timer = Timer(widget.delay, () { if (mounted) setState(() => _delayPassed = true); }); } @override void dispose() { _timer?.cancel(); super.dispose(); } @override Widget build(BuildContext context) { if (!widget.isLoading) return widget.whenReady; return _delayPassed ? widget.whileDelayed : const SizedBox.shrink(); } }