diff --git a/Linphone/Assets.xcassets/profil-picture-default.imageset/Contents.json b/Linphone/Assets.xcassets/profil-picture-default.imageset/Contents.json
new file mode 100644
index 000000000..68bdd056b
--- /dev/null
+++ b/Linphone/Assets.xcassets/profil-picture-default.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "filename" : "profil-picture-default.svg",
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/Linphone/Assets.xcassets/profil-picture-default.imageset/profil-picture-default.svg b/Linphone/Assets.xcassets/profil-picture-default.imageset/profil-picture-default.svg
new file mode 100644
index 000000000..b2bea3b29
--- /dev/null
+++ b/Linphone/Assets.xcassets/profil-picture-default.imageset/profil-picture-default.svg
@@ -0,0 +1,18 @@
+
diff --git a/Linphone/Contacts/ContactsManager.swift b/Linphone/Contacts/ContactsManager.swift
index 5de3eb683..a7a845569 100644
--- a/Linphone/Contacts/ContactsManager.swift
+++ b/Linphone/Contacts/ContactsManager.swift
@@ -24,213 +24,198 @@ import SwiftUI
final class ContactsManager: ObservableObject {
static let shared = ContactsManager()
-
+
private var coreContext = CoreContext.shared
-
- @Published var contacts: [Contact] = []
+ private var magicSearch = MagicSearchSingleton.shared
private let nativeAddressBookFriendList = "Native address-book"
let linphoneAddressBookFirendList = "Linphone address-book"
+
+ @Published var friendList: FriendList?
private init() {
fetchContacts()
}
func fetchContacts() {
- contacts.removeAll()
DispatchQueue.global().async {
- let store = CNContactStore()
- store.requestAccess(for: .contacts) { (granted, error) in
- if let error = error {
- print("failed to request access", error)
- return
- }
- if granted {
- let keys = [CNContactEmailAddressesKey, CNContactPhoneNumbersKey,
- CNContactFamilyNameKey, CNContactGivenNameKey, CNContactNicknameKey,
- CNContactPostalAddressesKey, CNContactIdentifierKey,
- CNInstantMessageAddressUsernameKey, CNContactInstantMessageAddressesKey,
- CNContactImageDataKey, CNContactThumbnailImageDataKey, CNContactOrganizationNameKey]
- let request = CNContactFetchRequest(keysToFetch: keys as [CNKeyDescriptor])
- do {
- try store.enumerateContacts(with: request, usingBlock: { (contact, _) in
-
- DispatchQueue.main.sync {
- self.contacts.append(
- Contact(
- firstName: contact.givenName,
- lastName: contact.familyName,
- organizationName: contact.organizationName,
- displayName: contact.nickname,
- sipAddresses: contact.instantMessageAddresses.map { $0.value.service == "SIP" ? $0.value.username : "" },
- phoneNumbers: contact.phoneNumbers.map { PhoneNumber(numLabel: $0.label ?? "", num: $0.value.stringValue)},
- imageData: self.saveImage(
- image:
- UIImage(data: contact.thumbnailImageData ?? Data())
- ?? self.textToImage(firstName: contact.givenName.isEmpty
- && contact.familyName.isEmpty
- && contact.phoneNumbers.first?.value.stringValue != nil
- ? contact.phoneNumbers.first!.value.stringValue
- : contact.givenName, lastName: contact.familyName),
- name: contact.identifier)
- )
- )
- }
- self.contacts.sort(by: {
- $0.firstName.folding(
- options: .diacriticInsensitive, locale: .current
- ) < $1.firstName.folding(
- options: .diacriticInsensitive, locale: .current
- )
- })
- })
-
- } catch let error {
- print("Failed to enumerate contact", error)
- }
-
- } else {
- print("access denied")
- }
- }
-
- var friends: [Friend] = []
-
- self.contacts.forEach { contact 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)
-
- 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 phoneNumber = try Factory.Instance.createFriendPhoneNumber(phoneNumber: phone.num, label: phone.numLabel)
- friend.addPhoneNumberWithLabel(phoneNumber: phoneNumber)
- friendPhoneNumbers.append(phone)
- }
- } catch let error {
- print("Failed to enumerate contact", error)
- }
- }
-
- let contactImage = contact.imageData.dropFirst(8)
- friend.photo = "file:/" + contactImage
-
- friend.done()
- friends.append(friend)
-
- } catch let error {
- print("Failed to enumerate contact", error)
- }
- }
-
if self.coreContext.mCore.globalState == GlobalState.Shutdown || self.coreContext.mCore.globalState == GlobalState.Off {
print("$TAG Core is being stopped or already destroyed, abort")
- } else if friends.isEmpty {
- print("$TAG No friend created!")
- } else {
+ } else {
print("$TAG ${friends.size} friends created")
- let fetchedFriends = friends
-
- let nativeFriendList = self.coreContext.mCore.getFriendListByName(name: self.nativeAddressBookFriendList)
- var friendList = nativeFriendList
- if friendList == nil {
+ self.friendList = self.coreContext.mCore.getFriendListByName(name: self.nativeAddressBookFriendList)
+ if self.friendList == nil {
do {
- friendList = try self.coreContext.mCore.createFriendList()
+ self.friendList = try self.coreContext.mCore.createFriendList()
} catch let error {
print("Failed to enumerate contact", error)
}
}
- if friendList!.displayName == nil || friendList!.displayName!.isEmpty {
+ if self.friendList!.displayName == nil || self.friendList!.displayName!.isEmpty {
print(
"$TAG Friend list [$nativeAddressBookFriendList] didn't exist yet, let's create it"
)
- friendList?.databaseStorageEnabled = false // We don't want to store local address-book in DB
+ self.friendList!.databaseStorageEnabled = false // We don't want to store local address-book in DB
- friendList!.displayName = self.nativeAddressBookFriendList
- self.coreContext.mCore.addFriendList(list: friendList!)
+ self.friendList!.displayName = self.nativeAddressBookFriendList
+ self.coreContext.mCore.addFriendList(list: self.friendList!)
} else {
print(
"$TAG Friend list [$LINPHONE_ADDRESS_BOOK_FRIEND_LIST] found, removing existing friends if any"
)
- friendList!.friends.forEach { friend in
- _ = friendList!.removeFriend(linphoneFriend: friend)
+ self.friendList!.friends.forEach { friend in
+ _ = self.friendList!.removeFriend(linphoneFriend: friend)
}
}
-
- fetchedFriends.forEach { friend in
- _ = friendList!.addLocalFriend(linphoneFriend: friend)
- }
-
- friends.removeAll()
-
- print("$TAG Friends added")
-
- friendList!.updateSubscriptions()
- print("$TAG Subscription(s) updated")
}
+
+ let store = CNContactStore()
+ store.requestAccess(for: .contacts) { (granted, error) in
+ if let error = error {
+ print("failed to request access", error)
+ return
+ }
+ if granted {
+ let keys = [CNContactEmailAddressesKey, CNContactPhoneNumbersKey,
+ CNContactFamilyNameKey, CNContactGivenNameKey, CNContactNicknameKey,
+ CNContactPostalAddressesKey, CNContactIdentifierKey,
+ CNInstantMessageAddressUsernameKey, CNContactInstantMessageAddressesKey,
+ CNContactImageDataKey, CNContactThumbnailImageDataKey, CNContactOrganizationNameKey]
+ let request = CNContactFetchRequest(keysToFetch: keys as [CNKeyDescriptor])
+ do {
+ try store.enumerateContacts(with: request, usingBlock: { (contact, _) in
+
+ DispatchQueue.main.sync {
+ let newContact = Contact(
+ firstName: contact.givenName,
+ lastName: contact.familyName,
+ organizationName: contact.organizationName,
+ displayName: contact.nickname,
+ sipAddresses: contact.instantMessageAddresses.map { $0.value.service == "SIP" ? $0.value.username : "" },
+ phoneNumbers: contact.phoneNumbers.map { PhoneNumber(numLabel: $0.label ?? "", num: $0.value.stringValue)},
+ imageData: ""
+ )
+
+ self.saveImage(
+ image:
+ UIImage(data: contact.thumbnailImageData ?? Data())
+ ?? self.textToImage(
+ firstName: contact.givenName.isEmpty
+ && contact.familyName.isEmpty
+ && contact.phoneNumbers.first?.value.stringValue != nil
+ ? contact.phoneNumbers.first!.value.stringValue
+ : contact.givenName, lastName: contact.familyName),
+ name: contact.givenName + contact.familyName + String(Int.random(in: 1...1000)),
+ contact: newContact)
+ }
+ })
+
+ } catch let error {
+ print("Failed to enumerate contact", error)
+ }
+
+ } else {
+ print("access denied")
+ }
+ }
+ self.magicSearch.searchForContacts(sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue)
}
}
+
+ func textToImage(firstName: String, lastName: String) -> UIImage {
+ let lblNameInitialize = UILabel()
+ lblNameInitialize.frame.size = CGSize(width: 100.0, height: 100.0)
+ lblNameInitialize.font = UIFont(name: "NotoSans-ExtraBold", size: 40)
+ lblNameInitialize.textColor = UIColor(Color.grayMain2c600)
+
+ var textToDisplay = ""
+ if firstName.first != nil {
+ textToDisplay += String(firstName.first!)
+ }
+ if lastName.first != nil {
+ textToDisplay += String(lastName.first!)
+ }
+
+ lblNameInitialize.text = textToDisplay.uppercased()
+ lblNameInitialize.textAlignment = .center
+ lblNameInitialize.backgroundColor = UIColor(Color.grayMain2c200)
+ lblNameInitialize.layer.cornerRadius = 10.0
+
+ var IBImgViewUserProfile = UIImage()
+ UIGraphicsBeginImageContext(lblNameInitialize.frame.size)
+ lblNameInitialize.layer.render(in: UIGraphicsGetCurrentContext()!)
+ IBImgViewUserProfile = UIGraphicsGetImageFromCurrentImageContext()!
+ UIGraphicsEndImageContext()
+
+ return IBImgViewUserProfile
+ }
- func saveImage(image: UIImage, name: String) -> String {
+ func saveImage(image: UIImage, name: String, contact: Contact) {
guard let data = image.jpegData(compressionQuality: 1) ?? image.pngData() else {
- return ""
- }
- let directory = FileManager.default.temporaryDirectory
- print("FileManagerFileManager \(directory.absoluteString)")
- do {
- try data.write(to: directory.appendingPathComponent(name + ".png"))
- return directory.appendingPathComponent(name + ".png").absoluteString
- } catch {
- print(error.localizedDescription)
- return ""
+ return
}
+
+ 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)
+
+ 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 phoneNumber = try Factory.Instance.createFriendPhoneNumber(phoneNumber: phone.num, label: phone.numLabel)
+ 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.done()
+
+ _ = self.friendList!.addLocalFriend(linphoneFriend: friend)
+
+ self.friendList!.updateSubscriptions()
+
+ } catch let error {
+ print("Failed to enumerate contact", error)
+ }
+ }
}
-
- func textToImage(firstName: String, lastName: String) -> UIImage {
-
- let lblNameInitialize = UILabel()
- lblNameInitialize.frame.size = CGSize(width: 100.0, height: 100.0)
- lblNameInitialize.font = UIFont(name: "NotoSans-ExtraBold", size: 40)
- lblNameInitialize.textColor = UIColor(Color.grayMain2c600)
-
- var textToDisplay = ""
- if firstName.first != nil {
- textToDisplay += String(firstName.first!)
- }
- if lastName.first != nil {
- textToDisplay += String(lastName.first!)
- }
-
- lblNameInitialize.text = textToDisplay.uppercased()
- lblNameInitialize.textAlignment = .center
- lblNameInitialize.backgroundColor = UIColor(Color.grayMain2c200)
- lblNameInitialize.layer.cornerRadius = 10.0
-
- var IBImgViewUserProfile = UIImage()
- UIGraphicsBeginImageContext(lblNameInitialize.frame.size)
- lblNameInitialize.layer.render(in: UIGraphicsGetCurrentContext()!)
- IBImgViewUserProfile = UIGraphicsGetImageFromCurrentImageContext()!
- UIGraphicsEndImageContext()
-
- return IBImgViewUserProfile
- }
+
+ func awaitDataWrite(data: Data, name: String, completion: @escaping ((), String) -> Void) {
+ let directory = FileManager.default.temporaryDirectory
+
+ DispatchQueue.main.async {
+ do {
+ let decodedData: () = try data.write(to: directory.appendingPathComponent(name + ".png"))
+ completion(decodedData, directory.appendingPathComponent(name + ".png").absoluteString) // <--- here, return the results
+ } catch {
+ print("Error: ", error) // need to deal with errors
+ completion((), "") // <--- here, should return the error
+ }
+ }
+ }
}
struct PhoneNumber {
diff --git a/Linphone/LinphoneApp.swift b/Linphone/LinphoneApp.swift
index b6eba8007..0efeb7e77 100644
--- a/Linphone/LinphoneApp.swift
+++ b/Linphone/LinphoneApp.swift
@@ -23,13 +23,22 @@ import SwiftUI
struct LinphoneApp: App {
@ObservedObject private var coreContext = CoreContext.shared
+ @ObservedObject private var sharedMainViewModel = SharedMainViewModel()
+
@State private var isActive = false
var body: some Scene {
WindowGroup {
if isActive {
- ContentView(sharedMainViewModel: SharedMainViewModel(), contactViewModel: ContactViewModel(), historyViewModel: HistoryViewModel())
- .toast(isShowing: $coreContext.toastMessage)
+ if !sharedMainViewModel.welcomeViewDisplayed {
+ WelcomeView(sharedMainViewModel: sharedMainViewModel)
+ } else if coreContext.mCore.defaultAccount == nil || sharedMainViewModel.displayProfileMode {
+ AssistantView(sharedMainViewModel: sharedMainViewModel)
+ .toast(isShowing: $coreContext.toastMessage)
+ } else {
+ ContentView(contactViewModel: ContactViewModel(), historyViewModel: HistoryViewModel())
+ .toast(isShowing: $coreContext.toastMessage)
+ }
} else {
SplashScreen(isActive: $isActive)
}
diff --git a/Linphone/UI/Main/Contacts/Fragments/ContactsFragment.swift b/Linphone/UI/Main/Contacts/Fragments/ContactsFragment.swift
index 00e11cc3a..155004e04 100644
--- a/Linphone/UI/Main/Contacts/Fragments/ContactsFragment.swift
+++ b/Linphone/UI/Main/Contacts/Fragments/ContactsFragment.swift
@@ -21,6 +21,7 @@ import SwiftUI
struct ContactsFragment: View {
+ @ObservedObject var magicSearch = MagicSearchSingleton.shared
@ObservedObject var contactViewModel: ContactViewModel
@State private var orientation = UIDevice.current.orientation
@@ -29,42 +30,43 @@ struct ContactsFragment: View {
var body: some View {
VStack(alignment: .leading) {
- HStack(alignment: .center) {
- Text("Favourites")
- .default_text_style_800(styleSize: 16)
-
- Spacer()
-
- Image(isFavoriteOpen ? "caret-up" : "caret-down")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(Color.grayMain2c600)
- .frame(width: 25, height: 25, alignment: .leading)
- }
- .padding(.top, 30)
- .padding(.horizontal, 16)
- .background(.white)
- .onTapGesture {
- withAnimation {
- isFavoriteOpen.toggle()
+ if !magicSearch.lastSearch.filter({ $0.friend?.starred == true }).isEmpty {
+ HStack(alignment: .center) {
+ Text("Favourites")
+ .default_text_style_800(styleSize: 16)
+
+ Spacer()
+
+ Image(isFavoriteOpen ? "caret-up" : "caret-down")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(Color.grayMain2c600)
+ .frame(width: 25, height: 25, alignment: .leading)
+ }
+ .padding(.top, 30)
+ .padding(.horizontal, 16)
+ .background(.white)
+ .onTapGesture {
+ withAnimation {
+ isFavoriteOpen.toggle()
+ }
}
- }
-
- if isFavoriteOpen {
- FavoriteContactsListFragment(contactViewModel: contactViewModel, favoriteContactsListViewModel: FavoriteContactsListViewModel())
- .zIndex(-1)
- .transition(.move(edge: .top))
- }
-
- HStack(alignment: .center) {
- Text("All contacts")
- .default_text_style_800(styleSize: 16)
- Spacer()
+ if isFavoriteOpen {
+ FavoriteContactsListFragment(contactViewModel: contactViewModel, favoriteContactsListViewModel: FavoriteContactsListViewModel())
+ .zIndex(-1)
+ .transition(.move(edge: .top))
+ }
+
+ HStack(alignment: .center) {
+ Text("All contacts")
+ .default_text_style_800(styleSize: 16)
+
+ Spacer()
+ }
+ .padding(.top, 10)
+ .padding(.horizontal, 16)
}
- .padding(.top, 10)
- .padding(.horizontal, 16)
-
ContactsListFragment(contactViewModel: contactViewModel, contactsListViewModel: ContactsListViewModel())
}
.navigationBarHidden(true)
diff --git a/Linphone/UI/Main/Contacts/Fragments/ContactsListFragment.swift b/Linphone/UI/Main/Contacts/Fragments/ContactsListFragment.swift
index cd1c984a1..174f00fa0 100644
--- a/Linphone/UI/Main/Contacts/Fragments/ContactsListFragment.swift
+++ b/Linphone/UI/Main/Contacts/Fragments/ContactsListFragment.swift
@@ -64,7 +64,7 @@ struct ContactsListFragment: View {
.frame(width: 45, height: 45)
.clipShape(Circle())
case .failure:
- Image("profile-image-example")
+ Image("profil-picture-default")
.resizable()
.frame(width: 45, height: 45)
.clipShape(Circle())
@@ -73,7 +73,7 @@ struct ContactsListFragment: View {
}
}
} else {
- Image("profile-image-example")
+ Image("profil-picture-default")
.resizable()
.frame(width: 45, height: 45)
.clipShape(Circle())
diff --git a/Linphone/UI/Main/Contacts/Fragments/FavoriteContactsListFragment.swift b/Linphone/UI/Main/Contacts/Fragments/FavoriteContactsListFragment.swift
index 73275c15e..c013cbd61 100644
--- a/Linphone/UI/Main/Contacts/Fragments/FavoriteContactsListFragment.swift
+++ b/Linphone/UI/Main/Contacts/Fragments/FavoriteContactsListFragment.swift
@@ -29,7 +29,7 @@ struct FavoriteContactsListFragment: View {
var body: some View {
ScrollView(.horizontal) {
HStack {
- ForEach(0.. UIScreen.main.bounds.size.height {
- VStack {
- Group {
- Spacer()
- Button(action: {
- self.index = 0
- }, label: {
- VStack {
- Image("address-book")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(self.index == 0 ? Color.orangeMain500 : Color.grayMain2c600)
- .frame(width: 25, height: 25)
- if self.index == 0 {
- Text("Contacts")
- .default_text_style_700(styleSize: 10)
- } else {
- Text("Contacts")
- .default_text_style(styleSize: 10)
- }
- }
- })
-
- Spacer()
-
- Button(action: {
- self.index = 1
- contactViewModel.contactTitle = ""
- }, label: {
- VStack {
- Image("phone")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(self.index == 1 ? Color.orangeMain500 : Color.grayMain2c600)
- .frame(width: 25, height: 25)
- if self.index == 1 {
- Text("Calls")
- .default_text_style_700(styleSize: 10)
- } else {
- Text("Calls")
- .default_text_style(styleSize: 10)
- }
- }
- })
-
- Spacer()
- }
- }
- .frame(width: 75)
- .padding(.leading,
- orientation == .landscapeRight && geometry.safeAreaInsets.bottom > 0
- ? -geometry.safeAreaInsets.leading
- : 0)
- }
-
- VStack(spacing: 0) {
- if searchIsActive == false {
- HStack {
- Image("profile-image-example")
- .resizable()
- .frame(width: 45, height: 45)
- .clipShape(Circle())
- .onTapGesture {
- openMenu()
- }
-
- Text(index == 0 ? "Contacts" : "Calls")
- .default_text_style_white_800(styleSize: 20)
- .padding(.leading, 10)
-
- Spacer()
-
- Button {
- withAnimation {
- searchIsActive.toggle()
- }
- } label: {
- Image("search")
- }
-
- Menu {
- Button {
- isMenuOpen = false
- magicSearch.allContact = true
- magicSearch.searchForContacts(
- sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue)
- } label: {
- HStack {
- Text("See all")
- Spacer()
- if magicSearch.allContact {
- Image("green-check")
- }
- }
+
+ var body: some View {
+ GeometryReader { geometry in
+ ZStack {
+ VStack(spacing: 0) {
+ HStack(spacing: 0) {
+ if orientation == .landscapeLeft
+ || orientation == .landscapeRight
+ || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height {
+ VStack {
+ Group {
+ Spacer()
+ Button(action: {
+ self.index = 0
+ }, label: {
+ VStack {
+ Image("address-book")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(self.index == 0 ? Color.orangeMain500 : Color.grayMain2c600)
+ .frame(width: 25, height: 25)
+ if self.index == 0 {
+ Text("Contacts")
+ .default_text_style_700(styleSize: 10)
+ } else {
+ Text("Contacts")
+ .default_text_style(styleSize: 10)
}
-
- Button {
- isMenuOpen = false
- magicSearch.allContact = false
- magicSearch.searchForContacts(
- sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue)
- } label: {
- HStack {
- Text("See Linphone contact")
- Spacer()
- if !magicSearch.allContact {
- Image("green-check")
- }
- }
- }
- } label: {
- Image(index == 0 ? "filtres" : "more")
- }
- .padding(.leading)
- .onTapGesture {
- isMenuOpen = true
}
- }
- .frame(maxWidth: .infinity)
- .frame(height: 50)
- .padding(.horizontal)
- .padding(.bottom, 5)
- .background(Color.orangeMain500)
- } else {
- HStack {
- Button {
- withAnimation {
- self.focusedField = false
- searchIsActive.toggle()
- }
-
- text = ""
- magicSearch.currentFilter = ""
+ })
+
+ Spacer()
+
+ Button(action: {
+ self.index = 1
+ contactViewModel.contactTitle = ""
+ }, label: {
+ VStack {
+ Image("phone")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(self.index == 1 ? Color.orangeMain500 : Color.grayMain2c600)
+ .frame(width: 25, height: 25)
+ if self.index == 1 {
+ Text("Calls")
+ .default_text_style_700(styleSize: 10)
+ } else {
+ Text("Calls")
+ .default_text_style(styleSize: 10)
+ }
+ }
+ })
+
+ Spacer()
+ }
+ }
+ .frame(width: 75)
+ .padding(.leading,
+ orientation == .landscapeRight && geometry.safeAreaInsets.bottom > 0
+ ? -geometry.safeAreaInsets.leading
+ : 0)
+ }
+
+ VStack(spacing: 0) {
+ if searchIsActive == false {
+ HStack {
+ Image("profile-image-example")
+ .resizable()
+ .frame(width: 45, height: 45)
+ .clipShape(Circle())
+ .onTapGesture {
+ openMenu()
+ }
+
+ Text(index == 0 ? "Contacts" : "Calls")
+ .default_text_style_white_800(styleSize: 20)
+ .padding(.leading, 10)
+
+ Spacer()
+
+ Button {
+ withAnimation {
+ searchIsActive.toggle()
+ }
+ } label: {
+ Image("search")
+ }
+
+ Menu {
+ Button {
+ isMenuOpen = false
+ magicSearch.allContact = true
magicSearch.searchForContacts(
sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue)
- } label: {
- Image("caret-left")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(.white)
- .frame(width: 25, height: 25, alignment: .leading)
- }
-
- if #available(iOS 16.0, *) {
- TextEditor(text: Binding(
- get: {
- return text
- },
- set: { value in
- var newValue = value
- if value.contains("\n") {
- newValue = value.replacingOccurrences(of: "\n", with: "")
- }
- text = newValue
- }
- ))
- .default_text_style_white_700(styleSize: 15)
- .padding(.all, 6)
- .accentColor(.white)
- .scrollContentBackground(.hidden)
- .focused($focusedField)
- .onAppear {
- self.focusedField = true
- }
- .onChange(of: text) { newValue in
- magicSearch.currentFilter = newValue
- magicSearch.searchForContacts(
- sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue)
- }
- } else {
- TextEditor(text: Binding(
- get: {
- return text
- },
- set: { value in
- var newValue = value
- if value.contains("\n") {
- newValue = value.replacingOccurrences(of: "\n", with: "")
- }
- text = newValue
- }
- ))
- .default_text_style_white_700(styleSize: 15)
- .padding(.all, 6)
- .accentColor(.white)
- .focused($focusedField)
- .onAppear {
- self.focusedField = true
- }
- .onChange(of: text) { newValue in
- magicSearch.currentFilter = newValue
- magicSearch.searchForContacts(
- sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue)
- }
- }
-
- Button {
- text = ""
- } label: {
- Image("x")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(.white)
- .frame(width: 25, height: 25, alignment: .leading)
- }
- .padding(.leading)
- }
- .frame(maxWidth: .infinity)
- .frame(height: 50)
- .padding(.horizontal)
- .padding(.bottom, 5)
- .background(Color.orangeMain500)
- }
-
- if self.index == 0 {
- ContactsView(contactViewModel: contactViewModel, historyViewModel: historyViewModel)
- } else if self.index == 1 {
- HistoryView()
- }
- }
- .frame(maxWidth:
- (orientation == .landscapeLeft
- || orientation == .landscapeRight
- || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height)
- ? geometry.size.width/100*40
- : .infinity
- )
- .background(
- Color.white
- .shadow(color: Color.gray200, radius: 4, x: 0, y: 0)
- .mask(Rectangle().padding(.horizontal, -8))
- )
-
- if orientation == .landscapeLeft
- || orientation == .landscapeRight
- || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height {
- Spacer()
- }
- }
-
- if !(orientation == .landscapeLeft
- || orientation == .landscapeRight
- || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) && !searchIsActive {
- HStack {
- Group {
- Spacer()
- Button(action: {
- self.index = 0
- }, label: {
- VStack {
- Image("address-book")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(self.index == 0 ? Color.orangeMain500 : Color.grayMain2c600)
- .frame(width: 25, height: 25)
- if self.index == 0 {
- Text("Contacts")
- .default_text_style_700(styleSize: 10)
- } else {
- Text("Contacts")
- .default_text_style(styleSize: 10)
- }
- }
- })
- .padding(.top)
-
- Spacer()
-
- Button(action: {
- self.index = 1
- contactViewModel.contactTitle = ""
- }, label: {
- VStack {
- Image("phone")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(self.index == 1 ? Color.orangeMain500 : Color.grayMain2c600)
- .frame(width: 25, height: 25)
- if self.index == 1 {
- Text("Calls")
- .default_text_style_700(styleSize: 10)
- } else {
- Text("Calls")
- .default_text_style(styleSize: 10)
- }
- }
- })
- .padding(.top)
- Spacer()
- }
- }
- .padding(.bottom, geometry.safeAreaInsets.bottom > 0 ? 0 : 15)
- .background(
- Color.white
- .shadow(color: Color.gray200, radius: 4, x: 0, y: 0)
- .mask(Rectangle().padding(.top, -8))
- )
- }
- }
-
- if !contactViewModel.contactTitle.isEmpty || !historyViewModel.historyTitle.isEmpty {
- HStack(spacing: 0) {
- Spacer()
- .frame(maxWidth:
- (orientation == .landscapeLeft
- || orientation == .landscapeRight
- || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height)
- ? (geometry.size.width/100*40) + 75
- : 0
- )
- if self.index == 0 {
- ContactFragment(contactViewModel: contactViewModel)
- .frame(maxWidth: .infinity)
- .background(Color.gray100)
- .ignoresSafeArea(.keyboard)
- } else if self.index == 1 {
- HistoryContactFragment()
- .frame(maxWidth: .infinity)
- .background(Color.gray100)
- .ignoresSafeArea(.keyboard)
- }
- }
- .onAppear {
- if !(orientation == .landscapeLeft
- || orientation == .landscapeRight
- || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height)
- && searchIsActive {
- self.focusedField = false
- }
- }
- .onDisappear {
- if !(orientation == .landscapeLeft
- || orientation == .landscapeRight
- || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height)
- && searchIsActive {
- self.focusedField = true
- }
- }
- .padding(.leading,
- orientation == .landscapeRight && geometry.safeAreaInsets.bottom > 0
- ? -geometry.safeAreaInsets.leading
- : 0)
- .transition(.move(edge: .trailing))
- .zIndex(1)
- }
-
- SideMenu(
- width: geometry.size.width / 5 * 4,
- isOpen: self.sideMenuIsOpen,
- menuClose: self.openMenu,
- safeAreaInsets: geometry.safeAreaInsets
- )
- .ignoresSafeArea(.all)
- .zIndex(2)
- }
- }
- .overlay {
- if isMenuOpen {
- Color.white.opacity(0.001)
+ } label: {
+ HStack {
+ Text("See all")
+ Spacer()
+ if magicSearch.allContact {
+ Image("green-check")
+ }
+ }
+ }
+
+ Button {
+ isMenuOpen = false
+ magicSearch.allContact = false
+ magicSearch.searchForContacts(
+ sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue)
+ } label: {
+ HStack {
+ Text("See Linphone contact")
+ Spacer()
+ if !magicSearch.allContact {
+ Image("green-check")
+ }
+ }
+ }
+ } label: {
+ Image(index == 0 ? "filtres" : "more")
+ }
+ .padding(.leading)
+ .onTapGesture {
+ isMenuOpen = true
+ }
+ }
+ .frame(maxWidth: .infinity)
+ .frame(height: 50)
+ .padding(.horizontal)
+ .padding(.bottom, 5)
+ .background(Color.orangeMain500)
+ } else {
+ HStack {
+ Button {
+ withAnimation {
+ self.focusedField = false
+ searchIsActive.toggle()
+ }
+
+ text = ""
+ magicSearch.currentFilter = ""
+ magicSearch.searchForContacts(
+ sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue)
+ } label: {
+ Image("caret-left")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(.white)
+ .frame(width: 25, height: 25, alignment: .leading)
+ }
+
+ if #available(iOS 16.0, *) {
+ TextEditor(text: Binding(
+ get: {
+ return text
+ },
+ set: { value in
+ var newValue = value
+ if value.contains("\n") {
+ newValue = value.replacingOccurrences(of: "\n", with: "")
+ }
+ text = newValue
+ }
+ ))
+ .default_text_style_white_700(styleSize: 15)
+ .padding(.all, 6)
+ .accentColor(.white)
+ .scrollContentBackground(.hidden)
+ .focused($focusedField)
+ .onAppear {
+ self.focusedField = true
+ }
+ .onChange(of: text) { newValue in
+ magicSearch.currentFilter = newValue
+ magicSearch.searchForContacts(
+ sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue)
+ }
+ } else {
+ TextEditor(text: Binding(
+ get: {
+ return text
+ },
+ set: { value in
+ var newValue = value
+ if value.contains("\n") {
+ newValue = value.replacingOccurrences(of: "\n", with: "")
+ }
+ text = newValue
+ }
+ ))
+ .default_text_style_white_700(styleSize: 15)
+ .padding(.all, 6)
+ .accentColor(.white)
+ .focused($focusedField)
+ .onAppear {
+ self.focusedField = true
+ }
+ .onChange(of: text) { newValue in
+ magicSearch.currentFilter = newValue
+ magicSearch.searchForContacts(
+ sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue)
+ }
+ }
+
+ Button {
+ text = ""
+ } label: {
+ Image("x")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(.white)
+ .frame(width: 25, height: 25, alignment: .leading)
+ }
+ .padding(.leading)
+ }
+ .frame(maxWidth: .infinity)
+ .frame(height: 50)
+ .padding(.horizontal)
+ .padding(.bottom, 5)
+ .background(Color.orangeMain500)
+ }
+
+ if self.index == 0 {
+ ContactsView(contactViewModel: contactViewModel, historyViewModel: historyViewModel)
+ } else if self.index == 1 {
+ HistoryView()
+ }
+ }
+ .frame(maxWidth:
+ (orientation == .landscapeLeft
+ || orientation == .landscapeRight
+ || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height)
+ ? geometry.size.width/100*40
+ : .infinity
+ )
+ .background(
+ Color.white
+ .shadow(color: Color.gray200, radius: 4, x: 0, y: 0)
+ .mask(Rectangle().padding(.horizontal, -8))
+ )
+
+ if orientation == .landscapeLeft
+ || orientation == .landscapeRight
+ || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height {
+ Spacer()
+ }
+ }
+
+ if !(orientation == .landscapeLeft
+ || orientation == .landscapeRight
+ || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) && !searchIsActive {
+ HStack {
+ Group {
+ Spacer()
+ Button(action: {
+ self.index = 0
+ }, label: {
+ VStack {
+ Image("address-book")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(self.index == 0 ? Color.orangeMain500 : Color.grayMain2c600)
+ .frame(width: 25, height: 25)
+ if self.index == 0 {
+ Text("Contacts")
+ .default_text_style_700(styleSize: 10)
+ } else {
+ Text("Contacts")
+ .default_text_style(styleSize: 10)
+ }
+ }
+ })
+ .padding(.top)
+
+ Spacer()
+
+ Button(action: {
+ self.index = 1
+ contactViewModel.contactTitle = ""
+ }, label: {
+ VStack {
+ Image("phone")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(self.index == 1 ? Color.orangeMain500 : Color.grayMain2c600)
+ .frame(width: 25, height: 25)
+ if self.index == 1 {
+ Text("Calls")
+ .default_text_style_700(styleSize: 10)
+ } else {
+ Text("Calls")
+ .default_text_style(styleSize: 10)
+ }
+ }
+ })
+ .padding(.top)
+ Spacer()
+ }
+ }
+ .padding(.bottom, geometry.safeAreaInsets.bottom > 0 ? 0 : 15)
+ .background(
+ Color.white
+ .shadow(color: Color.gray200, radius: 4, x: 0, y: 0)
+ .mask(Rectangle().padding(.top, -8))
+ )
+ }
+ }
+
+ if !contactViewModel.contactTitle.isEmpty || !historyViewModel.historyTitle.isEmpty {
+ HStack(spacing: 0) {
+ Spacer()
+ .frame(maxWidth:
+ (orientation == .landscapeLeft
+ || orientation == .landscapeRight
+ || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height)
+ ? (geometry.size.width/100*40) + 75
+ : 0
+ )
+ if self.index == 0 {
+ ContactFragment(contactViewModel: contactViewModel)
+ .frame(maxWidth: .infinity)
+ .background(Color.gray100)
+ .ignoresSafeArea(.keyboard)
+ } else if self.index == 1 {
+ HistoryContactFragment()
+ .frame(maxWidth: .infinity)
+ .background(Color.gray100)
+ .ignoresSafeArea(.keyboard)
+ }
+ }
+ .onAppear {
+ if !(orientation == .landscapeLeft
+ || orientation == .landscapeRight
+ || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height)
+ && searchIsActive {
+ self.focusedField = false
+ }
+ }
+ .onDisappear {
+ if !(orientation == .landscapeLeft
+ || orientation == .landscapeRight
+ || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height)
+ && searchIsActive {
+ self.focusedField = true
+ }
+ }
+ .padding(.leading,
+ orientation == .landscapeRight && geometry.safeAreaInsets.bottom > 0
+ ? -geometry.safeAreaInsets.leading
+ : 0)
+ .transition(.move(edge: .trailing))
+ .zIndex(1)
+ }
+
+ SideMenu(
+ width: geometry.size.width / 5 * 4,
+ isOpen: self.sideMenuIsOpen,
+ menuClose: self.openMenu,
+ safeAreaInsets: geometry.safeAreaInsets
+ )
+ .ignoresSafeArea(.all)
+ .zIndex(2)
+ }
+ }
+ .overlay {
+ if isMenuOpen {
+ Color.white.opacity(0.001)
.ignoresSafeArea()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.onTapGesture {
isMenuOpen = false
}
- }
}
- .onRotate { newOrientation in
- if (!contactViewModel.contactTitle.isEmpty || !historyViewModel.historyTitle.isEmpty) && searchIsActive {
- self.focusedField = false
- } else if searchIsActive {
- self.focusedField = true
- }
- orientation = newOrientation
- }
- }
- }
-
- func openMenu() {
- withAnimation {
- self.sideMenuIsOpen.toggle()
- }
- }
+ }
+ .onRotate { newOrientation in
+ if (!contactViewModel.contactTitle.isEmpty || !historyViewModel.historyTitle.isEmpty) && searchIsActive {
+ self.focusedField = false
+ } else if searchIsActive {
+ self.focusedField = true
+ }
+ orientation = newOrientation
+ }
+ }
+
+ func openMenu() {
+ withAnimation {
+ self.sideMenuIsOpen.toggle()
+ }
+ }
}
#Preview {
- ContentView(sharedMainViewModel: SharedMainViewModel(), contactViewModel: ContactViewModel(), historyViewModel: HistoryViewModel())
+ ContentView(contactViewModel: ContactViewModel(), historyViewModel: HistoryViewModel())
}