Skip to content

Commit

Permalink
Merge pull request #369 from 64characters/discarding-contact-matching…
Browse files Browse the repository at this point in the history
…-index

Discarding contact matching index
  • Loading branch information
eofster committed Jun 29, 2017
2 parents fd202ef + befde94 commit 8c0e72c
Show file tree
Hide file tree
Showing 17 changed files with 528 additions and 155 deletions.
78 changes: 67 additions & 11 deletions Telephone.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

@@ -0,0 +1,42 @@
//
// ABAddressBookNotificationsToContactsChangeEventTargetAdapter.swift
// Telephone
//
// Copyright © 2008-2016 Alexey Kuznetsov
// Copyright © 2016-2017 64 Characters
//
// Telephone is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Telephone is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//

import AddressBook
import Foundation
import UseCases

final class ABAddressBookNotificationsToContactsChangeEventTargetAdapter {
private let center: NotificationCenter
private let target: ContactsChangeEventTarget

init(center: NotificationCenter, target: ContactsChangeEventTarget) {
self.center = center
self.target = target
center.addObserver(self, selector: #selector(contactsDidChange), name: .abDatabaseChanged, object: nil)
center.addObserver(self, selector: #selector(contactsDidChange), name: .abDatabaseChangedExternally, object: nil)
}

deinit {
center.removeObserver(self, name: .abDatabaseChanged, object: nil)
center.removeObserver(self, name: .abDatabaseChangedExternally, object: nil)
}

@objc private func contactsDidChange(_ notification: Notification) {
target.contactsDidChange()
}
}
11 changes: 6 additions & 5 deletions Telephone/ABAddressBookToContactsAdapter.swift
Expand Up @@ -19,14 +19,15 @@
import AddressBook
import UseCases

final class ABAddressBookToContactsAdapter {
fileprivate lazy var book: ABAddressBook? = ABAddressBook()
fileprivate lazy var nameOrdering: Int = self.book?.defaultNameOrdering() ?? Int(kABFirstNameFirst)
}
final class ABAddressBookToContactsAdapter {}

extension ABAddressBookToContactsAdapter: Contacts {
func enumerate(_ body: @escaping (Contact) -> Void) {
guard let book = self.book else { return }
guard let book = ABAddressBook() as ABAddressBook? else { return }
enumerateRecords(in: book, nameOrdering: book.defaultNameOrdering(), body: body)
}

private func enumerateRecords(in book: ABAddressBook, nameOrdering: Int, body: @escaping (Contact) -> Void) {
for record in book.people() {
if let person = record as? ABPerson {
body(Contact.init(person, nameOrdering: nameOrdering))
Expand Down
@@ -0,0 +1,41 @@
//
// CNContactStoreNotificationsToContactsChangeEventTargetAdapter.swift
// Telephone
//
// Copyright © 2008-2016 Alexey Kuznetsov
// Copyright © 2016-2017 64 Characters
//
// Telephone is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Telephone is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//

import Contacts
import Foundation
import UseCases

@available(OSX 10.11, *)
final class CNContactStoreNotificationsToContactsChangeEventTargetAdapter {
private let center: NotificationCenter
private let target: ContactsChangeEventTarget

init(center: NotificationCenter, target: ContactsChangeEventTarget) {
self.center = center
self.target = target
center.addObserver(self, selector: #selector(contactsDidChange), name: .CNContactStoreDidChange, object: nil)
}

deinit {
center.removeObserver(self, name: .CNContactStoreDidChange, object: nil)
}

@objc private func contactsDidChange(_ notification: Notification) {
target.contactsDidChange()
}
}
22 changes: 18 additions & 4 deletions Telephone/CompositionRoot.swift
Expand Up @@ -39,6 +39,7 @@ final class CompositionRoot: NSObject {
private let devicesChangeEventSource: SystemAudioDevicesChangeEventSource!
private let accountsNotificationsToEventTargetAdapter: AccountsNotificationsToEventTargetAdapter
private let callNotificationsToEventTargetAdapter: CallNotificationsToEventTargetAdapter
private let contactStoreNotificationsToContactsChangeEventTargetAdapter: Any

init(preferencesControllerDelegate: PreferencesControllerDelegate, conditionalRingtonePlaybackUseCaseDelegate: ConditionalRingtonePlaybackUseCaseDelegate) {
userAgent = AKSIPUserAgent.shared()
Expand Down Expand Up @@ -188,15 +189,28 @@ final class CompositionRoot: NSObject {
queue: contactsBackground)
)

let main = GCDExecutionQueue(queue: DispatchQueue.main)
let contactMatchingSettings = SimpleContactMatchingSettings(settings: defaults)
let contactMatchingIndex = LazyDiscardingContactMatchingIndex(
factory: SimpleContactMatchingIndexFactory(contacts: contacts, settings: contactMatchingSettings)
)
let contactsChangeEventTarget = EnqueuingContactsChangeEventTarget(origin: contactMatchingIndex, queue: contactsBackground)

if #available(macOS 10.11, *) {
contactStoreNotificationsToContactsChangeEventTargetAdapter = CNContactStoreNotificationsToContactsChangeEventTargetAdapter(
center: NotificationCenter.default, target: contactsChangeEventTarget
)
} else {
contactStoreNotificationsToContactsChangeEventTargetAdapter = ABAddressBookNotificationsToContactsChangeEventTargetAdapter(
center: NotificationCenter.default, target: contactsChangeEventTarget
)
}

let main = GCDExecutionQueue(queue: DispatchQueue.main)

callHistoryViewEventTargetFactory = AsyncCallHistoryViewEventTargetFactory(
origin: CallHistoryViewEventTargetFactory(
histories: callHistories,
index: LazyContactMatchingIndex(
factory: SimpleContactMatchingIndexFactory(contacts: contacts), settings: contactMatchingSettings
),
index: contactMatchingIndex,
settings: contactMatchingSettings,
dateFormatter: ShortRelativeDateTimeFormatter(),
durationFormatter: DurationFormatter(),
Expand Down
2 changes: 1 addition & 1 deletion UseCases/ContactMatchingIndexFactory.swift
Expand Up @@ -17,5 +17,5 @@
//

public protocol ContactMatchingIndexFactory {
func make(maxPhoneNumberLength length: Int) -> ContactMatchingIndex
func make() -> ContactMatchingIndex
}
21 changes: 21 additions & 0 deletions UseCases/ContactsChangeEventTarget.swift
@@ -0,0 +1,21 @@
//
// ContactsChangeEventTarget.swift
// Telephone
//
// Copyright © 2008-2016 Alexey Kuznetsov
// Copyright © 2016-2017 64 Characters
//
// Telephone is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Telephone is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//

public protocol ContactsChangeEventTarget {
func contactsDidChange()
}
35 changes: 35 additions & 0 deletions UseCases/EnqueuingContactsChangeEventTarget.swift
@@ -0,0 +1,35 @@
//
// EnqueuingContactsChangeEventTarget.swift
// Telephone
//
// Copyright © 2008-2016 Alexey Kuznetsov
// Copyright © 2016-2017 64 Characters
//
// Telephone is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Telephone is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//

public final class EnqueuingContactsChangeEventTarget {
fileprivate let origin: ContactsChangeEventTarget
fileprivate let queue: ExecutionQueue

public init(origin: ContactsChangeEventTarget, queue: ExecutionQueue) {
self.origin = origin
self.queue = queue
}
}

extension EnqueuingContactsChangeEventTarget: ContactsChangeEventTarget {
public func contactsDidChange() {
queue.add {
self.origin.contactsDidChange()
}
}
}
@@ -1,5 +1,5 @@
//
// LazyContactMatchingIndex.swift
// LazyDiscardingContactMatchingIndex.swift
// Telephone
//
// Copyright © 2008-2016 Alexey Kuznetsov
Expand All @@ -16,21 +16,17 @@
// GNU General Public License for more details.
//

public final class LazyContactMatchingIndex {
fileprivate lazy var origin: ContactMatchingIndex = {
return self.factory.make(maxPhoneNumberLength: self.settings.significantPhoneNumberLength)
}()
public final class LazyDiscardingContactMatchingIndex {
fileprivate lazy var origin: ContactMatchingIndex! = { return self.factory.make() }()

private let factory: ContactMatchingIndexFactory
private let settings: ContactMatchingSettings
fileprivate let factory: ContactMatchingIndexFactory

public init(factory: ContactMatchingIndexFactory, settings: ContactMatchingSettings) {
public init(factory: ContactMatchingIndexFactory) {
self.factory = factory
self.settings = settings
}
}

extension LazyContactMatchingIndex: ContactMatchingIndex {
extension LazyDiscardingContactMatchingIndex: ContactMatchingIndex {
public func contact(forPhone phone: ExtractedPhoneNumber) -> MatchedContact? {
return origin.contact(forPhone: phone)
}
Expand All @@ -39,3 +35,9 @@ extension LazyContactMatchingIndex: ContactMatchingIndex {
return origin.contact(forEmail: email)
}
}

extension LazyDiscardingContactMatchingIndex: ContactsChangeEventTarget {
public func contactsDidChange() {
origin = nil
}
}
10 changes: 7 additions & 3 deletions UseCases/SimpleContactMatchingIndexFactory.swift
Expand Up @@ -18,14 +18,18 @@

public final class SimpleContactMatchingIndexFactory {
fileprivate let contacts: Contacts
fileprivate let settings: ContactMatchingSettings

public init(contacts: Contacts) {
public init(contacts: Contacts, settings: ContactMatchingSettings) {
self.contacts = contacts
self.settings = settings
}
}

extension SimpleContactMatchingIndexFactory: ContactMatchingIndexFactory {
public func make(maxPhoneNumberLength length: Int) -> ContactMatchingIndex {
return SimpleContactMatchingIndex(contacts: contacts, maxPhoneNumberLength: length)
public func make() -> ContactMatchingIndex {
return SimpleContactMatchingIndex(
contacts: contacts, maxPhoneNumberLength: settings.significantPhoneNumberLength
)
}
}
12 changes: 3 additions & 9 deletions UseCasesTestDoubles/ContactMatchingIndexFactorySpy.swift
Expand Up @@ -21,19 +21,13 @@ import UseCases
public final class ContactMatchingIndexFactorySpy {
public var didCallMake: Bool { return makeCallCount > 0 }
public fileprivate(set) var makeCallCount = 0
public fileprivate(set) var invokedMaxPhoneNumberLength: Int?

fileprivate let index: ContactMatchingIndex

public init(index: ContactMatchingIndex) {
self.index = index
}
public init() {}
}

extension ContactMatchingIndexFactorySpy: ContactMatchingIndexFactory {
public func make(maxPhoneNumberLength length: Int) -> ContactMatchingIndex {
public func make() -> ContactMatchingIndex {
makeCallCount += 1
invokedMaxPhoneNumberLength = length
return index
return ContactMatchingIndexDummy()
}
}
36 changes: 36 additions & 0 deletions UseCasesTestDoubles/ContactMatchingIndexFactoryStub.swift
@@ -0,0 +1,36 @@
//
// ContactMatchingIndexFactoryStub.swift
// Telephone
//
// Copyright © 2008-2016 Alexey Kuznetsov
// Copyright © 2016-2017 64 Characters
//
// Telephone is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Telephone is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//

import UseCases

public final class ContactMatchingIndexFactoryStub {
fileprivate let indexes: [ContactMatchingIndex]
fileprivate var callCount = 0

public init(indexes: [ContactMatchingIndex]) {
self.indexes = indexes
}
}

extension ContactMatchingIndexFactoryStub: ContactMatchingIndexFactory {
public func make() -> ContactMatchingIndex {
let result = indexes[callCount]
callCount += 1
return result
}
}
30 changes: 30 additions & 0 deletions UseCasesTestDoubles/ContactsChangeEventTargetSpy.swift
@@ -0,0 +1,30 @@
//
// ContactsChangeEventTargetSpy.swift
// Telephone
//
// Copyright © 2008-2016 Alexey Kuznetsov
// Copyright © 2016-2017 64 Characters
//
// Telephone is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Telephone is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//

import UseCases

public final class ContactsChangeEventTargetSpy {
public fileprivate(set) var didCallContactsDidChange = false
public init() {}
}

extension ContactsChangeEventTargetSpy: ContactsChangeEventTarget {
public func contactsDidChange() {
didCallContactsDidChange = true
}
}

0 comments on commit 8c0e72c

Please sign in to comment.