Skip to content
Open
Show file tree
Hide file tree
Changes from 7 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
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@
- \#1792 Add option 'Empty Trash' in folder menu

### Changed
- \#1755 Use TupleKey('ObjectId\|AccountId\|UserName') store data to cache
- \#1755 Use TupleKey('AccountId\|UserName\|ObjectId') store data to cache

### Fixed
- \#1385 Fix \[Email rule\] Icon edit and delete might be seen as disable
Expand Down
47 changes: 47 additions & 0 deletions assets/images/ic_logo_twake_horizontal.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions core/lib/presentation/resources/image_paths.dart
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ class ImagePaths {
String get icLogoTwakeWelcome => _getImagePath('ic_logo_twake_welcome.svg');
String get icCheckboxOn => _getImagePath('ic_checkbox_on.svg');
String get icCheckboxOff => _getImagePath('ic_checkbox_off.svg');
String get icLogoTwakeHorizontal => _getImagePath('ic_logo_twake_horizontal.svg');

String _getImagePath(String imageName) {
return AssetsPaths.images + imageName;
Expand Down
5 changes: 5 additions & 0 deletions core/lib/presentation/utils/theme_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class ThemeUtils {
),
bodyMedium: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 15
),
bodySmall: TextStyle(
fontWeight: FontWeight.w500
Expand All @@ -44,6 +45,10 @@ class ThemeUtils {
),
labelSmall: TextStyle(
fontWeight: FontWeight.normal
),
labelLarge: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 16
)
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 27. Use TupleKey store data cache
# 27. Use TupleKey store data to hive database

Date: 2023-04-27

Expand All @@ -9,13 +9,14 @@ Accepted
## Context

- Multiple accounts login at the same time in the same browser. The accounts will use the same database (`IndexDatabase`).
- To support multiple accounts

## Decision

- Use unique parameters (`AccountId`, `UserName`, `ObjectId(MailboxId/EmailId/StateType`) to form a unique `key` for storage (called `TupleKey`).
- TupleKey has the format: `ObjectId | AccountId | User`;
- Use unique parameters (`AccountId`, `UserName`, `ObjectId(MailboxId/EmailId/StateType/...)`) to form a unique `key` for storage (called `TupleKey`).
- TupleKey has the format: `AccountId | UserName | [ObjectId]`;
- `HiveDatabase` includes many `Box`. Each box is a `Map<Key, Object>` with `key=TupleKey`.

## Consequences

- The correct `mailbox` and `email` lists are obtained for each account
- Each account will manage its own data storage boxes
37 changes: 37 additions & 0 deletions lib/features/base/base_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_mixin.da
import 'package:tmail_ui_user/features/base/mixin/popup_context_menu_action_mixin.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/extensions/token_oidc_extension.dart';
import 'package:tmail_ui_user/features/login/data/network/config/authorization_interceptors.dart';
import 'package:tmail_ui_user/features/login/domain/state/logout_current_account_basic_auth_state.dart';
import 'package:tmail_ui_user/features/login/domain/state/logout_current_account_oidc_state.dart';
import 'package:tmail_ui_user/features/login/domain/state/logout_current_account_state.dart';
import 'package:tmail_ui_user/features/login/domain/usecases/logout_current_account_interactor.dart';
import 'package:tmail_ui_user/features/login/domain/usecases/set_current_account_active_interactor.dart';
import 'package:tmail_ui_user/features/login/presentation/login_form_type.dart';
import 'package:tmail_ui_user/features/login/presentation/model/login_arguments.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/bindings/contact_autocomplete_bindings.dart';
Expand Down Expand Up @@ -75,6 +77,7 @@ abstract class BaseController extends GetxController
final ResponsiveUtils responsiveUtils = Get.find<ResponsiveUtils>();
final Uuid uuid = Get.find<Uuid>();
final AppStore appStore = Get.find<AppStore>();
final SetCurrentAccountActiveInteractor _setCurrentAccountActiveInteractor = Get.find<SetCurrentAccountActiveInteractor>();

final _fcmReceiver = FcmReceiver.instance;
bool _isFcmEnabled = false;
Expand Down Expand Up @@ -385,4 +388,38 @@ abstract class BaseController extends GetxController
await clearDataAndGoToLoginPage();
}
}

void setUpInterceptors(PersonalAccount personalAccount) {
dynamicUrlInterceptors.setJmapUrl(personalAccount.baseUrl);
dynamicUrlInterceptors.changeBaseUrl(personalAccount.baseUrl);

switch(personalAccount.authType) {
case AuthenticationType.oidc:
authorizationInterceptors.setTokenAndAuthorityOidc(
newToken: personalAccount.tokenOidc,
newConfig: personalAccount.tokenOidc!.oidcConfiguration
);
authorizationIsolateInterceptors.setTokenAndAuthorityOidc(
newToken: personalAccount.tokenOidc,
newConfig: personalAccount.tokenOidc!.oidcConfiguration
);
break;
case AuthenticationType.basic:
authorizationInterceptors.setBasicAuthorization(
personalAccount.basicAuth!.userName,
personalAccount.basicAuth!.password,
);
authorizationIsolateInterceptors.setBasicAuthorization(
personalAccount.basicAuth!.userName,
personalAccount.basicAuth!.password,
);
break;
default:
break;
}
}

void setCurrentAccountActive(PersonalAccount activeAccount) {
consumeState(_setCurrentAccountActiveInteractor.execute(activeAccount));
}
}
62 changes: 19 additions & 43 deletions lib/features/base/reloadable/reloadable_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,24 @@ import 'package:get/get.dart';
import 'package:jmap_dart_client/jmap/account_id.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/authentication_type.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';
import 'package:tmail_ui_user/features/home/domain/state/get_session_state.dart';
import 'package:tmail_ui_user/features/home/domain/usecases/get_session_interactor.dart';
import 'package:tmail_ui_user/features/login/data/extensions/token_oidc_extension.dart';
import 'package:tmail_ui_user/features/login/domain/state/get_authenticated_account_state.dart';
import 'package:tmail_ui_user/features/login/domain/usecases/add_account_id_to_active_account_interactor.dart';
import 'package:tmail_ui_user/features/login/domain/usecases/get_authenticated_account_interactor.dart';
import 'package:tmail_ui_user/features/login/domain/usecases/update_authentication_account_interactor.dart';
import 'package:tmail_ui_user/features/login/presentation/login_form_type.dart';
import 'package:tmail_ui_user/features/login/presentation/model/login_arguments.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
import 'package:tmail_ui_user/main/utils/message_toast_utils.dart';

abstract class ReloadableController extends BaseController {
final GetSessionInteractor _getSessionInteractor = Get.find<GetSessionInteractor>();
final GetSessionInteractor getSessionInteractor = Get.find<GetSessionInteractor>();
final GetAuthenticatedAccountInteractor _getAuthenticatedAccountInteractor = Get.find<GetAuthenticatedAccountInteractor>();
final UpdateAuthenticationAccountInteractor _updateAuthenticationAccountInteractor = Get.find<UpdateAuthenticationAccountInteractor>();
final AddAccountIdToActiveAccountInteractor _addAccountIdToActiveAccountInteractor = Get.find<AddAccountIdToActiveAccountInteractor>();

@override
void handleFailureViewState(Failure failure) {
Expand Down Expand Up @@ -68,38 +65,8 @@ abstract class ReloadableController extends BaseController {
consumeState(_getAuthenticatedAccountInteractor.execute());
}

void setUpInterceptors(PersonalAccount personalAccount) {
dynamicUrlInterceptors.setJmapUrl(personalAccount.baseUrl);
dynamicUrlInterceptors.changeBaseUrl(personalAccount.baseUrl);

switch(personalAccount.authType) {
case AuthenticationType.oidc:
authorizationInterceptors.setTokenAndAuthorityOidc(
newToken: personalAccount.tokenOidc,
newConfig: personalAccount.tokenOidc!.oidcConfiguration
);
authorizationIsolateInterceptors.setTokenAndAuthorityOidc(
newToken: personalAccount.tokenOidc,
newConfig: personalAccount.tokenOidc!.oidcConfiguration
);
break;
case AuthenticationType.basic:
authorizationInterceptors.setBasicAuthorization(
personalAccount.basicAuth!.userName,
personalAccount.basicAuth!.password,
);
authorizationIsolateInterceptors.setBasicAuthorization(
personalAccount.basicAuth!.userName,
personalAccount.basicAuth!.password,
);
break;
default:
break;
}
}

void getSessionAction({AccountId? accountId, UserName? userName}) {
consumeState(_getSessionInteractor.execute(
consumeState(getSessionInteractor.execute(
accountId: accountId,
userName: userName
));
Expand All @@ -121,7 +88,11 @@ abstract class ReloadableController extends BaseController {
final apiUrl = session.getQualifiedApiUrl(baseUrl: dynamicUrlInterceptors.jmapUrl);
if (apiUrl.isNotEmpty) {
dynamicUrlInterceptors.changeBaseUrl(apiUrl);
updateAuthenticationAccount(session, personalAccount.accountId, session.username);
_addAccountIdToActiveAccount(
personalAccount.accountId,
session.username,
apiUrl
);
handleReloaded(session);
} else {
clearDataAndGoToLoginPage();
Expand All @@ -130,10 +101,15 @@ abstract class ReloadableController extends BaseController {

void handleReloaded(Session session) {}

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 _addAccountIdToActiveAccount(
AccountId accountId,
UserName userName,
String apiUrl,
) {
consumeState(_addAccountIdToActiveAccountInteractor.execute(
accountId,
apiUrl,
userName
));
}
}
6 changes: 3 additions & 3 deletions lib/features/caching/caching_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import 'package:core/utils/app_logger.dart';
import 'package:core/utils/file_utils.dart';
import 'package:core/utils/platform_info.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:jmap_dart_client/jmap/core/user_name.dart';
import 'package:tmail_ui_user/features/caching/clients/account_cache_client.dart';
import 'package:tmail_ui_user/features/caching/clients/email_cache_client.dart';
import 'package:tmail_ui_user/features/caching/clients/fcm_cache_client.dart';
Expand Down Expand Up @@ -97,9 +97,9 @@ class CachingManager {
], eagerError: true);
}

Future<void> clearEmailCacheAndStateCacheByTupleKey(AccountId accountId, Session session) {
Future<void> clearEmailCacheAndStateCacheByTupleKey(AccountId accountId, UserName userName) {
return Future.wait([
_stateCacheClient.deleteItem(StateType.email.getTupleKeyStored(accountId, session.username)),
_stateCacheClient.deleteItem(StateType.email.getTupleKeyStored(accountId, userName)),
_emailCacheClient.clearAllData(),
], eagerError: true);
}
Expand Down
4 changes: 2 additions & 2 deletions lib/features/caching/utils/cache_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ class TupleKey {

TupleKey(
String key1,
String key2,
[
String? key2,
String? key3,
String? key4,
]
) : parts = [
key1,
if (key2 != null) key2,
key2,
if (key3 != null) key3,
if (key4 != null) key4,
];
Expand Down
Loading