okay place within the development of the contacts feature
This commit is contained in:
@@ -38,6 +38,8 @@
|
|||||||
89BDCDEF2769B50C00577829 /* ContactsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89BDCDEE2769B50C00577829 /* ContactsView.swift */; };
|
89BDCDEF2769B50C00577829 /* ContactsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89BDCDEE2769B50C00577829 /* ContactsView.swift */; };
|
||||||
89BDCDF12769E64200577829 /* Firestore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89BDCDF02769E64200577829 /* Firestore.swift */; };
|
89BDCDF12769E64200577829 /* Firestore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89BDCDF02769E64200577829 /* Firestore.swift */; };
|
||||||
89D99D2E2766FD6B00237814 /* Liquid in Frameworks */ = {isa = PBXBuildFile; productRef = 89D99D2D2766FD6B00237814 /* Liquid */; };
|
89D99D2E2766FD6B00237814 /* Liquid in Frameworks */ = {isa = PBXBuildFile; productRef = 89D99D2D2766FD6B00237814 /* Liquid */; };
|
||||||
|
89F05B9B276A87920002E9C7 /* ContactsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F05B9A276A87920002E9C7 /* ContactsViewModel.swift */; };
|
||||||
|
89F05B9F276A8D360002E9C7 /* Contact.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F05B9E276A8D360002E9C7 /* Contact.swift */; };
|
||||||
89F1386D2767EB19006680ED /* SignInView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F1386C2767EB19006680ED /* SignInView.swift */; };
|
89F1386D2767EB19006680ED /* SignInView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F1386C2767EB19006680ED /* SignInView.swift */; };
|
||||||
89F138702767F55F006680ED /* GoogleSignIn in Frameworks */ = {isa = PBXBuildFile; productRef = 89F1386F2767F55F006680ED /* GoogleSignIn */; };
|
89F138702767F55F006680ED /* GoogleSignIn in Frameworks */ = {isa = PBXBuildFile; productRef = 89F1386F2767F55F006680ED /* GoogleSignIn */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
@@ -71,6 +73,8 @@
|
|||||||
89BDCDEB2769918D00577829 /* OnboardingTrioView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingTrioView.swift; sourceTree = "<group>"; };
|
89BDCDEB2769918D00577829 /* OnboardingTrioView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingTrioView.swift; sourceTree = "<group>"; };
|
||||||
89BDCDEE2769B50C00577829 /* ContactsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsView.swift; sourceTree = "<group>"; };
|
89BDCDEE2769B50C00577829 /* ContactsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsView.swift; sourceTree = "<group>"; };
|
||||||
89BDCDF02769E64200577829 /* Firestore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Firestore.swift; sourceTree = "<group>"; };
|
89BDCDF02769E64200577829 /* Firestore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Firestore.swift; sourceTree = "<group>"; };
|
||||||
|
89F05B9A276A87920002E9C7 /* ContactsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsViewModel.swift; sourceTree = "<group>"; };
|
||||||
|
89F05B9E276A8D360002E9C7 /* Contact.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Contact.swift; sourceTree = "<group>"; };
|
||||||
89F1386C2767EB19006680ED /* SignInView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInView.swift; sourceTree = "<group>"; };
|
89F1386C2767EB19006680ED /* SignInView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInView.swift; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
@@ -200,6 +204,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
891A160D27657CEA00B26659 /* User.swift */,
|
891A160D27657CEA00B26659 /* User.swift */,
|
||||||
|
89F05B9E276A8D360002E9C7 /* Contact.swift */,
|
||||||
);
|
);
|
||||||
path = Models;
|
path = Models;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -242,6 +247,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
89BDCDEE2769B50C00577829 /* ContactsView.swift */,
|
89BDCDEE2769B50C00577829 /* ContactsView.swift */,
|
||||||
|
89F05B9A276A87920002E9C7 /* ContactsViewModel.swift */,
|
||||||
);
|
);
|
||||||
path = Contacts;
|
path = Contacts;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -341,6 +347,7 @@
|
|||||||
files = (
|
files = (
|
||||||
89BDCDEC2769918D00577829 /* OnboardingTrioView.swift in Sources */,
|
89BDCDEC2769918D00577829 /* OnboardingTrioView.swift in Sources */,
|
||||||
891A15E327653A7000B26659 /* ContentView.swift in Sources */,
|
891A15E327653A7000B26659 /* ContentView.swift in Sources */,
|
||||||
|
89F05B9F276A8D360002E9C7 /* Contact.swift in Sources */,
|
||||||
891A160327656FC700B26659 /* HomeView.swift in Sources */,
|
891A160327656FC700B26659 /* HomeView.swift in Sources */,
|
||||||
891A160B2765732700B26659 /* HomeViewModel.swift in Sources */,
|
891A160B2765732700B26659 /* HomeViewModel.swift in Sources */,
|
||||||
892179E62765FECD001E6C60 /* FooterControlsViewModel.swift in Sources */,
|
892179E62765FECD001E6C60 /* FooterControlsViewModel.swift in Sources */,
|
||||||
@@ -352,6 +359,7 @@
|
|||||||
891A1611276590B000B26659 /* ChatsCarouselView.swift in Sources */,
|
891A1611276590B000B26659 /* ChatsCarouselView.swift in Sources */,
|
||||||
89BDCDE527695DB900577829 /* NirvanaImage.swift in Sources */,
|
89BDCDE527695DB900577829 /* NirvanaImage.swift in Sources */,
|
||||||
891A16132765A44300B26659 /* ChatsCarouselViewModel.swift in Sources */,
|
891A16132765A44300B26659 /* ChatsCarouselViewModel.swift in Sources */,
|
||||||
|
89F05B9B276A87920002E9C7 /* ContactsViewModel.swift in Sources */,
|
||||||
891A15E127653A7000B26659 /* nirvana_iosApp.swift in Sources */,
|
891A15E127653A7000B26659 /* nirvana_iosApp.swift in Sources */,
|
||||||
891A160127656FB200B26659 /* FooterView.swift in Sources */,
|
891A160127656FB200B26659 /* FooterView.swift in Sources */,
|
||||||
89BDCDEA27697F9C00577829 /* UserMenu.swift in Sources */,
|
89BDCDEA27697F9C00577829 /* UserMenu.swift in Sources */,
|
||||||
@@ -497,6 +505,7 @@
|
|||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = "nirvana-ios/Info.plist";
|
INFOPLIST_FILE = "nirvana-ios/Info.plist";
|
||||||
|
INFOPLIST_KEY_NSContactsUsageDescription = "Please provide access to build your inner circle 🌱";
|
||||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||||
@@ -529,6 +538,7 @@
|
|||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = "nirvana-ios/Info.plist";
|
INFOPLIST_FILE = "nirvana-ios/Info.plist";
|
||||||
|
INFOPLIST_KEY_NSContactsUsageDescription = "Please provide access to build your inner circle 🌱";
|
||||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
|
<key>NSContactsUsageDescription</key>
|
||||||
|
<string>Please provide access to build your inner circle 🌱</string>
|
||||||
<key>CFBundleURLTypes</key>
|
<key>CFBundleURLTypes</key>
|
||||||
<array>
|
<array>
|
||||||
<dict>
|
<dict>
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
//
|
||||||
|
// Contact.swift
|
||||||
|
// nirvana-ios
|
||||||
|
//
|
||||||
|
// Created by Arjun Patel on 12/15/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Contacts
|
||||||
|
|
||||||
|
struct Contact: Identifiable, Hashable {
|
||||||
|
var id = UUID()
|
||||||
|
var firstName: String
|
||||||
|
var lastName: String
|
||||||
|
var phoneNumbers: [String]
|
||||||
|
var emailAddresses: [String]
|
||||||
|
}
|
||||||
|
|
||||||
|
enum PermissionsError: Identifiable {
|
||||||
|
var id: String { UUID().uuidString }
|
||||||
|
case userError
|
||||||
|
case fetchError(_: Error)
|
||||||
|
var description: String {
|
||||||
|
switch self {
|
||||||
|
case .userError:
|
||||||
|
return "Please change permissions in settings"
|
||||||
|
case .fetchError(let error):
|
||||||
|
return error.localizedDescription
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -6,6 +6,8 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import Contacts
|
||||||
|
import ContactsUI
|
||||||
|
|
||||||
struct ContactsView: View {
|
struct ContactsView: View {
|
||||||
var testUsers:[TestUser] = [
|
var testUsers:[TestUser] = [
|
||||||
@@ -16,16 +18,23 @@ struct ContactsView: View {
|
|||||||
TestUser(_profilePic: "rohan", _firstN: "Rohan", _lastN: "Chadha")
|
TestUser(_profilePic: "rohan", _firstN: "Rohan", _lastN: "Chadha")
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ObservedObject var contactsViewModel = ContactsViewModel()
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
List {
|
VStack(spacing: 0) {
|
||||||
ForEach(testUsers) { user in
|
OnboardingTemplateView(imgName: "undraw_grades_re_j7d6", mainLeadingActText: "Add your ", mainHighlightedActText: "closest folks.", mainTrailingActText: "", subActText: "besties, bf or gf, siblings, parents, etc.")
|
||||||
let fullName = "\(user.firstName) \(user.lastName)"
|
|
||||||
IndividualContactView(name: fullName, imageName: user.profilePictureUrl)
|
Rectangle()
|
||||||
}
|
.strokeBorder(style: StrokeStyle(lineWidth: 4, dash: [10]))
|
||||||
|
|
||||||
|
}
|
||||||
|
.background(NirvanaColor.bgLightGrey)
|
||||||
|
.alert(item: $contactsViewModel.permissionsError) {_ in
|
||||||
|
Alert(title: Text("Permissions Needed"),
|
||||||
|
message: Text(contactsViewModel.permissionsError?.description ?? "unknown error"),
|
||||||
|
dismissButton: .default(Text("Ok"), action: contactsViewModel.openSettings))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ContactsView_Previews: PreviewProvider {
|
struct ContactsView_Previews: PreviewProvider {
|
||||||
@@ -40,7 +49,7 @@ private struct IndividualContactView: View {
|
|||||||
|
|
||||||
@Namespace private var animation
|
@Namespace private var animation
|
||||||
@State var isAddedUser = false
|
@State var isAddedUser = false
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(alignment: .center, spacing: 0) {
|
HStack(alignment: .center, spacing: 0) {
|
||||||
Image(imageName)
|
Image(imageName)
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
//
|
||||||
|
// ContactsViewModel.swift
|
||||||
|
// nirvana-ios
|
||||||
|
//
|
||||||
|
// Created by Arjun Patel on 12/15/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Contacts
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
final public class ContactsViewModel : ObservableObject {
|
||||||
|
@Published var contacts : [Contact] = []
|
||||||
|
@Published var permissionsError: PermissionsError? = .none
|
||||||
|
|
||||||
|
init() {
|
||||||
|
self.permissions()
|
||||||
|
}
|
||||||
|
|
||||||
|
func openSettings() {
|
||||||
|
self.permissionsError = .none
|
||||||
|
guard let settingsURL = URL(string: UIApplication.openSettingsURLString) else { return }
|
||||||
|
if UIApplication.shared.canOpenURL(settingsURL) { UIApplication.shared.open(settingsURL)}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func fetchContacts() {
|
||||||
|
//remove all current contacts from vm
|
||||||
|
contacts.removeAll()
|
||||||
|
|
||||||
|
let store = CNContactStore()
|
||||||
|
|
||||||
|
do {
|
||||||
|
let predicate = CNContact.predicateForContacts(matchingName: "sarth")
|
||||||
|
//specific contact details: ex: name, email, etc.
|
||||||
|
let keysToFetch = [CNContactGivenNameKey, CNContactFamilyNameKey] as [CNKeyDescriptor]
|
||||||
|
|
||||||
|
let contacts = try store.unifiedContacts(matching: predicate, keysToFetch: keysToFetch)
|
||||||
|
|
||||||
|
print("Fetched contacts: \(contacts)")
|
||||||
|
} catch {
|
||||||
|
print("Failed to fetch contacts, error: \(error)")
|
||||||
|
// Handle the error
|
||||||
|
self.permissionsError = .fetchError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func permissions() {
|
||||||
|
switch CNContactStore.authorizationStatus(for: .contacts) {
|
||||||
|
case.authorized:
|
||||||
|
print("fetching contacts")
|
||||||
|
fetchContacts()
|
||||||
|
case .notDetermined, .restricted, .denied:
|
||||||
|
CNContactStore().requestAccess(for: .contacts) {granted, error in
|
||||||
|
switch granted {
|
||||||
|
case true:
|
||||||
|
self.fetchContacts()
|
||||||
|
case false:
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
print("unable to get contacts")
|
||||||
|
self.permissionsError = .userError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
fatalError("Unknown Error!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user