import 'package:flutter/material.dart'; import '../screens/data_settings_screen.dart'; import '../services/onboarding_keys.dart'; import 'onboarding_tour_overlay.dart'; /// Shown right after a fuel entry is saved (see /// `ConfirmFuelEntryScreen._save`) when no cloud backup is configured yet — /// nudges the user toward Settings > Data before they forget and eventually /// lose everything to a lost, damaged, or replaced device. Returns true if /// they chose to set one up now. Future showBackupReminderDialog(BuildContext context) async { final wantsSetup = await showDialog( context: context, builder: (context) => AlertDialog( title: const Text("Your Data Isn't Backed Up"), content: const Text( "Until you enable a backup method, everything you log — including this " "receipt — only lives on this device. If it's lost, damaged, or " "replaced, that data could be lost with it.\n\n" 'Would you like to set up a backup method now?', ), actions: [ TextButton(onPressed: () => Navigator.of(context).pop(false), child: const Text('Not Now')), FilledButton(onPressed: () => Navigator.of(context).pop(true), child: const Text('Set Up Backup')), ], ), ); return wantsSetup ?? false; } /// Pushes Settings > Data with its cloud storage card spotlighted — the /// same visual treatment the first-launch tour's "Back Up to the Cloud" /// step uses (see [OnboardingTourOverlay] / `MainShell`), but as a one-off /// standalone overlay rather than part of a multi-step tour. Future openCloudBackupSetup(BuildContext context) { return Navigator.of(context).push( MaterialPageRoute(builder: (_) => const _SpotlightedDataSettingsScreen()), ); } class _SpotlightedDataSettingsScreen extends StatefulWidget { const _SpotlightedDataSettingsScreen(); @override State<_SpotlightedDataSettingsScreen> createState() => _SpotlightedDataSettingsScreenState(); } class _SpotlightedDataSettingsScreenState extends State<_SpotlightedDataSettingsScreen> { OverlayEntry? _entry; @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) => _showSpotlight()); } @override void dispose() { _entry?.remove(); super.dispose(); } /// Mirrors `MainShell._waitForTargets`/`_showTourStep` for this one /// target — duplicated rather than shared because that logic is /// entangled with the tour's multi-step sequencing, which doesn't apply /// to this standalone spotlight. Future _showSpotlight() async { final key = OnboardingKeys.cloudStorageCard; for (var attempt = 0; attempt < 30; attempt++) { if (!mounted) return; final renderObject = key.currentContext?.findRenderObject(); if (renderObject is RenderBox && renderObject.hasSize) break; await Future.delayed(const Duration(milliseconds: 16)); } if (!mounted) return; key.currentContext?.findRenderObject()?.showOnScreen(duration: Duration.zero); for (var i = 0; i < 5; i++) { if (!mounted) return; await Future.delayed(const Duration(milliseconds: 16)); } if (!mounted) return; _entry = OverlayEntry( builder: (_) => OnboardingTourOverlay( targetKeys: [key], title: 'Back Up to the Cloud', description: 'Connect a cloud storage account here to back up every vehicle, receipt, ' "and photo you log — so nothing is lost if this device is lost, damaged, or " 'replaced.', stepNumber: 1, totalSteps: 1, skipLabel: 'Close', onNext: _dismiss, onSkip: _dismiss, ), ); Overlay.of(context, rootOverlay: true).insert(_entry!); } void _dismiss() { _entry?.remove(); _entry = null; } @override Widget build(BuildContext context) => const DataSettingsScreen(); }