Edit CardDav friend

This commit is contained in:
Benoit Martins 2025-10-23 17:25:54 +02:00
parent ac6b478eb1
commit 5bb757d150
9 changed files with 146 additions and 55 deletions

View file

@ -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()
}
}
}
}

View file

@ -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 {

View file

@ -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)

View file

@ -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

View file

@ -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")

View file

@ -192,6 +192,7 @@ class SettingsViewModel: ObservableObject {
DispatchQueue.main.async {
self.cardDavFriendsLists = list
SharedMainViewModel.shared.updateCardDavFriendsListsCount(cardDavFriendsListsCount: self.cardDavFriendsLists.count)
}
}
}

View file

@ -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
}
}

View file

@ -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 = {

View file

@ -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"
}
}
],