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

[POC] TF-2955 Reduce time in opening tmail app #2959

Open
wants to merge 6 commits into
base: refactor
Choose a base branch
from
Open
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
26 changes: 6 additions & 20 deletions lib/features/base/base_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +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/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/base/consume_view_state_ui_controller.dart';
import 'package:tmail_ui_user/features/caching/caching_manager.dart';
import 'package:tmail_ui_user/features/email/presentation/bindings/mdn_interactor_bindings.dart';
import 'package:tmail_ui_user/features/login/data/network/interceptors/authorization_interceptors.dart';
Expand Down Expand Up @@ -61,9 +60,7 @@ import 'package:tmail_ui_user/main/utils/app_config.dart';
import 'package:tmail_ui_user/main/utils/app_utils.dart';
import 'package:uuid/uuid.dart';

abstract class BaseController extends GetxController
with MessageDialogActionMixin,
PopupContextMenuActionMixin {
abstract class BaseController extends ConsumeViewStateUIController {

final CachingManager cachingManager = Get.find<CachingManager>();
final LanguageCacheManager languageCacheManager = Get.find<LanguageCacheManager>();
Expand All @@ -84,21 +81,9 @@ abstract class BaseController extends GetxController
GetStoredFirebaseRegistrationInteractor? _getStoredFirebaseRegistrationInteractor;
DestroyFirebaseRegistrationInteractor? _destroyFirebaseRegistrationInteractor;

final viewState = Rx<Either<Failure, Success>>(Right(UIState.idle));
FpsCallback? fpsCallback;

void consumeState(Stream<Either<Failure, Success>> newStateStream) async {
newStateStream.listen(onData, onError: onError, onDone: onDone);
}

void dispatchState(Either<Failure, Success> newState) {
viewState.value = newState;
}

void clearState() {
viewState.value = Right(UIState.idle);
}

@override
void onData(Either<Failure, Success> newState) {
viewState.value = newState;
viewState.value.fold(
Expand All @@ -118,6 +103,7 @@ abstract class BaseController extends GetxController
handleSuccessViewState);
}

@override
void onError(Object error, StackTrace stackTrace) {
logError('BaseController::onError():error: $error | stackTrace: $stackTrace');
final exception = _performFilterExceptionInError(error);
Expand All @@ -128,8 +114,6 @@ abstract class BaseController extends GetxController
}
}

void onDone() {}

Exception? _performFilterExceptionInError(dynamic error) {
logError('BaseController::_performFilterExceptionInError(): $error');
if (error is NoNetworkError || error is ConnectionTimeout || error is InternalServerError) {
Expand Down Expand Up @@ -174,6 +158,7 @@ abstract class BaseController extends GetxController
}
}

@override
void handleFailureViewState(Failure failure) async {
logError('BaseController::handleFailureViewState(): ${failure.runtimeType}');
if (failure is LogoutOidcFailure) {
Expand All @@ -188,6 +173,7 @@ abstract class BaseController extends GetxController
}
}

@override
void handleSuccessViewState(Success success) async {
log('BaseController::handleSuccessViewState(): ${success.runtimeType}');
if (success is LogoutOidcSuccess) {
Expand Down
37 changes: 37 additions & 0 deletions lib/features/base/consume_view_state_ui_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:get/get.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';

abstract class ConsumeViewStateUIController extends GetxController
with MessageDialogActionMixin, PopupContextMenuActionMixin {

final viewState = Rx<Either<Failure, Success>>(Right(UIState.idle));

void consumeState(Stream<Either<Failure, Success>> newStateStream) {
newStateStream.listen(onData, onError: onError, onDone: onDone);
}

void dispatchState(Either<Failure, Success> newState) {
viewState.value = newState;
}

void clearState() {
viewState.value = Right(UIState.idle);
}

void onData(Either<Failure, Success> newState) {
viewState.value = newState;
viewState.value.fold(handleFailureViewState, handleSuccessViewState);
}

void onError(Object error, StackTrace stackTrace) {}

void onDone() {}

void handleFailureViewState(Failure failure);

void handleSuccessViewState(Success success);
}
29 changes: 19 additions & 10 deletions lib/features/base/reloadable/reloadable_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:jmap_dart_client/jmap/core/user_name.dart';
import 'package:model/account/personal_account.dart';
import 'package:model/extensions/session_extension.dart';
import 'package:tmail_ui_user/features/base/base_controller.dart';
import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions.dart';
Expand Down Expand Up @@ -81,10 +82,10 @@ abstract class ReloadableController extends BaseController {

void _handleGetCredentialSuccess(GetCredentialViewState credentialViewState) {
_setUpInterceptors(credentialViewState);
getSessionAction();
getSessionAction(personalAccount: credentialViewState.personalAccount);
}

void getSessionAction() {
void getSessionAction({PersonalAccount? personalAccount}) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused PersonalAccount param, consider remove

consumeState(_getSessionInteractor.execute());
}

Expand All @@ -100,11 +101,15 @@ abstract class ReloadableController extends BaseController {

void _handleGetSessionSuccess(GetSessionSuccess success) {
final session = success.session;
final personalAccount = session.personalAccount;
final jmapPersonalAccount = session.jmapPersonalAccount;
final apiUrl = session.getQualifiedApiUrl(baseUrl: dynamicUrlInterceptors.jmapUrl);
if (apiUrl.isNotEmpty) {
dynamicUrlInterceptors.changeBaseUrl(apiUrl);
updateAuthenticationAccount(session, personalAccount.accountId, session.username);
updateAuthenticationAccount(
apiUrl: apiUrl,
accountId: jmapPersonalAccount.accountId,
userName: session.username
);
handleReloaded(session);
} else {
clearDataAndGoToLoginPage();
Expand All @@ -115,7 +120,7 @@ abstract class ReloadableController extends BaseController {

void _handleGetStoredTokenOIDCSuccess(GetStoredTokenOidcSuccess tokenOidcSuccess) {
_setUpInterceptorsOidc(tokenOidcSuccess);
getSessionAction();
getSessionAction(personalAccount: tokenOidcSuccess.personalAccount);
}

void _setUpInterceptorsOidc(GetStoredTokenOidcSuccess tokenOidcSuccess) {
Expand All @@ -138,10 +143,14 @@ abstract class ReloadableController extends BaseController {
}
}

void updateAuthenticationAccount(Session session, AccountId accountId, UserName userName) {
final apiUrl = session.getQualifiedApiUrl(baseUrl: dynamicUrlInterceptors.jmapUrl);
if (apiUrl.isNotEmpty) {
consumeState(_updateAuthenticationAccountInteractor.execute(accountId, apiUrl, userName));
}
void updateAuthenticationAccount({
required String apiUrl,
required AccountId accountId,
required UserName userName
}) {
consumeState(_updateAuthenticationAccountInteractor.execute(
accountId,
apiUrl,
userName));
}
}
11 changes: 6 additions & 5 deletions lib/features/composer/presentation/composer_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -733,7 +733,8 @@ class ComposerController extends BaseController with DragDropFileMixin {
}

if (!isEnableEmailSendButton.value) {
showConfirmDialogAction(context,
showConfirmDialogAction(
context,
AppLocalizations.of(context).message_dialog_send_email_without_recipient,
AppLocalizations.of(context).add_recipients,
title: AppLocalizations.of(context).sending_failed,
Expand All @@ -749,7 +750,8 @@ class ComposerController extends BaseController with DragDropFileMixin {
.where((emailAddress) => !EmailUtils.isEmailAddressValid(emailAddress.emailAddress))
.toList();
if (listEmailAddressInvalid.isNotEmpty) {
showConfirmDialogAction(context,
showConfirmDialogAction(
context,
AppLocalizations.of(context).message_dialog_send_email_with_email_address_invalid,
AppLocalizations.of(context).fix_email_addresses,
onConfirmAction: () {
Expand All @@ -766,7 +768,8 @@ class ComposerController extends BaseController with DragDropFileMixin {
}

if (subjectEmail.value == null || subjectEmail.isEmpty == true) {
showConfirmDialogAction(context,
showConfirmDialogAction(
context,
AppLocalizations.of(context).message_dialog_send_email_without_a_subject,
AppLocalizations.of(context).send_anyway,
onConfirmAction: () => _handleSendMessages(context),
Expand Down Expand Up @@ -912,7 +915,6 @@ class ComposerController extends BaseController with DragDropFileMixin {
}) async {
await showConfirmDialogAction(
context,
title: '',
AppLocalizations.of(context).warningMessageWhenSendEmailFailure,
AppLocalizations.of(context).edit,
cancelTitle: AppLocalizations.of(context).closeAnyway,
Expand Down Expand Up @@ -2126,7 +2128,6 @@ class ComposerController extends BaseController with DragDropFileMixin {
}) async {
await showConfirmDialogAction(
context,
title: '',
AppLocalizations.of(context).warningMessageWhenSaveEmailToDraftsFailure,
AppLocalizations.of(context).edit,
cancelTitle: AppLocalizations.of(context).closeAnyway,
Expand Down
4 changes: 2 additions & 2 deletions lib/features/home/domain/extensions/session_extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ extension SessionExtensions on Session {
try {
if (GetUtils.isEmail(username.value)) {
return username.value.split('@').last;
} else if (GetUtils.isEmail(personalAccount.name.value)) {
return personalAccount.name.value.split('@').last;
} else if (GetUtils.isEmail(jmapPersonalAccount.name.value)) {
return jmapPersonalAccount.name.value.split('@').last;
} else {
return '';
}
Expand Down
31 changes: 31 additions & 0 deletions lib/features/home/domain/state/get_session_cache_state.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:model/account/personal_account.dart';

class GetSessionCacheLoading extends LoadingState {}

class GetSessionCacheSuccess extends UIState {
final Session session;
final PersonalAccount personalAccount;

GetSessionCacheSuccess({
required this.session,
required this.personalAccount
});

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

class GetSessionCacheFailure extends FeatureFailure {
final PersonalAccount personalAccount;

GetSessionCacheFailure({
required this.personalAccount,
dynamic exception
}) : super(exception: exception);

@override
List<Object?> get props => [personalAccount, ...super.props];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:model/account/personal_account.dart';
import 'package:tmail_ui_user/features/home/domain/repository/session_repository.dart';
import 'package:tmail_ui_user/features/home/domain/state/get_session_cache_state.dart';

class GetSessionCacheInteractor {
final SessionRepository _sessionRepository;

GetSessionCacheInteractor(this._sessionRepository);

Stream<Either<Failure, Success>> execute(PersonalAccount personalAccount) async* {
try {
yield Right<Failure, Success>(GetSessionCacheLoading());
final sessionCache = await _sessionRepository.getStoredSession();
yield Right<Failure, Success>(GetSessionCacheSuccess(
session: sessionCache,
personalAccount: personalAccount));
} catch (e) {
yield Left<Failure, Success>(GetSessionCacheFailure(
personalAccount: personalAccount,
exception: e));
}
}
}
4 changes: 4 additions & 0 deletions lib/features/home/presentation/home_bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_email_cac
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_recent_login_url_cache_interactor.dart';
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_recent_login_username_interactor.dart';
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_recent_search_cache_interactor.dart';
import 'package:tmail_ui_user/features/home/domain/repository/session_repository.dart';
import 'package:tmail_ui_user/features/home/domain/usecases/get_session_cache_interactor.dart';
import 'package:tmail_ui_user/features/home/presentation/home_controller.dart';
import 'package:tmail_ui_user/features/login/domain/repository/authentication_oidc_repository.dart';
import 'package:tmail_ui_user/features/login/domain/usecases/check_oidc_is_available_interactor.dart';
Expand All @@ -28,6 +30,7 @@ class HomeBindings extends BaseBindings {
Get.find<CleanupRecentSearchCacheInteractor>(),
Get.find<CleanupRecentLoginUrlCacheInteractor>(),
Get.find<CleanupRecentLoginUsernameCacheInteractor>(),
Get.find<GetSessionCacheInteractor>(),
));
}

Expand All @@ -54,6 +57,7 @@ class HomeBindings extends BaseBindings {
Get.lazyPut(() => CleanupRecentLoginUrlCacheInteractor(Get.find<CleanupRepository>()));
Get.lazyPut(() => CleanupRecentLoginUsernameCacheInteractor(Get.find<CleanupRepository>()));
Get.lazyPut(() => CheckOIDCIsAvailableInteractor(Get.find<AuthenticationOIDCRepository>()));
Get.lazyPut(() => GetSessionCacheInteractor(Get.find<SessionRepository>()));
}

@override
Expand Down
Loading
Loading