forked from mirrors/linphone-iphone
Move all Core related code to another dispatch queue. requires sdk built with feature/swift_wrapper_async_helpers
This commit is contained in:
parent
3fe7dd8884
commit
a3befe61cf
9 changed files with 245 additions and 190 deletions
|
|
@ -540,6 +540,7 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOLS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
|
|
@ -600,6 +601,7 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOLS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
|
|
|
|||
|
|
@ -38,16 +38,16 @@ final class ContactsManager: ObservableObject {
|
|||
}
|
||||
|
||||
func fetchContacts() {
|
||||
DispatchQueue.global().async {
|
||||
if self.coreContext.mCore.globalState == GlobalState.Shutdown || self.coreContext.mCore.globalState == GlobalState.Off {
|
||||
coreContext.doOnCoreQueue { core in
|
||||
if core.globalState == GlobalState.Shutdown || core.globalState == GlobalState.Off {
|
||||
print("$TAG Core is being stopped or already destroyed, abort")
|
||||
} else {
|
||||
print("$TAG ${friends.size} friends created")
|
||||
|
||||
self.friendList = self.coreContext.mCore.getFriendListByName(name: self.nativeAddressBookFriendList)
|
||||
self.friendList = core.getFriendListByName(name: self.nativeAddressBookFriendList)
|
||||
if self.friendList == nil {
|
||||
do {
|
||||
self.friendList = try self.coreContext.mCore.createFriendList()
|
||||
self.friendList = try core.createFriendList()
|
||||
} catch let error {
|
||||
print("Failed to enumerate contact", error)
|
||||
}
|
||||
|
|
@ -61,7 +61,7 @@ final class ContactsManager: ObservableObject {
|
|||
self.friendList!.databaseStorageEnabled = false // We don't want to store local address-book in DB
|
||||
|
||||
self.friendList!.displayName = self.nativeAddressBookFriendList
|
||||
self.coreContext.mCore.addFriendList(list: self.friendList!)
|
||||
core.addFriendList(list: self.friendList!)
|
||||
} else {
|
||||
print(
|
||||
"$TAG Friend list [$LINPHONE_ADDRESS_BOOK_FRIEND_LIST] found, removing existing friends if any"
|
||||
|
|
@ -159,52 +159,58 @@ final class ContactsManager: ObservableObject {
|
|||
}
|
||||
|
||||
awaitDataWrite(data: data, name: name) { _, result in
|
||||
do {
|
||||
let friend = try self.coreContext.mCore.createFriend()
|
||||
friend.edit()
|
||||
try friend.setName(newValue: contact.firstName + " " + contact.lastName)
|
||||
friend.organization = contact.organizationName
|
||||
|
||||
var friendAddresses: [Address] = []
|
||||
contact.sipAddresses.forEach { sipAddress in
|
||||
let address = self.coreContext.mCore.interpretUrl(url: sipAddress, applyInternationalPrefix: true)
|
||||
|
||||
self.coreContext.doOnCoreQueue() { core in
|
||||
do {
|
||||
var friend = try core.createFriend()
|
||||
|
||||
if address != nil && ((friendAddresses.firstIndex(where: {$0.asString() == address?.asString()})) == nil) {
|
||||
friend.addAddress(address: address!)
|
||||
friendAddresses.append(address!)
|
||||
}
|
||||
}
|
||||
|
||||
var friendPhoneNumbers: [PhoneNumber] = []
|
||||
contact.phoneNumbers.forEach { phone in
|
||||
do {
|
||||
if (friendPhoneNumbers.firstIndex(where: {$0.numLabel == phone.numLabel})) == nil {
|
||||
let labelDrop = String(phone.numLabel.dropFirst(4).dropLast(4))
|
||||
let phoneNumber = try Factory.Instance.createFriendPhoneNumber(phoneNumber: phone.num, label: labelDrop)
|
||||
friend.addPhoneNumberWithLabel(phoneNumber: phoneNumber)
|
||||
friendPhoneNumbers.append(phone)
|
||||
friend.edit()
|
||||
try friend.setName(newValue: contact.firstName + " " + contact.lastName)
|
||||
friend.organization = contact.organizationName
|
||||
|
||||
var friendAddresses: [Address] = []
|
||||
contact.sipAddresses.forEach { sipAddress in
|
||||
let address = core.interpretUrl(url: sipAddress, applyInternationalPrefix: true)
|
||||
|
||||
if address != nil && ((friendAddresses.firstIndex(where: {$0.asString() == address?.asString()})) == nil) {
|
||||
friend.addAddress(address: address!)
|
||||
friendAddresses.append(address!)
|
||||
}
|
||||
} catch let error {
|
||||
print("Failed to enumerate contact", error)
|
||||
}
|
||||
|
||||
var friendPhoneNumbers: [PhoneNumber] = []
|
||||
contact.phoneNumbers.forEach { phone in
|
||||
do {
|
||||
if (friendPhoneNumbers.firstIndex(where: {$0.numLabel == phone.numLabel})) == nil {
|
||||
let labelDrop = String(phone.numLabel.dropFirst(4).dropLast(4))
|
||||
let phoneNumber = try Factory.Instance.createFriendPhoneNumber(phoneNumber: phone.num, label: labelDrop)
|
||||
friend.addPhoneNumberWithLabel(phoneNumber: phoneNumber)
|
||||
friendPhoneNumbers.append(phone)
|
||||
}
|
||||
} catch let error {
|
||||
print("Failed to enumerate contact", error)
|
||||
}
|
||||
}
|
||||
|
||||
let contactImage = result.dropFirst(8)
|
||||
friend.photo = "file:/" + contactImage
|
||||
|
||||
friend.organization = contact.organizationName
|
||||
|
||||
friend.done()
|
||||
|
||||
DispatchQueue.main.async {
|
||||
_ = self.friendList!.addLocalFriend(linphoneFriend: friend)
|
||||
|
||||
self.friendList!.updateSubscriptions()
|
||||
}
|
||||
} catch let error {
|
||||
print("Failed to enumerate contact", error)
|
||||
}
|
||||
|
||||
let contactImage = result.dropFirst(8)
|
||||
friend.photo = "file:/" + contactImage
|
||||
|
||||
friend.organization = contact.organizationName
|
||||
|
||||
friend.done()
|
||||
|
||||
_ = self.friendList!.addLocalFriend(linphoneFriend: friend)
|
||||
|
||||
self.friendList!.updateSubscriptions()
|
||||
|
||||
} catch let error {
|
||||
print("Failed to enumerate contact", error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func awaitDataWrite(data: Data, name: String, completion: @escaping ((), String) -> Void) {
|
||||
let directory = FileManager.default.temporaryDirectory
|
||||
|
|
|
|||
|
|
@ -17,74 +17,104 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// swiftlint:disable large_tuple
|
||||
import linphonesw
|
||||
import Combine
|
||||
|
||||
final class CoreContext: ObservableObject {
|
||||
|
||||
static let shared = CoreContext()
|
||||
|
||||
var mCore: Core!
|
||||
var mRegistrationDelegate: CoreDelegate!
|
||||
var mConfigurationDelegate: CoreDelegate!
|
||||
|
||||
var coreVersion: String = Core.getVersion
|
||||
@Published var loggedIn: Bool = false
|
||||
@Published var loggingInProgress: Bool = false
|
||||
@Published var toastMessage: String = ""
|
||||
@Published var defaultAccount: Account?
|
||||
|
||||
private var mCore: Core!
|
||||
private var mIteratePublisher: AnyCancellable?
|
||||
|
||||
private init() {}
|
||||
|
||||
func initialiseCore() async throws {
|
||||
func doOnCoreQueue(synchronous : Bool = false, lambda: @escaping (Core) -> Void) {
|
||||
if synchronous {
|
||||
coreQueue.sync {
|
||||
lambda(self.mCore)
|
||||
}
|
||||
} else {
|
||||
coreQueue.async {
|
||||
lambda(self.mCore)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func initialiseCore() throws {
|
||||
LoggingService.Instance.logLevel = LogLevel.Debug
|
||||
|
||||
let factory = Factory.Instance
|
||||
let configDir = factory.getConfigDir(context: nil)
|
||||
try? mCore = Factory.Instance.createCore(configPath: "\(configDir)/MyConfig", factoryConfigPath: "", systemContext: nil)
|
||||
|
||||
mCore.friendsDatabasePath = "\(configDir)/friends.db"
|
||||
|
||||
try? mCore.start()
|
||||
|
||||
// Create a Core listener to listen for the callback we need
|
||||
// In this case, we want to know about the account registration status
|
||||
|
||||
mRegistrationDelegate =
|
||||
CoreDelegateStub(
|
||||
onConfiguringStatus: {(_: Core, state: Config.ConfiguringState, message: String) in
|
||||
NSLog("New configuration state is \(state) = \(message)\n")
|
||||
if state == .Successful {
|
||||
coreQueue.async {
|
||||
let configDir = Factory.Instance.getConfigDir(context: nil)
|
||||
try? self.mCore = Factory.Instance.createCore(configPath: "\(configDir)/MyConfig", factoryConfigPath: "", systemContext: nil)
|
||||
self.mCore.autoIterateEnabled = false
|
||||
self.mCore.friendsDatabasePath = "\(configDir)/friends.db"
|
||||
|
||||
self.mCore.publisher?.onGlobalStateChanged?.postOnMainQueue { (cbVal: (core: Core, state: GlobalState, message: String)) in
|
||||
if cbVal.state == GlobalState.On {
|
||||
self.defaultAccount = self.mCore.defaultAccount
|
||||
} else if cbVal.state == GlobalState.Off {
|
||||
self.defaultAccount = nil
|
||||
}
|
||||
}
|
||||
try? self.mCore.start()
|
||||
|
||||
// Create a Core listener to listen for the callback we need
|
||||
// In this case, we want to know about the account registration status
|
||||
self.mCore.publisher?.onConfiguringStatus?.postOnMainQueue { (cbVal: (core: Core, status: Config.ConfiguringState, message: String)) in
|
||||
NSLog("New configuration state is \(cbVal.status) = \(cbVal.message)\n")
|
||||
if cbVal.status == Config.ConfiguringState.Successful {
|
||||
self.toastMessage = "Successful"
|
||||
} else {
|
||||
self.toastMessage = "Failed"
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
onAccountRegistrationStateChanged: {(_: Core, account: Account, state: RegistrationState, message: String) in
|
||||
self.mCore.publisher?.onAccountRegistrationStateChanged?.postOnMainQueue { (cbVal: (core: Core, account: Account, state: RegistrationState, message: String)) in
|
||||
// If account has been configured correctly, we will go through Progress and Ok states
|
||||
// Otherwise, we will be Failed.
|
||||
NSLog("New registration state is \(state) for user id \( String(describing: account.params?.identityAddress?.asString())) = \(message)\n")
|
||||
if state == .Ok {
|
||||
NSLog("New registration state is \(cbVal.state) for user id " +
|
||||
"\( String(describing: cbVal.account.params?.identityAddress?.asString())) = \(cbVal.message)\n")
|
||||
if cbVal.state == .Ok {
|
||||
self.loggingInProgress = false
|
||||
self.loggedIn = true
|
||||
} else if state == .Progress {
|
||||
} else if cbVal.state == .Progress {
|
||||
self.loggingInProgress = true
|
||||
} else {
|
||||
self.toastMessage = "Registration failed"
|
||||
self.loggingInProgress = false
|
||||
self.loggedIn = false
|
||||
|
||||
let params = account.params
|
||||
}
|
||||
}.postOnCoreQueue { (cbVal: (core: Core, account: Account, state: RegistrationState, message: String)) in
|
||||
// If registration failed, remove account from core
|
||||
if cbVal.state != .Ok && cbVal.state != .Progress {
|
||||
let params = cbVal.account.params
|
||||
let clonedParams = params?.clone()
|
||||
clonedParams?.registerEnabled = false
|
||||
account.params = clonedParams
|
||||
cbVal.account.params = clonedParams
|
||||
|
||||
self.mCore!.removeAccount(account: account)
|
||||
self.mCore!.clearAccounts()
|
||||
self.mCore!.clearAllAuthInfo()
|
||||
cbVal.core.removeAccount(account: cbVal.account)
|
||||
cbVal.core.clearAccounts()
|
||||
cbVal.core.clearAllAuthInfo()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
mCore.addDelegate(delegate: mRegistrationDelegate)
|
||||
|
||||
self.mIteratePublisher = Timer.publish(every: 0.02, on: .main, in: .common)
|
||||
.autoconnect()
|
||||
.receive(on: coreQueue)
|
||||
.sink { _ in
|
||||
self.mCore.iterate()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// swiftlint:enable large_tuple
|
||||
|
|
|
|||
|
|
@ -32,10 +32,10 @@ struct LinphoneApp: App {
|
|||
if isActive {
|
||||
if !sharedMainViewModel.welcomeViewDisplayed {
|
||||
WelcomeView(sharedMainViewModel: sharedMainViewModel)
|
||||
} else if coreContext.mCore.defaultAccount == nil || sharedMainViewModel.displayProfileMode {
|
||||
} else if coreContext.defaultAccount == nil || sharedMainViewModel.displayProfileMode {
|
||||
AssistantView(sharedMainViewModel: sharedMainViewModel)
|
||||
.toast(isShowing: $coreContext.toastMessage)
|
||||
} else if coreContext.mCore.defaultAccount != nil {
|
||||
} else if coreContext.defaultAccount != nil {
|
||||
ContentView(contactViewModel: ContactViewModel(), historyViewModel: HistoryViewModel())
|
||||
.toast(isShowing: $coreContext.toastMessage)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ struct SplashScreen: View {
|
|||
.ignoresSafeArea(.all)
|
||||
.onAppear {
|
||||
Task {
|
||||
try await coreContext.initialiseCore()
|
||||
try coreContext.initialiseCore()
|
||||
withAnimation {
|
||||
self.isActive = true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,83 +33,95 @@ class AccountLoginViewModel: ObservableObject {
|
|||
init() {}
|
||||
|
||||
func login() {
|
||||
do {
|
||||
// Get the transport protocol to use.
|
||||
// TLS is strongly recommended
|
||||
// Only use UDP if you don't have the choice
|
||||
var transport: TransportType
|
||||
if transportType == "TLS" {
|
||||
transport = TransportType.Tls
|
||||
} else if transportType == "TCP" {
|
||||
transport = TransportType.Tcp
|
||||
} else { transport = TransportType.Udp }
|
||||
|
||||
// To configure a SIP account, we need an Account object and an AuthInfo object
|
||||
// The first one is how to connect to the proxy server, the second one stores the credentials
|
||||
|
||||
// The auth info can be created from the Factory as it's only a data class
|
||||
// userID is set to null as it's the same as the username in our case
|
||||
// ha1 is set to null as we are using the clear text password. Upon first register, the hash will be computed automatically.
|
||||
// The realm will be determined automatically from the first register, as well as the algorithm
|
||||
let authInfo = try Factory.Instance.createAuthInfo(username: username, userid: "", passwd: passwd, ha1: "", realm: "", domain: domain)
|
||||
|
||||
// Account object replaces deprecated ProxyConfig object
|
||||
// Account object is configured through an AccountParams object that we can obtain from the Core
|
||||
|
||||
let accountParams = try coreContext.mCore!.createAccountParams()
|
||||
|
||||
// A SIP account is identified by an identity address that we can construct from the username and domain
|
||||
let identity = try Factory.Instance.createAddress(addr: String("sip:" + username + "@" + domain))
|
||||
try accountParams.setIdentityaddress(newValue: identity)
|
||||
|
||||
// We also need to configure where the proxy server is located
|
||||
let address = try Factory.Instance.createAddress(addr: String("sip:" + domain))
|
||||
|
||||
// We use the Address object to easily set the transport protocol
|
||||
try address.setTransport(newValue: transport)
|
||||
try accountParams.setServeraddress(newValue: address)
|
||||
// And we ensure the account will start the registration process
|
||||
accountParams.registerEnabled = true
|
||||
|
||||
// Now that our AccountParams is configured, we can create the Account object
|
||||
let account = try coreContext.mCore!.createAccount(params: accountParams)
|
||||
|
||||
// Now let's add our objects to the Core
|
||||
coreContext.mCore!.addAuthInfo(info: authInfo)
|
||||
try coreContext.mCore!.addAccount(account: account)
|
||||
|
||||
// Also set the newly added account as default
|
||||
coreContext.mCore!.defaultAccount = account
|
||||
|
||||
} catch { NSLog(error.localizedDescription) }
|
||||
coreContext.doOnCoreQueue { core in
|
||||
do {
|
||||
// Get the transport protocol to use.
|
||||
// TLS is strongly recommended
|
||||
// Only use UDP if you don't have the choice
|
||||
var transport: TransportType
|
||||
if self.transportType == "TLS" {
|
||||
transport = TransportType.Tls
|
||||
} else if self.transportType == "TCP" {
|
||||
transport = TransportType.Tcp
|
||||
} else { transport = TransportType.Udp }
|
||||
|
||||
// To configure a SIP account, we need an Account object and an AuthInfo object
|
||||
// The first one is how to connect to the proxy server, the second one stores the credentials
|
||||
|
||||
// The auth info can be created from the Factory as it's only a data class
|
||||
// userID is set to null as it's the same as the username in our case
|
||||
// ha1 is set to null as we are using the clear text password. Upon first register, the hash will be computed automatically.
|
||||
// The realm will be determined automatically from the first register, as well as the algorithm
|
||||
let authInfo = try Factory.Instance.createAuthInfo(username: self.username, userid: "", passwd: self.passwd, ha1: "", realm: "", domain: self.domain)
|
||||
|
||||
// Account object replaces deprecated ProxyConfig object
|
||||
// Account object is configured through an AccountParams object that we can obtain from the Core
|
||||
|
||||
let accountParams = try core.createAccountParams()
|
||||
|
||||
// A SIP account is identified by an identity address that we can construct from the username and domain
|
||||
let identity = try Factory.Instance.createAddress(addr: String("sip:" + self.username + "@" + self.domain))
|
||||
try accountParams.setIdentityaddress(newValue: identity)
|
||||
|
||||
// We also need to configure where the proxy server is located
|
||||
let address = try Factory.Instance.createAddress(addr: String("sip:" + self.domain))
|
||||
|
||||
// We use the Address object to easily set the transport protocol
|
||||
try address.setTransport(newValue: transport)
|
||||
try accountParams.setServeraddress(newValue: address)
|
||||
// And we ensure the account will start the registration process
|
||||
accountParams.registerEnabled = true
|
||||
|
||||
// Now that our AccountParams is configured, we can create the Account object
|
||||
let account = try core.createAccount(params: accountParams)
|
||||
|
||||
// Now let's add our objects to the Core
|
||||
core.addAuthInfo(info: authInfo)
|
||||
try core.addAccount(account: account)
|
||||
|
||||
// Also set the newly added account as default
|
||||
core.defaultAccount = account
|
||||
DispatchQueue.main.async {
|
||||
self.coreContext.defaultAccount = account
|
||||
}
|
||||
|
||||
} catch { NSLog(error.localizedDescription) }
|
||||
}
|
||||
}
|
||||
|
||||
func unregister() {
|
||||
// Here we will disable the registration of our Account
|
||||
if let account = coreContext.mCore!.defaultAccount {
|
||||
|
||||
let params = account.params
|
||||
// Returned params object is const, so to make changes we first need to clone it
|
||||
let clonedParams = params?.clone()
|
||||
|
||||
// Now let's make our changes
|
||||
clonedParams?.registerEnabled = false
|
||||
|
||||
// And apply them
|
||||
account.params = clonedParams
|
||||
coreContext.doOnCoreQueue { core in
|
||||
// Here we will disable the registration of our Account
|
||||
if let account = core.defaultAccount {
|
||||
|
||||
let params = account.params
|
||||
// Returned params object is const, so to make changes we first need to clone it
|
||||
let clonedParams = params?.clone()
|
||||
|
||||
// Now let's make our changes
|
||||
clonedParams?.registerEnabled = false
|
||||
|
||||
// And apply them
|
||||
account.params = clonedParams
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func delete() {
|
||||
// To completely remove an Account
|
||||
if let account = coreContext.mCore!.defaultAccount {
|
||||
coreContext.mCore!.removeAccount(account: account)
|
||||
|
||||
// To remove all accounts use
|
||||
coreContext.mCore!.clearAccounts()
|
||||
|
||||
// Same for auth info
|
||||
coreContext.mCore!.clearAllAuthInfo()
|
||||
coreContext.doOnCoreQueue { core in
|
||||
// To completely remove an Account
|
||||
if let account = core.defaultAccount {
|
||||
core.removeAccount(account: account)
|
||||
DispatchQueue.main.async {
|
||||
self.coreContext.defaultAccount = nil
|
||||
}
|
||||
|
||||
// To remove all accounts use
|
||||
core.clearAccounts()
|
||||
|
||||
// Same for auth info
|
||||
core.clearAllAuthInfo()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,14 +70,11 @@ class Coordinator: NSObject, AVCaptureMetadataOutputObjectsDelegate {
|
|||
if let url = NSURL(string: result) {
|
||||
if UIApplication.shared.canOpenURL(url as URL) {
|
||||
lastResult = result
|
||||
do {
|
||||
try coreContext.mCore.setProvisioninguri(newValue: result)
|
||||
coreContext.mCore.stop()
|
||||
try coreContext.mCore.start()
|
||||
} catch {
|
||||
|
||||
coreContext.doOnCoreQueue { core in
|
||||
try? core.setProvisioninguri(newValue: result)
|
||||
core.stop()
|
||||
try? core.start()
|
||||
}
|
||||
|
||||
} else {
|
||||
coreContext.toastMessage = "Invalide URI"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -416,11 +416,11 @@ struct ContentView: View {
|
|||
if isShowDeletePopup {
|
||||
PopupView(sharedMainViewModel: SharedMainViewModel(), isShowPopup: $isShowDeletePopup,
|
||||
title: Text(
|
||||
contactViewModel.selectedFriend != nil
|
||||
? "Delete \(contactViewModel.selectedFriend!.name!)?"
|
||||
: (contactViewModel.displayedFriend != nil
|
||||
? "Delete \(contactViewModel.displayedFriend!.name!)?"
|
||||
: "Error Name")),
|
||||
contactViewModel.selectedFriend != nil
|
||||
? "Delete \(contactViewModel.selectedFriend!.name!)?"
|
||||
: (contactViewModel.displayedFriend != nil
|
||||
? "Delete \(contactViewModel.displayedFriend!.name!)?"
|
||||
: "Error Name")),
|
||||
content: Text("This contact will be deleted definitively."),
|
||||
titleFirstButton: Text("Cancel"),
|
||||
actionFirstButton: {self.isShowDeletePopup.toggle()},
|
||||
|
|
|
|||
|
|
@ -25,9 +25,8 @@ final class MagicSearchSingleton: ObservableObject {
|
|||
private var coreContext = CoreContext.shared
|
||||
|
||||
private var magicSearch: MagicSearch!
|
||||
var magicSearchDelegate: MagicSearchDelegate?
|
||||
|
||||
@objc var currentFilter: String = ""
|
||||
var currentFilter: String = ""
|
||||
var previousFilter: String?
|
||||
|
||||
var needUpdateLastSearchContacts = false
|
||||
|
|
@ -35,36 +34,45 @@ final class MagicSearchSingleton: ObservableObject {
|
|||
@Published var lastSearch: [SearchResult] = []
|
||||
|
||||
private var limitSearchToLinphoneAccounts = true
|
||||
|
||||
@Published var allContact = false
|
||||
private var domainDefaultAccount = ""
|
||||
|
||||
@Published var allContact = false
|
||||
private var domainDefaultAccount = ""
|
||||
|
||||
private init() {
|
||||
domainDefaultAccount = coreContext.mCore.defaultAccount!.params!.domain!
|
||||
|
||||
magicSearch = try? coreContext.mCore.createMagicSearch()
|
||||
magicSearch.limitedSearch = false
|
||||
|
||||
magicSearchDelegate = MagicSearchDelegateStub(onSearchResultsReceived: { (magicSearch: MagicSearch) in
|
||||
self.needUpdateLastSearchContacts = true
|
||||
self.lastSearch = magicSearch.lastSearch
|
||||
})
|
||||
|
||||
magicSearch.addDelegate(delegate: magicSearchDelegate!)
|
||||
coreContext.doOnCoreQueue{ core in
|
||||
self.domainDefaultAccount = core.defaultAccount?.params?.domain ?? ""
|
||||
|
||||
self.magicSearch = try? core.createMagicSearch()
|
||||
self.magicSearch.limitedSearch = false
|
||||
|
||||
self.magicSearch.publisher?.onSearchResultsReceived?.postOnMainQueue { (magicSearch: MagicSearch) in
|
||||
self.needUpdateLastSearchContacts = true
|
||||
self.lastSearch = magicSearch.lastSearch
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func searchForContacts(sourceFlags: Int) {
|
||||
if let oldFilter = previousFilter {
|
||||
if oldFilter.count > currentFilter.count || oldFilter != currentFilter {
|
||||
magicSearch.resetSearchCache()
|
||||
coreContext.doOnCoreQueue{ core in
|
||||
var needResetCache = false
|
||||
|
||||
DispatchQueue.main.sync {
|
||||
if let oldFilter = self.previousFilter {
|
||||
if oldFilter.count > self.currentFilter.count || oldFilter != self.currentFilter {
|
||||
needResetCache = true
|
||||
}
|
||||
}
|
||||
self.previousFilter = self.currentFilter
|
||||
}
|
||||
if needResetCache {
|
||||
self.magicSearch.resetSearchCache()
|
||||
}
|
||||
|
||||
self.magicSearch.getContactsListAsync(
|
||||
filter: self.currentFilter,
|
||||
domain: self.allContact ? "" : self.domainDefaultAccount,
|
||||
sourceFlags: sourceFlags,
|
||||
aggregation: MagicSearch.Aggregation.Friend)
|
||||
}
|
||||
previousFilter = currentFilter
|
||||
|
||||
magicSearch.getContactsListAsync(
|
||||
filter: currentFilter,
|
||||
domain: allContact ? "" : domainDefaultAccount,
|
||||
sourceFlags: sourceFlags,
|
||||
aggregation: MagicSearch.Aggregation.Friend)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue