TF-2901 Create before unload manager to handle before log out callbacks

This commit is contained in:
DatDang
2024-06-18 15:23:06 +07:00
committed by Dat H. Pham
parent fc4ca58d4e
commit c4bffd6626
5 changed files with 138 additions and 0 deletions
+13
View File
@@ -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';
@@ -169,7 +170,14 @@ abstract class BaseController extends GetxController
if (!authorizationInterceptors.isAppRunning) {
return;
}
_executeBeforeUnloadAndLogOut(exception);
}
Future<void> _executeBeforeUnloadAndLogOut(Exception? exception) async {
if (exception is BadCredentialsException || exception is ConnectionError) {
if (PlatformInfo.isWeb) {
await executeBeforeUnload();
}
clearDataAndGoToLoginPage();
}
}
@@ -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();
@@ -0,0 +1,3 @@
abstract class BeforeUnloadHandler {
Future<void> onBeforeUnload();
}
@@ -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 {
await Future.wait(_listeners.map((listener) => listener.call()))
.onError((error, stackTrace) => [logError(error.toString())]);
}
}
@@ -12,6 +12,7 @@ import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:tmail_ui_user/features/base/before_unload_manager.dart';
import 'package:tmail_ui_user/features/sending_queue/presentation/utils/sending_queue_isolate_manager.dart';
import 'package:tmail_ui_user/main/utils/app_config.dart';
import 'package:tmail_ui_user/main/utils/email_receive_manager.dart';
@@ -64,6 +65,7 @@ class CoreBindings extends Bindings {
Get.put(FileUtils());
Get.put(PrintUtils());
Get.put(ApplicationManager(Get.find<DeviceInfoPlugin>()));
Get.put(BeforeUnloadManager());
}
void _bindingIsolate() {
@@ -0,0 +1,96 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:tmail_ui_user/features/base/before_unload_manager.dart';
void main() {
group('before unload manager test:', () {
test(
'should finish all futures '
'when no future fails',
() async {
// arrange
List<int> result = [];
future1Second() => Future<void>.delayed(const Duration(seconds: 1), () => result.add(1));
future2Second() => Future<void>.delayed(const Duration(seconds: 2), () => result.add(2));
future3Second() => Future<void>.delayed(const Duration(seconds: 3), () => result.add(3));
final beforeUnloadManager = BeforeUnloadManager();
beforeUnloadManager.addListener(future1Second);
beforeUnloadManager.addListener(future2Second);
beforeUnloadManager.addListener(future3Second);
// act
await beforeUnloadManager.executeBeforeUnloadListeners();
// assert
expect(result.length, 3);
});
test(
'should finish all possible futures '
'when one future fail',
() async {
// arrange
List<int> result = [];
final exception = Exception('error');
future1Second() => Future<void>.delayed(const Duration(seconds: 1), () => result.add(1));
future2Second() => Future<void>.delayed(const Duration(seconds: 2), () => throw exception);
future3Second() => Future<void>.delayed(const Duration(seconds: 3), () => result.add(3));
final beforeUnloadManager = BeforeUnloadManager();
beforeUnloadManager.addListener(future1Second);
beforeUnloadManager.addListener(future2Second);
beforeUnloadManager.addListener(future3Second);
// act
await beforeUnloadManager.executeBeforeUnloadListeners();
// assert
expect(result.length, 2);
});
test(
'should finish all possible futures '
'when more than one future fail',
() async {
// arrange
List<int> result = [];
final exception1 = Exception('error 1');
final exception2 = Exception('error 2');
future1Second() => Future<void>.delayed(const Duration(seconds: 1), () => throw exception1);
future2Second() => Future<void>.delayed(const Duration(seconds: 2), () => throw exception2);
future3Second() => Future<void>.delayed(const Duration(seconds: 3), () => result.add(3));
final beforeUnloadManager = BeforeUnloadManager();
beforeUnloadManager.addListener(future1Second);
beforeUnloadManager.addListener(future2Second);
beforeUnloadManager.addListener(future3Second);
// act
await beforeUnloadManager.executeBeforeUnloadListeners();
// assert
expect(result.length, 1);
});
test(
'should finish all possible futures '
'when more than one future fail',
() async {
// arrange
List<int> result = [];
final exception3 = Exception('error 3');
final exception2 = Exception('error 2');
future1Second() => Future<void>.delayed(const Duration(seconds: 1), () => result.add(1));
future2Second() => Future<void>.delayed(const Duration(seconds: 2), () => throw exception2);
future3Second() => Future<void>.delayed(const Duration(seconds: 3), () => throw exception3);
final beforeUnloadManager = BeforeUnloadManager();
beforeUnloadManager.addListener(future1Second);
beforeUnloadManager.addListener(future2Second);
beforeUnloadManager.addListener(future3Second);
// act
await beforeUnloadManager.executeBeforeUnloadListeners();
// assert
expect(result.length, 1);
});
});
}