From e2e76685e28f5dda1d6fc2c49dd56eb7daaa6dcf Mon Sep 17 00:00:00 2001 From: Quang Huy Nguyen Date: Mon, 17 Jun 2024 22:57:59 +0700 Subject: [PATCH] TW-1791: Improve display contacts on multiple homeserver (#1857) * TW-1791: Refresh contacts when switch another account or login new account * TW-1791: Write unit test for this case * TW-1791: Refresh contacts when login or logout * TW-1791: Fix missing `setUpToMServices` when switch account --- lib/app_state/success.dart | 6 + .../contact_manager/contacts_manager.dart | 28 +- .../multiple_accounts_picker.dart | 1 + .../extensions/value_notifier_custom.dart | 15 + .../contacts_view_controller_mixin.dart | 20 +- lib/widgets/matrix.dart | 25 +- .../contacts/contacts_manager_test.dart | 741 ++++++++++++++++++ .../contacts_view_controller_mixin_test.dart | 189 ++--- 8 files changed, 918 insertions(+), 107 deletions(-) create mode 100644 lib/presentation/extensions/value_notifier_custom.dart diff --git a/lib/app_state/success.dart b/lib/app_state/success.dart index 776a2c3624..6b04b9257f 100644 --- a/lib/app_state/success.dart +++ b/lib/app_state/success.dart @@ -1,5 +1,6 @@ import 'package:dartz/dartz.dart'; import 'package:equatable/equatable.dart'; +import 'package:fluffychat/app_state/failure.dart'; abstract class Success extends Equatable { const Success(); @@ -10,4 +11,9 @@ extension SuccessExtension on Either { (failure) => fallbackValue, (success) => success is T ? success : fallbackValue, ); + + T? getFailureOrNull({T? fallbackValue}) => fold( + (failure) => failure is T ? failure : fallbackValue, + (success) => fallbackValue, + ); } diff --git a/lib/domain/contact_manager/contacts_manager.dart b/lib/domain/contact_manager/contacts_manager.dart index fe2dae4d70..81a86b2fdd 100644 --- a/lib/domain/contact_manager/contacts_manager.dart +++ b/lib/domain/contact_manager/contacts_manager.dart @@ -6,7 +6,7 @@ import 'package:fluffychat/domain/app_state/contact/get_contacts_state.dart'; import 'package:fluffychat/domain/app_state/contact/get_phonebook_contacts_state.dart'; import 'package:fluffychat/domain/usecase/contacts/get_tom_contacts_interactor.dart'; import 'package:fluffychat/domain/usecase/contacts/phonebook_contact_interactor.dart'; -import 'package:flutter/foundation.dart'; +import 'package:fluffychat/presentation/extensions/value_notifier_custom.dart'; class ContactsManager { static const int _lookupChunkSize = 50; @@ -17,24 +17,25 @@ class ContactsManager { bool _doNotShowWarningContactsBannerAgain = false; - final ValueNotifier> _contactsNotifier = - ValueNotifier(const Right(ContactsInitial())); + final ValueNotifierCustom> _contactsNotifier = + ValueNotifierCustom(const Right(ContactsInitial())); - final ValueNotifier> _phonebookContactsNotifier = - ValueNotifier(const Right(GetPhonebookContactsInitial())); + final ValueNotifierCustom> + _phonebookContactsNotifier = + ValueNotifierCustom(const Right(GetPhonebookContactsInitial())); ContactsManager({ required this.getTomContactsInteractor, required this.phonebookContactInteractor, }); - ValueNotifier> getContactsNotifier() => + ValueNotifierCustom> getContactsNotifier() => _contactsNotifier; - ValueNotifier> getPhonebookContactsNotifier() => - _phonebookContactsNotifier; + ValueNotifierCustom> + getPhonebookContactsNotifier() => _phonebookContactsNotifier; - bool get _isInitial => + bool get _isSynchronizedTomContacts => _contactsNotifier.value.getSuccessOrNull() != null; bool get isDoNotShowWarningContactsBannerAgain => @@ -44,10 +45,16 @@ class ContactsManager { _doNotShowWarningContactsBannerAgain = value; } + Future reSyncContacts() async { + _contactsNotifier.value = const Right(ContactsInitial()); + _phonebookContactsNotifier.value = + const Right(GetPhonebookContactsInitial()); + } + void initialSynchronizeContacts({ bool isAvailableSupportPhonebookContacts = false, }) async { - if (!_isInitial) { + if (!_isSynchronizedTomContacts) { return; } _getAllContacts( @@ -76,6 +83,7 @@ class ContactsManager { if (!isAvailableSupportPhonebookContacts) { return; } + phonebookContactInteractor .execute(lookupChunkSize: _lookupChunkSize) .listen( diff --git a/lib/pages/multiple_accounts/multiple_accounts_picker.dart b/lib/pages/multiple_accounts/multiple_accounts_picker.dart index 892dc9a618..abd4ddfe08 100644 --- a/lib/pages/multiple_accounts/multiple_accounts_picker.dart +++ b/lib/pages/multiple_accounts/multiple_accounts_picker.dart @@ -91,6 +91,7 @@ class MultipleAccountsPickerController { Future _setActiveClient(Client newClient) async { final result = await _matrixState.setActiveClient(newClient); if (result.isSuccess) { + _matrixState.reSyncContacts(); context.go( '/rooms', extra: SwitchActiveAccountBodyArgs( diff --git a/lib/presentation/extensions/value_notifier_custom.dart b/lib/presentation/extensions/value_notifier_custom.dart new file mode 100644 index 0000000000..835b41c681 --- /dev/null +++ b/lib/presentation/extensions/value_notifier_custom.dart @@ -0,0 +1,15 @@ +import 'package:flutter/foundation.dart'; + +class ValueNotifierCustom extends ValueNotifier { + bool _isDisposed = false; + + ValueNotifierCustom(super.value); + + bool get isDisposed => _isDisposed; + + @override + void dispose() { + _isDisposed = true; + super.dispose(); + } +} diff --git a/lib/presentation/mixins/contacts_view_controller_mixin.dart b/lib/presentation/mixins/contacts_view_controller_mixin.dart index b0a43570db..358f3f0ebf 100644 --- a/lib/presentation/mixins/contacts_view_controller_mixin.dart +++ b/lib/presentation/mixins/contacts_view_controller_mixin.dart @@ -12,6 +12,7 @@ import 'package:fluffychat/domain/model/extensions/contact/contacts_extension.da import 'package:fluffychat/domain/usecase/search/search_recent_chat_interactor.dart'; import 'package:fluffychat/presentation/enum/contacts/warning_contacts_banner_enum.dart'; import 'package:fluffychat/presentation/extensions/contact/presentation_contact_extension.dart'; +import 'package:fluffychat/presentation/extensions/value_notifier_custom.dart'; import 'package:fluffychat/presentation/model/contact/get_presentation_contacts_empty.dart'; import 'package:fluffychat/presentation/model/contact/get_presentation_contacts_failure.dart'; import 'package:fluffychat/presentation/model/contact/get_presentation_contacts_success.dart'; @@ -45,14 +46,15 @@ mixin class ContactsViewControllerMixin { final ValueNotifier isSearchModeNotifier = ValueNotifier(false); final presentationRecentContactNotifier = - ValueNotifier>([]); + ValueNotifierCustom>([]); - final presentationContactNotifier = ValueNotifier>( + final presentationContactNotifier = + ValueNotifierCustom>( const Right(ContactsInitial()), ); final presentationPhonebookContactNotifier = - ValueNotifier>( + ValueNotifierCustom>( const Right(GetPhonebookContactsInitial()), ); @@ -123,6 +125,10 @@ mixin class ContactsViewControllerMixin { }) { final keyword = _debouncer.value; if (keyword.isValidMatrixId && keyword.startsWith("@")) { + if (presentationContactNotifier.isDisposed && + presentationPhonebookContactNotifier.isDisposed) { + return; + } presentationContactNotifier.value = Right( PresentationExternalContactSuccess( contact: PresentationContact( @@ -151,6 +157,7 @@ mixin class ContactsViewControllerMixin { } Future _refreshContacts(String keyword) async { + if (presentationContactNotifier.isDisposed) return; presentationContactNotifier.value = contactsManager.getContactsNotifier().value.fold( (failure) { @@ -198,6 +205,7 @@ mixin class ContactsViewControllerMixin { } Future _refreshPhoneBookContacts(String keyword) async { + if (presentationPhonebookContactNotifier.isDisposed) return; presentationPhonebookContactNotifier.value = contactsManager.getPhonebookContactsNotifier().value.fold( (failure) { @@ -264,7 +272,7 @@ mixin class ContactsViewControllerMixin { .contacts .where((contact) => contact.directChatMatrixID != null) .toList(); - + if (presentationRecentContactNotifier.isDisposed) return; presentationRecentContactNotifier.value = recent .take( keyword == null ? _defaultLimitRecentContacts : recent.length, @@ -321,9 +329,11 @@ mixin class ContactsViewControllerMixin { textEditingController.clear(); searchFocusNode.dispose(); textEditingController.dispose(); + warningBannerNotifier.dispose(); + isSearchModeNotifier.dispose(); + presentationRecentContactNotifier.dispose(); presentationContactNotifier.dispose(); presentationPhonebookContactNotifier.dispose(); - presentationRecentContactNotifier.dispose(); } @visibleForTesting diff --git a/lib/widgets/matrix.dart b/lib/widgets/matrix.dart index 33f33860b2..1386b849df 100644 --- a/lib/widgets/matrix.dart +++ b/lib/widgets/matrix.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:io'; +import 'package:fluffychat/domain/contact_manager/contacts_manager.dart'; import 'package:fluffychat/presentation/mixins/init_config_mixin.dart'; import 'package:fluffychat/presentation/model/client_login_state_event.dart'; import 'package:fluffychat/widgets/layouts/agruments/logout_body_args.dart'; @@ -76,6 +77,8 @@ class MatrixState extends State with WidgetsBindingObserver, ReceiveSharingIntentMixin, InitConfigMixin { final tomConfigurationRepository = getIt.get(); + final _contactsManager = getIt.get(); + int _activeClient = -1; String? activeBundle; Store store = Store(); @@ -398,6 +401,7 @@ class MatrixState extends State await _cancelSubs(currentClient.clientName); widget.clients.remove(currentClient); await ClientManager.removeClientNameFromStore(currentClient.clientName); + matrixState.reSyncContacts(); TwakeSnackBar.show( TwakeApp.routerKey.currentContext!, L10n.of(context)!.oneClientLoggedOut, @@ -423,6 +427,7 @@ class MatrixState extends State waitForFirstSync = false; await setUpToMServicesInLogin(newActiveClient); await _storePersistActiveAccount(newActiveClient); + matrixState.reSyncContacts(); onClientLoginStateChanged.add( ClientLoginStateEvent( client: client, @@ -452,6 +457,7 @@ class MatrixState extends State waitForFirstSync = false; await setUpToMServicesInLogin(activeClient); final result = await setActiveClient(activeClient); + matrixState.reSyncContacts(); if (result.isSuccess) { onClientLoginStateChanged.add( ClientLoginStateEvent( @@ -593,7 +599,9 @@ class MatrixState extends State ToMServerInformation tomServer, IdentityServerInformation? identityServer, ) { - Logs().d('MatrixState::setUpToMServices: $tomServer, $identityServer'); + Logs().d( + 'MatrixState::setUpToMServices: $tomServer, ${identityServer?.baseUrl}', + ); _setUpToMServer(tomServer); if (identityServer != null) { _setUpIdentityServer(identityServer); @@ -637,6 +645,9 @@ class MatrixState extends State void setUpAuthorization(Client client) { final authorizationInterceptor = getIt.get(); + Logs().d( + 'MatrixState::setUpAuthorization: accessToken ${client.accessToken}', + ); authorizationInterceptor.accessToken = client.accessToken; } @@ -710,13 +721,18 @@ class MatrixState extends State if (toMConfigurations == null) { _setUpToMServer(null); _setupAuthUrl(); + setUpAuthorization(client); } else { - _setUpToMServer(toMConfigurations.tomServerInformation); _setupAuthUrl(url: toMConfigurations.authUrl); + setUpToMServices( + toMConfigurations.tomServerInformation, + toMConfigurations.identityServerInformation, + ); } } catch (e) { _setUpToMServer(null); _setupAuthUrl(); + setUpAuthorization(client!); Logs().e('Matrix::_checkHomeserverExists: error - $e'); } Logs().d( @@ -801,6 +817,7 @@ class MatrixState extends State } Future _handleLastLogout() async { + matrixState.reSyncContacts(); if (PlatformInfos.isMobile) { await _deletePersistActiveAccount(); TwakeApp.router.go('/home/twakeWelcome'); @@ -810,6 +827,10 @@ class MatrixState extends State await _deleteAllTomConfigurations(); } + Future reSyncContacts() async { + _contactsManager.reSyncContacts(); + } + @override void didChangeAppLifecycleState(AppLifecycleState state) { Logs().i('didChangeAppLifecycleState: AppLifecycleState = $state'); diff --git a/test/domain/contacts/contacts_manager_test.dart b/test/domain/contacts/contacts_manager_test.dart index bc10c05ae7..4254c460c9 100644 --- a/test/domain/contacts/contacts_manager_test.dart +++ b/test/domain/contacts/contacts_manager_test.dart @@ -672,5 +672,746 @@ void main() { ).called(1); }, ); + + test( + '[Account-A] WHEN it is available get Phonebook contact.\n' + '[Account-A] AND contactsNotifier return GetContactsSuccess with contacts is empty.\n' + '[Account-A] AND phonebookContactInteractor return GetPhonebookContactsSuccess with contacts is empty.\n' + '[Account-A] THEN contactsNotifier in ContactsManager SHOULD have GetContactsSuccess state.\n' + '[Account-A] THEN phonebookContactInteractor in ContactsManager SHOULD have GetPhonebookContactsSuccess state.\n' + '[Account-A] THEN list ToM contact SHOULD is empty.\n' + '[Account-A] THEN list Phonebook contact SHOULD is empty.\n' + 'Trigger UI => switch to another account and call synchronize contacts.\n' + '[Account-B] AND contactsNotifier return GetContactsSuccess with contacts is empty.\n' + '[Account-B] AND phonebookContactInteractor return GetPhonebookContactsSuccess with contacts is empty.\n' + '[Account-B] THEN contactsNotifier in ContactsManager SHOULD have GetContactsSuccess state.\n' + '[Account-B] THEN phonebookContactInteractor in ContactsManager SHOULD have GetPhonebookContactsSuccess state.\n' + '[Account-B] THEN list ToM contact SHOULD is empty.\n' + '[Account-B] THEN list Phonebook contact SHOULD is empty.\n', + () async { + final mockGetTomContactsInteractor = MockGetTomContactsInteractor(); + final mockPhonebookContactInteractor = MockPhonebookContactInteractor(); + + final contactsManager = ContactsManager( + getTomContactsInteractor: mockGetTomContactsInteractor, + phonebookContactInteractor: mockPhonebookContactInteractor, + ); + + final List listTomContactsSuccessState = []; + + final List listPhonebookContactsSuccessState = []; + + when( + mockGetTomContactsInteractor.execute( + limit: AppConfig.maxFetchContacts, + ), + ).thenAnswer( + (_) => Stream.fromIterable([ + const Right(ContactsLoading()), + const Left(GetContactsIsEmpty()), + ]), + ); + + when(mockPhonebookContactInteractor.execute()).thenAnswer( + (_) => Stream.fromIterable([ + const Right(GetPhonebookContactsLoading(progress: 0)), + const Left(GetPhonebookContactsIsEmpty()), + ]), + ); + + contactsManager.getContactsNotifier().addListener(() { + contactsManager.getContactsNotifier().value.fold( + (failure) => null, + (success) => listTomContactsSuccessState.add(success), + ); + }); + + contactsManager.getPhonebookContactsNotifier().addListener(() { + contactsManager.getPhonebookContactsNotifier().value.fold( + (failure) => null, + (success) => listPhonebookContactsSuccessState.add(success), + ); + }); + + contactsManager.initialSynchronizeContacts( + isAvailableSupportPhonebookContacts: true, + ); + + await Future.delayed(const Duration(seconds: 1)); + + verify( + mockGetTomContactsInteractor.execute( + limit: AppConfig.maxFetchContacts, + ), + ).called(1); + + verify( + mockPhonebookContactInteractor.execute(), + ).called(1); + + expectLater(listTomContactsSuccessState.length, 1); + + expectLater( + listTomContactsSuccessState, + [ + const ContactsLoading(), + ], + ); + + expectLater(listPhonebookContactsSuccessState.length, 1); + + expectLater( + listPhonebookContactsSuccessState, + [ + const GetPhonebookContactsLoading(progress: 0), + ], + ); + + /// Trigger switch account + contactsManager.reSyncContacts(); + + listTomContactsSuccessState.clear(); + + listPhonebookContactsSuccessState.clear(); + + when( + mockGetTomContactsInteractor.execute( + limit: AppConfig.maxFetchContacts, + ), + ).thenAnswer( + (_) => Stream.fromIterable([ + const Right(ContactsLoading()), + const Left(GetContactsIsEmpty()), + ]), + ); + + when(mockPhonebookContactInteractor.execute()).thenAnswer( + (_) => Stream.fromIterable([ + const Right(GetPhonebookContactsLoading(progress: 0)), + const Left(GetPhonebookContactsIsEmpty()), + ]), + ); + + contactsManager.initialSynchronizeContacts( + isAvailableSupportPhonebookContacts: true, + ); + + await Future.delayed(const Duration(seconds: 1)); + + verify( + mockGetTomContactsInteractor.execute( + limit: AppConfig.maxFetchContacts, + ), + ).called(1); + + verify( + mockPhonebookContactInteractor.execute(), + ).called(1); + + expectLater(listTomContactsSuccessState.length, 1); + + expectLater( + listTomContactsSuccessState, + [ + const ContactsLoading(), + ], + ); + + expectLater(listPhonebookContactsSuccessState.length, 1); + + expectLater( + listPhonebookContactsSuccessState, + [ + const GetPhonebookContactsLoading(progress: 0), + ], + ); + }, + ); + + test( + '[Account-A] WHEN it is available get Phonebook contact.\n' + '[Account-A] AND call initialSynchronizeContacts success.\n' + '[Account-A] AND contactsNotifier return GetContactsSuccess with contacts is not empty.\n' + '[Account-A] AND phonebookContactInteractor return GetPhonebookContactsSuccess with contacts is not empty.\n' + '[Account-A] THEN contactsNotifier in ContactsManager SHOULD have GetContactsSuccess state.\n' + '[Account-A] THEN phonebookContactInteractor in ContactsManager SHOULD have GetPhonebookContactsSuccess state.\n' + '[Account-A] THEN list ToM contact SHOULD is not empty.\n' + '[Account-A] THEN list Phonebook contact SHOULD is not empty.\n' + '[Account-A] THEN contactsNotifier and phonebookContactInteractor just call only one time.\n' + 'Trigger UI => switch to another account and call synchronize contacts.\n' + '[Account-B] AND THEN call initialSynchronizeContacts again.\n' + '[Account-B] AND contactsNotifier return GetContactsSuccess with contacts is not empty.\n' + '[Account-B] AND phonebookContactInteractor return GetPhonebookContactsSuccess with contacts is not empty.\n' + '[Account-B] THEN contactsNotifier in ContactsManager SHOULD have GetContactsSuccess state.\n' + '[Account-B] THEN phonebookContactInteractor in ContactsManager SHOULD have GetPhonebookContactsSuccess state.\n' + '[Account-B] THEN list ToM contact SHOULD is not empty.\n' + '[Account-B] THEN list Phonebook contact SHOULD is not empty.\n' + '[Account-B] THEN contactsNotifier and phonebookContactInteractor just call only one time.\n', + () async { + final mockGetTomContactsInteractor = MockGetTomContactsInteractor(); + final mockPhonebookContactInteractor = MockPhonebookContactInteractor(); + + final contactsManager = ContactsManager( + getTomContactsInteractor: mockGetTomContactsInteractor, + phonebookContactInteractor: mockPhonebookContactInteractor, + ); + + final List listTomContactsSuccessState = []; + + final List listPhonebookContactsSuccessState = []; + + when( + mockGetTomContactsInteractor.execute( + limit: AppConfig.maxFetchContacts, + ), + ).thenAnswer( + (_) => Stream.fromIterable([ + const Right(ContactsLoading()), + Right(GetContactsSuccess(contacts: tomContacts)), + ]), + ); + + when(mockPhonebookContactInteractor.execute()).thenAnswer( + (_) => Stream.fromIterable([ + const Right(GetPhonebookContactsLoading(progress: 0)), + Right(GetPhonebookContactsSuccess(contacts: phonebookContacts)), + ]), + ); + + contactsManager.getContactsNotifier().addListener(() { + contactsManager.getContactsNotifier().value.fold( + (failure) => null, + (success) => listTomContactsSuccessState.add(success), + ); + }); + + contactsManager.getPhonebookContactsNotifier().addListener(() { + contactsManager.getPhonebookContactsNotifier().value.fold( + (failure) => null, + (success) => listPhonebookContactsSuccessState.add(success), + ); + }); + + expect( + contactsManager + .getContactsNotifier() + .value + .getSuccessOrNull() != + null, + true, + ); + + contactsManager.initialSynchronizeContacts( + isAvailableSupportPhonebookContacts: true, + ); + + await Future.delayed(const Duration(seconds: 1)); + + verify( + mockGetTomContactsInteractor.execute( + limit: AppConfig.maxFetchContacts, + ), + ).called(1); + + verify( + mockPhonebookContactInteractor.execute(), + ).called(1); + + expectLater(listTomContactsSuccessState.length, 2); + + expectLater( + listTomContactsSuccessState, + [ + const ContactsLoading(), + GetContactsSuccess(contacts: tomContacts), + ], + ); + + expectLater(listPhonebookContactsSuccessState.length, 2); + + expectLater( + listPhonebookContactsSuccessState, + [ + const GetPhonebookContactsLoading(progress: 0), + GetPhonebookContactsSuccess(contacts: phonebookContacts), + ], + ); + + /// Trigger switch account + + contactsManager.reSyncContacts(); + + listTomContactsSuccessState.clear(); + + listPhonebookContactsSuccessState.clear(); + + when( + mockGetTomContactsInteractor.execute( + limit: AppConfig.maxFetchContacts, + ), + ).thenAnswer( + (_) => Stream.fromIterable([ + const Right(ContactsLoading()), + Right(GetContactsSuccess(contacts: tomContacts)), + ]), + ); + + when(mockPhonebookContactInteractor.execute()).thenAnswer( + (_) => Stream.fromIterable([ + const Right(GetPhonebookContactsLoading(progress: 0)), + Right(GetPhonebookContactsSuccess(contacts: phonebookContacts)), + ]), + ); + + expect( + contactsManager + .getContactsNotifier() + .value + .getSuccessOrNull() != + null, + true, + ); + + contactsManager.initialSynchronizeContacts( + isAvailableSupportPhonebookContacts: true, + ); + + await Future.delayed(const Duration(seconds: 1)); + + verify( + mockGetTomContactsInteractor.execute( + limit: AppConfig.maxFetchContacts, + ), + ).called(1); + + verify( + mockPhonebookContactInteractor.execute(), + ).called(1); + + expectLater(listTomContactsSuccessState.length, 2); + + expectLater( + listTomContactsSuccessState, + [ + const ContactsLoading(), + GetContactsSuccess(contacts: tomContacts), + ], + ); + + expectLater(listPhonebookContactsSuccessState.length, 2); + + expectLater( + listPhonebookContactsSuccessState, + [ + const GetPhonebookContactsLoading(progress: 0), + GetPhonebookContactsSuccess(contacts: phonebookContacts), + ], + ); + }, + ); + + test( + '[Account-A] WHEN it is available get Phonebook contact.\n' + '[Account-A] AND call initialSynchronizeContacts success.\n' + '[Account-A] AND contactsNotifier return GetContactsSuccess with contacts is not empty.\n' + '[Account-A] AND phonebookContactInteractor return GetPhonebookContactsSuccess with contacts is not empty.\n' + '[Account-A] THEN contactsNotifier in ContactsManager SHOULD have GetContactsSuccess state.\n' + '[Account-A] THEN phonebookContactInteractor in ContactsManager SHOULD have GetPhonebookContactsSuccess state.\n' + '[Account-A] THEN list ToM contact SHOULD is not empty.\n' + '[Account-A] THEN list Phonebook contact SHOULD is not empty.\n' + '[Account-A] THEN contactsNotifier and phonebookContactInteractor just call only one time.\n' + 'Trigger UI => switch to another account and call synchronize contacts.\n' + '[Account-B] AND THEN call initialSynchronizeContacts again.\n' + '[Account-B] AND contactsNotifier return GetContactsSuccess with contacts is empty.\n' + '[Account-B] AND phonebookContactInteractor return GetPhonebookContactsSuccess with contacts is not empty.\n' + '[Account-B] THEN contactsNotifier in ContactsManager SHOULD have GetContactsIsEmpty state.\n' + '[Account-B] THEN phonebookContactInteractor in ContactsManager SHOULD have GetPhonebookContactsSuccess state.\n' + '[Account-B] THEN list ToM contact SHOULD is empty.\n' + '[Account-B] THEN list Phonebook contact SHOULD is not empty.\n' + '[Account-B] THEN contactsNotifier and phonebookContactInteractor just call only one time.\n', + () async { + final mockGetTomContactsInteractor = MockGetTomContactsInteractor(); + final mockPhonebookContactInteractor = MockPhonebookContactInteractor(); + + final contactsManager = ContactsManager( + getTomContactsInteractor: mockGetTomContactsInteractor, + phonebookContactInteractor: mockPhonebookContactInteractor, + ); + + final List listTomContactsSuccessState = []; + + final List listPhonebookContactsSuccessState = []; + + when( + mockGetTomContactsInteractor.execute( + limit: AppConfig.maxFetchContacts, + ), + ).thenAnswer( + (_) => Stream.fromIterable([ + const Right(ContactsLoading()), + Right(GetContactsSuccess(contacts: tomContacts)), + ]), + ); + + when(mockPhonebookContactInteractor.execute()).thenAnswer( + (_) => Stream.fromIterable([ + const Right(GetPhonebookContactsLoading(progress: 0)), + Right(GetPhonebookContactsSuccess(contacts: phonebookContacts)), + ]), + ); + + contactsManager.getContactsNotifier().addListener(() { + contactsManager.getContactsNotifier().value.fold( + (failure) => null, + (success) => listTomContactsSuccessState.add(success), + ); + }); + + contactsManager.getPhonebookContactsNotifier().addListener(() { + contactsManager.getPhonebookContactsNotifier().value.fold( + (failure) => null, + (success) => listPhonebookContactsSuccessState.add(success), + ); + }); + + expect( + contactsManager + .getContactsNotifier() + .value + .getSuccessOrNull() != + null, + true, + ); + + contactsManager.initialSynchronizeContacts( + isAvailableSupportPhonebookContacts: true, + ); + + await Future.delayed(const Duration(seconds: 1)); + + expect( + contactsManager + .getContactsNotifier() + .value + .getSuccessOrNull() != + null, + true, + ); + + expect( + contactsManager + .getPhonebookContactsNotifier() + .value + .getSuccessOrNull() != + null, + true, + ); + + verify( + mockGetTomContactsInteractor.execute( + limit: AppConfig.maxFetchContacts, + ), + ).called(1); + + verify( + mockPhonebookContactInteractor.execute(), + ).called(1); + + expectLater(listTomContactsSuccessState.length, 2); + + expectLater( + listTomContactsSuccessState, + [ + const ContactsLoading(), + GetContactsSuccess(contacts: tomContacts), + ], + ); + + expectLater(listPhonebookContactsSuccessState.length, 2); + + expectLater( + listPhonebookContactsSuccessState, + [ + const GetPhonebookContactsLoading(progress: 0), + GetPhonebookContactsSuccess(contacts: phonebookContacts), + ], + ); + + /// Trigger switch account + + contactsManager.reSyncContacts(); + + listTomContactsSuccessState.clear(); + + listPhonebookContactsSuccessState.clear(); + + when( + mockGetTomContactsInteractor.execute( + limit: AppConfig.maxFetchContacts, + ), + ).thenAnswer( + (_) => Stream.fromIterable([ + const Right(ContactsLoading()), + const Left(GetContactsIsEmpty()), + ]), + ); + + when(mockPhonebookContactInteractor.execute()).thenAnswer( + (_) => Stream.fromIterable([ + const Right(GetPhonebookContactsLoading(progress: 0)), + Right(GetPhonebookContactsSuccess(contacts: phonebookContacts)), + ]), + ); + + contactsManager.initialSynchronizeContacts( + isAvailableSupportPhonebookContacts: true, + ); + + await Future.delayed(const Duration(seconds: 1)); + + expect( + contactsManager + .getContactsNotifier() + .value + .getFailureOrNull() != + null, + true, + ); + + expect( + contactsManager + .getPhonebookContactsNotifier() + .value + .getSuccessOrNull() != + null, + true, + ); + verify( + mockGetTomContactsInteractor.execute( + limit: AppConfig.maxFetchContacts, + ), + ).called(1); + + verify( + mockPhonebookContactInteractor.execute(), + ).called(1); + + expectLater(listTomContactsSuccessState.length, 1); + + expectLater( + listTomContactsSuccessState, + [ + const ContactsLoading(), + ], + ); + + expectLater(listPhonebookContactsSuccessState.length, 2); + + expectLater( + listPhonebookContactsSuccessState, + [ + const GetPhonebookContactsLoading(progress: 0), + GetPhonebookContactsSuccess(contacts: phonebookContacts), + ], + ); + }, + ); + + test( + '[Account-A] WHEN it is available get Phonebook contact.\n' + '[Account-A] AND call initialSynchronizeContacts success.\n' + '[Account-A] AND contactsNotifier return GetContactsSuccess with contacts is empty.\n' + '[Account-A] AND phonebookContactInteractor return GetPhonebookContactsSuccess with contacts is empty.\n' + '[Account-A] THEN contactsNotifier in ContactsManager SHOULD have GetContactsIsEmpty state.\n' + '[Account-A] THEN phonebookContactInteractor in ContactsManager SHOULD have GetPhonebookContactsIsEmpty state.\n' + '[Account-A] THEN list ToM contact SHOULD is empty.\n' + '[Account-A] THEN list Phonebook contact SHOULD is empty.\n' + '[Account-A] THEN contactsNotifier and phonebookContactInteractor just call only one time.\n' + 'Trigger UI => switch to another account and call synchronize contacts.\n' + '[Account-B] AND THEN call initialSynchronizeContacts again.\n' + '[Account-B] AND contactsNotifier return GetContactsSuccess with contacts is empty.\n' + '[Account-B] AND phonebookContactInteractor return GetPhonebookContactsSuccess with contacts is not empty.\n' + '[Account-B] THEN contactsNotifier in ContactsManager SHOULD have GetContactsIsEmpty state.\n' + '[Account-B] THEN phonebookContactInteractor in ContactsManager SHOULD have GetPhonebookContactsSuccess state.\n' + '[Account-B] THEN list ToM contact SHOULD is empty.\n' + '[Account-B] THEN list Phonebook contact SHOULD is not empty.\n' + '[Account-B] THEN contactsNotifier and phonebookContactInteractor just call only one time.\n', + () async { + final mockGetTomContactsInteractor = MockGetTomContactsInteractor(); + final mockPhonebookContactInteractor = MockPhonebookContactInteractor(); + + final contactsManager = ContactsManager( + getTomContactsInteractor: mockGetTomContactsInteractor, + phonebookContactInteractor: mockPhonebookContactInteractor, + ); + + final List listTomContactsSuccessState = []; + + final List listPhonebookContactsSuccessState = []; + + when( + mockGetTomContactsInteractor.execute( + limit: AppConfig.maxFetchContacts, + ), + ).thenAnswer( + (_) => Stream.fromIterable([ + const Right(ContactsLoading()), + const Left(GetContactsIsEmpty()), + ]), + ); + + when(mockPhonebookContactInteractor.execute()).thenAnswer( + (_) => Stream.fromIterable([ + const Right(GetPhonebookContactsLoading(progress: 0)), + const Left(GetPhonebookContactsIsEmpty()), + ]), + ); + + contactsManager.getContactsNotifier().addListener(() { + contactsManager.getContactsNotifier().value.fold( + (failure) => null, + (success) => listTomContactsSuccessState.add(success), + ); + }); + + contactsManager.getPhonebookContactsNotifier().addListener(() { + contactsManager.getPhonebookContactsNotifier().value.fold( + (failure) => null, + (success) => listPhonebookContactsSuccessState.add(success), + ); + }); + + contactsManager.initialSynchronizeContacts( + isAvailableSupportPhonebookContacts: true, + ); + + await Future.delayed(const Duration(seconds: 1)); + + expect( + contactsManager + .getContactsNotifier() + .value + .getFailureOrNull() != + null, + true, + ); + + expect( + contactsManager + .getPhonebookContactsNotifier() + .value + .getFailureOrNull() != + null, + true, + ); + + verify( + mockGetTomContactsInteractor.execute( + limit: AppConfig.maxFetchContacts, + ), + ).called(1); + + verify( + mockPhonebookContactInteractor.execute(), + ).called(1); + + expectLater(listTomContactsSuccessState.length, 1); + + expectLater( + listTomContactsSuccessState, + [ + const ContactsLoading(), + ], + ); + + expectLater(listPhonebookContactsSuccessState.length, 1); + + expectLater( + listPhonebookContactsSuccessState, + [ + const GetPhonebookContactsLoading(progress: 0), + ], + ); + + /// Trigger switch account + + contactsManager.reSyncContacts(); + + listTomContactsSuccessState.clear(); + + listPhonebookContactsSuccessState.clear(); + + when( + mockGetTomContactsInteractor.execute( + limit: AppConfig.maxFetchContacts, + ), + ).thenAnswer( + (_) => Stream.fromIterable([ + const Right(ContactsLoading()), + Right(GetContactsSuccess(contacts: tomContacts)), + ]), + ); + + when(mockPhonebookContactInteractor.execute()).thenAnswer( + (_) => Stream.fromIterable([ + const Right(GetPhonebookContactsLoading(progress: 0)), + Right(GetPhonebookContactsSuccess(contacts: phonebookContacts)), + ]), + ); + + contactsManager.initialSynchronizeContacts( + isAvailableSupportPhonebookContacts: true, + ); + + await Future.delayed(const Duration(seconds: 1)); + + expect( + contactsManager + .getContactsNotifier() + .value + .getSuccessOrNull() != + null, + true, + ); + + expect( + contactsManager + .getPhonebookContactsNotifier() + .value + .getSuccessOrNull() != + null, + true, + ); + verify( + mockGetTomContactsInteractor.execute( + limit: AppConfig.maxFetchContacts, + ), + ).called(1); + + verify( + mockPhonebookContactInteractor.execute(), + ).called(1); + + expectLater(listTomContactsSuccessState.length, 2); + + expectLater( + listTomContactsSuccessState, + [ + const ContactsLoading(), + GetContactsSuccess(contacts: tomContacts), + ], + ); + + expectLater(listPhonebookContactsSuccessState.length, 2); + + expectLater( + listPhonebookContactsSuccessState, + [ + const GetPhonebookContactsLoading(progress: 0), + GetPhonebookContactsSuccess(contacts: phonebookContacts), + ], + ); + }, + ); }); } diff --git a/test/mixin/contacts_view_controller_mixin_test.dart b/test/mixin/contacts_view_controller_mixin_test.dart index bc64c6c9ce..6b12c652ae 100644 --- a/test/mixin/contacts_view_controller_mixin_test.dart +++ b/test/mixin/contacts_view_controller_mixin_test.dart @@ -4,6 +4,7 @@ import 'package:fluffychat/app_state/success.dart'; import 'package:fluffychat/domain/app_state/contact/get_contacts_state.dart'; import 'package:fluffychat/domain/app_state/contact/get_phonebook_contacts_state.dart'; import 'package:fluffychat/domain/model/contact/contact_status.dart'; +import 'package:fluffychat/presentation/extensions/value_notifier_custom.dart'; import 'package:fluffychat/presentation/mixins/contacts_view_controller_mixin.dart'; import 'package:fluffychat/presentation/model/contact/get_presentation_contacts_success.dart'; import 'package:fluffychat/presentation/model/search/presentation_search.dart'; @@ -141,18 +142,18 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier([])); + ).thenReturn(ValueNotifierCustom([])); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier(const Left(GetContactsIsEmpty())), + ValueNotifierCustom(const Left(GetContactsIsEmpty())), ); when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, ).thenReturn( - ValueNotifier(const Right(GetPhonebookContactsInitial())), + ValueNotifierCustom(const Right(GetPhonebookContactsInitial())), ); mockContactsViewControllerMixin.initialFetchContacts( @@ -216,15 +217,17 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier(recentContacts)); + ).thenReturn(ValueNotifierCustom(recentContacts)); when( mockContactsViewControllerMixin.presentationContactNotifier, - ).thenReturn(ValueNotifier(const Left(GetContactsIsEmpty()))); + ).thenReturn(ValueNotifierCustom(const Left(GetContactsIsEmpty()))); when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, - ).thenReturn(ValueNotifier(const Right(GetPhonebookContactsInitial()))); + ).thenReturn( + ValueNotifierCustom(const Right(GetPhonebookContactsInitial())), + ); mockContactsViewControllerMixin.initialFetchContacts( client: mockClient, @@ -287,17 +290,19 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier(recentContacts)); + ).thenReturn(ValueNotifierCustom(recentContacts)); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier(Right(GetContactsSuccess(contacts: tomContacts))), + ValueNotifierCustom(Right(GetContactsSuccess(contacts: tomContacts))), ); when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, - ).thenReturn(ValueNotifier(const Right(GetPhonebookContactsInitial()))); + ).thenReturn( + ValueNotifierCustom(const Right(GetPhonebookContactsInitial())), + ); mockContactsViewControllerMixin.initialFetchContacts( client: mockClient, @@ -374,19 +379,21 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier([])); + ).thenReturn(ValueNotifierCustom([])); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier( + ValueNotifierCustom( const Left(GetContactsFailure(keyword: '', exception: dynamic)), ), ); when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, - ).thenReturn(ValueNotifier(const Right(GetPhonebookContactsInitial()))); + ).thenReturn( + ValueNotifierCustom(const Right(GetPhonebookContactsInitial())), + ); mockContactsViewControllerMixin.initialFetchContacts( client: mockClient, @@ -471,18 +478,18 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier([])); + ).thenReturn(ValueNotifierCustom([])); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier(const Left(GetContactsIsEmpty())), + ValueNotifierCustom(const Left(GetContactsIsEmpty())), ); when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, ).thenReturn( - ValueNotifier(const Right(GetPhonebookContactsInitial())), + ValueNotifierCustom(const Right(GetPhonebookContactsInitial())), ); mockContactsViewControllerMixin.initialFetchContacts( @@ -533,18 +540,18 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier([])); + ).thenReturn(ValueNotifierCustom([])); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier(const Left(GetContactsIsEmpty())), + ValueNotifierCustom(const Left(GetContactsIsEmpty())), ); when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, ).thenReturn( - ValueNotifier(const Right(GetPhonebookContactsInitial())), + ValueNotifierCustom(const Right(GetPhonebookContactsInitial())), ); mockContactsViewControllerMixin.refreshAllContactsTest( @@ -641,18 +648,18 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier(recentContacts)); + ).thenReturn(ValueNotifierCustom(recentContacts)); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier(const Left(GetContactsIsEmpty())), + ValueNotifierCustom(const Left(GetContactsIsEmpty())), ); when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, ).thenReturn( - ValueNotifier(const Right(GetPhonebookContactsInitial())), + ValueNotifierCustom(const Right(GetPhonebookContactsInitial())), ); mockContactsViewControllerMixin.initialFetchContacts( @@ -703,18 +710,18 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier([])); + ).thenReturn(ValueNotifierCustom([])); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier(const Left(GetContactsIsEmpty())), + ValueNotifierCustom(const Left(GetContactsIsEmpty())), ); when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, ).thenReturn( - ValueNotifier(const Right(GetPhonebookContactsInitial())), + ValueNotifierCustom(const Right(GetPhonebookContactsInitial())), ); mockContactsViewControllerMixin.refreshAllContactsTest( @@ -811,18 +818,18 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier(recentContacts)); + ).thenReturn(ValueNotifierCustom(recentContacts)); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier(Right(GetContactsSuccess(contacts: tomContacts))), + ValueNotifierCustom(Right(GetContactsSuccess(contacts: tomContacts))), ); when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, ).thenReturn( - ValueNotifier(const Right(GetPhonebookContactsInitial())), + ValueNotifierCustom(const Right(GetPhonebookContactsInitial())), ); mockContactsViewControllerMixin.initialFetchContacts( @@ -873,18 +880,18 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier([])); + ).thenReturn(ValueNotifierCustom([])); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier(const Left(GetContactsIsEmpty())), + ValueNotifierCustom(const Left(GetContactsIsEmpty())), ); when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, ).thenReturn( - ValueNotifier(const Right(GetPhonebookContactsInitial())), + ValueNotifierCustom(const Right(GetPhonebookContactsInitial())), ); mockContactsViewControllerMixin.refreshAllContactsTest( @@ -981,18 +988,18 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier(recentContacts)); + ).thenReturn(ValueNotifierCustom(recentContacts)); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier(Right(GetContactsSuccess(contacts: tomContacts))), + ValueNotifierCustom(Right(GetContactsSuccess(contacts: tomContacts))), ); when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, ).thenReturn( - ValueNotifier(const Right(GetPhonebookContactsInitial())), + ValueNotifierCustom(const Right(GetPhonebookContactsInitial())), ); mockContactsViewControllerMixin.initialFetchContacts( @@ -1043,12 +1050,12 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier(recentContacts)); + ).thenReturn(ValueNotifierCustom(recentContacts)); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier( + ValueNotifierCustom( Right( GetPresentationContactsSuccess( contacts: tomContacts, @@ -1061,7 +1068,7 @@ void main() { when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, ).thenReturn( - ValueNotifier(const Right(GetPhonebookContactsInitial())), + ValueNotifierCustom(const Right(GetPhonebookContactsInitial())), ); mockContactsViewControllerMixin.refreshAllContactsTest( @@ -1180,18 +1187,18 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier(recentContacts)); + ).thenReturn(ValueNotifierCustom(recentContacts)); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier(Right(GetContactsSuccess(contacts: tomContacts))), + ValueNotifierCustom(Right(GetContactsSuccess(contacts: tomContacts))), ); when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, ).thenReturn( - ValueNotifier(const Right(GetPhonebookContactsInitial())), + ValueNotifierCustom(const Right(GetPhonebookContactsInitial())), ); mockContactsViewControllerMixin.initialFetchContacts( @@ -1242,12 +1249,12 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier(recentContacts)); + ).thenReturn(ValueNotifierCustom(recentContacts)); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier( + ValueNotifierCustom( Right( GetPresentationContactsSuccess( contacts: tomContacts, @@ -1260,7 +1267,7 @@ void main() { when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, ).thenReturn( - ValueNotifier(const Right(GetPhonebookContactsInitial())), + ValueNotifierCustom(const Right(GetPhonebookContactsInitial())), ); mockContactsViewControllerMixin.refreshAllContactsTest( @@ -1335,12 +1342,12 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier(recentContacts)); + ).thenReturn(ValueNotifierCustom(recentContacts)); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier( + ValueNotifierCustom( const Right( GetPresentationContactsSuccess( contacts: [], @@ -1353,7 +1360,7 @@ void main() { when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, ).thenReturn( - ValueNotifier(const Right(GetPhonebookContactsInitial())), + ValueNotifierCustom(const Right(GetPhonebookContactsInitial())), ); mockContactsViewControllerMixin.refreshAllContactsTest( @@ -1447,18 +1454,18 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier([])); + ).thenReturn(ValueNotifierCustom([])); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier(const Left(GetContactsIsEmpty())), + ValueNotifierCustom(const Left(GetContactsIsEmpty())), ); when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, ).thenReturn( - ValueNotifier(const Left(GetPhonebookContactsIsEmpty())), + ValueNotifierCustom(const Left(GetPhonebookContactsIsEmpty())), ); mockContactsViewControllerMixin.initialFetchContacts( @@ -1522,15 +1529,17 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier(recentContacts)); + ).thenReturn(ValueNotifierCustom(recentContacts)); when( mockContactsViewControllerMixin.presentationContactNotifier, - ).thenReturn(ValueNotifier(const Left(GetContactsIsEmpty()))); + ).thenReturn(ValueNotifierCustom(const Left(GetContactsIsEmpty()))); when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, - ).thenReturn(ValueNotifier(const Left(GetPhonebookContactsIsEmpty()))); + ).thenReturn( + ValueNotifierCustom(const Left(GetPhonebookContactsIsEmpty())), + ); mockContactsViewControllerMixin.initialFetchContacts( client: mockClient, @@ -1593,18 +1602,18 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier(recentContacts)); + ).thenReturn(ValueNotifierCustom(recentContacts)); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier(Right(GetContactsSuccess(contacts: tomContacts))), + ValueNotifierCustom(Right(GetContactsSuccess(contacts: tomContacts))), ); when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, ).thenReturn( - ValueNotifier( + ValueNotifierCustom( Right(GetPhonebookContactsSuccess(contacts: phonebookContacts)), ), ); @@ -1694,12 +1703,12 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier([])); + ).thenReturn(ValueNotifierCustom([])); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier( + ValueNotifierCustom( const Left(GetContactsFailure(keyword: '', exception: dynamic)), ), ); @@ -1707,7 +1716,7 @@ void main() { when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, ).thenReturn( - ValueNotifier( + ValueNotifierCustom( const Left(GetPhonebookContactsFailure(exception: dynamic)), ), ); @@ -1795,18 +1804,18 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier([])); + ).thenReturn(ValueNotifierCustom([])); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier(const Left(GetContactsIsEmpty())), + ValueNotifierCustom(const Left(GetContactsIsEmpty())), ); when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, ).thenReturn( - ValueNotifier(const Left(GetPhonebookContactsIsEmpty())), + ValueNotifierCustom(const Left(GetPhonebookContactsIsEmpty())), ); mockContactsViewControllerMixin.initialFetchContacts( @@ -1857,18 +1866,18 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier([])); + ).thenReturn(ValueNotifierCustom([])); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier(const Left(GetContactsIsEmpty())), + ValueNotifierCustom(const Left(GetContactsIsEmpty())), ); when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, ).thenReturn( - ValueNotifier(const Left(GetPhonebookContactsIsEmpty())), + ValueNotifierCustom(const Left(GetPhonebookContactsIsEmpty())), ); mockContactsViewControllerMixin.refreshAllContactsTest( @@ -1965,18 +1974,18 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier(recentContacts)); + ).thenReturn(ValueNotifierCustom(recentContacts)); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier(const Left(GetContactsIsEmpty())), + ValueNotifierCustom(const Left(GetContactsIsEmpty())), ); when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, ).thenReturn( - ValueNotifier(const Left(GetPhonebookContactsIsEmpty())), + ValueNotifierCustom(const Left(GetPhonebookContactsIsEmpty())), ); mockContactsViewControllerMixin.initialFetchContacts( @@ -2027,18 +2036,18 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier([])); + ).thenReturn(ValueNotifierCustom([])); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier(const Left(GetContactsIsEmpty())), + ValueNotifierCustom(const Left(GetContactsIsEmpty())), ); when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, ).thenReturn( - ValueNotifier(const Left(GetPhonebookContactsIsEmpty())), + ValueNotifierCustom(const Left(GetPhonebookContactsIsEmpty())), ); mockContactsViewControllerMixin.refreshAllContactsTest( @@ -2135,18 +2144,18 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier(recentContacts)); + ).thenReturn(ValueNotifierCustom(recentContacts)); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier(Right(GetContactsSuccess(contacts: tomContacts))), + ValueNotifierCustom(Right(GetContactsSuccess(contacts: tomContacts))), ); when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, ).thenReturn( - ValueNotifier( + ValueNotifierCustom( Right(GetPhonebookContactsSuccess(contacts: phonebookContacts)), ), ); @@ -2199,18 +2208,18 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier([])); + ).thenReturn(ValueNotifierCustom([])); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier(const Left(GetContactsIsEmpty())), + ValueNotifierCustom(const Left(GetContactsIsEmpty())), ); when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, ).thenReturn( - ValueNotifier(const Left(GetPhonebookContactsIsEmpty())), + ValueNotifierCustom(const Left(GetPhonebookContactsIsEmpty())), ); mockContactsViewControllerMixin.refreshAllContactsTest( @@ -2307,18 +2316,18 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier(recentContacts)); + ).thenReturn(ValueNotifierCustom(recentContacts)); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier(Right(GetContactsSuccess(contacts: tomContacts))), + ValueNotifierCustom(Right(GetContactsSuccess(contacts: tomContacts))), ); when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, ).thenReturn( - ValueNotifier( + ValueNotifierCustom( Right(GetPhonebookContactsSuccess(contacts: phonebookContacts)), ), ); @@ -2371,12 +2380,12 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier(recentContacts)); + ).thenReturn(ValueNotifierCustom(recentContacts)); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier( + ValueNotifierCustom( Right( GetPresentationContactsSuccess( contacts: tomContacts, @@ -2389,7 +2398,7 @@ void main() { when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, ).thenReturn( - ValueNotifier(const Left(GetPhonebookContactsIsEmpty())), + ValueNotifierCustom(const Left(GetPhonebookContactsIsEmpty())), ); mockContactsViewControllerMixin.refreshAllContactsTest( @@ -2508,18 +2517,18 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier(recentContacts)); + ).thenReturn(ValueNotifierCustom(recentContacts)); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier(Right(GetContactsSuccess(contacts: tomContacts))), + ValueNotifierCustom(Right(GetContactsSuccess(contacts: tomContacts))), ); when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, ).thenReturn( - ValueNotifier( + ValueNotifierCustom( Right(GetPhonebookContactsSuccess(contacts: phonebookContacts)), ), ); @@ -2572,12 +2581,12 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier(recentContacts)); + ).thenReturn(ValueNotifierCustom(recentContacts)); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier( + ValueNotifierCustom( Right( GetPresentationContactsSuccess( contacts: tomContacts, @@ -2590,7 +2599,7 @@ void main() { when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, ).thenReturn( - ValueNotifier(const Left(GetPhonebookContactsIsEmpty())), + ValueNotifierCustom(const Left(GetPhonebookContactsIsEmpty())), ); mockContactsViewControllerMixin.refreshAllContactsTest( @@ -2665,12 +2674,12 @@ void main() { when( mockContactsViewControllerMixin.presentationRecentContactNotifier, - ).thenReturn(ValueNotifier(recentContacts)); + ).thenReturn(ValueNotifierCustom(recentContacts)); when( mockContactsViewControllerMixin.presentationContactNotifier, ).thenReturn( - ValueNotifier( + ValueNotifierCustom( const Right( GetPresentationContactsSuccess( contacts: [], @@ -2683,7 +2692,7 @@ void main() { when( mockContactsViewControllerMixin.presentationPhonebookContactNotifier, ).thenReturn( - ValueNotifier(const Left(GetPhonebookContactsIsEmpty())), + ValueNotifierCustom(const Left(GetPhonebookContactsIsEmpty())), ); mockContactsViewControllerMixin.refreshAllContactsTest(