// Version: 1.0.0 | Created: 2026-07-04 // Post-login prompt: if the account has secret storage (key backup) and this // fresh device cannot read encrypted history yet, offer the recovery-key // restore straight away instead of leaving it buried in Profile > Security. // // Shown at most once per login session. "Later" keeps the old behaviour // (restore manually from the Profile tab). import 'dart:async'; import 'package:flutter/material.dart'; import 'package:matrix/matrix.dart'; import 'key_restore_dialog.dart'; bool _promptedThisSession = false; /// Reset when a new login happens (called from the login flow if needed). void resetKeyRestorePrompt() => _promptedThisSession = false; /// Checks whether the freshly logged-in session needs a key restore and, /// if so, asks the user. Safe to call multiple times; only fires once. Future maybePromptKeyRestore(BuildContext context, Client client) async { if (_promptedThisSession) return; _promptedThisSession = true; try { // Wait for the first sync so account data (secret storage config) exists. if (client.prevBatch == null) { await client.onSync.stream.first.timeout(const Duration(seconds: 30)); } } on TimeoutException { debugPrint('[KeyRestorePrompt] first sync timed out — skipping'); return; } final enc = client.encryption; if (enc == null) return; // No secret storage on the account → nothing to restore from. final hasSecretStorage = client.accountData.containsKey('m.secret_storage.default_key'); if (!hasSecretStorage) return; // Keys already cached (or session verified) → nothing to do. var cached = false; try { cached = await enc.keyManager.isCached(); } on Exception catch (e) { debugPrint('[KeyRestorePrompt] isCached failed: $e'); } if (cached && !client.isUnknownSession) return; if (!context.mounted) return; final wantsRestore = await showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('Restore encrypted messages?'), content: const Text( 'This device cannot read your older encrypted messages yet. ' 'Enter your recovery key now to unlock them, or do it later ' 'from Profile > Security & Privacy.', ), actions: [ TextButton( onPressed: () => Navigator.of(ctx).pop(false), child: const Text('Later'), ), FilledButton( onPressed: () => Navigator.of(ctx).pop(true), child: const Text('Enter recovery key'), ), ], ), ); if (wantsRestore != true || !context.mounted) return; await showKeyRestoreDialog(context, client); }