Skip to content

Commit

Permalink
MAILIOS-4144, Device contacts don't be represented in composer sugges…
Browse files Browse the repository at this point in the history
…tion list
  • Loading branch information
xxi511 authored and xavigil committed Feb 14, 2024
1 parent a7a34e5 commit e4d381c
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,17 @@ class ContactPicker: UIView, AccessibleView {
// #pragma mark - Keyboard Notification Handling
//

/// Reloads the list of contacts only if there is a query string already set. Call this function if more contacts are
/// available to be listed in the picker.
func reloadContactsList() {
guard let query = searchTableViewController?.queryString else {
return
}
// this forces to read the list of contacts again
let filteredContacts = self.filteredContacts(by: query)
searchTableViewController?.filteredContacts = filteredContacts
}

internal func reloadData() {
self.contactCollectionView.selectedContacts.removeAll()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
// You should have received a copy of the GNU General Public License
// along with Proton Mail. If not, see <https://www.gnu.org/licenses/>.

import Combine
import MBProgressHUD
import PromiseKit
import ProtonCoreDataModel
Expand Down Expand Up @@ -59,6 +60,7 @@ class ComposeContentViewController: HorizontallyScrollableWebViewContainer, Acce
var pickedCallback: (([DraftEmailData]) -> Void)?
var groupSubSelectionPresenter: ContactGroupSubSelectionActionSheetPresenter?
private lazy var schemeHandler: ComposerSchemeHandler = .init(imageProxy: dependencies.imageProxy)
private var cancellables = Set<AnyCancellable>()

private let dependencies: Dependencies

Expand Down Expand Up @@ -106,48 +108,42 @@ class ComposeContentViewController: HorizontallyScrollableWebViewContainer, Acce

// load all contacts and groups
viewModel.fetchContacts()
// TODO: move to view model
firstly { [weak self] () -> Promise<Void> in
self?.retrievePhoneContacts() ?? Promise<Void>()
}.done { [weak self] in
guard let self = self else { return }

self.headerView?.toContactPicker?.reloadData()
self.headerView?.ccContactPicker?.reloadData()
self.headerView?.bccContactPicker?.reloadData()

self.headerView?.toContactPicker?.contactCollectionView?.layoutIfNeeded()
self.headerView?.bccContactPicker?.contactCollectionView?.layoutIfNeeded()
self.headerView?.ccContactPicker?.contactCollectionView?.layoutIfNeeded()

delay(0.5) {
// There is a height observer in ComposeContainerViewController
// If the tableview reload, the keyboard will be dismissed
switch self.viewModel.messageAction {
case .openDraft, .reply, .replyAll:
self.headerView?.notifyViewSize(true)
case .forward:
_ = self.headerView?.toContactPicker.becomeFirstResponder()
default:
_ = self.headerView?.toContactPicker.becomeFirstResponder()
}
viewModel.fetchPhoneContacts()

viewModel
.contactsDidChangePublisher
.receive(on: DispatchQueue.main)
.sink { _ in
self.headerView?.toContactPicker?.reloadContactsList()
self.headerView?.ccContactPicker?.reloadContactsList()
self.headerView?.bccContactPicker?.reloadContactsList()
}.store(in: &cancellables)

self.headerView?.toContactPicker?.reloadData()
self.headerView?.ccContactPicker?.reloadData()
self.headerView?.bccContactPicker?.reloadData()

self.headerView?.toContactPicker?.contactCollectionView?.layoutIfNeeded()
self.headerView?.bccContactPicker?.contactCollectionView?.layoutIfNeeded()
self.headerView?.ccContactPicker?.contactCollectionView?.layoutIfNeeded()

delay(0.5) {
// There is a height observer in ComposeContainerViewController
// If the tableview reload, the keyboard will be dismissed
switch self.viewModel.messageAction {
case .openDraft, .reply, .replyAll:
self.headerView?.notifyViewSize(true)
case .forward:
_ = self.headerView?.toContactPicker.becomeFirstResponder()
default:
_ = self.headerView?.toContactPicker.becomeFirstResponder()
}

}.catch { _ in
}

self.viewModel.markAsRead()
generateAccessibilityIdentifiers()
}

private func retrievePhoneContacts() -> Promise<Void> {
return Promise { seal in
viewModel.fetchPhoneContacts {
seal.fulfill(())
}
}
}

@objc
func dismiss() {
if self.presentingViewController != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,25 @@ class ComposeViewModel: NSObject {
return Set(schemes.map(\.rawValue))
}

private(set) var contacts: [ContactPickerModelProtocol] = []
var contacts: [ContactPickerModelProtocol] {
// sort the contact group and phone address together
let sortedContacts = phoneContacts.appending(protonGroupContacts).sorted(by: { $0.contactTitle.lowercased() < $1.contactTitle.lowercased() })
return protonContacts + sortedContacts
}
private var phoneContacts: [ContactPickerModelProtocol] = [] {
didSet {
contactsDidChangePublisher.send()
}
}
private var protonContacts: [ContactPickerModelProtocol] = [] {
didSet {
contactsDidChangePublisher.send()
}
}
private var protonGroupContacts: [ContactPickerModelProtocol] = []
private var emailPublisher: EmailPublisher?
private var cancellable: AnyCancellable?

private(set) var phoneContacts: [ContactPickerModelProtocol] = []

private(set) var messageAction: ComposeMessageAction = .newDraft
private(set) var subject: String = .empty
var body: String = .empty
Expand Down Expand Up @@ -89,6 +102,8 @@ class ComposeViewModel: NSObject {
dependencies.keychain[.metadataStripping] == .stripMetadata
}

let contactsDidChangePublisher = PassthroughSubject<Void, Never>()

// For share extension
init(
subject: String,
Expand Down Expand Up @@ -1253,35 +1268,24 @@ extension ComposeViewModel {
filteredResult.append(contact)
}
}
self?.contacts = filteredResult
self?.addContactWithPhoneContact()
self?.protonContacts = filteredResult
})
emailPublisher?.start()
fetchGroupContacts()
}

func fetchPhoneContacts(completion: (() -> Void)?) {
func fetchPhoneContacts() {
let service = user.contactService
service.getContactVOsFromPhone { contacts, error in
DispatchQueue.main.async {
self.phoneContacts = contacts
completion?()
}
}
}

private func addContactWithPhoneContact() {
var contactsWithoutLastTimeUsed: [ContactPickerModelProtocol] = phoneContacts

if user.hasPaidMailPlan {
let contactGroupsToAdd = user.contactGroupService.getAllContactGroupVOs().filter {
$0.contactCount > 0
}
contactsWithoutLastTimeUsed.append(contentsOf: contactGroupsToAdd)
}
// sort the contact group and phone address together
contactsWithoutLastTimeUsed.sort(by: { $0.contactTitle.lowercased() < $1.contactTitle.lowercased() })

self.contacts += contactsWithoutLastTimeUsed
private func fetchGroupContacts() {
guard user.hasPaidMailPlan else { return }
protonGroupContacts = user.contactGroupService.getAllContactGroupVOs().filter { $0.contactCount > 0 }
}
}

Expand Down

0 comments on commit e4d381c

Please sign in to comment.