Skip to content

Commit 658e836

Browse files
committed
TF-2431 Handle switch active account
Signed-off-by: dab246 <[email protected]>
1 parent 149508a commit 658e836

28 files changed

+418
-99
lines changed

lib/features/base/base_controller.dart

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@ import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_mixin.da
2525
import 'package:tmail_ui_user/features/base/mixin/popup_context_menu_action_mixin.dart';
2626
import 'package:tmail_ui_user/features/caching/caching_manager.dart';
2727
import 'package:tmail_ui_user/features/email/presentation/bindings/mdn_interactor_bindings.dart';
28+
import 'package:tmail_ui_user/features/login/data/extensions/token_oidc_extension.dart';
2829
import 'package:tmail_ui_user/features/login/data/network/config/authorization_interceptors.dart';
2930
import 'package:tmail_ui_user/features/login/domain/state/logout_current_account_basic_auth_state.dart';
3031
import 'package:tmail_ui_user/features/login/domain/state/logout_current_account_oidc_state.dart';
3132
import 'package:tmail_ui_user/features/login/domain/state/logout_current_account_state.dart';
3233
import 'package:tmail_ui_user/features/login/domain/usecases/logout_current_account_interactor.dart';
34+
import 'package:tmail_ui_user/features/login/domain/usecases/set_current_account_active_interactor.dart';
3335
import 'package:tmail_ui_user/features/login/presentation/login_form_type.dart';
3436
import 'package:tmail_ui_user/features/login/presentation/model/login_arguments.dart';
3537
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/bindings/contact_autocomplete_bindings.dart';
@@ -75,6 +77,7 @@ abstract class BaseController extends GetxController
7577
final ResponsiveUtils responsiveUtils = Get.find<ResponsiveUtils>();
7678
final Uuid uuid = Get.find<Uuid>();
7779
final AppStore appStore = Get.find<AppStore>();
80+
final SetCurrentAccountActiveInteractor _setCurrentAccountActiveInteractor = Get.find<SetCurrentAccountActiveInteractor>();
7881

7982
final _fcmReceiver = FcmReceiver.instance;
8083
bool _isFcmEnabled = false;
@@ -385,4 +388,38 @@ abstract class BaseController extends GetxController
385388
await clearDataAndGoToLoginPage();
386389
}
387390
}
391+
392+
void setUpInterceptors(PersonalAccount personalAccount) {
393+
dynamicUrlInterceptors.setJmapUrl(personalAccount.baseUrl);
394+
dynamicUrlInterceptors.changeBaseUrl(personalAccount.baseUrl);
395+
396+
switch(personalAccount.authType) {
397+
case AuthenticationType.oidc:
398+
authorizationInterceptors.setTokenAndAuthorityOidc(
399+
newToken: personalAccount.tokenOidc,
400+
newConfig: personalAccount.tokenOidc!.oidcConfiguration
401+
);
402+
authorizationIsolateInterceptors.setTokenAndAuthorityOidc(
403+
newToken: personalAccount.tokenOidc,
404+
newConfig: personalAccount.tokenOidc!.oidcConfiguration
405+
);
406+
break;
407+
case AuthenticationType.basic:
408+
authorizationInterceptors.setBasicAuthorization(
409+
personalAccount.basicAuth!.userName,
410+
personalAccount.basicAuth!.password,
411+
);
412+
authorizationIsolateInterceptors.setBasicAuthorization(
413+
personalAccount.basicAuth!.userName,
414+
personalAccount.basicAuth!.password,
415+
);
416+
break;
417+
default:
418+
break;
419+
}
420+
}
421+
422+
void setCurrentAccountActive(PersonalAccount activeAccount) {
423+
consumeState(_setCurrentAccountActiveInteractor.execute(activeAccount));
424+
}
388425
}

lib/features/base/reloadable/reloadable_controller.dart

Lines changed: 19 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,24 @@ import 'package:get/get.dart';
55
import 'package:jmap_dart_client/jmap/account_id.dart';
66
import 'package:jmap_dart_client/jmap/core/session/session.dart';
77
import 'package:jmap_dart_client/jmap/core/user_name.dart';
8-
import 'package:model/account/authentication_type.dart';
9-
import 'package:model/account/personal_account.dart';
108
import 'package:model/extensions/session_extension.dart';
119
import 'package:tmail_ui_user/features/base/base_controller.dart';
1210
import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions.dart';
1311
import 'package:tmail_ui_user/features/home/domain/state/get_session_state.dart';
1412
import 'package:tmail_ui_user/features/home/domain/usecases/get_session_interactor.dart';
15-
import 'package:tmail_ui_user/features/login/data/extensions/token_oidc_extension.dart';
1613
import 'package:tmail_ui_user/features/login/domain/state/get_authenticated_account_state.dart';
14+
import 'package:tmail_ui_user/features/login/domain/usecases/add_account_id_to_active_account_interactor.dart';
1715
import 'package:tmail_ui_user/features/login/domain/usecases/get_authenticated_account_interactor.dart';
18-
import 'package:tmail_ui_user/features/login/domain/usecases/update_authentication_account_interactor.dart';
1916
import 'package:tmail_ui_user/features/login/presentation/login_form_type.dart';
2017
import 'package:tmail_ui_user/features/login/presentation/model/login_arguments.dart';
2118
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
2219
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
2320
import 'package:tmail_ui_user/main/utils/message_toast_utils.dart';
2421

2522
abstract class ReloadableController extends BaseController {
26-
final GetSessionInteractor _getSessionInteractor = Get.find<GetSessionInteractor>();
23+
final GetSessionInteractor getSessionInteractor = Get.find<GetSessionInteractor>();
2724
final GetAuthenticatedAccountInteractor _getAuthenticatedAccountInteractor = Get.find<GetAuthenticatedAccountInteractor>();
28-
final UpdateAuthenticationAccountInteractor _updateAuthenticationAccountInteractor = Get.find<UpdateAuthenticationAccountInteractor>();
25+
final AddAccountIdToActiveAccountInteractor _addAccountIdToActiveAccountInteractor = Get.find<AddAccountIdToActiveAccountInteractor>();
2926

3027
@override
3128
void handleFailureViewState(Failure failure) {
@@ -68,38 +65,8 @@ abstract class ReloadableController extends BaseController {
6865
consumeState(_getAuthenticatedAccountInteractor.execute());
6966
}
7067

71-
void setUpInterceptors(PersonalAccount personalAccount) {
72-
dynamicUrlInterceptors.setJmapUrl(personalAccount.baseUrl);
73-
dynamicUrlInterceptors.changeBaseUrl(personalAccount.baseUrl);
74-
75-
switch(personalAccount.authType) {
76-
case AuthenticationType.oidc:
77-
authorizationInterceptors.setTokenAndAuthorityOidc(
78-
newToken: personalAccount.tokenOidc,
79-
newConfig: personalAccount.tokenOidc!.oidcConfiguration
80-
);
81-
authorizationIsolateInterceptors.setTokenAndAuthorityOidc(
82-
newToken: personalAccount.tokenOidc,
83-
newConfig: personalAccount.tokenOidc!.oidcConfiguration
84-
);
85-
break;
86-
case AuthenticationType.basic:
87-
authorizationInterceptors.setBasicAuthorization(
88-
personalAccount.basicAuth!.userName,
89-
personalAccount.basicAuth!.password,
90-
);
91-
authorizationIsolateInterceptors.setBasicAuthorization(
92-
personalAccount.basicAuth!.userName,
93-
personalAccount.basicAuth!.password,
94-
);
95-
break;
96-
default:
97-
break;
98-
}
99-
}
100-
10168
void getSessionAction({AccountId? accountId, UserName? userName}) {
102-
consumeState(_getSessionInteractor.execute(
69+
consumeState(getSessionInteractor.execute(
10370
accountId: accountId,
10471
userName: userName
10572
));
@@ -121,7 +88,11 @@ abstract class ReloadableController extends BaseController {
12188
final apiUrl = session.getQualifiedApiUrl(baseUrl: dynamicUrlInterceptors.jmapUrl);
12289
if (apiUrl.isNotEmpty) {
12390
dynamicUrlInterceptors.changeBaseUrl(apiUrl);
124-
updateAuthenticationAccount(session, personalAccount.accountId, session.username);
91+
_addAccountIdToActiveAccount(
92+
personalAccount.accountId,
93+
session.username,
94+
apiUrl
95+
);
12596
handleReloaded(session);
12697
} else {
12798
clearDataAndGoToLoginPage();
@@ -130,10 +101,15 @@ abstract class ReloadableController extends BaseController {
130101

131102
void handleReloaded(Session session) {}
132103

133-
void updateAuthenticationAccount(Session session, AccountId accountId, UserName userName) {
134-
final apiUrl = session.getQualifiedApiUrl(baseUrl: dynamicUrlInterceptors.jmapUrl);
135-
if (apiUrl.isNotEmpty) {
136-
consumeState(_updateAuthenticationAccountInteractor.execute(accountId, apiUrl, userName));
137-
}
104+
void _addAccountIdToActiveAccount(
105+
AccountId accountId,
106+
UserName userName,
107+
String apiUrl,
108+
) {
109+
consumeState(_addAccountIdToActiveAccountInteractor.execute(
110+
accountId,
111+
apiUrl,
112+
userName
113+
));
138114
}
139115
}

lib/features/home/presentation/home_controller.dart

Lines changed: 100 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
import 'dart:async';
2+
13
import 'package:core/presentation/utils/theme_utils.dart';
4+
import 'package:core/utils/app_logger.dart';
25
import 'package:core/utils/platform_info.dart';
36
import 'package:flutter/foundation.dart';
47
import 'package:flutter_downloader/flutter_downloader.dart';
@@ -22,7 +25,12 @@ import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_email_cac
2225
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_recent_login_url_cache_interactor.dart';
2326
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_recent_login_username_interactor.dart';
2427
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_recent_search_cache_interactor.dart';
28+
import 'package:tmail_ui_user/features/home/domain/state/get_session_state.dart';
29+
import 'package:tmail_ui_user/features/login/presentation/model/login_navigate_arguments.dart';
30+
import 'package:tmail_ui_user/features/login/presentation/model/login_navigate_type.dart';
2531
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/preview_email_arguments.dart';
32+
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/restore_active_account_arguments.dart';
33+
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/switch_active_account_arguments.dart';
2634
import 'package:tmail_ui_user/features/push_notification/presentation/services/fcm_receiver.dart';
2735
import 'package:tmail_ui_user/main/routes/app_routes.dart';
2836
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
@@ -45,8 +53,8 @@ class HomeController extends ReloadableController {
4553
this._cleanupRecentLoginUsernameCacheInteractor,
4654
);
4755

48-
PersonalAccount? currentAccount;
4956
EmailId? _emailIdPreview;
57+
StreamSubscription? _sessionStreamSubscription;
5058

5159
@override
5260
void onInit() {
@@ -68,6 +76,12 @@ class HomeController extends ReloadableController {
6876
super.onReady();
6977
}
7078

79+
@override
80+
void onClose() {
81+
_sessionStreamSubscription?.cancel();
82+
super.onClose();
83+
}
84+
7185
@override
7286
void handleReloaded(Session session) {
7387
if (_emailIdPreview != null) {
@@ -87,20 +101,26 @@ class HomeController extends ReloadableController {
87101
}
88102

89103
void _initFlutterDownloader() {
90-
FlutterDownloader
91-
.initialize(debug: kDebugMode)
92-
.then((_) => FlutterDownloader.registerCallback(downloadCallback));
104+
if (!FlutterDownloader.initialized) {
105+
FlutterDownloader
106+
.initialize(debug: kDebugMode)
107+
.then((_) => FlutterDownloader.registerCallback(downloadCallback));
108+
}
93109
}
94110

95111
static void downloadCallback(String id, DownloadTaskStatus status, int progress) {}
96112

97113
void _handleNavigateToScreen() async {
98114
if (PlatformInfo.isMobile) {
99-
final firstTimeAppLaunch = await appStore.getItemBoolean(AppConfig.firstTimeAppLaunchKey);
100-
if (firstTimeAppLaunch) {
101-
await _cleanupCache();
115+
if (Get.arguments is LoginNavigateArguments) {
116+
_handleLoginNavigateArguments(Get.arguments);
102117
} else {
103-
_navigateToTwakeWelcomePage();
118+
final firstTimeAppLaunch = await appStore.getItemBoolean(AppConfig.firstTimeAppLaunchKey);
119+
if (firstTimeAppLaunch) {
120+
await _cleanupCache();
121+
} else {
122+
_navigateToTwakeWelcomePage();
123+
}
104124
}
105125
} else {
106126
await _cleanupCache();
@@ -151,4 +171,76 @@ class HomeController extends ReloadableController {
151171
}
152172
}
153173
}
174+
175+
void _handleLoginNavigateArguments(LoginNavigateArguments navigateArguments) async {
176+
if (navigateArguments.navigateType == LoginNavigateType.switchActiveAccount) {
177+
_switchActiveAccount(
178+
navigateArguments.currentAccount!,
179+
navigateArguments.sessionCurrentAccount!,
180+
navigateArguments.nextActiveAccount!);
181+
} else {
182+
await _cleanupCache();
183+
}
184+
}
185+
186+
void _switchActiveAccount(
187+
PersonalAccount currentActiveAccount,
188+
Session sessionCurrentAccount,
189+
PersonalAccount nextActiveAccount
190+
) {
191+
setUpInterceptors(nextActiveAccount);
192+
193+
_sessionStreamSubscription = getSessionInteractor.execute(
194+
accountId: nextActiveAccount.accountId,
195+
userName: nextActiveAccount.userName
196+
).listen(
197+
(viewState) {
198+
viewState.fold(
199+
(failure) => _handleGetSessionFailureWhenSwitchActiveAccount(
200+
currentActiveAccount: currentActiveAccount,
201+
session: sessionCurrentAccount,
202+
exception: failure),
203+
(success) => success is GetSessionSuccess
204+
? _handleGetSessionSuccessWhenSwitchActiveAccount(nextActiveAccount, success.session)
205+
: null,
206+
);
207+
},
208+
onError: (error, stack) {
209+
logError('HomeController::_switchActiveAccount:Exception: $error | Stack: $stack');
210+
_handleGetSessionFailureWhenSwitchActiveAccount(
211+
currentActiveAccount: currentActiveAccount,
212+
session: sessionCurrentAccount,
213+
exception: error);
214+
}
215+
);
216+
}
217+
218+
void _handleGetSessionSuccessWhenSwitchActiveAccount(
219+
PersonalAccount nextActiveAccount,
220+
Session sessionActiveAccount
221+
) async {
222+
log('HomeController::_handleGetSessionSuccessWhenSwitchActiveAccount:sessionActiveAccount: $sessionActiveAccount');
223+
await popAndPush(
224+
RouteUtils.generateNavigationRoute(AppRoutes.dashboard),
225+
arguments: SwitchActiveAccountArguments(
226+
session: sessionActiveAccount,
227+
nextActiveAccount: nextActiveAccount,
228+
)
229+
);
230+
}
231+
232+
void _handleGetSessionFailureWhenSwitchActiveAccount({
233+
required PersonalAccount currentActiveAccount,
234+
required Session session,
235+
dynamic exception
236+
}) async {
237+
logError('HomeController::_handleGetSessionFailureWhenSwitchActiveAccount:exception: $exception');
238+
await popAndPush(
239+
RouteUtils.generateNavigationRoute(AppRoutes.dashboard),
240+
arguments: RestoreActiveAccountArguments(
241+
currentAccount: currentActiveAccount,
242+
session: session
243+
)
244+
);
245+
}
154246
}

lib/features/login/data/datasource/account_datasource.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ abstract class AccountDatasource {
88
Future<void> deleteCurrentAccount(String accountId);
99

1010
Future<List<PersonalAccount>> getAllAccount();
11+
12+
Future<void> setCurrentAccountActive(PersonalAccount activeAccount);
1113
}

lib/features/login/data/datasource_impl/hive_account_datasource_impl.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,11 @@ class HiveAccountDatasourceImpl extends AccountDatasource {
4848
return await _accountCacheManager.getAllAccount();
4949
}).catchError(_exceptionThrower.throwException);
5050
}
51+
52+
@override
53+
Future<void> setCurrentAccountActive(PersonalAccount activeAccount) {
54+
return Future.sync(() async {
55+
return await _accountCacheManager.setCurrentAccountActive(activeAccount);
56+
}).catchError(_exceptionThrower.throwException);
57+
}
5158
}

lib/features/login/data/extensions/personal_account_extension.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ import 'package:tmail_ui_user/features/login/data/extensions/token_oidc_extensio
88
import 'package:tmail_ui_user/features/login/data/model/account_cache.dart';
99

1010
extension PersonalAccountExtension on PersonalAccount {
11-
AccountCache toCache() {
11+
AccountCache toCache({bool? isSelected}) {
1212
return AccountCache(
1313
id: id,
1414
authType: authType.name,
15-
isSelected: isSelected,
15+
isSelected: isSelected ?? this.isSelected,
1616
baseUrl: baseUrl,
1717
accountId: accountId?.id.value,
1818
apiUrl: apiUrl,
@@ -36,7 +36,7 @@ extension PersonalAccountExtension on PersonalAccount {
3636
);
3737
}
3838

39-
PersonalAccount updateAccountId({
39+
PersonalAccount addAccountId({
4040
required AccountId accountId,
4141
required String apiUrl,
4242
required UserName userName,

lib/features/login/data/local/account_cache_manager.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,18 @@ class AccountCacheManager {
5757
throw NotFoundAuthenticatedAccountException();
5858
}
5959
}
60+
61+
Future<void> setCurrentAccountActive(PersonalAccount activeAccount) async {
62+
log('AccountCacheManager::setCurrentAccountActive(): $activeAccount');
63+
final newAccountCache = activeAccount.toCache(isSelected: true);
64+
final allAccounts = await _accountCacheClient.getAll();
65+
log('AccountCacheManager::setCurrentAccountActive::allAccounts(): $allAccounts');
66+
if (allAccounts.isNotEmpty) {
67+
final newAllAccounts = allAccounts.unselected().toList();
68+
if (newAllAccounts.isNotEmpty) {
69+
await _accountCacheClient.updateMultipleItem(newAllAccounts.toMap());
70+
}
71+
}
72+
return _accountCacheClient.insertItem(newAccountCache.id, newAccountCache);
73+
}
6074
}

lib/features/login/data/repository/account_repository_impl.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,9 @@ class AccountRepositoryImpl extends AccountRepository {
2727
Future<List<PersonalAccount>> getAllAccount() {
2828
return _accountDatasource.getAllAccount();
2929
}
30+
31+
@override
32+
Future<void> setCurrentAccountActive(PersonalAccount activeAccount) {
33+
return _accountDatasource.setCurrentAccountActive(activeAccount);
34+
}
3035
}

0 commit comments

Comments
 (0)