Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TF-2901 Composer cache web #2941

Merged
merged 3 commits into from
Jul 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions core/lib/domain/exceptions/web_session_exception.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ class NotFoundInWebSessionException with EquatableMixin implements Exception {
List<Object> get props => [];
}

class NotMatchInWebSessionException with EquatableMixin implements Exception {
const NotMatchInWebSessionException();

@override
List<Object> get props => [];
}

class SaveToWebSessionFailException with EquatableMixin implements Exception {
final String? errorMessage;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class ImageTransformer extends DomTransformer {
imageSource: src
);
imageElement.attributes['src'] = imageBase64 ?? src;
imageElement.attributes['id'] ??= src;
} else if (src.startsWith('https://') || src.startsWith('http://')) {
if (!imageElement.attributes.containsKey('loading')) {
imageElement.attributes['loading'] = 'lazy';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ class TransformConfiguration {

factory TransformConfiguration.forPreviewEmail() => TransformConfiguration.standardConfiguration;

factory TransformConfiguration.forRestoreEmail() => TransformConfiguration.fromDomTransformers([const ImageTransformer()]);

factory TransformConfiguration.forPrintEmail() => TransformConfiguration.fromDomTransformers([
if (PlatformInfo.isWeb)
const RemoveTooltipLinkTransformer(),
Expand Down
13 changes: 13 additions & 0 deletions lib/features/base/base_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:model/account/authentication_type.dart';
import 'package:rule_filter/rule_filter/capability_rule_filter.dart';
import 'package:tmail_ui_user/features/base/before_unload_manager.dart';
import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_mixin.dart';
import 'package:tmail_ui_user/features/base/mixin/popup_context_menu_action_mixin.dart';
import 'package:tmail_ui_user/features/caching/caching_manager.dart';
Expand Down Expand Up @@ -169,7 +170,14 @@ abstract class BaseController extends GetxController
if (!authorizationInterceptors.isAppRunning) {
return;
}
_executeBeforeUnloadAndLogOut(exception);
dab246 marked this conversation as resolved.
Show resolved Hide resolved
}

Future<void> _executeBeforeUnloadAndLogOut(Exception? exception) async {
if (exception is BadCredentialsException || exception is ConnectionError) {
if (PlatformInfo.isWeb) {
await executeBeforeUnload();
}
clearDataAndGoToLoginPage();
}
}
Expand Down Expand Up @@ -334,6 +342,11 @@ abstract class BaseController extends GetxController
}
}

Future<void> executeBeforeUnload() async {
final beforeUnloadManager = getBinding<BeforeUnloadManager>();
await beforeUnloadManager?.executeBeforeUnloadListeners();
}

Future<void> clearDataAndGoToLoginPage() async {
log('BaseController::clearDataAndGoToLoginPage:');
await clearAllData();
Expand Down
3 changes: 3 additions & 0 deletions lib/features/base/before_unload_handler.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
abstract class BeforeUnloadHandler {
Future<void> onBeforeUnload();
}
24 changes: 24 additions & 0 deletions lib/features/base/before_unload_manager.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import 'package:core/utils/app_logger.dart';

typedef BeforeUnloadListener = Future<void> Function();

class BeforeUnloadManager {
static final BeforeUnloadManager _instance = BeforeUnloadManager._();
factory BeforeUnloadManager() => _instance;
BeforeUnloadManager._();

final _listeners = <BeforeUnloadListener>[];

void addListener(BeforeUnloadListener listener) {
_listeners.add(listener);
}

void removeListener(BeforeUnloadListener listener) {
_listeners.remove(listener);
}

Future<void> executeBeforeUnloadListeners() async {
hoangdat marked this conversation as resolved.
Show resolved Hide resolved
await Future.wait(_listeners.map((listener) => listener.call()))
.onError((error, stackTrace) => [logError(error.toString())]);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';

class RestoringEmailInlineImages extends LoadingState {}

class RestoreEmailInlineImagesSuccess extends UIState {
final String emailContent;

RestoreEmailInlineImagesSuccess(this.emailContent);

@override
List<Object?> get props => [emailContent];
}

class RestoreEmailInlineImagesFailure extends FeatureFailure {

RestoreEmailInlineImagesFailure({super.exception});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:core/presentation/utils/html_transformer/transform_configuration.dart';
import 'package:dartz/dartz.dart';
import 'package:tmail_ui_user/features/composer/domain/state/restore_email_inline_images_state.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/composer_cache_repository.dart';

class RestoreEmailInlineImagesInteractor {
RestoreEmailInlineImagesInteractor(this._composerCacheRepository);

final ComposerCacheRepository _composerCacheRepository;

Stream<Either<Failure, Success>> execute({
required String htmlContent,
required TransformConfiguration transformConfiguration,
required Map<String, String> mapUrlDownloadCID
}) async* {
try {
yield Right(RestoringEmailInlineImages());

final emailContent = await _composerCacheRepository.restoreEmailInlineImages(
htmlContent,
transformConfiguration,
mapUrlDownloadCID);
yield Right(RestoreEmailInlineImagesSuccess(emailContent));
} catch (exception) {
yield Left(RestoreEmailInlineImagesFailure(exception: exception));
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/user_name.dart';
import 'package:tmail_ui_user/features/composer/domain/repository/composer_repository.dart';
import 'package:tmail_ui_user/features/composer/presentation/model/create_email_request.dart';
import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/composer_cache_repository.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/save_composer_cache_state.dart';

Expand All @@ -15,10 +18,22 @@ class SaveComposerCacheOnWebInteractor {
this._composerRepository,
);

Future<Either<Failure, Success>> execute(CreateEmailRequest createEmailRequest) async {
Future<Either<Failure, Success>> execute(
CreateEmailRequest createEmailRequest,
AccountId accountId,
UserName userName,
{required ScreenDisplayMode displayMode}
) async {
try {
final emailCreated = await _composerRepository.generateEmail(createEmailRequest);
_composerCacheRepository.saveComposerCacheOnWeb(emailCreated);
final identity = createEmailRequest.identity;
await _composerCacheRepository.saveComposerCacheOnWeb(
emailCreated,
accountId: accountId,
userName: userName,
displayMode: displayMode,
identity: identity,
readReceipentEnabled: createEmailRequest.isRequestReadReceipt);
return Right(SaveComposerCacheSuccess());
} catch (exception) {
return Left(SaveComposerCacheFailure(exception));
Expand Down
3 changes: 3 additions & 0 deletions lib/features/composer/presentation/composer_bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import 'package:tmail_ui_user/features/composer/domain/repository/contact_reposi
import 'package:tmail_ui_user/features/composer/domain/usecases/create_new_and_save_email_to_drafts_interactor.dart';
import 'package:tmail_ui_user/features/composer/domain/usecases/create_new_and_send_email_interactor.dart';
import 'package:tmail_ui_user/features/composer/domain/usecases/download_image_as_base64_interactor.dart';
import 'package:tmail_ui_user/features/composer/domain/usecases/restore_email_inline_images_interactor.dart';
import 'package:tmail_ui_user/features/composer/domain/usecases/save_composer_cache_on_web_interactor.dart';
import 'package:tmail_ui_user/features/composer/domain/usecases/upload_attachment_interactor.dart';
import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart';
Expand Down Expand Up @@ -208,6 +209,8 @@ class ComposerBindings extends BaseBindings {
Get.find<MailboxRepository>(),
Get.find<ComposerRepository>(),
));
Get.lazyPut(() => RestoreEmailInlineImagesInteractor(
Get.find<ComposerCacheRepository>()));

IdentityInteractorsBindings().dependencies();
}
Expand Down
Loading
Loading