getting to decent place now
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// StringExtension.swift
|
||||
// nirvana-ios
|
||||
//
|
||||
// Created by Arjun Patel on 12/20/21.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension String {
|
||||
func matchingStrings(regex: String) -> [[String]] {
|
||||
guard let regex = try? NSRegularExpression(pattern: regex, options: []) else { return [] }
|
||||
let nsString = self as NSString
|
||||
let results = regex.matches(in: self, options: [], range: NSMakeRange(0, nsString.length))
|
||||
return results.map { result in
|
||||
(0..<result.numberOfRanges).map {
|
||||
result.range(at: $0).location != NSNotFound
|
||||
? nsString.substring(with: result.range(at: $0))
|
||||
: ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var digits: String {
|
||||
return components(separatedBy: CharacterSet.decimalDigits.inverted)
|
||||
.joined()
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
//
|
||||
// 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]
|
||||
}
|
||||
@@ -50,6 +50,28 @@ class FirestoreService {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getUserByPhoneNumber(phoneNumber: String, completion: @escaping((_ user: User?) -> ())) {
|
||||
// TODO: validation here as well to verify that phone number string is even valid
|
||||
db.collection(Collection.users.rawValue).whereField("phoneNumber", isEqualTo: phoneNumber)
|
||||
.getDocuments() { (querySnapshot, err) in
|
||||
if let err = err {
|
||||
print("Error getting documents: \(err)")
|
||||
completion(nil)
|
||||
} else {
|
||||
if !(querySnapshot?.isEmpty)! {
|
||||
print("existing user found!!!!: \(querySnapshot?.documents)")
|
||||
|
||||
for document in querySnapshot!.documents {
|
||||
let returnedUser = try? document.data(as: User.self)
|
||||
completion(returnedUser)
|
||||
}
|
||||
} else {
|
||||
completion(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createUser(user: User) {
|
||||
do {
|
||||
|
||||
@@ -1,82 +1,82 @@
|
||||
////
|
||||
//// ContactsPickerView.swift
|
||||
//// nirvana-ios
|
||||
////
|
||||
//// Created by Arjun Patel on 12/15/21.
|
||||
////
|
||||
//
|
||||
// ContactsPickerView.swift
|
||||
// nirvana-ios
|
||||
//import SwiftUI
|
||||
//import Contacts
|
||||
//
|
||||
// Created by Arjun Patel on 12/15/21.
|
||||
//struct ContactsPickerView: View {
|
||||
// @Environment(\.dismiss) var dismiss
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Contacts
|
||||
|
||||
struct ContactsPickerView: View {
|
||||
@Environment(\.dismiss) var dismiss
|
||||
|
||||
// updates the parent view for it to do something with the new contact
|
||||
@State var selectedContact: CNContact?
|
||||
|
||||
var contacts: [String: [CNContact]] = loadContactsGrouped()
|
||||
|
||||
var body: some View {
|
||||
let keys = (Array(contacts.keys) as [String]).sorted()
|
||||
NavigationView {
|
||||
List {
|
||||
ForEach(keys.sorted(), id: \.self) { key in
|
||||
Section(header: Text(key)) {
|
||||
ForEach(contacts[key] ?? [CNContact](), id: \.identifier) { contact in
|
||||
ContactRow(contact: contact, selectedContact: self.$selectedContact)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.listStyle(GroupedListStyle())
|
||||
.navigationTitle("All Contacts".localized)
|
||||
.navigationBarItems(trailing: Button(action: {
|
||||
dismiss()
|
||||
|
||||
}, label: {
|
||||
Text("Cancel".localized)
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
static func loadContactsGrouped() -> [String: [CNContact]] {
|
||||
let provider = ContactsViewModel()
|
||||
let contacts = provider.fetchContacts()
|
||||
|
||||
let group = Dictionary(grouping: contacts) { (contact) -> String in
|
||||
return String(contact.familyName.first ?? "?")
|
||||
}
|
||||
|
||||
print(group)
|
||||
|
||||
return group
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct ContactRow: View {
|
||||
var contact: CNContact
|
||||
@Binding var selectedContact: CNContact?
|
||||
|
||||
var body: some View {
|
||||
Button(action: {
|
||||
selectContact()
|
||||
}) {
|
||||
HStack {
|
||||
Text("\(contact.familyName)").fontWeight(.bold)
|
||||
Text("\(contact.givenName) \(contact.middleName)")
|
||||
}
|
||||
.foregroundColor(.black)
|
||||
}
|
||||
}
|
||||
|
||||
func selectContact() {
|
||||
self.selectedContact = self.contact
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
var localized: String {
|
||||
return NSLocalizedString(self, comment: "")
|
||||
}
|
||||
}
|
||||
// // updates the parent view for it to do something with the new contact
|
||||
// @State var selectedContact: CNContact?
|
||||
//
|
||||
// var contacts: [String: [CNContact]] = loadContactsGrouped()
|
||||
//
|
||||
// var body: some View {
|
||||
// let keys = (Array(contacts.keys) as [String]).sorted()
|
||||
// NavigationView {
|
||||
// List {
|
||||
// ForEach(keys.sorted(), id: \.self) { key in
|
||||
// Section(header: Text(key)) {
|
||||
// ForEach(contacts[key] ?? [CNContact](), id: \.identifier) { contact in
|
||||
// ContactRow(contact: contact, selectedContact: self.$selectedContact)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// .listStyle(GroupedListStyle())
|
||||
// .navigationTitle("All Contacts".localized)
|
||||
// .navigationBarItems(trailing: Button(action: {
|
||||
// dismiss()
|
||||
//
|
||||
// }, label: {
|
||||
// Text("Cancel".localized)
|
||||
// }))
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// static func loadContactsGrouped() -> [String: [CNContact]] {
|
||||
// let provider = ContactsViewModel()
|
||||
// let contacts = provider.fetchContacts()
|
||||
// print(contacts)
|
||||
// let group = Dictionary(grouping: contacts) { (contact) -> String in
|
||||
// return String(contact.familyName.first ?? "?")
|
||||
// }
|
||||
//
|
||||
// print(group)
|
||||
//
|
||||
// return group
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//
|
||||
//struct ContactRow: View {
|
||||
// var contact: CNContact
|
||||
// @Binding var selectedContact: CNContact?
|
||||
//
|
||||
// var body: some View {
|
||||
// Button(action: {
|
||||
// selectContact()
|
||||
// }) {
|
||||
// HStack {
|
||||
// Text("\(contact.familyName)").fontWeight(.bold)
|
||||
// Text("\(contact.givenName) \(contact.middleName)")
|
||||
// }
|
||||
// .foregroundColor(.black)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// func selectContact() {
|
||||
// self.selectedContact = self.contact
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//extension String {
|
||||
// var localized: String {
|
||||
// return NSLocalizedString(self, comment: "")
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -42,7 +42,7 @@ struct ContactsView: View {
|
||||
.shadow(radius:10)
|
||||
})
|
||||
|
||||
Text(selectedContact != nil ? "Selected: \((selectedContact?.familyName)!) \((selectedContact?.givenName)!)" : "Nothing selected".localized)
|
||||
Text(selectedContact != nil ? "Selected: \((selectedContact?.familyName)!) \((selectedContact?.givenName)!)" : "Nothing selected")
|
||||
|
||||
Button {
|
||||
self.navigationStack.push(InnerCircleView())
|
||||
|
||||
@@ -11,6 +11,9 @@ import SwiftUI
|
||||
|
||||
class ContactsViewModel : ObservableObject {
|
||||
@Published var showPermissionAlert = false
|
||||
@Published var contacts: [ContactsViewModelContact] = []
|
||||
|
||||
private var firestoreService = FirestoreService()
|
||||
|
||||
let store: CNContactStore = CNContactStore()
|
||||
let keys: [CNKeyDescriptor] = [CNContactImageDataKey as CNKeyDescriptor,
|
||||
@@ -18,6 +21,10 @@ class ContactsViewModel : ObservableObject {
|
||||
CNContactEmailAddressesKey as CNKeyDescriptor,
|
||||
CNContactFormatter.descriptorForRequiredKeys(for: .fullName)]
|
||||
|
||||
init() {
|
||||
self.fetchContacts()
|
||||
}
|
||||
|
||||
func openSettings() {
|
||||
guard let settingsURL = URL(string: UIApplication.openSettingsURLString) else { return }
|
||||
if UIApplication.shared.canOpenURL(settingsURL) { UIApplication.shared.open(settingsURL)}
|
||||
@@ -31,7 +38,7 @@ class ContactsViewModel : ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
func fetchContacts(sortOrder: CNContactSortOrder = .userDefault) -> [CNContact] {
|
||||
func fetchContacts() {
|
||||
let authStatus = CNContactStore.authorizationStatus(for: .contacts)
|
||||
|
||||
if authStatus == .notDetermined {
|
||||
@@ -42,20 +49,57 @@ class ContactsViewModel : ObservableObject {
|
||||
}
|
||||
|
||||
let fetchRequest = CNContactFetchRequest(keysToFetch: keys)
|
||||
fetchRequest.sortOrder = sortOrder
|
||||
|
||||
var fetchedContacts = [CNContact]()
|
||||
fetchRequest.sortOrder = .userDefault
|
||||
|
||||
do {
|
||||
try store.enumerateContacts(with: fetchRequest) {
|
||||
(contact, stop) in
|
||||
fetchedContacts.append(contact)
|
||||
try store.enumerateContacts(with: fetchRequest) {(contact, stop) in
|
||||
// only checking if american number or not for now
|
||||
var cnPhoneNumber = contact.phoneNumbers.first?.value.stringValue
|
||||
let contactDisplayName = contact.givenName
|
||||
// strip out nondigits
|
||||
// add or keep country code
|
||||
|
||||
// TODO: take out hard coding to US country code
|
||||
var formattedNumber = cnPhoneNumber?.digits.suffix(10)
|
||||
|
||||
// only show contacts if they have a phone number
|
||||
if formattedNumber != nil {
|
||||
formattedNumber = "+1" + formattedNumber! // adding country code
|
||||
|
||||
let contactNumber = String(formattedNumber!)
|
||||
var contactVm = ContactsViewModelContact(cnName: contactDisplayName, cnPhoneNumber: contactNumber)
|
||||
|
||||
print(contactVm)
|
||||
// check if the contact is an existing user by phone number
|
||||
|
||||
|
||||
self.firestoreService.getUserByPhoneNumber(phoneNumber: contactNumber) {[weak self] returnedUser in
|
||||
print(returnedUser)
|
||||
DispatchQueue.main.async {
|
||||
if returnedUser == nil {
|
||||
// do nothing, keep contactsVm object user property nil
|
||||
} else {
|
||||
// adding user details if this contact is existing user
|
||||
contactVm.user = returnedUser
|
||||
}
|
||||
|
||||
self?.contacts.append(contactVm)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
print("Unable to fetch contacts. \(error)")
|
||||
|
||||
}
|
||||
|
||||
return fetchedContacts
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct ContactsViewModelContact : Identifiable {
|
||||
var id : String = UUID().uuidString
|
||||
var user: User?
|
||||
var cnName: String
|
||||
var cnPhoneNumber: String
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// FindFriendsView.swift
|
||||
// nirvana-ios
|
||||
//
|
||||
// Created by Arjun Patel on 12/20/21.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Contacts
|
||||
|
||||
|
||||
|
||||
struct FindFriendsView: View {
|
||||
@Environment(\.dismiss) var dismiss
|
||||
|
||||
@StateObject var contactsVM = ContactsViewModel()
|
||||
|
||||
@State private var searchQuery: String = ""
|
||||
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
// list with search bar
|
||||
List {
|
||||
ForEach(contactsVM.contacts) { contact in
|
||||
Text(contact.cnName)
|
||||
}
|
||||
}
|
||||
.searchable(text: $searchQuery)
|
||||
.listStyle(GroupedListStyle())
|
||||
.navigationTitle("Find Friends")
|
||||
.navigationBarItems(trailing: Button(action: {
|
||||
dismiss()
|
||||
}, label: {
|
||||
Text("Cancel")
|
||||
}))
|
||||
}
|
||||
.onAppear {
|
||||
// organize contacts
|
||||
// sort by has account and then show all other contacts
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct FindFriendsView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
FindFriendsView().environmentObject(AuthSessionStore())
|
||||
}
|
||||
}
|
||||
|
||||
struct ListContactRow: View {
|
||||
var contact: CNContact
|
||||
|
||||
@State var showAlert = false
|
||||
@State var alertText = ""
|
||||
@State var alertMessage = ""
|
||||
|
||||
var body: some View {
|
||||
Button(action: {
|
||||
|
||||
}) {
|
||||
HStack {
|
||||
Text("\(contact.familyName)").fontWeight(.bold)
|
||||
Text("\(contact.givenName) \(contact.middleName)")
|
||||
|
||||
Spacer()
|
||||
|
||||
// if the user is already an existing user
|
||||
}
|
||||
.foregroundColor(.black)
|
||||
}
|
||||
.alert(self.alertText, isPresented: self.$showAlert) {
|
||||
Button("OK", role: ButtonRole.cancel) { }
|
||||
} message: {
|
||||
Text(self.alertMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ struct InnerCircleView: View {
|
||||
@EnvironmentObject var authSessionStore: AuthSessionStore
|
||||
@EnvironmentObject var navigationStack: NavigationStack
|
||||
|
||||
@State var sheetView: SheetView? = nil
|
||||
@State var sheetView: SheetView? = .contacts
|
||||
|
||||
let universalSize = UIScreen.main.bounds
|
||||
|
||||
@@ -43,7 +43,7 @@ struct InnerCircleView: View {
|
||||
.sheet(item: self.$sheetView) {page in
|
||||
switch page {
|
||||
case SheetView.contacts:
|
||||
ContactsPickerView()
|
||||
FindFriendsView()
|
||||
case SheetView.inbox:
|
||||
InboxView()// test one for now
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user