74 lines
2.4 KiB
Dart
74 lines
2.4 KiB
Dart
|
|
// lib/core/utils/error_utils.dart
|
||
|
|
|
||
|
|
/// Converts raw exceptions into user-friendly messages.
|
||
|
|
/// Strips technical details (hostnames, ports, stack traces, exception chains)
|
||
|
|
/// and returns a clean message safe to display in the UI.
|
||
|
|
String userFriendlyError(Object e) {
|
||
|
|
final raw = e.toString();
|
||
|
|
|
||
|
|
// Network / connectivity issues
|
||
|
|
if (raw.contains('SocketException') ||
|
||
|
|
raw.contains('Connection refused') ||
|
||
|
|
raw.contains('Connection reset') ||
|
||
|
|
raw.contains('Network is unreachable') ||
|
||
|
|
raw.contains('No address associated') ||
|
||
|
|
raw.contains('Failed to fetch') ||
|
||
|
|
raw.contains('HandshakeException') ||
|
||
|
|
raw.contains('ClientException')) {
|
||
|
|
return 'Unable to connect. Please check your internet connection and try again.';
|
||
|
|
}
|
||
|
|
|
||
|
|
// Timeout
|
||
|
|
if (raw.contains('TimeoutException') || raw.contains('timed out')) {
|
||
|
|
return 'The request took too long. Please try again.';
|
||
|
|
}
|
||
|
|
|
||
|
|
// Rate limited
|
||
|
|
if (raw.contains('status 429') || raw.contains('throttled') || raw.contains('Too Many Requests')) {
|
||
|
|
return 'Too many requests. Please wait a moment and try again.';
|
||
|
|
}
|
||
|
|
|
||
|
|
// Auth expired / forbidden
|
||
|
|
if (raw.contains('status 401') || raw.contains('Unauthorized')) {
|
||
|
|
return 'Session expired. Please log in again.';
|
||
|
|
}
|
||
|
|
if (raw.contains('status 403') || raw.contains('Forbidden')) {
|
||
|
|
return 'You do not have permission to perform this action.';
|
||
|
|
}
|
||
|
|
|
||
|
|
// Server error
|
||
|
|
if (RegExp(r'status 5\d\d').hasMatch(raw)) {
|
||
|
|
return 'Something went wrong on our end. Please try again later.';
|
||
|
|
}
|
||
|
|
|
||
|
|
// Not found
|
||
|
|
if (raw.contains('status 404') || raw.contains('Not Found')) {
|
||
|
|
return 'The requested resource was not found.';
|
||
|
|
}
|
||
|
|
|
||
|
|
// Strip Exception wrappers and nested chains for validation messages
|
||
|
|
var cleaned = raw
|
||
|
|
.replaceAll(RegExp(r'Exception:\s*'), '')
|
||
|
|
.replaceAll(RegExp(r'Failed to \w+ \w+:\s*'), '')
|
||
|
|
.replaceAll(RegExp(r'Network error:\s*'), '')
|
||
|
|
.replaceAll(RegExp(r'Request failed \(status \d+\)\s*'), '')
|
||
|
|
.trim();
|
||
|
|
|
||
|
|
// If the cleaned message is empty or still looks technical, use a generic fallback
|
||
|
|
if (cleaned.isEmpty ||
|
||
|
|
cleaned.contains('errno') ||
|
||
|
|
cleaned.contains('address =') ||
|
||
|
|
cleaned.contains('port =') ||
|
||
|
|
cleaned.startsWith('{') ||
|
||
|
|
cleaned.startsWith('[')) {
|
||
|
|
return 'Something went wrong. Please try again.';
|
||
|
|
}
|
||
|
|
|
||
|
|
// Capitalize first letter
|
||
|
|
if (cleaned.isNotEmpty) {
|
||
|
|
cleaned = cleaned[0].toUpperCase() + cleaned.substring(1);
|
||
|
|
}
|
||
|
|
|
||
|
|
return cleaned;
|
||
|
|
}
|