diff --git a/Linphone/Contacts/ContactsManager.swift b/Linphone/Contacts/ContactsManager.swift index 2eb923525..194e7a556 100644 --- a/Linphone/Contacts/ContactsManager.swift +++ b/Linphone/Contacts/ContactsManager.swift @@ -247,33 +247,47 @@ final class ContactsManager: ObservableObject { return UIImage(data: imageData) } - func saveImage(image: UIImage, name: String, prefix: String, contact: Contact, linphoneFriend: String, existingFriend: Friend?, completion: @escaping () -> Void) { + func saveImage(image: UIImage, name: String, prefix: String, contact: Contact, linphoneFriend: String, existingFriend: Friend?, editingFriend: Bool = false, completion: @escaping () -> Void) { guard let data = image.jpegData(compressionQuality: 1) ?? image.pngData() else { return } - awaitDataWrite(data: data, name: name, prefix: prefix) { result in - self.saveFriend(result: result, contact: contact, existingFriend: existingFriend) { resultFriend in - self.coreContext.doOnCoreQueue { core in - if let friend = resultFriend { - if linphoneFriend != self.nativeAddressBookFriendList && existingFriend == nil { - if let linphoneFL = self.linphoneFriendList, linphoneFriend == linphoneFL.displayName { - _ = linphoneFL.addFriend(linphoneFriend: friend) - } else if let linphoneFL = self.tempRemoteFriendList { - if friend.friendList?.type != .CardDAV { + let base64Tmp = existingFriend?.friendList?.type == .CardDAV || linphoneAddressBookFriendList != CorePreferences.friendListInWhichStoreNewlyCreatedFriends + + awaitDataWrite(data: data, name: name, prefix: prefix, base64: base64Tmp) { result in + if existingFriend?.friendList?.type != .CardDAV + || (existingFriend?.friendList?.type == .CardDAV && linphoneFriend == self.linphoneAddressBookFriendList) + || (editingFriend && linphoneFriend == CorePreferences.friendListInWhichStoreNewlyCreatedFriends) { + self.saveFriend(result: result, contact: contact, existingFriend: existingFriend) { resultFriend in + self.coreContext.doOnCoreQueue { core in + if let friend = resultFriend { + if linphoneFriend != self.nativeAddressBookFriendList && existingFriend == nil { + if let linphoneFL = self.linphoneFriendList, linphoneFriend == linphoneFL.displayName { _ = linphoneFL.addFriend(linphoneFriend: friend) + } else if let linphoneFL = core.friendsLists.first(where: { $0.type == .CardDAV && $0.displayName == CorePreferences.friendListInWhichStoreNewlyCreatedFriends }) { + if linphoneFL.type == .CardDAV { + _ = linphoneFL.addFriend(linphoneFriend: friend) + } + } else if let linphoneFL = self.tempRemoteFriendList { + if friend.friendList?.type != .CardDAV { + _ = linphoneFL.addFriend(linphoneFriend: friend) + } + } + } else if existingFriend == nil { + if let friendListTmp = self.friendList { + _ = friendListTmp.addLocalFriend(linphoneFriend: friend) } } - } else if existingFriend == nil { - if let friendListTmp = self.friendList { - _ = friendListTmp.addLocalFriend(linphoneFriend: friend) - } + } + + DispatchQueue.main.async { + completion() } } - - DispatchQueue.main.async { - completion() - } + } + } else { + DispatchQueue.main.async { + completion() } } } @@ -323,7 +337,7 @@ final class ContactsManager: ObservableObject { } // Set photo - friend.photo = "file:/" + result + friend.photo = (friend.friendList?.type != .CardDAV && self.linphoneAddressBookFriendList == CorePreferences.friendListInWhichStoreNewlyCreatedFriends ? "file:/" : "") + result // Linphone subscription settings try friend.setSubscribesenabled(newValue: false) @@ -350,22 +364,41 @@ final class ContactsManager: ObservableObject { return imagePath } - func awaitDataWrite(data: Data, name: String, prefix: String, completion: @escaping (String) -> Void) { + func awaitDataWrite(data: Data, name: String, prefix: String, base64: Bool? = false, completion: @escaping (String) -> Void) { guard let directory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { completion("") return } - - do { - let fileName = name + prefix + ".png" - - let fileURL = directory.appendingPathComponent(fileName.replacingOccurrences(of: " ", with: "")) - - try data.write(to: fileURL) - completion(fileName.replacingOccurrences(of: " ", with: "")) - } catch { - print("Error writing image: \(error)") - completion("") + if base64 == false { + do { + let fileName = name + prefix + ".png" + + let fileURL = directory.appendingPathComponent(fileName.replacingOccurrences(of: " ", with: "")) + + try data.write(to: fileURL) + completion(fileName.replacingOccurrences(of: " ", with: "")) + } catch { + print("Error writing image: \(error)") + completion("") + } + } else { + do { + let fileName = name + prefix + ".png" + + let fileURL = directory.appendingPathComponent(fileName.replacingOccurrences(of: " ", with: "")) + + try data.write(to: fileURL) + + if prefix.isEmpty { + let base64 = data.base64EncodedString() + completion("data:image/jpeg;base64,\(base64)") + } else { + completion("") + } + } catch { + print("Error writing image: \(error)") + completion("") + } } } @@ -472,24 +505,42 @@ final class ContactsManager: ObservableObject { ) let image: UIImage? - if let photo = friend.photo, !photo.isEmpty { + + if let photo = friend.photo, !photo.isEmpty, friendList.type == .CardDAV { if let imageTmp = self.imageFromBase64(photo) { image = imageTmp + if let image = image { + self.saveImage( + image: image, + name: friend.name ?? addressTmp, + prefix: "", + contact: newContact, linphoneFriend: friendList.displayName ?? "No Display Name", existingFriend: friend.friendList?.type == .CardDAV ? friend : nil) { + dispatchGroup.leave() + } + } } else { image = self.textToImage(firstName: friend.name ?? addressTmp, lastName: "") + if let image = image { + self.saveImage( + image: image, + name: friend.name ?? addressTmp, + prefix: "-default", + contact: newContact, linphoneFriend: friendList.displayName ?? "No Display Name", existingFriend: friend.friendList?.type == .CardDAV ? friend : nil) { + dispatchGroup.leave() + } + } } } else { image = self.textToImage(firstName: friend.name ?? addressTmp, lastName: "") - } - - if let image = image { - self.saveImage( - image: image, - name: friend.name ?? addressTmp, - prefix: "-default", - contact: newContact, linphoneFriend: friendList.displayName ?? "No Display Name", existingFriend: friend.friendList?.type == .CardDAV ? friend : nil) { - dispatchGroup.leave() - } + if let image = image { + self.saveImage( + image: image, + name: friend.name ?? addressTmp, + prefix: "-default", + contact: newContact, linphoneFriend: friendList.displayName ?? "No Display Name", existingFriend: friend.friendList?.type == .CardDAV ? friend : nil) { + dispatchGroup.leave() + } + } } } diff --git a/Linphone/UI/Main/Contacts/Fragments/ContactsInnerFragment.swift b/Linphone/UI/Main/Contacts/Fragments/ContactsInnerFragment.swift index defc2f8cd..8d6c362d9 100644 --- a/Linphone/UI/Main/Contacts/Fragments/ContactsInnerFragment.swift +++ b/Linphone/UI/Main/Contacts/Fragments/ContactsInnerFragment.swift @@ -22,6 +22,7 @@ import linphonesw struct ContactsInnerFragment: View { + @ObservedObject var sharedMainViewModel = SharedMainViewModel.shared @ObservedObject var contactsManager = ContactsManager.shared @EnvironmentObject var contactsListViewModel: ContactsListViewModel @@ -74,14 +75,16 @@ struct ContactsInnerFragment: View { VStack { List { - ContactsListFragment(showingSheet: $showingSheet, startCallFunc: {_ in })} + ContactsListFragment(showingSheet: $showingSheet, startCallFunc: {_ in })} .safeAreaInset(edge: .top, content: { Spacer() .frame(height: 12) }) .listStyle(.plain) - .refreshable { - contactsManager.refreshCardDavContacts() + .if(sharedMainViewModel.cardDavFriendsListsCount > 0) { view in + view.refreshable { + contactsManager.refreshCardDavContacts() + } } .overlay( VStack { diff --git a/Linphone/UI/Main/Contacts/Fragments/EditContactFragment.swift b/Linphone/UI/Main/Contacts/Fragments/EditContactFragment.swift index fdddf4b22..48851dfa9 100644 --- a/Linphone/UI/Main/Contacts/Fragments/EditContactFragment.swift +++ b/Linphone/UI/Main/Contacts/Fragments/EditContactFragment.swift @@ -545,7 +545,7 @@ struct EditContactFragment: View { prefix: prefix, contact: newContact, existingFriend: existingFriend, - linphoneFriend: "Linphone address-book" + linphoneFriend: CorePreferences.friendListInWhichStoreNewlyCreatedFriends ) } } @@ -558,7 +558,8 @@ struct EditContactFragment: View { prefix: prefix, contact: contact, linphoneFriend: linphoneFriend, - existingFriend: existingFriend + existingFriend: existingFriend, + editingFriend: true ) { if let existingFriend = existingFriend { self.updateAvatar(for: existingFriend) diff --git a/Linphone/UI/Main/Contacts/Model/ContactAvatarModel.swift b/Linphone/UI/Main/Contacts/Model/ContactAvatarModel.swift index dfc17eb88..bf1478136 100644 --- a/Linphone/UI/Main/Contacts/Model/ContactAvatarModel.swift +++ b/Linphone/UI/Main/Contacts/Model/ContactAvatarModel.swift @@ -77,7 +77,13 @@ class ContactAvatarModel: ObservableObject, Identifiable { let vcardTmp = friend?.vcard ?? nil let organizationTmp = friend?.organization ?? "" let jobTitleTmp = friend?.jobTitle ?? "" - let photoTmp = friend?.photo ?? "" + var photoTmp = friend?.photo ?? "" + + if friend?.friendList?.type == .CardDAV && friend?.photo?.isEmpty == false { + let fileName = "file:/" + name + ".png" + photoTmp = fileName.replacingOccurrences(of: " ", with: "") + } + var lastPresenceInfoTmp = "" var presenceStatusTmp: ConsolidatedPresence = .Offline diff --git a/Linphone/UI/Main/Settings/ViewModel/CardDavViewModel.swift b/Linphone/UI/Main/Settings/ViewModel/CardDavViewModel.swift index 7c10aa8d1..5853bcb6f 100644 --- a/Linphone/UI/Main/Settings/ViewModel/CardDavViewModel.swift +++ b/Linphone/UI/Main/Settings/ViewModel/CardDavViewModel.swift @@ -241,7 +241,10 @@ class CardDavViewModel: ObservableObject { Log.info("\(CardDavViewModel.TAG) Updating default friend list to store newly created contacts from \(previous) to \(name)") CorePreferences.friendListInWhichStoreNewlyCreatedFriends = name } - self.isReadOnly = friendList.isReadOnly + + DispatchQueue.main.async { + self.isReadOnly = friendList.isReadOnly + } } Log.info("\(CardDavViewModel.TAG) Notifying contacts manager that contacts have changed") diff --git a/Linphone/UI/Main/Settings/ViewModel/SettingsViewModel.swift b/Linphone/UI/Main/Settings/ViewModel/SettingsViewModel.swift index 6b6958b0b..59fbd88ed 100644 --- a/Linphone/UI/Main/Settings/ViewModel/SettingsViewModel.swift +++ b/Linphone/UI/Main/Settings/ViewModel/SettingsViewModel.swift @@ -192,6 +192,7 @@ class SettingsViewModel: ObservableObject { DispatchQueue.main.async { self.cardDavFriendsLists = list + SharedMainViewModel.shared.updateCardDavFriendsListsCount(cardDavFriendsListsCount: self.cardDavFriendsLists.count) } } } diff --git a/Linphone/UI/Main/Viewmodel/SharedMainViewModel.swift b/Linphone/UI/Main/Viewmodel/SharedMainViewModel.swift index 9a6efe12b..87e4bd06b 100644 --- a/Linphone/UI/Main/Viewmodel/SharedMainViewModel.swift +++ b/Linphone/UI/Main/Viewmodel/SharedMainViewModel.swift @@ -45,6 +45,7 @@ class SharedMainViewModel: ObservableObject { @Published var unreadMessages: Int = 0 @Published var missedCallsCount: Int = 0 + @Published var cardDavFriendsListsCount: Int = 0 @Published var disableChatFeature: Bool = false @Published var disableMeetingFeature: Bool = false @@ -96,6 +97,8 @@ class SharedMainViewModel: ObservableObject { updateUnreadMessagesCount() updateDisableChatFeature() updateDisableMeetingFeature() + + getCardDavFriendsListsCount() } func changeWelcomeView() { @@ -240,4 +243,27 @@ class SharedMainViewModel: ObservableObject { } } } + + func getCardDavFriendsListsCount() { + CoreContext.shared.doOnCoreQueue { core in + var list: [String] = [] + + core.friendsLists.forEach({ friendList in + if friendList.type == .CardDAV { + let label = friendList.displayName ?? friendList.uri ?? "" + if !label.isEmpty { + list.append(label) + } + } + }) + + DispatchQueue.main.async { + self.updateCardDavFriendsListsCount(cardDavFriendsListsCount: list.count) + } + } + } + + func updateCardDavFriendsListsCount(cardDavFriendsListsCount: Int) { + self.cardDavFriendsListsCount = cardDavFriendsListsCount + } } diff --git a/LinphoneApp.xcodeproj/project.pbxproj b/LinphoneApp.xcodeproj/project.pbxproj index b580d4d3e..6d2badfb0 100644 --- a/LinphoneApp.xcodeproj/project.pbxproj +++ b/LinphoneApp.xcodeproj/project.pbxproj @@ -1181,7 +1181,7 @@ D7D5AD7B2DD34E4D00016721 /* XCRemoteSwiftPackageReference "AppAuth-iOS" */, D7D5AD7C2DD34E7C00016721 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */, D7DF8BE42E2104D0003A3BC7 /* XCRemoteSwiftPackageReference "Elegant-Emoji-Picker" */, - D74F6DA62E5C6A17006A3C55 /* XCRemoteSwiftPackageReference "linphone-sdk-swift-ios" */, + D7690B3B2EAF8878009CB3B7 /* XCRemoteSwiftPackageReference "linphone-sdk-swift-ios" */, ); productRefGroup = D719ABB42ABC67BF00B41C10 /* Products */; projectDirPath = ""; @@ -1920,7 +1920,7 @@ kind = branch; }; }; - D74F6DA62E5C6A17006A3C55 /* XCRemoteSwiftPackageReference "linphone-sdk-swift-ios" */ = { + D7690B3B2EAF8878009CB3B7 /* XCRemoteSwiftPackageReference "linphone-sdk-swift-ios" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://gitlab.linphone.org/BC/public/linphone-sdk-swift-ios.git"; requirement = { diff --git a/LinphoneApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/LinphoneApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 0e27a7170..7cc611a1d 100644 --- a/LinphoneApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/LinphoneApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -34,7 +34,7 @@ "location" : "https://github.com/Finalet/Elegant-Emoji-Picker", "state" : { "branch" : "main", - "revision" : "598ff0a72198375d7317b61982fa8648d0ba3a44" + "revision" : "31605313f26a5997495aba6906b1c5bf8bf7b124" } }, { @@ -124,7 +124,7 @@ "location" : "https://gitlab.linphone.org/BC/public/linphone-sdk-swift-ios.git", "state" : { "branch" : "alpha", - "revision" : "3b79481215d235e3e7cd142bc7c7eda077f1d99a" + "revision" : "92aaa6e23f62bffdca8946c0ec172c5eb4605e76" } }, { @@ -150,8 +150,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-protobuf.git", "state" : { - "revision" : "2547102afd04fe49f1b286090f13ebce07284980", - "version" : "1.31.1" + "revision" : "c6fe6442e6a64250495669325044052e113e990c", + "version" : "1.32.0" } } ],