getting to decent place now

This commit is contained in:
talksik
2021-12-20 15:41:27 -08:00
parent dec69ecf4e
commit 081ab46a86
9 changed files with 272 additions and 112 deletions
+8 -4
View File
@@ -33,6 +33,8 @@
896CE7002770847400DB474E /* CircleFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 896CE6FF2770847400DB474E /* CircleFooterView.swift */; };
896CE7022770892F00DB474E /* CircleGridView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 896CE7012770892F00DB474E /* CircleGridView.swift */; };
896CE7052770AE5D00DB474E /* InboxView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 896CE7042770AE5D00DB474E /* InboxView.swift */; };
896CE70727711BAB00DB474E /* FindFriendsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 896CE70627711BAB00DB474E /* FindFriendsView.swift */; };
896CE70927712CED00DB474E /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 896CE70827712CED00DB474E /* StringExtension.swift */; };
89AD5573276DD790001658E0 /* SplashView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AD5572276DD790001658E0 /* SplashView.swift */; };
89AD5575276DE724001658E0 /* PhoneCodeVerificationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AD5574276DE724001658E0 /* PhoneCodeVerificationView.swift */; };
89AD5578276DEAB3001658E0 /* LogoHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89AD5577276DEAB3001658E0 /* LogoHeaderView.swift */; };
@@ -50,7 +52,6 @@
89BDCDEF2769B50C00577829 /* ContactsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89BDCDEE2769B50C00577829 /* ContactsView.swift */; };
89BDCDF12769E64200577829 /* Messages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89BDCDF02769E64200577829 /* Messages.swift */; };
89F05B9B276A87920002E9C7 /* ContactsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F05B9A276A87920002E9C7 /* ContactsViewModel.swift */; };
89F05B9F276A8D360002E9C7 /* Contact.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F05B9E276A8D360002E9C7 /* Contact.swift */; };
89F05BA4276ACC060002E9C7 /* ContactService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F05BA3276ACC060002E9C7 /* ContactService.swift */; };
89F05BA6276ACD830002E9C7 /* ContactsPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F05BA5276ACD830002E9C7 /* ContactsPickerView.swift */; };
89F1386D2767EB19006680ED /* SignInView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F1386C2767EB19006680ED /* SignInView.swift */; };
@@ -105,6 +106,8 @@
896CE6FF2770847400DB474E /* CircleFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleFooterView.swift; sourceTree = "<group>"; };
896CE7012770892F00DB474E /* CircleGridView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleGridView.swift; sourceTree = "<group>"; };
896CE7042770AE5D00DB474E /* InboxView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InboxView.swift; sourceTree = "<group>"; };
896CE70627711BAB00DB474E /* FindFriendsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FindFriendsView.swift; sourceTree = "<group>"; };
896CE70827712CED00DB474E /* StringExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtension.swift; sourceTree = "<group>"; };
89AD5572276DD790001658E0 /* SplashView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashView.swift; sourceTree = "<group>"; };
89AD5574276DE724001658E0 /* PhoneCodeVerificationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhoneCodeVerificationView.swift; sourceTree = "<group>"; };
89AD5577276DEAB3001658E0 /* LogoHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogoHeaderView.swift; sourceTree = "<group>"; };
@@ -121,7 +124,6 @@
89BDCDEE2769B50C00577829 /* ContactsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsView.swift; sourceTree = "<group>"; };
89BDCDF02769E64200577829 /* Messages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Messages.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>"; };
89F05BA3276ACC060002E9C7 /* ContactService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactService.swift; sourceTree = "<group>"; };
89F05BA5276ACD830002E9C7 /* ContactsPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsPickerView.swift; sourceTree = "<group>"; };
89F1386C2767EB19006680ED /* SignInView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInView.swift; sourceTree = "<group>"; };
@@ -270,6 +272,7 @@
89BDCDE62769616600577829 /* UIImage+Extension.swift */,
89F18AEB276E92BF00115B1E /* CustomExtensions.swift */,
894E80BD276ED7A700624B72 /* avatars.swift */,
896CE70827712CED00DB474E /* StringExtension.swift */,
);
path = Globals;
sourceTree = "<group>";
@@ -279,7 +282,6 @@
children = (
89BDCDF02769E64200577829 /* Messages.swift */,
891A160D27657CEA00B26659 /* User.swift */,
89F05B9E276A8D360002E9C7 /* Contact.swift */,
);
path = Models;
sourceTree = "<group>";
@@ -379,6 +381,7 @@
89BDCDEE2769B50C00577829 /* ContactsView.swift */,
89F05B9A276A87920002E9C7 /* ContactsViewModel.swift */,
89F05BA5276ACD830002E9C7 /* ContactsPickerView.swift */,
896CE70627711BAB00DB474E /* FindFriendsView.swift */,
);
path = Contacts;
sourceTree = "<group>";
@@ -525,8 +528,9 @@
896CE7002770847400DB474E /* CircleFooterView.swift in Sources */,
894E80BE276ED7A700624B72 /* avatars.swift in Sources */,
896CE7052770AE5D00DB474E /* InboxView.swift in Sources */,
89F05B9F276A8D360002E9C7 /* Contact.swift in Sources */,
891A160327656FC700B26659 /* HomeView.swift in Sources */,
896CE70927712CED00DB474E /* StringExtension.swift in Sources */,
896CE70727711BAB00DB474E /* FindFriendsView.swift in Sources */,
891A160B2765732700B26659 /* HomeViewModel.swift in Sources */,
89BCABEB276D2A09009E9B10 /* PhoneVerificationView.swift in Sources */,
892179E62765FECD001E6C60 /* FooterControlsViewModel.swift in Sources */,
+28
View File
@@ -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()
}
}
-17
View File
@@ -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: