Skip to content

Commit

Permalink
TW-1791: Improve display contacts on multiple homeserver (#1857)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
nqhhdev authored Jun 17, 2024
1 parent d628f95 commit e2e7668
Show file tree
Hide file tree
Showing 8 changed files with 918 additions and 107 deletions.
6 changes: 6 additions & 0 deletions lib/app_state/success.dart
Original file line number Diff line number Diff line change
@@ -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();
Expand All @@ -10,4 +11,9 @@ extension SuccessExtension on Either {
(failure) => fallbackValue,
(success) => success is T ? success : fallbackValue,
);

T? getFailureOrNull<T extends Failure>({T? fallbackValue}) => fold(
(failure) => failure is T ? failure : fallbackValue,
(success) => fallbackValue,
);
}
28 changes: 18 additions & 10 deletions lib/domain/contact_manager/contacts_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -17,24 +17,25 @@ class ContactsManager {

bool _doNotShowWarningContactsBannerAgain = false;

final ValueNotifier<Either<Failure, Success>> _contactsNotifier =
ValueNotifier(const Right(ContactsInitial()));
final ValueNotifierCustom<Either<Failure, Success>> _contactsNotifier =
ValueNotifierCustom(const Right(ContactsInitial()));

final ValueNotifier<Either<Failure, Success>> _phonebookContactsNotifier =
ValueNotifier(const Right(GetPhonebookContactsInitial()));
final ValueNotifierCustom<Either<Failure, Success>>
_phonebookContactsNotifier =
ValueNotifierCustom(const Right(GetPhonebookContactsInitial()));

ContactsManager({
required this.getTomContactsInteractor,
required this.phonebookContactInteractor,
});

ValueNotifier<Either<Failure, Success>> getContactsNotifier() =>
ValueNotifierCustom<Either<Failure, Success>> getContactsNotifier() =>
_contactsNotifier;

ValueNotifier<Either<Failure, Success>> getPhonebookContactsNotifier() =>
_phonebookContactsNotifier;
ValueNotifierCustom<Either<Failure, Success>>
getPhonebookContactsNotifier() => _phonebookContactsNotifier;

bool get _isInitial =>
bool get _isSynchronizedTomContacts =>
_contactsNotifier.value.getSuccessOrNull<ContactsInitial>() != null;

bool get isDoNotShowWarningContactsBannerAgain =>
Expand All @@ -44,10 +45,16 @@ class ContactsManager {
_doNotShowWarningContactsBannerAgain = value;
}

Future<void> reSyncContacts() async {
_contactsNotifier.value = const Right(ContactsInitial());
_phonebookContactsNotifier.value =
const Right(GetPhonebookContactsInitial());
}

void initialSynchronizeContacts({
bool isAvailableSupportPhonebookContacts = false,
}) async {
if (!_isInitial) {
if (!_isSynchronizedTomContacts) {
return;
}
_getAllContacts(
Expand Down Expand Up @@ -76,6 +83,7 @@ class ContactsManager {
if (!isAvailableSupportPhonebookContacts) {
return;
}

phonebookContactInteractor
.execute(lookupChunkSize: _lookupChunkSize)
.listen(
Expand Down
1 change: 1 addition & 0 deletions lib/pages/multiple_accounts/multiple_accounts_picker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ class MultipleAccountsPickerController {
Future<void> _setActiveClient(Client newClient) async {
final result = await _matrixState.setActiveClient(newClient);
if (result.isSuccess) {
_matrixState.reSyncContacts();
context.go(
'/rooms',
extra: SwitchActiveAccountBodyArgs(
Expand Down
15 changes: 15 additions & 0 deletions lib/presentation/extensions/value_notifier_custom.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import 'package:flutter/foundation.dart';

class ValueNotifierCustom<T> extends ValueNotifier<T> {
bool _isDisposed = false;

ValueNotifierCustom(super.value);

bool get isDisposed => _isDisposed;

@override
void dispose() {
_isDisposed = true;
super.dispose();
}
}
20 changes: 15 additions & 5 deletions lib/presentation/mixins/contacts_view_controller_mixin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -45,14 +46,15 @@ mixin class ContactsViewControllerMixin {
final ValueNotifier<bool> isSearchModeNotifier = ValueNotifier(false);

final presentationRecentContactNotifier =
ValueNotifier<List<PresentationSearch>>([]);
ValueNotifierCustom<List<PresentationSearch>>([]);

final presentationContactNotifier = ValueNotifier<Either<Failure, Success>>(
final presentationContactNotifier =
ValueNotifierCustom<Either<Failure, Success>>(
const Right(ContactsInitial()),
);

final presentationPhonebookContactNotifier =
ValueNotifier<Either<Failure, Success>>(
ValueNotifierCustom<Either<Failure, Success>>(
const Right(GetPhonebookContactsInitial()),
);

Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -151,6 +157,7 @@ mixin class ContactsViewControllerMixin {
}

Future<void> _refreshContacts(String keyword) async {
if (presentationContactNotifier.isDisposed) return;
presentationContactNotifier.value =
contactsManager.getContactsNotifier().value.fold(
(failure) {
Expand Down Expand Up @@ -198,6 +205,7 @@ mixin class ContactsViewControllerMixin {
}

Future<void> _refreshPhoneBookContacts(String keyword) async {
if (presentationPhonebookContactNotifier.isDisposed) return;
presentationPhonebookContactNotifier.value =
contactsManager.getPhonebookContactsNotifier().value.fold(
(failure) {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down
25 changes: 23 additions & 2 deletions lib/widgets/matrix.dart
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -76,6 +77,8 @@ class MatrixState extends State<Matrix>
with WidgetsBindingObserver, ReceiveSharingIntentMixin, InitConfigMixin {
final tomConfigurationRepository = getIt.get<ToMConfigurationsRepository>();

final _contactsManager = getIt.get<ContactsManager>();

int _activeClient = -1;
String? activeBundle;
Store store = Store();
Expand Down Expand Up @@ -398,6 +401,7 @@ class MatrixState extends State<Matrix>
await _cancelSubs(currentClient.clientName);
widget.clients.remove(currentClient);
await ClientManager.removeClientNameFromStore(currentClient.clientName);
matrixState.reSyncContacts();
TwakeSnackBar.show(
TwakeApp.routerKey.currentContext!,
L10n.of(context)!.oneClientLoggedOut,
Expand All @@ -423,6 +427,7 @@ class MatrixState extends State<Matrix>
waitForFirstSync = false;
await setUpToMServicesInLogin(newActiveClient);
await _storePersistActiveAccount(newActiveClient);
matrixState.reSyncContacts();
onClientLoginStateChanged.add(
ClientLoginStateEvent(
client: client,
Expand Down Expand Up @@ -452,6 +457,7 @@ class MatrixState extends State<Matrix>
waitForFirstSync = false;
await setUpToMServicesInLogin(activeClient);
final result = await setActiveClient(activeClient);
matrixState.reSyncContacts();
if (result.isSuccess) {
onClientLoginStateChanged.add(
ClientLoginStateEvent(
Expand Down Expand Up @@ -593,7 +599,9 @@ class MatrixState extends State<Matrix>
ToMServerInformation tomServer,
IdentityServerInformation? identityServer,
) {
Logs().d('MatrixState::setUpToMServices: $tomServer, $identityServer');
Logs().d(
'MatrixState::setUpToMServices: $tomServer, ${identityServer?.baseUrl}',
);
_setUpToMServer(tomServer);
if (identityServer != null) {
_setUpIdentityServer(identityServer);
Expand Down Expand Up @@ -637,6 +645,9 @@ class MatrixState extends State<Matrix>

void setUpAuthorization(Client client) {
final authorizationInterceptor = getIt.get<AuthorizationInterceptor>();
Logs().d(
'MatrixState::setUpAuthorization: accessToken ${client.accessToken}',
);
authorizationInterceptor.accessToken = client.accessToken;
}

Expand Down Expand Up @@ -710,13 +721,18 @@ class MatrixState extends State<Matrix>
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(
Expand Down Expand Up @@ -801,6 +817,7 @@ class MatrixState extends State<Matrix>
}

Future<void> _handleLastLogout() async {
matrixState.reSyncContacts();
if (PlatformInfos.isMobile) {
await _deletePersistActiveAccount();
TwakeApp.router.go('/home/twakeWelcome');
Expand All @@ -810,6 +827,10 @@ class MatrixState extends State<Matrix>
await _deleteAllTomConfigurations();
}

Future<void> reSyncContacts() async {
_contactsManager.reSyncContacts();
}

@override
void didChangeAppLifecycleState(AppLifecycleState state) {
Logs().i('didChangeAppLifecycleState: AppLifecycleState = $state');
Expand Down
Loading

0 comments on commit e2e7668

Please sign in to comment.