/// Shared helpers to open Settings from app bars. library; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../providers/auth_provider.dart'; import '../providers/sync_provider.dart'; import '../screens/account_screen.dart'; import '../screens/login_screen.dart'; import '../screens/settings_screen.dart'; Widget authAppBarAction(BuildContext context) { final auth = context.watch(); final sync = context.watch(); final showRing = sync.showProgressRing; final progress = sync.syncProgress; final success = sync.progressSuccess; final syncActive = sync.isSyncing || showRing; if (auth.isLoggedIn) { final ringColor = success ? const Color(0xFF16A34A) : Theme.of(context).colorScheme.primary; return PopupMenuButton<_AccountMenuAction>( tooltip: sync.isSyncing ? 'Syncing… ${(progress * 100).round()}%' : auth.displayName, offset: const Offset(0, 48), onSelected: (action) async { switch (action) { case _AccountMenuAction.account: await Navigator.of(context).push( MaterialPageRoute(builder: (_) => const AccountScreen()), ); case _AccountMenuAction.logout: await auth.logout(); } }, itemBuilder: (context) { final email = auth.email; // Capture whether sync was active when the menu opened; the tile // itself keeps listening so the % can update while the menu is open. final showSyncRow = syncActive; return [ if (email != null) PopupMenuItem<_AccountMenuAction>( enabled: false, child: Text( email, style: Theme.of(context).textTheme.bodySmall, ), ), if (showSyncRow) const PopupMenuItem<_AccountMenuAction>( enabled: false, child: _SyncProgressMenuTile(), ), const PopupMenuItem<_AccountMenuAction>( value: _AccountMenuAction.account, child: ListTile( contentPadding: EdgeInsets.zero, leading: Icon(Icons.person_outline), title: Text('Account'), ), ), const PopupMenuItem<_AccountMenuAction>( value: _AccountMenuAction.logout, child: ListTile( contentPadding: EdgeInsets.zero, leading: Icon(Icons.logout), title: Text('Sign out'), ), ), ]; }, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: SizedBox( width: 32, height: 32, child: Stack( alignment: Alignment.center, children: [ CircleAvatar( radius: 16, backgroundColor: Theme.of(context).colorScheme.primaryContainer, child: Text( auth.initials, style: Theme.of(context).textTheme.labelLarge?.copyWith( color: Theme.of(context).colorScheme.onPrimaryContainer, ), ), ), if (showRing) SizedBox( width: 32, height: 32, child: CircularProgressIndicator( value: progress <= 0 ? null : progress.clamp(0.02, 1.0), strokeWidth: 2.5, color: ringColor, backgroundColor: Theme.of(context) .colorScheme .outlineVariant .withValues(alpha: 0.45), ), ), ], ), ), ), ); } return IconButton( tooltip: 'Sign in', onPressed: () { Navigator.of(context).push( MaterialPageRoute(builder: (_) => const LoginScreen()), ); }, icon: const Icon(Icons.person_outline), ); } /// Live sync status row inside the account popup (watches [SyncController]). class _SyncProgressMenuTile extends StatelessWidget { const _SyncProgressMenuTile(); @override Widget build(BuildContext context) { final sync = context.watch(); final theme = Theme.of(context); final colors = theme.colorScheme; final pct = (sync.syncProgress * 100).round().clamp(0, 100); final detail = sync.statusDetail.trim(); if (sync.progressSuccess) { return ListTile( contentPadding: EdgeInsets.zero, leading: Icon(Icons.check_circle_outline, color: colors.primary), title: Text( 'Sync complete', style: theme.textTheme.bodyMedium?.copyWith( color: colors.onSurface, ), ), ); } return ListTile( contentPadding: EdgeInsets.zero, leading: SizedBox( width: 24, height: 24, child: CircularProgressIndicator( value: sync.syncProgress <= 0 ? null : sync.syncProgress.clamp(0.02, 1.0), strokeWidth: 2.5, ), ), title: Text( detail.isEmpty ? 'Sync in progress ($pct%)' : detail, style: theme.textTheme.bodyMedium?.copyWith( color: colors.onSurface, ), ), subtitle: detail.isEmpty ? null : Text('Sync in progress ($pct%)'), ); } } enum _AccountMenuAction { account, logout } List bankAppBarActions({ required BuildContext context, VoidCallback? onRefresh, bool refreshing = false, }) { return [ if (onRefresh != null) IconButton( tooltip: 'Refresh', onPressed: refreshing ? null : onRefresh, icon: const Icon(Icons.refresh), ), IconButton( tooltip: 'Settings', onPressed: () { Navigator.of(context).push( MaterialPageRoute(builder: (_) => const SettingsScreen()), ); }, icon: const Icon(Icons.settings_outlined), ), authAppBarAction(context), ]; }