home_hint.dart 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. import 'dart:async';
  2. import 'package:flutter/material.dart';
  3. /// The one-time long-press hint. It is anchored to the first launch after
  4. /// installation and never returns once the ten-minute onboarding window ends.
  5. class HomeHint extends StatefulWidget {
  6. const HomeHint({
  7. super.key,
  8. required this.text,
  9. required this.firstLaunchAt,
  10. this.style,
  11. this.lifetime = const Duration(minutes: 10),
  12. this.clock,
  13. });
  14. final String text;
  15. final DateTime firstLaunchAt;
  16. final TextStyle? style;
  17. final Duration lifetime;
  18. final DateTime Function()? clock;
  19. @override
  20. State<HomeHint> createState() => _HomeHintState();
  21. }
  22. class _HomeHintState extends State<HomeHint> {
  23. Timer? _timer;
  24. bool _visible = true;
  25. @override
  26. void initState() {
  27. super.initState();
  28. final now = widget.clock?.call() ?? DateTime.now();
  29. final remaining = widget.firstLaunchAt.add(widget.lifetime).difference(now);
  30. if (remaining <= Duration.zero) {
  31. _visible = false;
  32. } else {
  33. _timer = Timer(remaining, () {
  34. if (mounted) setState(() => _visible = false);
  35. });
  36. }
  37. }
  38. @override
  39. void dispose() {
  40. _timer?.cancel();
  41. super.dispose();
  42. }
  43. @override
  44. Widget build(BuildContext context) {
  45. return AnimatedSwitcher(
  46. duration: const Duration(milliseconds: 350),
  47. switchInCurve: Curves.easeOut,
  48. switchOutCurve: Curves.easeIn,
  49. child: _visible
  50. ? Text(
  51. widget.text,
  52. key: const ValueKey('home-hint'),
  53. textAlign: TextAlign.center,
  54. style: widget.style,
  55. )
  56. : const SizedBox.shrink(key: ValueKey('home-hint-gone')),
  57. );
  58. }
  59. }