fix: Prefer reusing AppBaseException instead of redefining the exception contract CacheException and RemoteException

This commit is contained in:
dab246
2026-03-09 10:27:16 +07:00
committed by Dat H. Pham
parent 236ad5f075
commit 8a21e35d1e
139 changed files with 344 additions and 325 deletions
@@ -38,8 +38,8 @@ import 'package:tmail_ui_user/features/login/domain/usecases/get_token_oidc_inte
import 'package:tmail_ui_user/features/login/domain/usecases/remove_auth_destination_url_interactor.dart';
import 'package:tmail_ui_user/features/login/domain/usecases/update_account_cache_interactor.dart';
import 'package:tmail_ui_user/features/manage_account/domain/usecases/log_out_oidc_interactor.dart';
import 'package:tmail_ui_user/main/exceptions/cache_exception_thrower.dart';
import 'package:tmail_ui_user/main/exceptions/remote_exception_thrower.dart';
import 'package:tmail_ui_user/main/exceptions/thrower/cache_exception_thrower.dart';
import 'package:tmail_ui_user/main/exceptions/thrower/remote_exception_thrower.dart';
import 'package:tmail_ui_user/main/utils/ios_sharing_manager.dart';
class CredentialBindings extends InteractorsBindings {
+1 -1
View File
@@ -44,7 +44,7 @@ import 'package:tmail_ui_user/features/offline_mode/manager/sending_email_cache_
import 'package:tmail_ui_user/features/push_notification/data/keychain/keychain_sharing_manager.dart';
import 'package:tmail_ui_user/features/push_notification/data/local/fcm_cache_manager.dart';
import 'package:tmail_ui_user/features/thread/data/local/email_cache_manager.dart';
import 'package:tmail_ui_user/main/exceptions/cache_exception_thrower.dart';
import 'package:tmail_ui_user/main/exceptions/thrower/cache_exception_thrower.dart';
class LocalBindings extends Bindings {
@@ -35,8 +35,8 @@ import 'package:tmail_ui_user/features/push_notification/data/network/web_socket
import 'package:tmail_ui_user/features/quotas/data/network/quotas_api.dart';
import 'package:tmail_ui_user/features/server_settings/data/network/server_settings_api.dart';
import 'package:tmail_ui_user/features/thread/data/network/thread_api.dart';
import 'package:tmail_ui_user/main/exceptions/remote_exception_thrower.dart';
import 'package:tmail_ui_user/main/exceptions/send_email_exception_thrower.dart';
import 'package:tmail_ui_user/main/exceptions/thrower/remote_exception_thrower.dart';
import 'package:tmail_ui_user/main/exceptions/thrower/send_email_exception_thrower.dart';
import 'package:tmail_ui_user/main/utils/ios_sharing_manager.dart';
import 'package:uuid/uuid.dart';
import 'package:worker_manager/worker_manager.dart';
@@ -9,8 +9,8 @@ import 'package:tmail_ui_user/features/home/data/network/session_api.dart';
import 'package:tmail_ui_user/features/home/data/repository/session_repository_impl.dart';
import 'package:tmail_ui_user/features/home/domain/repository/session_repository.dart';
import 'package:tmail_ui_user/features/home/domain/usecases/get_session_interactor.dart';
import 'package:tmail_ui_user/main/exceptions/cache_exception_thrower.dart';
import 'package:tmail_ui_user/main/exceptions/remote_exception_thrower.dart';
import 'package:tmail_ui_user/main/exceptions/thrower/cache_exception_thrower.dart';
import 'package:tmail_ui_user/main/exceptions/thrower/remote_exception_thrower.dart';
class SessionBindings extends InteractorsBindings {
+12
View File
@@ -0,0 +1,12 @@
import 'package:core/domain/exceptions/app_base_exception.dart';
abstract class CacheException extends AppBaseException {
const CacheException([super.message]);
}
class UnknownCacheError extends CacheException {
const UnknownCacheError([super.message]);
@override
String get exceptionName => 'UnknownCacheError';
}
-30
View File
@@ -1,30 +0,0 @@
import 'package:equatable/equatable.dart';
abstract class CacheException with EquatableMixin implements Exception {
final String? message;
const CacheException({this.message});
String get exceptionName;
@override
String toString() {
if (message?.trim().isNotEmpty == true) {
return '$exceptionName: $message';
}
return exceptionName;
}
@override
List<Object?> get props => [message];
}
class UnknownCacheError extends CacheException {
const UnknownCacheError({String? message}) : super(message: message);
@override
String get exceptionName => 'UnknownCacheError';
@override
List<Object?> get props => [message];
}
@@ -0,0 +1,28 @@
import 'package:tmail_ui_user/main/exceptions/remote/remote_exception.dart';
class AuthenticationException extends RemoteException {
const AuthenticationException({super.message});
@override
String get exceptionName => 'AuthenticationException';
}
class BadCredentialsException extends AuthenticationException {
const BadCredentialsException() : super(message: 'Bad credentials');
@override
String get exceptionName => 'BadCredentialsException';
}
class RefreshTokenFailedException extends AuthenticationException {
RefreshTokenFailedException({
int code = 400,
String? message,
}) : super(
message: message ??
'Refresh token failed with status $code. Session invalid or revoked.',
);
@override
String get exceptionName => 'RefreshTokenFailedException';
}
@@ -0,0 +1,34 @@
import 'package:jmap_dart_client/jmap/core/error/error_type.dart';
import 'package:jmap_dart_client/jmap/core/error/method/error_method_response.dart';
import 'package:tmail_ui_user/main/exceptions/remote/remote_exception.dart';
class MethodLevelErrors extends RemoteException {
final ErrorType type;
const MethodLevelErrors(
this.type, {
String? message,
}) : super(message: message);
@override
String get exceptionName => 'MethodLevelErrors';
@override
String toString() {
return '$exceptionName(type: $type): $message';
}
@override
List<Object?> get props => [type, ...super.props];
}
class CannotCalculateChangesMethodResponseException extends MethodLevelErrors {
CannotCalculateChangesMethodResponseException({String? message})
: super(
ErrorMethodResponse.cannotCalculateChanges,
message: message,
);
@override
String get exceptionName => 'CannotCalculateChangesMethodResponseException';
}
@@ -0,0 +1,38 @@
import 'package:tmail_ui_user/main/exceptions/remote/remote_exception.dart';
class NetworkException extends RemoteException {
const NetworkException({super.message});
@override
String get exceptionName => 'NetworkException';
}
class NoNetworkError extends NetworkException {
const NoNetworkError() : super(message: 'No network connection');
@override
String get exceptionName => 'NoNetworkError';
}
class ConnectionError extends NetworkException {
const ConnectionError({String? message})
: super(message: message ?? 'Connection error');
@override
String get exceptionName => 'ConnectionError';
}
class ConnectionTimeout extends NetworkException {
const ConnectionTimeout({String? message})
: super(message: message ?? 'Connection timeout');
@override
String get exceptionName => 'ConnectionTimeout';
}
class SocketError extends NetworkException {
const SocketError() : super(message: 'Socket exception');
@override
String get exceptionName => 'SocketError';
}
@@ -0,0 +1,26 @@
import 'package:core/domain/exceptions/app_base_exception.dart';
abstract class RemoteException extends AppBaseException {
final int? code;
const RemoteException({
this.code,
String? message,
}) : super(message);
@override
String toString() {
if (code != null && message != null) {
return '$exceptionName(code: $code): $message';
}
if (code != null) {
return '$exceptionName(code: $code)';
}
return super.toString();
}
@override
List<Object?> get props => [code, ...super.props];
}
@@ -0,0 +1,16 @@
import 'package:tmail_ui_user/main/exceptions/remote/remote_exception.dart';
class ServerException extends RemoteException {
const ServerException({super.code, super.message});
@override
String get exceptionName => 'ServerException';
}
class InternalServerError extends ServerException {
const InternalServerError()
: super(message: 'Internal Server Error');
@override
String get exceptionName => 'InternalServerError';
}
@@ -0,0 +1,11 @@
import 'package:tmail_ui_user/main/exceptions/remote/remote_exception.dart';
class UnknownRemoteException extends RemoteException {
const UnknownRemoteException({
super.code,
super.message,
});
@override
String get exceptionName => 'UnknownRemoteException';
}
-128
View File
@@ -1,128 +0,0 @@
import 'package:equatable/equatable.dart';
import 'package:jmap_dart_client/jmap/core/error/error_type.dart';
import 'package:jmap_dart_client/jmap/core/error/method/error_method_response.dart';
abstract class RemoteException with EquatableMixin implements Exception {
static const connectionTimeout = 'Connection Timeout';
static const connectionError = 'Connection error';
static const internalServerError = 'Internal Server Error';
static const noNetworkError = 'No network error';
static const badCredentials = 'Bad credentials';
static const socketException = 'Socket exception';
final Object? message;
final int? code;
const RemoteException({this.code, this.message});
String get exceptionName;
@override
String toString() {
if (code != null) {
return '$exceptionName(code: $code): $message';
}
return '$exceptionName: $message';
}
@override
List<Object?> get props => [message, code];
}
class BadCredentialsException extends RemoteException {
const BadCredentialsException()
: super(message: RemoteException.badCredentials);
@override
String get exceptionName => 'BadCredentialsException';
}
class UnknownError extends RemoteException {
const UnknownError({int? code, Object? message})
: super(code: code, message: message);
@override
String get exceptionName => 'UnknownError';
}
class ConnectionError extends RemoteException {
const ConnectionError({String? message})
: super(message: message ?? RemoteException.connectionError);
@override
String get exceptionName => 'ConnectionError';
}
class ConnectionTimeout extends RemoteException {
const ConnectionTimeout({String? message})
: super(message: message ?? RemoteException.connectionTimeout);
@override
String get exceptionName => 'ConnectionTimeout';
}
class SocketError extends RemoteException {
const SocketError() : super(message: RemoteException.socketException);
@override
String get exceptionName => 'SocketError';
}
class InternalServerError extends RemoteException {
const InternalServerError()
: super(message: RemoteException.internalServerError);
@override
String get exceptionName => 'InternalServerError';
}
class MethodLevelErrors extends RemoteException {
final ErrorType type;
const MethodLevelErrors(this.type, {String? message})
: super(message: message);
@override
String get exceptionName => 'MethodLevelErrors';
@override
String toString() {
return '$exceptionName(type: $type): $message';
}
@override
List<Object?> get props => [type, ...super.props];
}
class CannotCalculateChangesMethodResponseException extends MethodLevelErrors {
CannotCalculateChangesMethodResponseException({String? message})
: super(ErrorMethodResponse.cannotCalculateChanges, message: message);
@override
String get exceptionName => 'CannotCalculateChangesMethodResponseException';
}
class NoNetworkError extends RemoteException {
const NoNetworkError() : super(message: RemoteException.noNetworkError);
@override
String get exceptionName => 'NoNetworkError';
}
class RefreshTokenFailedException extends RemoteException {
RefreshTokenFailedException({
int code = 400,
Object? message
}) : super(
code: code,
message: message ??
'Refresh Token failed with status $code. The session is invalid/revoked.',
);
@override
String get exceptionName => 'RefreshTokenFailedException';
@override
String toString() => "$exceptionName(status: $code): $message";
}
@@ -1,5 +1,5 @@
import 'package:core/utils/app_logger.dart';
import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart';
import 'package:tmail_ui_user/main/exceptions/thrower/exception_thrower.dart';
class CacheExceptionThrower extends ExceptionThrower {
@@ -9,8 +9,12 @@ import 'package:tmail_ui_user/features/login/domain/exceptions/authentication_ex
import 'package:tmail_ui_user/features/login/domain/exceptions/oauth_authorization_error.dart';
import 'package:tmail_ui_user/features/network_connection/presentation/network_connection_controller.dart'
if (dart.library.html) 'package:tmail_ui_user/features/network_connection/presentation/web_network_connection_controller.dart';
import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart';
import 'package:tmail_ui_user/main/exceptions/remote_exception.dart';
import 'package:tmail_ui_user/main/exceptions/remote/authentication_exception.dart';
import 'package:tmail_ui_user/main/exceptions/remote/method_level_exception.dart';
import 'package:tmail_ui_user/main/exceptions/remote/network_exception.dart';
import 'package:tmail_ui_user/main/exceptions/remote/server_exception.dart';
import 'package:tmail_ui_user/main/exceptions/remote/unknown_remote_exception.dart';
import 'package:tmail_ui_user/main/exceptions/thrower/exception_thrower.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
class RemoteExceptionThrower extends ExceptionThrower {
@@ -53,7 +57,7 @@ class RemoteExceptionThrower extends ExceptionThrower {
case HttpStatus.unauthorized:
throw const BadCredentialsException();
default:
throw UnknownError(
throw UnknownRemoteException(
code: statusCode,
message: response.statusMessage,
);
@@ -93,9 +97,9 @@ class RemoteExceptionThrower extends ExceptionThrower {
} else if (underlyingError is OAuthAuthorizationError) {
throw underlyingError;
} else if (underlyingError != null) {
throw UnknownError(message: underlyingError);
throw UnknownRemoteException(message: underlyingError.toString());
} else {
throw const UnknownError();
throw const UnknownRemoteException();
}
}
}
@@ -3,8 +3,8 @@ import 'dart:async';
import 'package:core/utils/app_logger.dart';
import 'package:tmail_ui_user/features/network_connection/presentation/network_connection_controller.dart'
if (dart.library.html) 'package:tmail_ui_user/features/network_connection/presentation/web_network_connection_controller.dart';
import 'package:tmail_ui_user/main/exceptions/remote_exception.dart';
import 'package:tmail_ui_user/main/exceptions/remote_exception_thrower.dart';
import 'package:tmail_ui_user/main/exceptions/remote/network_exception.dart';
import 'package:tmail_ui_user/main/exceptions/thrower/remote_exception_thrower.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
class SendEmailExceptionThrower extends RemoteExceptionThrower {
+5 -2
View File
@@ -51,7 +51,10 @@ import 'package:tmail_ui_user/features/thread/domain/state/empty_spam_folder_sta
import 'package:tmail_ui_user/features/thread/domain/state/empty_trash_folder_state.dart';
import 'package:tmail_ui_user/features/thread/domain/state/move_multiple_email_to_mailbox_state.dart';
import 'package:tmail_ui_user/main/exceptions/permission_exception.dart';
import 'package:tmail_ui_user/main/exceptions/remote_exception.dart';
import 'package:tmail_ui_user/main/exceptions/remote/authentication_exception.dart';
import 'package:tmail_ui_user/main/exceptions/remote/method_level_exception.dart';
import 'package:tmail_ui_user/main/exceptions/remote/network_exception.dart';
import 'package:tmail_ui_user/main/exceptions/remote/unknown_remote_exception.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
@@ -95,7 +98,7 @@ class ToastManager {
return appLocalizations.badCredentials;
} else if (exception is ConnectionError) {
return appLocalizations.connectionError;
} else if (exception is UnknownError && exception.message != null) {
} else if (exception is UnknownRemoteException && exception.message != null) {
return '[${exception.code ?? ''}] ${exception.message}';
} else if (exception is NotFoundSessionException) {
return appLocalizations.notFoundSession;