fix(auth): Improve auth error handling without token clearing
This commit is contained in:
@@ -142,6 +142,7 @@ final authNavigationStateProvider = Provider<AuthNavigationState>((ref) {
|
||||
return AuthNavigationState.authenticated;
|
||||
case AuthStatus.unauthenticated:
|
||||
case AuthStatus.tokenExpired:
|
||||
case AuthStatus.credentialError:
|
||||
return AuthNavigationState.needsLogin;
|
||||
case AuthStatus.error:
|
||||
return AuthNavigationState.error;
|
||||
|
||||
@@ -3,12 +3,11 @@ import 'dart:io' show Platform;
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../../core/auth/auth_state_manager.dart';
|
||||
import '../../../core/models/server_config.dart';
|
||||
import '../../../core/providers/app_providers.dart';
|
||||
import '../../../core/services/connectivity_service.dart';
|
||||
import '../../../core/services/navigation_service.dart';
|
||||
import '../../../core/widgets/error_boundary.dart';
|
||||
import '../../../l10n/app_localizations.dart';
|
||||
import '../../../shared/theme/theme_extensions.dart';
|
||||
@@ -25,6 +24,7 @@ class ConnectionIssuePage extends ConsumerStatefulWidget {
|
||||
|
||||
class _ConnectionIssuePageState extends ConsumerState<ConnectionIssuePage> {
|
||||
bool _isLoggingOut = false;
|
||||
bool _isRetrying = false;
|
||||
String? _statusMessage;
|
||||
|
||||
@override
|
||||
@@ -174,9 +174,8 @@ class _ConnectionIssuePageState extends ConsumerState<ConnectionIssuePage> {
|
||||
children: [
|
||||
ConduitButton(
|
||||
text: l10n.retry,
|
||||
onPressed: _isLoggingOut
|
||||
? null
|
||||
: () => context.go(Routes.serverConnection),
|
||||
onPressed: (_isLoggingOut || _isRetrying) ? null : _retryConnection,
|
||||
isLoading: _isRetrying,
|
||||
icon: Platform.isIOS
|
||||
? CupertinoIcons.refresh
|
||||
: Icons.refresh_rounded,
|
||||
@@ -185,7 +184,9 @@ class _ConnectionIssuePageState extends ConsumerState<ConnectionIssuePage> {
|
||||
const SizedBox(height: Spacing.sm),
|
||||
ConduitButton(
|
||||
text: l10n.signOut,
|
||||
onPressed: _isLoggingOut ? null : () => _logout(l10n),
|
||||
onPressed: (_isLoggingOut || _isRetrying)
|
||||
? null
|
||||
: () => _logout(l10n),
|
||||
isLoading: _isLoggingOut,
|
||||
isSecondary: true,
|
||||
icon: Platform.isIOS
|
||||
@@ -212,6 +213,40 @@ class _ConnectionIssuePageState extends ConsumerState<ConnectionIssuePage> {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _retryConnection() async {
|
||||
setState(() {
|
||||
_isRetrying = true;
|
||||
_statusMessage = null;
|
||||
});
|
||||
|
||||
try {
|
||||
// Clear the error state and attempt to re-establish connection
|
||||
final authManager = ref.read(authStateManagerProvider.notifier);
|
||||
|
||||
// Reset retry counter for manual retry attempts
|
||||
authManager.resetRetryCounter();
|
||||
|
||||
await authManager.silentLogin();
|
||||
|
||||
// If successful, router will automatically navigate to chat
|
||||
if (!mounted) return;
|
||||
|
||||
// Small delay to show loading state
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
} catch (_) {
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_statusMessage = 'Connection failed. Please try again.';
|
||||
});
|
||||
} finally {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_isRetrying = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _logout(AppLocalizations l10n) async {
|
||||
setState(() {
|
||||
_isLoggingOut = true;
|
||||
|
||||
@@ -698,7 +698,8 @@ class AppCustomizationPage extends ConsumerWidget {
|
||||
children: [
|
||||
Text(
|
||||
l10n.sttSilenceDuration,
|
||||
style: theme.bodyMedium?.copyWith(
|
||||
style:
|
||||
theme.bodyMedium?.copyWith(
|
||||
color: theme.sidebarForeground,
|
||||
fontWeight: FontWeight.w600,
|
||||
) ??
|
||||
@@ -711,13 +712,16 @@ class AppCustomizationPage extends ConsumerWidget {
|
||||
const SizedBox(height: Spacing.xs),
|
||||
Text(
|
||||
'${settings.voiceSilenceDuration}ms',
|
||||
style: theme.bodySmall?.copyWith(
|
||||
color: theme.sidebarForeground
|
||||
.withValues(alpha: 0.7),
|
||||
style:
|
||||
theme.bodySmall?.copyWith(
|
||||
color: theme.sidebarForeground.withValues(
|
||||
alpha: 0.7,
|
||||
),
|
||||
) ??
|
||||
TextStyle(
|
||||
color: theme.sidebarForeground
|
||||
.withValues(alpha: 0.7),
|
||||
color: theme.sidebarForeground.withValues(
|
||||
alpha: 0.7,
|
||||
),
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
@@ -726,7 +730,8 @@ class AppCustomizationPage extends ConsumerWidget {
|
||||
),
|
||||
Text(
|
||||
'${(settings.voiceSilenceDuration / 1000).toStringAsFixed(1)}s',
|
||||
style: theme.bodyMedium?.copyWith(
|
||||
style:
|
||||
theme.bodyMedium?.copyWith(
|
||||
color: theme.buttonPrimary,
|
||||
fontWeight: FontWeight.w600,
|
||||
) ??
|
||||
@@ -752,7 +757,8 @@ class AppCustomizationPage extends ConsumerWidget {
|
||||
),
|
||||
Text(
|
||||
l10n.sttSilenceDurationDescription,
|
||||
style: theme.bodySmall?.copyWith(
|
||||
style:
|
||||
theme.bodySmall?.copyWith(
|
||||
color: theme.sidebarForeground.withValues(alpha: 0.7),
|
||||
) ??
|
||||
TextStyle(
|
||||
|
||||
Reference in New Issue
Block a user