fix(profile): add sign out option when profile fails to load

Prevents users from being trapped in the app when their atProto profile
is misconfigured or not found. Adds optional secondary action support
to FullScreenError widget.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Changed files
+32 -1
lib
+7
lib/screens/home/profile_screen.dart
··· 180 180 // Show error state 181 181 if (profileProvider.profileError != null && 182 182 profileProvider.profile == null) { 183 + // Only show sign out option for own profile (no actor param) 184 + // This prevents users from being trapped with a misconfigured profile 185 + final isOwnProfile = widget.actor == null; 186 + 183 187 return Scaffold( 184 188 backgroundColor: AppColors.background, 185 189 appBar: _buildAppBar(context, null), ··· 187 191 title: 'Failed to load profile', 188 192 message: profileProvider.profileError!, 189 193 onRetry: () => profileProvider.retryProfile(), 194 + secondaryActionLabel: isOwnProfile ? 'Sign Out' : null, 195 + onSecondaryAction: isOwnProfile ? _handleSignOut : null, 196 + secondaryActionDestructive: true, 190 197 ), 191 198 ); 192 199 }
+25 -1
lib/widgets/loading_error_states.dart
··· 14 14 } 15 15 } 16 16 17 - /// Full-screen error state with retry button 17 + /// Full-screen error state with retry button and optional secondary action 18 18 class FullScreenError extends StatelessWidget { 19 19 const FullScreenError({ 20 20 required this.message, 21 21 required this.onRetry, 22 22 this.title = 'Failed to load', 23 + this.secondaryActionLabel, 24 + this.onSecondaryAction, 25 + this.secondaryActionDestructive = false, 23 26 super.key, 24 27 }); 25 28 26 29 final String title; 27 30 final String message; 28 31 final VoidCallback onRetry; 32 + 33 + /// Optional secondary action button label (e.g., "Sign Out") 34 + final String? secondaryActionLabel; 35 + 36 + /// Optional secondary action callback 37 + final VoidCallback? onSecondaryAction; 38 + 39 + /// Whether the secondary action is destructive (shows in red) 40 + final bool secondaryActionDestructive; 29 41 30 42 @override 31 43 Widget build(BuildContext context) { ··· 62 74 ), 63 75 child: const Text('Retry'), 64 76 ), 77 + if (secondaryActionLabel != null && onSecondaryAction != null) ...[ 78 + const SizedBox(height: 12), 79 + TextButton( 80 + onPressed: onSecondaryAction, 81 + style: TextButton.styleFrom( 82 + foregroundColor: secondaryActionDestructive 83 + ? Colors.red.shade400 84 + : AppColors.textSecondary, 85 + ), 86 + child: Text(secondaryActionLabel!), 87 + ), 88 + ], 65 89 ], 66 90 ), 67 91 ),