Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GROOMING-REVIEW] Contact sync v2 #2205

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
f49e459
[SYNC-CONTACT-V2] Create new contact model v2
nqhhdev Jan 7, 2025
d65f2df
[SYNC-CONTACT-V2] Create fetch contact on new datasource
nqhhdev Jan 7, 2025
62c11f6
[SYNC-CONTACT-V2] Add unit test for `fetchContacts` func on new datas…
nqhhdev Jan 7, 2025
3179301
[SYNC-CONTACT-V2] Update check duplicated email
nqhhdev Jan 14, 2025
d810993
[SYNC-CONTACT-V2] Add `altLookupPeppers` to `HashDetailsResponse`
nqhhdev Jan 14, 2025
c09e41b
[SYNC-CONTACT-V2] Update `LookupListMxidResponse`
nqhhdev Jan 15, 2025
4100dc7
[SYNC-CONTACT-V2] Create `PhonebookContactRepositoryV2`
nqhhdev Jan 15, 2025
28596a4
[SYNC-CONTACT-V2] Update `calculateHashUsingAllPeppers` func
nqhhdev Jan 15, 2025
e505675
[SYNC-CONTACT-V2] Create `PhonebookContactInteractorV2`
nqhhdev Jan 15, 2025
d82a71b
[SYNC-CONTACT-V2] Update get phonebook interactor
nqhhdev Jan 16, 2025
0acfdf2
[SYNC-CONTACT-V2] Update sort contact and remove duplicated email
nqhhdev Jan 16, 2025
6c72fe6
[SYNC-CONTACT-V2] Fix up phonebook contact interactor
nqhhdev Jan 16, 2025
1e8cd29
[SYNC-CONTACT-V2] Mock data for phonebook contact
nqhhdev Jan 16, 2025
d5b2337
[temp] mock data for lookup request
hoangdat Jan 16, 2025
0ddca20
[SYNC-CONTACT-V2] Mock response for hash details
nqhhdev Jan 16, 2025
4cf4c8d
[SYNC-CONTACT-V2] Update contact model
nqhhdev Jan 20, 2025
33eccfd
[SYNC-CONTACT-V2] Update data layer
nqhhdev Jan 20, 2025
85c4b92
[SYNC-CONTACT-V2] Update mock data
nqhhdev Jan 21, 2025
636f42f
[SYNC-CONTACT-V2] Integration UI with mock data
nqhhdev Jan 22, 2025
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
5 changes: 5 additions & 0 deletions lib/data/datasource/contact/phonebook_datasource_v2.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import 'package:fluffychat/domain/model/contact/contact_new.dart';

abstract class PhonebookContactDatasourceV2 {
Future<List<Contact>> fetchContacts();
}
2 changes: 1 addition & 1 deletion lib/data/datasource/tom_contacts_datasource.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:fluffychat/domain/model/contact/contact.dart';
import 'package:fluffychat/domain/model/contact/contact_new.dart';
import 'package:fluffychat/domain/model/contact/contact_query.dart';
import 'package:fluffychat/domain/model/contact/lookup_mxid_request.dart';

Expand Down
142 changes: 136 additions & 6 deletions lib/data/datasource_impl/contact/lookup_datasource_impl.dart
Original file line number Diff line number Diff line change
@@ -1,22 +1,152 @@
import 'package:fluffychat/data/datasource/lookup_datasource.dart';
import 'package:fluffychat/data/network/contact/lookup_api.dart';
import 'package:fluffychat/di/global/get_it_initializer.dart';

// import 'package:fluffychat/data/network/contact/lookup_api.dart';
// import 'package:fluffychat/di/global/get_it_initializer.dart';
import 'package:fluffychat/domain/model/contact/hash_details_response.dart';
import 'package:fluffychat/domain/model/contact/lookup_list_mxid_request.dart';
import 'package:fluffychat/domain/model/contact/lookup_list_mxid_response.dart';

class LookupDatasourceImpl implements LookupDatasource {
final LookupAPI _lookupAPI = getIt.get<LookupAPI>();
// final LookupAPI _lookupAPI = getIt.get<LookupAPI>();

@override
Future<HashDetailsResponse> getHashDetails() {
return _lookupAPI.getHashDetails();
Future<HashDetailsResponse> getHashDetails() async {
// TODO: Implement this method
// return _lookupAPI.getHashDetails();

return _mockHashDetailsResponse();
}

@override
Future<LookupListMxidResponse> lookupListMxid(
LookupListMxidRequest request,
) async {
return _lookupAPI.lookupListMxid(request);
final mappings = [
mapping1,
mapping2,
mapping3,
mapping4,
mapping5,
mapping6,
mapping7,
mapping8,
mapping9,
mapping10,
mapping11,
mapping12,
mapping13,
];

for (final mapping in mappings) {
if (request.addresses?.containsAll(mapping.keys) == true) {
await Future.delayed(const Duration(seconds: 2));
return _createLookupListMxidResponse(mapping);
}
}

return _createLookupListMxidResponse({});
}

// [TEMP] Mock response
HashDetailsResponse _mockHashDetailsResponse() {
return const HashDetailsResponse(
algorithms: {
"sha256",
},
lookupPepper: "your-pepper-string",
altLookupPeppers: {},
);
}

LookupListMxidResponse _createLookupListMxidResponse(
Map<String, String> mapping,
) {
return LookupListMxidResponse(
mappings: mapping,
);
}

final mapping1 = {
"fJcNGXVoRaa8cxZJpE9gfVX4JF4u1cWUb7SzlGXIWSI": "@hello1:matrix.org",
"Rs8uZy6KNiVcjpk1dDKtsvrB9LTNEpNU5ZyZnP1txjo": "@hello3:matrix.org",
"1rqNXP6OpnZrXtlA_k0NE6a-8vdmLwlm8lyKF0wTYq4": "@hello5:matrix.org",
"fBIs-RZlUX9sfHtHo_dvRBAvNpUqPgfC8cUPUbkXXIU": "@hello7:matrix.org",
"PIfY-6L-CB9h3YzC1Mn33EtXv5TFbTETHC7FERgBWpw": "@hello9:matrix.org",
};

final mapping2 = {
"mMdPZHt4WrzcqlCL2KRpDSqZVyw1kGld-SmGVfwFQcU": "@hello11:matrix.org",
"lxvAR5E06tcWbuZoaTnG3TnGAAUoW4mkT8S2yu5SCT8": "@hello13:matrix.org",
"3i7Wh86KNkH8-BIC4PypN9j4mnP9k_qR1riO_oHHxmE": "@hello15:matrix.org",
};

final mapping3 = {
"tW3qKESX2ptWMrsSP2sKO4vYK-0Wp-m91tdqDULuMyE": "@hello21:matrix.org",
"tFSISDS7qbRU1AXjqQ9NOpxOytv9E603eWY7j34bw4M": "hello24:matrix.org",
"HEPHSgkhTDGWWhu7DOWgwhDfW-iXgmoalzKqfgk-rws": "@hello25:matrix.org",
"ppKaWeAwOOHYVsdaGqoPrjTO-9azTzjoS2ROlB-VuWI": "@hello29:matrix.org",
"5j3Q5o8nFu1AtQ0XjbVHnNacT110P0z52AK27Oj_Kw4": "@hello30:matrix.org",
};

final mapping4 = {
"QDLfPwaO2HnZyb-6ywscoxJ5qvsAJjbJIPAPg4zH0Es": "@hello31:matrix.org",
"yjk5lzHL_XSP4Un-6wuH_Lna558IZMLksuSntEq2xaY": "@hello32:matrix.org",
"EWujCkcxjriGcHp3316jNl3GCCHm952FuBgZKViHICg": "@hello33:matrix.org",
"zMGiIN-TN4lVmCAR63phhDfqHSCQyOL1c-3fqmpW50g": "@hello34:matrix.org",
"iC7b4PG4a7vwyqF8ITiMZMxVQPHFELK02uPECh1NorU": "@hello35:matrix.org",
"HMSCmpsEvNIkgmGUAxOLCB5IYCLlumDnS4aSEm8ecgE": "@hello36:matrix.org",
"-jWCkSp5FqBVudCEYADpHa-fXk42b7rt5zwKIBDOBdA": "@hello37:matrix.org",
"3kHKgujM9UrS6DvI1nXlt-cDpFAKr68Lb927U6zP5ns": "@hello39:matrix.org",
};

final mapping5 = {
"33Nl5nMsY2E7-xzASrFxzvHeYVdBFzzbsU6ncqUU2k8": "@hello45:matrix.org",
};

final mapping6 = {
"Dmw20FcaG8I7t9D27FoxsDYjwxdkvyskJU5F-Gji4qE": "@hello51:matrix.org",
"9C-kscxjsIYgRDt4RpPSJzyjeFwqbctAqzupKXUeSko": "@hello52:matrix.org",
"ZnZozSu5fyBocNQFUoa47Ww6IuiruUEaIgxyVr7vpvc": "@hello53:matrix.org",
"zM2nsjxiGaE_8C3EuJyv_vpJK7Rpp7XA5BL6rnGKuXc": "@hello54:matrix.org",
"LJ7b4GxljYBbT0lmcKsvYDY2UdcuKBuTuDaWtV9WvUo": "@hello55:matrix.org",
"y71UYBG6QjLxf4yFIJBnqKrHKKg8pW7Qn4II7I4EQD0": "@hello56:matrix.org",
"lBt2yLPK_J5oMbtQA5AcwHF7BvpcxaErEFHPZiIRELw": "@hello57:matrix.org",
"bNdiPfDVW8Kj8osBT1rDYkg--QY_FhPT8dpk6_1KySI": "@hello58:matrix.org",
};

final mapping7 = {
"1KMDVNNUBOVrsXmBjLOX00qaZjEzZYiVGKSOl7Xh8yA": "@hello61:matrix.org",
"q12hf3M4aP6ywGHjAAaG9gIYgauVDfYuS3Zyc_r5Tvs": "@hello62:matrix.org",
"5MswbBSEl5uvf7h5JecoXgFvfPeddMVej_u5CM1uMXE": "@hello63:matrix.org",
"DORPEU8wI0uDdjKWxSY12gnWw_pfTFvb-yo715eLVg": "@hello64:matrix.org",
"ukMYUaIQ6lI6lE5UnJUjXplaPkflPh5IXJ5pPD1Gy2k": "@hello65:matrix.org",
"y4dnb1YSFotwcMPzFDRxT5DvV4gyrcjwNNBeqaUzzlk": "@hello67:matrix.org",
"YAeYKxhTZXc1cR1NWt6Sx_06kfOaLnBtZHw-idfQDiY": "@hello69:matrix.org",
};
final mapping8 = {
"Vl4VMUfsMJT8JExN5_-bWmaCMXEUXurK6zLk-wZ1RiQ": "@hello71:matrix.org",
"WUUcVbuq8nYl2rxuI7PjX8ltjIObQrj26fyTxvhL1yM": "@hello72:matrix.org",
"joKCqtbf5ESNsHR8MiMgYi_6I__Vb7u7sDsNhvFiyRQ": "@hello74:matrix.org",
};

final mapping9 = {
"p9b0OuiUPeBkvYyWiJtQbxJWQWDjT-na--zuQW57FRw": "@hello81:matrix.org",
};
final mapping10 = {
"5RN14rVi1Y0Duen0XcMNIig8pV0aUzj6P4kOOZKQWwc": "@hello91:matrix.org",
"rmxEC4cVsjx-YFTS8Z8epWn2emSOsr5wTYIuPSqdAAw": "@hello92:matrix.org",
};

final mapping11 = {
"j8jA8FYPxtccIP2yRkrusmcxu59mxBgjM3-PV1Y66ec": "@hello105:matrix.org",
};
final mapping12 = {
"laIgw-feEKS-lE-r0KVH-1Xu_ioazfiZSJmtGWmHNNg": "@hello112:matrix.org",
"dzN5qAjM4SRRDnoS9n-qUQ5ztEF9KwgpyE6Hh1gnGPk": "@hello113:matrix.org",
};

final mapping13 = {
"ODQ5ODY0MTc0OTIgbXNpc2RuIHlvdXItcGVwcGVyLXN0cmluZw":
"@hello123:matrix.org",
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import 'package:fluffychat/domain/model/contact/contact_new.dart';
import 'package:fluffychat/utils/string_extension.dart';
import 'package:flutter_contacts/flutter_contacts.dart' as flutter_contact;
import 'package:fluffychat/data/datasource/contact/phonebook_datasource_v2.dart';

class PhonebookContactDatasourceV2Impl implements PhonebookContactDatasourceV2 {
@override
Future<List<Contact>> fetchContacts() async {
final phonebookContacts =
await flutter_contact.FlutterContacts.getContacts(withProperties: true);

final contacts = mappingToContact(phonebookContacts);
return _sortContactsByDisplayName(contacts);
}

List<Contact> mappingToContact(
List<flutter_contact.Contact> phoneBookContacts,
) {
final listAllContacts = phoneBookContacts.map((contact) {
final phoneNumbers = contact.phones
.map((phone) => PhoneNumber(number: phone.number))
.toList();
final emails =
contact.emails.map((email) => Email(address: email.address)).toList();

return Contact(
id: contact.id,
displayName: contact.displayName,
phoneNumbers: _removeDuplicatedPhoneNumbers(phoneNumbers).toSet(),
emails: _removeDuplicatedEmails(emails).toSet(),
);
}).toList();

return listAllContacts;
}

List<Contact> _sortContactsByDisplayName(List<Contact> contacts) {
contacts.sort(
(pre, next) => (pre.displayName ?? '').compareTo(next.displayName ?? ''),
);
return contacts;
}

List<PhoneNumber> _removeDuplicatedPhoneNumbers(
List<PhoneNumber> phoneNumbers,
) {
final listVisitedPhoneNumbers = <String>[];
final filteredPhoneNumbers = <PhoneNumber>[];

for (final contact in phoneNumbers) {
final phoneNumber = contact.number;
final normalizedPhoneNumber = phoneNumber.normalizePhoneNumber();

if (listVisitedPhoneNumbers.contains(normalizedPhoneNumber)) {
final hasSameFilteredContact = _hasSameFilteredPhoneNumber(
filteredPhoneNumbers,
normalizedPhoneNumber,
);
if (!hasSameFilteredContact) {
filteredPhoneNumbers.add(contact);
}
} else {
listVisitedPhoneNumbers.add(normalizedPhoneNumber);
filteredPhoneNumbers.add(contact);
}
}

return filteredPhoneNumbers;
}

bool _hasSameFilteredPhoneNumber(
List<PhoneNumber> filteredPhoneNumbers,
String phoneNumberNormalized,
) {
return filteredPhoneNumbers.any(
(filteredContact) =>
filteredContact.number.normalizePhoneNumber() ==
phoneNumberNormalized,
);
}

List<Email> _removeDuplicatedEmails(List<Email> emails) {
final listVisitedEmails = <String>[];
final filteredEmails = <Email>[];

for (final email in emails) {
final emailAddress = email.address;

if (listVisitedEmails.contains(emailAddress)) {
final hasSameFilteredEmail = _hasSameFilteredEmail(
filteredEmails,
emailAddress,
);
if (!hasSameFilteredEmail) {
filteredEmails.add(email);
}
} else {
listVisitedEmails.add(emailAddress);
filteredEmails.add(email);
}
}

return filteredEmails;
}

bool _hasSameFilteredEmail(
List<Email> filteredEmails,
String emailAddress,
) {
return filteredEmails.any(
(filteredEmail) => filteredEmail.address == emailAddress,
);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'package:fluffychat/data/datasource/tom_contacts_datasource.dart';
import 'package:fluffychat/data/network/contact/tom_contact_api.dart';
import 'package:fluffychat/di/global/get_it_initializer.dart';
import 'package:fluffychat/domain/model/contact/contact.dart';
import 'package:fluffychat/domain/model/contact/contact_new.dart';
import 'package:fluffychat/domain/model/contact/contact_query.dart';
import 'package:fluffychat/domain/model/contact/contact_status.dart';
import 'package:fluffychat/domain/model/contact/lookup_mxid_request.dart';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'package:fluffychat/data/datasource/tom_contacts_datasource.dart';
import 'package:fluffychat/di/global/get_it_initializer.dart';
import 'package:fluffychat/domain/model/contact/contact.dart';
import 'package:fluffychat/domain/model/contact/contact_new.dart';
import 'package:fluffychat/domain/model/contact/contact_query.dart';
import 'package:fluffychat/domain/model/contact/lookup_mxid_request.dart';
import 'package:fluffychat/domain/repository/contact_repository.dart';
Expand Down
9 changes: 9 additions & 0 deletions lib/di/global/get_it_initializer.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:collection';

import 'package:fluffychat/config/app_grid_config/app_config_loader.dart';
import 'package:fluffychat/data/datasource/contact/phonebook_datasource_v2.dart';
import 'package:fluffychat/data/datasource/localizations/localizations_datasource.dart';
import 'package:fluffychat/data/datasource/lookup_datasource.dart';
import 'package:fluffychat/data/datasource/media/media_data_source.dart';
Expand All @@ -13,6 +14,7 @@ import 'package:fluffychat/data/datasource/tom_configurations_datasource.dart';
import 'package:fluffychat/data/datasource/tom_contacts_datasource.dart';
import 'package:fluffychat/data/datasource_impl/contact/lookup_datasource_impl.dart';
import 'package:fluffychat/data/datasource_impl/contact/phonebook_contact_datasource_impl.dart';
import 'package:fluffychat/data/datasource_impl/contact/phonebook_contact_datasource_v2_impl.dart';
import 'package:fluffychat/data/datasource_impl/contact/tom_contacts_datasource_impl.dart';
import 'package:fluffychat/data/datasource_impl/localizations/localizations_datasource_impl.dart';
import 'package:fluffychat/data/datasource_impl/media/media_data_source_impl.dart';
Expand Down Expand Up @@ -55,6 +57,7 @@ import 'package:fluffychat/domain/repository/server_search_repository.dart';
import 'package:fluffychat/domain/repository/tom_configurations_repository.dart';
import 'package:fluffychat/domain/usecase/app_grid/get_app_grid_configuration_interactor.dart';
import 'package:fluffychat/domain/usecase/contacts/lookup_match_contact_interactor.dart';
import 'package:fluffychat/domain/usecase/contacts/phonebook_contact_interactor_v2.dart';
import 'package:fluffychat/domain/usecase/create_direct_chat_interactor.dart';
import 'package:fluffychat/domain/usecase/download_file_for_preview_interactor.dart';
import 'package:fluffychat/domain/usecase/forward/forward_message_interactor.dart';
Expand Down Expand Up @@ -206,6 +209,9 @@ class GetItInitializer {
getIt.registerFactory<PhonebookContactDatasource>(
() => PhonebookContactDatasourceImpl(),
);
getIt.registerFactory<PhonebookContactDatasourceV2>(
() => PhonebookContactDatasourceV2Impl(),
);
getIt.registerLazySingleton(
() => MediaDataSourceImpl(
getIt.get<MediaAPI>(),
Expand Down Expand Up @@ -271,6 +277,9 @@ class GetItInitializer {
getIt.registerFactory<PhonebookContactInteractor>(
() => PhonebookContactInteractor(),
);
getIt.registerFactory<PhonebookContactInteractorV2>(
() => PhonebookContactInteractorV2(),
);
getIt.registerSingleton<DownloadFileForPreviewInteractor>(
DownloadFileForPreviewInteractor(),
);
Expand Down
2 changes: 1 addition & 1 deletion lib/domain/app_state/contact/get_contacts_state.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'package:fluffychat/app_state/failure.dart';
import 'package:fluffychat/app_state/initial.dart';
import 'package:fluffychat/app_state/success.dart';
import 'package:fluffychat/domain/model/contact/contact.dart';
import 'package:fluffychat/domain/model/contact/contact_new.dart';

class ContactsInitial extends Initial {
const ContactsInitial() : super();
Expand Down
Loading
Loading