From 4673b81a1a5222bb252733a91d805dbd20ca3f92 Mon Sep 17 00:00:00 2001 From: talksik Date: Mon, 20 Dec 2021 01:48:21 -0800 Subject: [PATCH 01/18] step one, starting to separate the big inner circle view page --- nirvana-ios.xcodeproj/project.pbxproj | 8 + .../Views/InnerCircle/CircleFooterView.swift | 74 ++++++++ .../InnerCircle/CircleNavigationView.swift | 112 +++++++++++ .../Views/InnerCircle/InnerCircleView.swift | 174 +----------------- 4 files changed, 196 insertions(+), 172 deletions(-) create mode 100644 nirvana-ios/Views/InnerCircle/CircleFooterView.swift create mode 100644 nirvana-ios/Views/InnerCircle/CircleNavigationView.swift diff --git a/nirvana-ios.xcodeproj/project.pbxproj b/nirvana-ios.xcodeproj/project.pbxproj index 4c9975d..2692ad5 100644 --- a/nirvana-ios.xcodeproj/project.pbxproj +++ b/nirvana-ios.xcodeproj/project.pbxproj @@ -29,6 +29,8 @@ 894E80BE276ED7A700624B72 /* avatars.swift in Sources */ = {isa = PBXBuildFile; fileRef = 894E80BD276ED7A700624B72 /* avatars.swift */; }; 894E80C1276EFD0500624B72 /* AudioPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 894E80C0276EFD0400624B72 /* AudioPlayerView.swift */; }; 894E80C327702E5900624B72 /* AddBasicInfoViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 894E80C227702E5800624B72 /* AddBasicInfoViewModel.swift */; }; + 896CE6FE27707E6B00DB474E /* CircleNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 896CE6FD27707E6B00DB474E /* CircleNavigationView.swift */; }; + 896CE7002770847400DB474E /* CircleFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 896CE6FF2770847400DB474E /* CircleFooterView.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 */; }; @@ -97,6 +99,8 @@ 894E80BD276ED7A700624B72 /* avatars.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = avatars.swift; sourceTree = ""; }; 894E80C0276EFD0400624B72 /* AudioPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioPlayerView.swift; sourceTree = ""; }; 894E80C227702E5800624B72 /* AddBasicInfoViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddBasicInfoViewModel.swift; sourceTree = ""; }; + 896CE6FD27707E6B00DB474E /* CircleNavigationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleNavigationView.swift; sourceTree = ""; }; + 896CE6FF2770847400DB474E /* CircleFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleFooterView.swift; sourceTree = ""; }; 89AD5572276DD790001658E0 /* SplashView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashView.swift; sourceTree = ""; }; 89AD5574276DE724001658E0 /* PhoneCodeVerificationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhoneCodeVerificationView.swift; sourceTree = ""; }; 89AD5577276DEAB3001658E0 /* LogoHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogoHeaderView.swift; sourceTree = ""; }; @@ -331,6 +335,8 @@ children = ( 89BCABE4276B3D58009E9B10 /* InnerCircleView.swift */, 89BCABE6276B3D64009E9B10 /* InnerCircleViewModel.swift */, + 896CE6FD27707E6B00DB474E /* CircleNavigationView.swift */, + 896CE6FF2770847400DB474E /* CircleFooterView.swift */, ); path = InnerCircle; sourceTree = ""; @@ -502,6 +508,7 @@ buildActionMask = 2147483647; files = ( 891A15E327653A7000B26659 /* ContentView.swift in Sources */, + 896CE7002770847400DB474E /* CircleFooterView.swift in Sources */, 894E80BE276ED7A700624B72 /* avatars.swift in Sources */, 89F05B9F276A8D360002E9C7 /* Contact.swift in Sources */, 891A160327656FC700B26659 /* HomeView.swift in Sources */, @@ -520,6 +527,7 @@ 89BDCDE527695DB900577829 /* NirvanaImage.swift in Sources */, 891A16132765A44300B26659 /* ChatsCarouselViewModel.swift in Sources */, 89F05B9B276A87920002E9C7 /* ContactsViewModel.swift in Sources */, + 896CE6FE27707E6B00DB474E /* CircleNavigationView.swift in Sources */, 89AD5573276DD790001658E0 /* SplashView.swift in Sources */, 89F18AEC276E92BF00115B1E /* CustomExtensions.swift in Sources */, 89F18AF1276ECAA300115B1E /* RouterView.swift in Sources */, diff --git a/nirvana-ios/Views/InnerCircle/CircleFooterView.swift b/nirvana-ios/Views/InnerCircle/CircleFooterView.swift new file mode 100644 index 0000000..2ef1e04 --- /dev/null +++ b/nirvana-ios/Views/InnerCircle/CircleFooterView.swift @@ -0,0 +1,74 @@ +// +// CircleFooterView.swift +// nirvana-ios +// +// Created by Arjun Patel on 12/20/21. +// + +import SwiftUI +import NavigationStack + +struct CircleFooterView: View { + @EnvironmentObject var navigationStack: NavigationStack + @EnvironmentObject var authSessionStore: AuthSessionStore + + + var body: some View { + // TODO: do cool animations with this footer background fill in while recording or playing a message + ZStack(alignment:.bottomTrailing) { + VStack(alignment:.center) { + Spacer() + + HStack { + if self.selectedUserIndex != nil { + Image("Artboards_Diversity_Avatars_by_Netguru-\(self.selectedUserIndex! + 1)") + .resizable() + .scaledToFit() + .background(NirvanaColor.teal.opacity(0.1)) + .frame(width: 40, height: 40) + .clipShape(Circle()) + .padding(5) + } + + + VStack (alignment: .leading) { + Text("Sarth Shah") + .font(.footnote) + .foregroundColor(NirvanaColor.light) + Text("sent 20 minutes ago") + .font(.caption) + .foregroundColor(.gray) + } + + Spacer() + + Label("Replay", systemImage: "repeat.1.circle.fill") + .font(.title2) + .labelStyle(.iconOnly) + .foregroundColor(Color.orange) + + + Spacer(minLength: 65) + } + .frame(maxWidth: .infinity, maxHeight: 60) // 60 is the height of the footer control big circle + .background(Color.white.opacity(0.5)) + .clipShape(RoundedRectangle(cornerRadius: 30, style: .continuous)) + .shadow(color: Color.black.opacity(0.25), radius: 30, x: 0, y: 20) + } + + FooterControlsView() + } + .padding() + .offset( + x:0, + y:self.selectedUserIndex == nil ? 150 : 0 + ) + .animation(Animation.spring(), value: self.selectedUserIndex) + } +} + +struct CircleFooterView_Previews: PreviewProvider { + static var previews: some View { + CircleFooterView() + } +} diff --git a/nirvana-ios/Views/InnerCircle/CircleNavigationView.swift b/nirvana-ios/Views/InnerCircle/CircleNavigationView.swift new file mode 100644 index 0000000..8f73f04 --- /dev/null +++ b/nirvana-ios/Views/InnerCircle/CircleNavigationView.swift @@ -0,0 +1,112 @@ +// +// NavigationView.swift +// nirvana-ios +// +// Created by Arjun Patel on 12/20/21. +// + +import SwiftUI +import NavigationStack + +struct CircleNavigationView: View { + @EnvironmentObject var navigationStack: NavigationStack + @EnvironmentObject var authSessionStore: AuthSessionStore + + var body: some View { + HStack(alignment: .center) { + Menu { + Button("Edit Profile") { + self.navigationStack.push(AddBasicInfoView()) + } + + Button("Friends") { + print("manage friends page") + } + + Button("Log out") { + print("log out button clicked") + + self.authSessionStore.logOut() + + // once logged out, then the listener will listen and router view will take care of us thereafter + } + } label: { + if self.authSessionStore.user?.avatar == nil { + Image("Artboards_Diversity_Avatars_by_Netguru-1") + .resizable() + .scaledToFit() + .background(NirvanaColor.teal.opacity(0.1)) + .blur(radius: 5) + .frame(width: 40, height: 40) + .clipShape(Circle()) + .padding(5) + } else { + Image((self.authSessionStore.user?.avatar)!) + .resizable() + .scaledToFit() + .background(NirvanaColor.teal.opacity(0.1)) + .frame(width: 40, height: 40) + .clipShape(Circle()) + .padding(5) + } + + } + + ScrollView(.horizontal) { + HStack { + Button { + + } label: { + Label("circle", systemImage: "peacesign") + .font(.caption2) + .foregroundColor(Color.white) + .padding(.vertical, 10) + .padding(.horizontal, 8) + .background( + RoundedRectangle(cornerRadius: 20, style: .continuous) + .fill(Color.teal.opacity(0.5)) + ).overlay( + RoundedRectangle(cornerRadius: 20, style: .continuous) + .strokeBorder(Color.white.opacity(01), lineWidth: 1) + ) + } + + Button { + + } label: { + Label("groups", systemImage: "rectangle.3.group") + .font(.caption2) + .foregroundColor(Color.gray) + .padding(.vertical, 10) + .padding(.horizontal, 8) + .overlay( + RoundedRectangle(cornerRadius: 20, style: .continuous) + .strokeBorder(Color.white.opacity(1), lineWidth: 1) + ) + } + + Button { + + } label: { + Label("work", systemImage: "suitcase") + .font(.caption2) + .foregroundColor(Color.gray) + .padding(.vertical, 10) + .padding(.horizontal, 8) + .overlay( + RoundedRectangle(cornerRadius: 20, style: .continuous) + .strokeBorder(Color.white.opacity(1), lineWidth: 1) + ) + } + } + } + } + .padding(.horizontal) + } +} + +struct CircleNavigationView_Previews: PreviewProvider { + static var previews: some View { + CircleNavigationView() + } +} diff --git a/nirvana-ios/Views/InnerCircle/InnerCircleView.swift b/nirvana-ios/Views/InnerCircle/InnerCircleView.swift index 8190c3d..b4b0089 100644 --- a/nirvana-ios/Views/InnerCircle/InnerCircleView.swift +++ b/nirvana-ios/Views/InnerCircle/InnerCircleView.swift @@ -28,31 +28,13 @@ struct InnerCircleView: View { // header VStack(alignment: .leading) { - header - bubbleNavigation + CircleNavigationView() Spacer() } -// Path { path in -// -// //draw the axes -// path.move(to: CGPoint(x:0, y:universalSize.height*0.5 )) -// -// path.addLine(to: CGPoint(x:universalSize.width, y: universalSize.height*0.5)) -// -// path.move(to: CGPoint(x:universalSize.width*0.5, y:0 )) -// -// path.addLine(to: CGPoint(x:universalSize.width * 0.5, y: universalSize.height)) -// -// -// //TODO: draw the acceptance boxes -// } -// .stroke(Color.black) -// .edgesIgnoringSafeArea(.all) - - footerNavigation + CircleFooterView() } .onAppear() { // TESTING @@ -63,112 +45,7 @@ struct InnerCircleView: View { } } - // TODO: do cool animations with this footer background fill in while - // recording or playing a message - var footerNavigation: some View { - ZStack(alignment:.bottomTrailing) { - VStack(alignment:.center) { - Spacer() - - HStack { - if self.selectedUserIndex != nil { - Image("Artboards_Diversity_Avatars_by_Netguru-\(self.selectedUserIndex! + 1)") - .resizable() - .scaledToFit() - .background(NirvanaColor.teal.opacity(0.1)) - .frame(width: 40, height: 40) - .clipShape(Circle()) - .padding(5) - } - - - VStack (alignment: .leading) { - Text("Sarth Shah") - .font(.footnote) - .foregroundColor(NirvanaColor.light) - Text("sent 20 minutes ago") - .font(.caption) - .foregroundColor(.gray) - } - - Spacer() - - Label("Replay", systemImage: "repeat.1.circle.fill") - .font(.title2) - .labelStyle(.iconOnly) - .foregroundColor(Color.orange) - - - Spacer(minLength: 65) - } - .frame(maxWidth: .infinity, maxHeight: 60) // 60 is the height of the footer control big circle - .background(Color.white.opacity(0.5)) - .clipShape(RoundedRectangle(cornerRadius: 30, style: .continuous)) - .shadow(color: Color.black.opacity(0.25), radius: 30, x: 0, y: 20) - } - - FooterControlsView() - } - .padding() - .offset( - x:0, - y:self.selectedUserIndex == nil ? 150 : 0 - ) - .animation(Animation.spring(), value: self.selectedUserIndex) - } - - var bubbleNavigation : some View { - HStack(alignment: .center) { - Button { - - } label: { - Label("circle", systemImage: "peacesign") - .font(.caption2) - .foregroundColor(Color.white) - .padding(.vertical, 10) - .padding(.horizontal, 8) - .background( - RoundedRectangle(cornerRadius: 20, style: .continuous) - .fill(Color.teal.opacity(0.5)) - ).overlay( - RoundedRectangle(cornerRadius: 20, style: .continuous) - .strokeBorder(Color.white.opacity(01), lineWidth: 1) - ) - } - - Button { - - } label: { - Label("groups", systemImage: "rectangle.3.group") - .font(.caption2) - .foregroundColor(Color.gray) - .padding(.vertical, 10) - .padding(.horizontal, 8) - .overlay( - RoundedRectangle(cornerRadius: 20, style: .continuous) - .strokeBorder(Color.white.opacity(1), lineWidth: 1) - ) - } - - Button { - - } label: { - Label("work", systemImage: "suitcase") - .font(.caption2) - .foregroundColor(Color.gray) - .padding(.vertical, 10) - .padding(.horizontal, 8) - .overlay( - RoundedRectangle(cornerRadius: 20, style: .continuous) - .strokeBorder(Color.white.opacity(1), lineWidth: 1) - ) - } - } - .padding(.horizontal) - } - // magic variables for grid - // TODO: change the number of columns based on the number of items // TODO: make the top left person or one horizontal person be in the center of screen...makes the top honeycomb pop private static var numberOfItems: Int = 12 private static let size: CGFloat = UIScreen.main.bounds.height*0.15 // scaling with screen size @@ -328,53 +205,6 @@ struct InnerCircleView: View { return 0 } - - private var header: some View { - HStack(alignment: .center) { - Image("undraw_handcrafts_leaf") - .resizable() - .frame(width: 20.0, height: 32.132) - .padding(.leading, 20) - - Spacer() - - Image(systemName: "message.and.waveform") - .foregroundColor(Color.red.opacity(1)) - .font(.title2) - - Menu { - Button("Edit Profile") { - self.navigationStack.push(AddBasicInfoView()) - } - - Button("Friends") { - print("manage friends page") - } - - Button("Log out") { - print("log out button clicked") - - self.authSessionStore.logOut() - - // once logged out, then the listener will listen and router view will take care of us thereafter - } - } label: { - Image("Artboards_Diversity_Avatars_by_Netguru-51") - .resizable() - .scaledToFit() - .background(NirvanaColor.teal.opacity(0.1)) - .frame(width: 40, height: 40) - .clipShape(Circle()) - .padding(5) - } - - } - .frame(maxWidth: .infinity) - .background(Color.white.opacity(0.5)) - .clipShape(RoundedRectangle(cornerRadius: 30, style: .continuous)) - .shadow(color: Color.black.opacity(0.25), radius: 30, x: 0, y: 20) - .padding(.horizontal) - } } struct InnerCircleView_Previews: PreviewProvider { From 2a7dfd3500ddeb673a5177779497281521d5fdcc Mon Sep 17 00:00:00 2001 From: talksik Date: Mon, 20 Dec 2021 02:31:22 -0800 Subject: [PATCH 02/18] cleaner state to start working on data hookup --- nirvana-ios.xcodeproj/project.pbxproj | 4 + .../Views/InnerCircle/CircleFooterView.swift | 27 ++- .../Views/InnerCircle/CircleGridView.swift | 188 ++++++++++++++++++ .../InnerCircle/CircleNavigationView.swift | 2 +- .../Views/InnerCircle/InnerCircleView.swift | 174 +--------------- 5 files changed, 208 insertions(+), 187 deletions(-) create mode 100644 nirvana-ios/Views/InnerCircle/CircleGridView.swift diff --git a/nirvana-ios.xcodeproj/project.pbxproj b/nirvana-ios.xcodeproj/project.pbxproj index 2692ad5..f995612 100644 --- a/nirvana-ios.xcodeproj/project.pbxproj +++ b/nirvana-ios.xcodeproj/project.pbxproj @@ -31,6 +31,7 @@ 894E80C327702E5900624B72 /* AddBasicInfoViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 894E80C227702E5800624B72 /* AddBasicInfoViewModel.swift */; }; 896CE6FE27707E6B00DB474E /* CircleNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 896CE6FD27707E6B00DB474E /* CircleNavigationView.swift */; }; 896CE7002770847400DB474E /* CircleFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 896CE6FF2770847400DB474E /* CircleFooterView.swift */; }; + 896CE7022770892F00DB474E /* CircleGridView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 896CE7012770892F00DB474E /* CircleGridView.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 */; }; @@ -101,6 +102,7 @@ 894E80C227702E5800624B72 /* AddBasicInfoViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddBasicInfoViewModel.swift; sourceTree = ""; }; 896CE6FD27707E6B00DB474E /* CircleNavigationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleNavigationView.swift; sourceTree = ""; }; 896CE6FF2770847400DB474E /* CircleFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleFooterView.swift; sourceTree = ""; }; + 896CE7012770892F00DB474E /* CircleGridView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleGridView.swift; sourceTree = ""; }; 89AD5572276DD790001658E0 /* SplashView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashView.swift; sourceTree = ""; }; 89AD5574276DE724001658E0 /* PhoneCodeVerificationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhoneCodeVerificationView.swift; sourceTree = ""; }; 89AD5577276DEAB3001658E0 /* LogoHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogoHeaderView.swift; sourceTree = ""; }; @@ -337,6 +339,7 @@ 89BCABE6276B3D64009E9B10 /* InnerCircleViewModel.swift */, 896CE6FD27707E6B00DB474E /* CircleNavigationView.swift */, 896CE6FF2770847400DB474E /* CircleFooterView.swift */, + 896CE7012770892F00DB474E /* CircleGridView.swift */, ); path = InnerCircle; sourceTree = ""; @@ -536,6 +539,7 @@ 89BCABED276D2B05009E9B10 /* WavesGlassBackgroundView.swift in Sources */, 89F05BA6276ACD830002E9C7 /* ContactsPickerView.swift in Sources */, 8904DEC8277055E90071E6CA /* OnboardingTrioView.swift in Sources */, + 896CE7022770892F00DB474E /* CircleGridView.swift in Sources */, 89BDCDEA27697F9C00577829 /* UserMenu.swift in Sources */, 89BCABE7276B3D64009E9B10 /* InnerCircleViewModel.swift in Sources */, 89AD557C276DF86A001658E0 /* FirestoreService.swift in Sources */, diff --git a/nirvana-ios/Views/InnerCircle/CircleFooterView.swift b/nirvana-ios/Views/InnerCircle/CircleFooterView.swift index 2ef1e04..8f7110f 100644 --- a/nirvana-ios/Views/InnerCircle/CircleFooterView.swift +++ b/nirvana-ios/Views/InnerCircle/CircleFooterView.swift @@ -20,15 +20,14 @@ struct CircleFooterView: View { Spacer() HStack { - if self.selectedUserIndex != nil { - Image("Artboards_Diversity_Avatars_by_Netguru-\(self.selectedUserIndex! + 1)") - .resizable() - .scaledToFit() - .background(NirvanaColor.teal.opacity(0.1)) - .frame(width: 40, height: 40) - .clipShape(Circle()) - .padding(5) - } + Image("Artboards_Diversity_Avatars_by_Netguru-1") + .resizable() + .scaledToFit() + .background(NirvanaColor.teal.opacity(0.1)) + .frame(width: 40, height: 40) + .clipShape(Circle()) + .padding(5) + VStack (alignment: .leading) { @@ -59,11 +58,11 @@ struct CircleFooterView: View { FooterControlsView() } .padding() - .offset( - x:0, - y:self.selectedUserIndex == nil ? 150 : 0 - ) - .animation(Animation.spring(), value: self.selectedUserIndex) +// .offset( +// x:0, +// y:self.selectedUserIndex == nil ? 150 : 0 +// ) +// .animation(Animation.spring(), value: self.selectedUserIndex) } } diff --git a/nirvana-ios/Views/InnerCircle/CircleGridView.swift b/nirvana-ios/Views/InnerCircle/CircleGridView.swift new file mode 100644 index 0000000..c51751b --- /dev/null +++ b/nirvana-ios/Views/InnerCircle/CircleGridView.swift @@ -0,0 +1,188 @@ +// +// CircleGridView.swift +// nirvana-ios +// +// Created by Arjun Patel on 12/20/21. +// + +import SwiftUI +import NavigationStack + +struct CircleGridView: View { + @EnvironmentObject var authSessionStore: AuthSessionStore + @EnvironmentObject var navigationStack: NavigationStack + + let universalSize = UIScreen.main.bounds + + // magic variables for grid + // TODO: make the top left person or one horizontal person be in the center of screen...makes the top honeycomb pop + private static var numberOfItems: Int = 59 + private static let size: CGFloat = UIScreen.main.bounds.height*0.15 // scaling with screen size + private static let spacingBetweenColumns: CGFloat = 0 + private static let spacingBetweenRows: CGFloat = 0 + private static let totalColumns: Int = Int(log2(Double(Self.numberOfItems))) // scaling the circles and calculating column count + + @State private var selectedUserIndex: Int? = nil + + // TODO: change the size to adaptive or something to make outer ring items shrink their overall size and fit better + let gridItems: [GridItem] = Array( + repeating: GridItem(.fixed(Self.size), spacing: spacingBetweenColumns, alignment: .center), + count: totalColumns) + + private let big:CGFloat = 1 + private let medium:CGFloat = 0.75 + private let small:CGFloat = 0.5 + private let supersmall:CGFloat = 0.3 + + // TODO: centered honeycomb + side: maybe have two honeycombs: one in the center of 7 people and then everyone else surrounding + // TODO: maybe make our "center" offset to a little to the top left to make it more honeycomb from top left + private let center: CGPoint = CGPoint(x: UIScreen.main.bounds.width*0.5,y: UIScreen.main.bounds.height*0.5) + + var body: some View { + gridContent + } + + private var gridContent: some View { + // main communication hub + // TODO: client side, sort the honeycomb from top left to bottom right + // based on most close friends to least + ScrollViewReader {scrollReaderValue in + ScrollView([.horizontal, .vertical], showsIndicators: false) { + LazyVGrid( + columns: gridItems, + alignment: .center, + spacing: Self.spacingBetweenRows + ) { + ForEach(0.. Color { + if (userIndex == self.selectedUserIndex) { // user clicked on this user + return NirvanaColor.dimTeal.opacity(0.4) + } +// else if self.usersWithNewMessage.contains(userIndex) { // this user has a message +// return Color.orange.opacity(0.8) +// } + + return Color.white.opacity(0.4) + } + + // getting the proxy of an individual item + // and decoding into a scale that the item should take + private func getScale(proxy: GeometryProxy, itemNumber: Int) -> CGFloat { + // if this user is selected + if itemNumber == self.selectedUserIndex { + return big + 0.2 + } + + // if this user that we are rendering + // has a new message for us + // TODO: too much memory usage doing this across the board +// if self.usersWithNewMessage.contains(itemNumber) { +// return big + 0.2 +// } + + let posRelToGrid = proxy.frame(in: .global) // relative to the entire screen + let midX = getRowNumber(itemNumber) % 2 == 0 ? posRelToGrid.midX + (Self.size / 2) + (Self.spacingBetweenColumns / 2) : posRelToGrid.midX + let midY = posRelToGrid.midY + + let xdelta = abs(midX - self.center.x) + let ydelta = abs(midY - self.center.y) + + let innerCircleXAcceptance = Self.size * 0.75 + let innerCircleYAcceptance = Self.size * 0.75 + let outerRingXAcceptance = self.universalSize.width * 0.4 + let outerRingYAcceptance = self.universalSize.height * 0.25 + let wayOutRingXAcceptance = self.universalSize.width * 0.425 + let wayOutRingYAcceptance = self.universalSize.height * 0.375 + + + if xdelta <= innerCircleXAcceptance && ydelta < innerCircleYAcceptance { + return big + } else if xdelta <= outerRingXAcceptance && ydelta < outerRingYAcceptance { + return medium + } else if xdelta <= wayOutRingXAcceptance && ydelta < wayOutRingYAcceptance { + return small + } + return supersmall + } + + private static func distanceBetweenPoints(p1: CGPoint, p2: CGPoint) -> CGFloat { + let xDist = abs(p2.x - p1.x) + let yDist = abs(p2.y - p2.y) + + return CGFloat( + sqrt( + pow(xDist, 2) + pow(yDist, 2) + ) + ) + } + //get row number given a value/item number in the list + private func getRowNumber(_ value: Int) -> Int { + return value / Self.totalColumns + } + private func honeycombOffSetX(_ value: Int) -> CGFloat { + let rowNumber = self.getRowNumber(value) + + // make every even row have the honeycomb offset + if rowNumber % 2 == 0 { + return Self.size / 2 + Self.spacingBetweenColumns / 2 // account for the column spacing from before + } + + return 0 + } +} + +struct CircleGridView_Previews: PreviewProvider { + static var previews: some View { + CircleGridView() + } +} diff --git a/nirvana-ios/Views/InnerCircle/CircleNavigationView.swift b/nirvana-ios/Views/InnerCircle/CircleNavigationView.swift index 8f73f04..d478d4c 100644 --- a/nirvana-ios/Views/InnerCircle/CircleNavigationView.swift +++ b/nirvana-ios/Views/InnerCircle/CircleNavigationView.swift @@ -44,7 +44,7 @@ struct CircleNavigationView: View { Image((self.authSessionStore.user?.avatar)!) .resizable() .scaledToFit() - .background(NirvanaColor.teal.opacity(0.1)) + .background(NirvanaColor.teal.opacity(0.5)) .frame(width: 40, height: 40) .clipShape(Circle()) .padding(5) diff --git a/nirvana-ios/Views/InnerCircle/InnerCircleView.swift b/nirvana-ios/Views/InnerCircle/InnerCircleView.swift index b4b0089..e99c19b 100644 --- a/nirvana-ios/Views/InnerCircle/InnerCircleView.swift +++ b/nirvana-ios/Views/InnerCircle/InnerCircleView.swift @@ -14,17 +14,13 @@ struct InnerCircleView: View { let universalSize = UIScreen.main.bounds - // TESTING - // users who will have a thumping thing because they sent a message - @State var usersWithNewMessage: [Int] = [] - var body: some View { ZStack { // background WavesGlassBackgroundView() // content - gridContent + CircleGridView() // header VStack(alignment: .leading) { @@ -36,175 +32,9 @@ struct InnerCircleView: View { CircleFooterView() } - .onAppear() { - // TESTING - // fake like these users sent a message to view - DispatchQueue.main.asyncAfter(deadline: .now() + 3) { - self.usersWithNewMessage = [1, 5, 10] - } + .onAppear() { } } - - // magic variables for grid - // TODO: make the top left person or one horizontal person be in the center of screen...makes the top honeycomb pop - private static var numberOfItems: Int = 12 - private static let size: CGFloat = UIScreen.main.bounds.height*0.15 // scaling with screen size - private static let spacingBetweenColumns: CGFloat = 0 - private static let spacingBetweenRows: CGFloat = 0 - private static let totalColumns: Int = Int(log2(Double(Self.numberOfItems))) // scaling the circles and calculating column count - - @State private var selectedUserIndex: Int? = nil - - // TODO: change the size to adaptive or something to make outer ring items shrink their overall size and fit better - let gridItems: [GridItem] = Array( - repeating: GridItem(.fixed(Self.size), spacing: spacingBetweenColumns, alignment: .center), - count: totalColumns) - - private let big:CGFloat = 1 - private let medium:CGFloat = 0.75 - private let small:CGFloat = 0.5 - private let supersmall:CGFloat = 0.3 - - // TODO: centered honeycomb + side: maybe have two honeycombs: one in the center of 7 people and then everyone else surrounding - // TODO: maybe make our "center" offset to a little to the top left to make it more honeycomb from top left - private let center: CGPoint = CGPoint(x: UIScreen.main.bounds.width*0.5,y: UIScreen.main.bounds.height*0.5) - - private var gridContent: some View { - // main communication hub - // TODO: client side, sort the honeycomb from top left to bottom right - // based on most close friends to least - ScrollViewReader {scrollReaderValue in - ScrollView([.horizontal, .vertical], showsIndicators: false) { - LazyVGrid( - columns: gridItems, - alignment: .center, - spacing: Self.spacingBetweenRows - ) { - ForEach(0.. Color { - if (userIndex == self.selectedUserIndex) { // user clicked on this user - return NirvanaColor.dimTeal.opacity(0.4) - } else if self.usersWithNewMessage.contains(userIndex) { // this user has a message - return Color.orange.opacity(0.8) - } - - return Color.white.opacity(0.4) - } - - // getting the proxy of an individual item - // and decoding into a scale that the item should take - private func getScale(proxy: GeometryProxy, itemNumber: Int) -> CGFloat { - // if this user is selected - if itemNumber == self.selectedUserIndex { - return big + 0.2 - } - - // if this user that we are rendering - // has a new message for us - // TODO: too much memory usage doing this across the board - if self.usersWithNewMessage.contains(itemNumber) { - return big + 0.2 - } - - let posRelToGrid = proxy.frame(in: .global) // relative to the entire screen - let midX = getRowNumber(itemNumber) % 2 == 0 ? posRelToGrid.midX + (Self.size / 2) + (Self.spacingBetweenColumns / 2) : posRelToGrid.midX - let midY = posRelToGrid.midY - - let xdelta = abs(midX - self.center.x) - let ydelta = abs(midY - self.center.y) - - let innerCircleXAcceptance = Self.size * 0.75 - let innerCircleYAcceptance = Self.size * 0.75 - let outerRingXAcceptance = self.universalSize.width * 0.4 - let outerRingYAcceptance = self.universalSize.height * 0.25 - let wayOutRingXAcceptance = self.universalSize.width * 0.425 - let wayOutRingYAcceptance = self.universalSize.height * 0.375 - - - if xdelta <= innerCircleXAcceptance && ydelta < innerCircleYAcceptance { - return big - } else if xdelta <= outerRingXAcceptance && ydelta < outerRingYAcceptance { - return medium - } else if xdelta <= wayOutRingXAcceptance && ydelta < wayOutRingYAcceptance { - return small - } - return supersmall - } - - private static func distanceBetweenPoints(p1: CGPoint, p2: CGPoint) -> CGFloat { - let xDist = abs(p2.x - p1.x) - let yDist = abs(p2.y - p2.y) - - return CGFloat( - sqrt( - pow(xDist, 2) + pow(yDist, 2) - ) - ) - } - //get row number given a value/item number in the list - private func getRowNumber(_ value: Int) -> Int { - return value / Self.totalColumns - } - private func honeycombOffSetX(_ value: Int) -> CGFloat { - let rowNumber = self.getRowNumber(value) - - // make every even row have the honeycomb offset - if rowNumber % 2 == 0 { - return Self.size / 2 + Self.spacingBetweenColumns / 2 // account for the column spacing from before - } - - return 0 - } } struct InnerCircleView_Previews: PreviewProvider { From 91fc937b216ebd11e28c7772ba00a9c4f6fd4462 Mon Sep 17 00:00:00 2001 From: talksik Date: Mon, 20 Dec 2021 03:23:13 -0800 Subject: [PATCH 03/18] nicer navigation --- .../InnerCircle/CircleNavigationView.swift | 45 ++++++++++++++++--- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/nirvana-ios/Views/InnerCircle/CircleNavigationView.swift b/nirvana-ios/Views/InnerCircle/CircleNavigationView.swift index d478d4c..4efe256 100644 --- a/nirvana-ios/Views/InnerCircle/CircleNavigationView.swift +++ b/nirvana-ios/Views/InnerCircle/CircleNavigationView.swift @@ -15,21 +15,56 @@ struct CircleNavigationView: View { var body: some View { HStack(alignment: .center) { Menu { - Button("Edit Profile") { + Button { + print("manage inbox") + } label: { + Label("inbox", systemImage: "envelope.badge") + .foregroundColor(NirvanaColor.teal) + } + + Button { + self.navigationStack.push(ContactsView()) + } label: { + Label("add peeps", systemImage: "person.2.wave.2") + .foregroundColor(NirvanaColor.teal) + } + + Button { self.navigationStack.push(AddBasicInfoView()) + } label: { + Label("profile", systemImage: "person.crop.circle") + .foregroundColor(NirvanaColor.teal) } - Button("Friends") { - print("manage friends page") + Button { + self.navigationStack.push(OnboardingTrioView()) + } label: { + Label("Why?", systemImage: "sun.min") + .foregroundColor(NirvanaColor.teal) } - Button("Log out") { + Button { + print("navigate to usenirvana.com") + if let url = URL(string: "https://usenirvana.com") { + UIApplication.shared.open(url) + } + + } label: { + Label("why?", systemImage: "leaf") + .foregroundColor(NirvanaColor.teal) + } + + Button { print("log out button clicked") self.authSessionStore.logOut() // once logged out, then the listener will listen and router view will take care of us thereafter + } label: { + Label("log out", systemImage: "rectangle.portrait.and.arrow.right") + .foregroundColor(NirvanaColor.teal) } + } label: { if self.authSessionStore.user?.avatar == nil { Image("Artboards_Diversity_Avatars_by_Netguru-1") @@ -107,6 +142,6 @@ struct CircleNavigationView: View { struct CircleNavigationView_Previews: PreviewProvider { static var previews: some View { - CircleNavigationView() + CircleNavigationView().environmentObject(AuthSessionStore(isPreview: true)) } } From a3374050ff7178024ef800b9ca897415077cbedf Mon Sep 17 00:00:00 2001 From: talksik Date: Mon, 20 Dec 2021 03:32:55 -0800 Subject: [PATCH 04/18] cleaning up nav --- nirvana-ios/Views/InnerCircle/CircleNavigationView.swift | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/nirvana-ios/Views/InnerCircle/CircleNavigationView.swift b/nirvana-ios/Views/InnerCircle/CircleNavigationView.swift index 4efe256..dfdc447 100644 --- a/nirvana-ios/Views/InnerCircle/CircleNavigationView.swift +++ b/nirvana-ios/Views/InnerCircle/CircleNavigationView.swift @@ -15,7 +15,7 @@ struct CircleNavigationView: View { var body: some View { HStack(alignment: .center) { Menu { - Button { + Button(role: .destructive) { print("manage inbox") } label: { Label("inbox", systemImage: "envelope.badge") @@ -39,7 +39,7 @@ struct CircleNavigationView: View { Button { self.navigationStack.push(OnboardingTrioView()) } label: { - Label("Why?", systemImage: "sun.min") + Label("why?", systemImage: "leaf") .foregroundColor(NirvanaColor.teal) } @@ -50,11 +50,11 @@ struct CircleNavigationView: View { } } label: { - Label("why?", systemImage: "leaf") + Label("about us", systemImage: "globe.americas") .foregroundColor(NirvanaColor.teal) } - Button { + Button(role: .destructive) { print("log out button clicked") self.authSessionStore.logOut() @@ -84,7 +84,6 @@ struct CircleNavigationView: View { .clipShape(Circle()) .padding(5) } - } ScrollView(.horizontal) { From e2f8d9d1e28a6a32dfd3b4284747f1e55dce62b7 Mon Sep 17 00:00:00 2001 From: talksik Date: Mon, 20 Dec 2021 04:27:18 -0800 Subject: [PATCH 05/18] nice sheet for adding contacts --- .../Views/Contacts/ContactsPickerView.swift | 18 +++++++------ nirvana-ios/Views/Contacts/ContactsView.swift | 2 +- .../Views/Contacts/ContactsViewModel.swift | 25 ++++++++----------- .../Views/InnerCircle/CircleGridView.swift | 2 +- .../InnerCircle/CircleNavigationView.swift | 7 ++++-- .../Views/InnerCircle/InnerCircleView.swift | 18 ++++++++++++- 6 files changed, 45 insertions(+), 27 deletions(-) diff --git a/nirvana-ios/Views/Contacts/ContactsPickerView.swift b/nirvana-ios/Views/Contacts/ContactsPickerView.swift index bb89b93..07af937 100644 --- a/nirvana-ios/Views/Contacts/ContactsPickerView.swift +++ b/nirvana-ios/Views/Contacts/ContactsPickerView.swift @@ -8,10 +8,11 @@ import SwiftUI import Contacts -struct ContactPickerView: View { - @Binding var showPicker: Bool +struct ContactsPickerView: View { + @Environment(\.dismiss) var dismiss + // updates the parent view for it to do something with the new contact - @Binding var selectedContact: CNContact? + @State var selectedContact: CNContact? var contacts: [String: [CNContact]] = loadContactsGrouped() @@ -22,14 +23,17 @@ struct ContactPickerView: View { ForEach(keys.sorted(), id: \.self) { key in Section(header: Text(key)) { ForEach(contacts[key] ?? [CNContact](), id: \.identifier) { contact in - ContactRow(contact: contact, showPicker: self.$showPicker, selectedContact: self.$selectedContact) + ContactRow(contact: contact, selectedContact: self.$selectedContact) } } } } .listStyle(GroupedListStyle()) .navigationTitle("All Contacts".localized) - .navigationBarItems(trailing: Button(action: {self.showPicker = false}, label: { + .navigationBarItems(trailing: Button(action: { + dismiss() + + }, label: { Text("Cancel".localized) })) } @@ -43,6 +47,8 @@ struct ContactPickerView: View { return String(contact.familyName.first ?? "?") } + print(group) + return group } } @@ -50,7 +56,6 @@ struct ContactPickerView: View { struct ContactRow: View { var contact: CNContact - @Binding var showPicker: Bool @Binding var selectedContact: CNContact? var body: some View { @@ -67,7 +72,6 @@ struct ContactRow: View { func selectContact() { self.selectedContact = self.contact - self.showPicker = false } } diff --git a/nirvana-ios/Views/Contacts/ContactsView.swift b/nirvana-ios/Views/Contacts/ContactsView.swift index f376d14..b704ba1 100644 --- a/nirvana-ios/Views/Contacts/ContactsView.swift +++ b/nirvana-ios/Views/Contacts/ContactsView.swift @@ -53,7 +53,7 @@ struct ContactsView: View { Spacer() } .sheet(isPresented: self.$showPicker) { - ContactPickerView(showPicker: self.$showPicker, selectedContact: self.$selectedContact) +// ContactPickerView(showPicker: self.$showPicker, selectedContact: self.$selectedContact) } .padding() .background(NirvanaColor.bgLightGrey) diff --git a/nirvana-ios/Views/Contacts/ContactsViewModel.swift b/nirvana-ios/Views/Contacts/ContactsViewModel.swift index f792014..2873d21 100644 --- a/nirvana-ios/Views/Contacts/ContactsViewModel.swift +++ b/nirvana-ios/Views/Contacts/ContactsViewModel.swift @@ -12,17 +12,11 @@ import SwiftUI class ContactsViewModel : ObservableObject { @Published var showPermissionAlert = false - let store: CNContactStore - let keys: [CNKeyDescriptor] - - init() { - store = CNContactStore() - - keys = [CNContactImageDataKey as CNKeyDescriptor, - CNContactPhoneNumbersKey as CNKeyDescriptor, - CNContactEmailAddressesKey as CNKeyDescriptor, - CNContactFormatter.descriptorForRequiredKeys(for: .fullName)] - } + let store: CNContactStore = CNContactStore() + let keys: [CNKeyDescriptor] = [CNContactImageDataKey as CNKeyDescriptor, + CNContactPhoneNumbersKey as CNKeyDescriptor, + CNContactEmailAddressesKey as CNKeyDescriptor, + CNContactFormatter.descriptorForRequiredKeys(for: .fullName)] func openSettings() { guard let settingsURL = URL(string: UIApplication.openSettingsURLString) else { return } @@ -30,19 +24,20 @@ class ContactsViewModel : ObservableObject { } func requestAccess() { - store.requestAccess(for: .contacts) { - (granted, error) in + + store.requestAccess(for: .contacts) {(granted, error) in + // TODO: do something useful with completionHandler return } - // TODO do something useful with completionHandler } func fetchContacts(sortOrder: CNContactSortOrder = .userDefault) -> [CNContact] { let authStatus = CNContactStore.authorizationStatus(for: .contacts) + if authStatus == .notDetermined { requestAccess() } else if authStatus == .restricted { - // TODO prompt user that app is useless without access to contacts + // TODO: prompt user that app is useless without access to contacts self.showPermissionAlert = true } diff --git a/nirvana-ios/Views/InnerCircle/CircleGridView.swift b/nirvana-ios/Views/InnerCircle/CircleGridView.swift index c51751b..96ffa5b 100644 --- a/nirvana-ios/Views/InnerCircle/CircleGridView.swift +++ b/nirvana-ios/Views/InnerCircle/CircleGridView.swift @@ -16,7 +16,7 @@ struct CircleGridView: View { // magic variables for grid // TODO: make the top left person or one horizontal person be in the center of screen...makes the top honeycomb pop - private static var numberOfItems: Int = 59 + private static var numberOfItems: Int = 12 private static let size: CGFloat = UIScreen.main.bounds.height*0.15 // scaling with screen size private static let spacingBetweenColumns: CGFloat = 0 private static let spacingBetweenRows: CGFloat = 0 diff --git a/nirvana-ios/Views/InnerCircle/CircleNavigationView.swift b/nirvana-ios/Views/InnerCircle/CircleNavigationView.swift index dfdc447..7c96176 100644 --- a/nirvana-ios/Views/InnerCircle/CircleNavigationView.swift +++ b/nirvana-ios/Views/InnerCircle/CircleNavigationView.swift @@ -12,6 +12,8 @@ struct CircleNavigationView: View { @EnvironmentObject var navigationStack: NavigationStack @EnvironmentObject var authSessionStore: AuthSessionStore + @Binding var sheetView: SheetView? + var body: some View { HStack(alignment: .center) { Menu { @@ -23,7 +25,8 @@ struct CircleNavigationView: View { } Button { - self.navigationStack.push(ContactsView()) + print("going to show contacts now") + self.sheetView = .contacts } label: { Label("add peeps", systemImage: "person.2.wave.2") .foregroundColor(NirvanaColor.teal) @@ -141,6 +144,6 @@ struct CircleNavigationView: View { struct CircleNavigationView_Previews: PreviewProvider { static var previews: some View { - CircleNavigationView().environmentObject(AuthSessionStore(isPreview: true)) + CircleNavigationView(sheetView: .constant(SheetView.contacts)).environmentObject(AuthSessionStore(isPreview: true)) } } diff --git a/nirvana-ios/Views/InnerCircle/InnerCircleView.swift b/nirvana-ios/Views/InnerCircle/InnerCircleView.swift index e99c19b..7e3f3c7 100644 --- a/nirvana-ios/Views/InnerCircle/InnerCircleView.swift +++ b/nirvana-ios/Views/InnerCircle/InnerCircleView.swift @@ -8,10 +8,18 @@ import SwiftUI import NavigationStack +enum SheetView : Identifiable { + var id: Self { self } + case contacts + case inbox +} + struct InnerCircleView: View { @EnvironmentObject var authSessionStore: AuthSessionStore @EnvironmentObject var navigationStack: NavigationStack + @State var sheetView: SheetView? = nil + let universalSize = UIScreen.main.bounds var body: some View { @@ -25,13 +33,21 @@ struct InnerCircleView: View { // header VStack(alignment: .leading) { - CircleNavigationView() + CircleNavigationView(sheetView: self.$sheetView) Spacer() } CircleFooterView() } + .sheet(item: self.$sheetView) {page in + switch page { + case SheetView.contacts: + ContactsPickerView() + case SheetView.inbox: + OnboardingTrioView()// test one for now + } + } .onAppear() { } } From 7039fe63b1c952330b904f20f93f8517b16793dc Mon Sep 17 00:00:00 2001 From: talksik Date: Mon, 20 Dec 2021 04:35:02 -0800 Subject: [PATCH 06/18] adding routing for the inbox sheet --- nirvana-ios.xcodeproj/project.pbxproj | 12 +++++++++++ nirvana-ios/Views/Inbox/InboxView.swift | 21 +++++++++++++++++++ .../InnerCircle/CircleNavigationView.swift | 1 + .../Views/InnerCircle/InnerCircleView.swift | 5 ++++- 4 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 nirvana-ios/Views/Inbox/InboxView.swift diff --git a/nirvana-ios.xcodeproj/project.pbxproj b/nirvana-ios.xcodeproj/project.pbxproj index f995612..ac71bf7 100644 --- a/nirvana-ios.xcodeproj/project.pbxproj +++ b/nirvana-ios.xcodeproj/project.pbxproj @@ -32,6 +32,7 @@ 896CE6FE27707E6B00DB474E /* CircleNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 896CE6FD27707E6B00DB474E /* CircleNavigationView.swift */; }; 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 */; }; 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 */; }; @@ -103,6 +104,7 @@ 896CE6FD27707E6B00DB474E /* CircleNavigationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleNavigationView.swift; sourceTree = ""; }; 896CE6FF2770847400DB474E /* CircleFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleFooterView.swift; sourceTree = ""; }; 896CE7012770892F00DB474E /* CircleGridView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleGridView.swift; sourceTree = ""; }; + 896CE7042770AE5D00DB474E /* InboxView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InboxView.swift; sourceTree = ""; }; 89AD5572276DD790001658E0 /* SplashView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashView.swift; sourceTree = ""; }; 89AD5574276DE724001658E0 /* PhoneCodeVerificationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhoneCodeVerificationView.swift; sourceTree = ""; }; 89AD5577276DEAB3001658E0 /* LogoHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogoHeaderView.swift; sourceTree = ""; }; @@ -211,6 +213,7 @@ 891A15F62765639B00B26659 /* Views */ = { isa = PBXGroup; children = ( + 896CE7032770AE3400DB474E /* Inbox */, 894E80BF276EFCF500624B72 /* AudioPlayer */, 89F18AF3276ECF1800115B1E /* AddBasicInfo */, 89F18AF2276ECD5D00115B1E /* OnBoarding */, @@ -307,6 +310,14 @@ path = AudioPlayer; sourceTree = ""; }; + 896CE7032770AE3400DB474E /* Inbox */ = { + isa = PBXGroup; + children = ( + 896CE7042770AE5D00DB474E /* InboxView.swift */, + ); + path = Inbox; + sourceTree = ""; + }; 89AD5571276DD77D001658E0 /* SplashView */ = { isa = PBXGroup; children = ( @@ -513,6 +524,7 @@ 891A15E327653A7000B26659 /* ContentView.swift in Sources */, 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 */, 891A160B2765732700B26659 /* HomeViewModel.swift in Sources */, diff --git a/nirvana-ios/Views/Inbox/InboxView.swift b/nirvana-ios/Views/Inbox/InboxView.swift new file mode 100644 index 0000000..4292bbe --- /dev/null +++ b/nirvana-ios/Views/Inbox/InboxView.swift @@ -0,0 +1,21 @@ +// +// InboxView.swift +// nirvana-ios +// +// Created by Arjun Patel on 12/20/21. +// + +import SwiftUI + +struct InboxView: View { + var body: some View { + Text("This is the inbox where you can see a bunch of inboxes") + //TODO: add illustration if there is no one in inbox, but have button to open sheet for contacts with the sheet view object + } +} + +struct InboxView_Previews: PreviewProvider { + static var previews: some View { + InboxView() + } +} diff --git a/nirvana-ios/Views/InnerCircle/CircleNavigationView.swift b/nirvana-ios/Views/InnerCircle/CircleNavigationView.swift index 7c96176..a292ade 100644 --- a/nirvana-ios/Views/InnerCircle/CircleNavigationView.swift +++ b/nirvana-ios/Views/InnerCircle/CircleNavigationView.swift @@ -19,6 +19,7 @@ struct CircleNavigationView: View { Menu { Button(role: .destructive) { print("manage inbox") + self.sheetView = .inbox } label: { Label("inbox", systemImage: "envelope.badge") .foregroundColor(NirvanaColor.teal) diff --git a/nirvana-ios/Views/InnerCircle/InnerCircleView.swift b/nirvana-ios/Views/InnerCircle/InnerCircleView.swift index 7e3f3c7..d835d7a 100644 --- a/nirvana-ios/Views/InnerCircle/InnerCircleView.swift +++ b/nirvana-ios/Views/InnerCircle/InnerCircleView.swift @@ -45,8 +45,11 @@ struct InnerCircleView: View { case SheetView.contacts: ContactsPickerView() case SheetView.inbox: - OnboardingTrioView()// test one for now + InboxView()// test one for now + default: + Text("asdf") } + } .onAppear() { } From 7d4800188422372c075609e375f87958a1476be5 Mon Sep 17 00:00:00 2001 From: talksik Date: Mon, 20 Dec 2021 04:45:01 -0800 Subject: [PATCH 07/18] needed the dispatch to update the user on the main thread to show in ui immediately instead of waiting on next refresh or whatever --- nirvana-ios/Services/AuthSessionStore.swift | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/nirvana-ios/Services/AuthSessionStore.swift b/nirvana-ios/Services/AuthSessionStore.swift index 99db033..0cf764d 100644 --- a/nirvana-ios/Services/AuthSessionStore.swift +++ b/nirvana-ios/Services/AuthSessionStore.swift @@ -136,9 +136,11 @@ final class AuthSessionStore: ObservableObject, SessionStore { // when we have a user get signed in, we can activate the listener for fetching the user's data to keep our auth session store always up to date for all of the ui self.firestoreService.getUserRealtime(userId: uid) {[weak self] realtimeUpdatedUser in - if realtimeUpdatedUser != nil { - print("up to date user: \(realtimeUpdatedUser)") - self?.user = realtimeUpdatedUser + DispatchQueue.main.async { + if realtimeUpdatedUser != nil { + print("up to date user: \(realtimeUpdatedUser)") + self?.user = realtimeUpdatedUser + } } } } else { From dec69ecf4e038200e279b60145af86a1e6f05a62 Mon Sep 17 00:00:00 2001 From: talksik Date: Mon, 20 Dec 2021 11:26:38 -0800 Subject: [PATCH 08/18] Update CircleGridView.swift --- nirvana-ios/Views/InnerCircle/CircleGridView.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nirvana-ios/Views/InnerCircle/CircleGridView.swift b/nirvana-ios/Views/InnerCircle/CircleGridView.swift index 96ffa5b..930e6ff 100644 --- a/nirvana-ios/Views/InnerCircle/CircleGridView.swift +++ b/nirvana-ios/Views/InnerCircle/CircleGridView.swift @@ -89,6 +89,10 @@ struct CircleGridView: View { print("the selected item is: \(value)") } + .onLongPressGesture { // haptics for recording + let impactHeavy = UIImpactFeedbackGenerator(style: .heavy) + impactHeavy.impactOccurred() + } // .animation(Animation.easeInOut(duration: 2).repeatForever(autoreverses: true), value: self.usersWithNewMessage) .animation(Animation.spring()) } From 081ab46a86aaa8d26ce68d5c4f49b7c11436d96f Mon Sep 17 00:00:00 2001 From: talksik Date: Mon, 20 Dec 2021 15:41:27 -0800 Subject: [PATCH 09/18] getting to decent place now --- nirvana-ios.xcodeproj/project.pbxproj | 12 +- nirvana-ios/Globals/StringExtension.swift | 28 ++++ nirvana-ios/Models/Contact.swift | 17 -- .../Repositories/FirestoreService.swift | 22 +++ .../Views/Contacts/ContactsPickerView.swift | 158 +++++++++--------- nirvana-ios/Views/Contacts/ContactsView.swift | 2 +- .../Views/Contacts/ContactsViewModel.swift | 62 ++++++- .../Views/Contacts/FindFriendsView.swift | 79 +++++++++ .../Views/InnerCircle/InnerCircleView.swift | 4 +- 9 files changed, 272 insertions(+), 112 deletions(-) create mode 100644 nirvana-ios/Globals/StringExtension.swift delete mode 100644 nirvana-ios/Models/Contact.swift create mode 100644 nirvana-ios/Views/Contacts/FindFriendsView.swift diff --git a/nirvana-ios.xcodeproj/project.pbxproj b/nirvana-ios.xcodeproj/project.pbxproj index ac71bf7..75335e9 100644 --- a/nirvana-ios.xcodeproj/project.pbxproj +++ b/nirvana-ios.xcodeproj/project.pbxproj @@ -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 = ""; }; 896CE7012770892F00DB474E /* CircleGridView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleGridView.swift; sourceTree = ""; }; 896CE7042770AE5D00DB474E /* InboxView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InboxView.swift; sourceTree = ""; }; + 896CE70627711BAB00DB474E /* FindFriendsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FindFriendsView.swift; sourceTree = ""; }; + 896CE70827712CED00DB474E /* StringExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtension.swift; sourceTree = ""; }; 89AD5572276DD790001658E0 /* SplashView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashView.swift; sourceTree = ""; }; 89AD5574276DE724001658E0 /* PhoneCodeVerificationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhoneCodeVerificationView.swift; sourceTree = ""; }; 89AD5577276DEAB3001658E0 /* LogoHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogoHeaderView.swift; sourceTree = ""; }; @@ -121,7 +124,6 @@ 89BDCDEE2769B50C00577829 /* ContactsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsView.swift; sourceTree = ""; }; 89BDCDF02769E64200577829 /* Messages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Messages.swift; sourceTree = ""; }; 89F05B9A276A87920002E9C7 /* ContactsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsViewModel.swift; sourceTree = ""; }; - 89F05B9E276A8D360002E9C7 /* Contact.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Contact.swift; sourceTree = ""; }; 89F05BA3276ACC060002E9C7 /* ContactService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactService.swift; sourceTree = ""; }; 89F05BA5276ACD830002E9C7 /* ContactsPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsPickerView.swift; sourceTree = ""; }; 89F1386C2767EB19006680ED /* SignInView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInView.swift; sourceTree = ""; }; @@ -270,6 +272,7 @@ 89BDCDE62769616600577829 /* UIImage+Extension.swift */, 89F18AEB276E92BF00115B1E /* CustomExtensions.swift */, 894E80BD276ED7A700624B72 /* avatars.swift */, + 896CE70827712CED00DB474E /* StringExtension.swift */, ); path = Globals; sourceTree = ""; @@ -279,7 +282,6 @@ children = ( 89BDCDF02769E64200577829 /* Messages.swift */, 891A160D27657CEA00B26659 /* User.swift */, - 89F05B9E276A8D360002E9C7 /* Contact.swift */, ); path = Models; sourceTree = ""; @@ -379,6 +381,7 @@ 89BDCDEE2769B50C00577829 /* ContactsView.swift */, 89F05B9A276A87920002E9C7 /* ContactsViewModel.swift */, 89F05BA5276ACD830002E9C7 /* ContactsPickerView.swift */, + 896CE70627711BAB00DB474E /* FindFriendsView.swift */, ); path = Contacts; sourceTree = ""; @@ -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 */, diff --git a/nirvana-ios/Globals/StringExtension.swift b/nirvana-ios/Globals/StringExtension.swift new file mode 100644 index 0000000..35cbc8a --- /dev/null +++ b/nirvana-ios/Globals/StringExtension.swift @@ -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.. ())) { + // 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 { diff --git a/nirvana-ios/Views/Contacts/ContactsPickerView.swift b/nirvana-ios/Views/Contacts/ContactsPickerView.swift index 07af937..e0840f4 100644 --- a/nirvana-ios/Views/Contacts/ContactsPickerView.swift +++ b/nirvana-ios/Views/Contacts/ContactsPickerView.swift @@ -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: "") +// } +//} diff --git a/nirvana-ios/Views/Contacts/ContactsView.swift b/nirvana-ios/Views/Contacts/ContactsView.swift index b704ba1..0dd46f3 100644 --- a/nirvana-ios/Views/Contacts/ContactsView.swift +++ b/nirvana-ios/Views/Contacts/ContactsView.swift @@ -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()) diff --git a/nirvana-ios/Views/Contacts/ContactsViewModel.swift b/nirvana-ios/Views/Contacts/ContactsViewModel.swift index 2873d21..f2e4ac6 100644 --- a/nirvana-ios/Views/Contacts/ContactsViewModel.swift +++ b/nirvana-ios/Views/Contacts/ContactsViewModel.swift @@ -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 +} diff --git a/nirvana-ios/Views/Contacts/FindFriendsView.swift b/nirvana-ios/Views/Contacts/FindFriendsView.swift new file mode 100644 index 0000000..787d87a --- /dev/null +++ b/nirvana-ios/Views/Contacts/FindFriendsView.swift @@ -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) + } + } +} diff --git a/nirvana-ios/Views/InnerCircle/InnerCircleView.swift b/nirvana-ios/Views/InnerCircle/InnerCircleView.swift index d835d7a..9f7cf3a 100644 --- a/nirvana-ios/Views/InnerCircle/InnerCircleView.swift +++ b/nirvana-ios/Views/InnerCircle/InnerCircleView.swift @@ -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: From 250e3f9284f3bb58c76592067420702e22aa4671 Mon Sep 17 00:00:00 2001 From: talksik Date: Mon, 20 Dec 2021 15:48:23 -0800 Subject: [PATCH 10/18] nice full list fixing the main problem and sorting it --- nirvana-ios/Views/Contacts/ContactsViewModel.swift | 5 +++-- nirvana-ios/Views/Contacts/FindFriendsView.swift | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/nirvana-ios/Views/Contacts/ContactsViewModel.swift b/nirvana-ios/Views/Contacts/ContactsViewModel.swift index f2e4ac6..1a1d91c 100644 --- a/nirvana-ios/Views/Contacts/ContactsViewModel.swift +++ b/nirvana-ios/Views/Contacts/ContactsViewModel.swift @@ -74,19 +74,19 @@ class ContactsViewModel : ObservableObject { 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 + contactVm.isExisting = false } else { // adding user details if this contact is existing user contactVm.user = returnedUser + contactVm.isExisting = true } self?.contacts.append(contactVm) } } - } } } catch { @@ -102,4 +102,5 @@ struct ContactsViewModelContact : Identifiable { var user: User? var cnName: String var cnPhoneNumber: String + var isExisting: Bool = false } diff --git a/nirvana-ios/Views/Contacts/FindFriendsView.swift b/nirvana-ios/Views/Contacts/FindFriendsView.swift index 787d87a..8843870 100644 --- a/nirvana-ios/Views/Contacts/FindFriendsView.swift +++ b/nirvana-ios/Views/Contacts/FindFriendsView.swift @@ -22,8 +22,8 @@ struct FindFriendsView: View { NavigationView { // list with search bar List { - ForEach(contactsVM.contacts) { contact in - Text(contact.cnName) + ForEach(contactsVM.contacts.sorted { $0.isExisting && !$1.isExisting }) { contact in + } } .searchable(text: $searchQuery) From a041c0b46a2c8edbbf7380c5a9750dcf8dcc6ab2 Mon Sep 17 00:00:00 2001 From: talksik Date: Mon, 20 Dec 2021 16:04:32 -0800 Subject: [PATCH 11/18] nicer ui for the list --- .../Views/Contacts/ContactsViewModel.swift | 3 - .../Views/Contacts/FindFriendsView.swift | 63 ++++++++++++++----- 2 files changed, 47 insertions(+), 19 deletions(-) diff --git a/nirvana-ios/Views/Contacts/ContactsViewModel.swift b/nirvana-ios/Views/Contacts/ContactsViewModel.swift index 1a1d91c..f892a6d 100644 --- a/nirvana-ios/Views/Contacts/ContactsViewModel.swift +++ b/nirvana-ios/Views/Contacts/ContactsViewModel.swift @@ -69,10 +69,7 @@ class ContactsViewModel : ObservableObject { 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 DispatchQueue.main.async { if returnedUser == nil { diff --git a/nirvana-ios/Views/Contacts/FindFriendsView.swift b/nirvana-ios/Views/Contacts/FindFriendsView.swift index 8843870..fc20d93 100644 --- a/nirvana-ios/Views/Contacts/FindFriendsView.swift +++ b/nirvana-ios/Views/Contacts/FindFriendsView.swift @@ -23,11 +23,9 @@ struct FindFriendsView: View { // list with search bar List { ForEach(contactsVM.contacts.sorted { $0.isExisting && !$1.isExisting }) { contact in - + ListContactRow(contact: contact) } } - .searchable(text: $searchQuery) - .listStyle(GroupedListStyle()) .navigationTitle("Find Friends") .navigationBarItems(trailing: Button(action: { dismiss() @@ -50,30 +48,63 @@ struct FindFriendsView_Previews: PreviewProvider { } struct ListContactRow: View { - var contact: CNContact + var contact: ContactsViewModelContact @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)") + if contact.isExisting { // add to circle + HStack(alignment: .center, spacing: 0) { + Image(contact.user?.avatar ?? "") + .resizable() + .scaledToFit() + .clipShape(Circle()) + .frame(width: 40, height: 40) + .padding(.trailing, 10) + + Text(contact.cnName) + .font(.headline) Spacer() - // if the user is already an existing user + Button { + print("adding contact to circle") + + //show alert if circle is full + + } label: { + Label("Add", systemImage: "plus.circle") + .font(.title2) + .foregroundColor(NirvanaColor.solidTeal) + } } - .foregroundColor(.black) } - .alert(self.alertText, isPresented: self.$showAlert) { - Button("OK", role: ButtonRole.cancel) { } - } message: { - Text(self.alertMessage) + else { // invite button to text the person + HStack(alignment: .center, spacing: 0) { + Image(Avatars.avatarSystemNames[1]) + .resizable() + .scaledToFit() + .clipShape(Circle()) + .frame(width: 40, height: 40) + .blur(radius: 8) + .padding(.trailing, 10) + + Text(contact.cnName) + .font(.headline) + + Spacer() + + Button { + print("inviting user now") + // text message to him/her + } label: { + Label("Invite", systemImage: "paperplane") + .font(.title2) + .foregroundColor(Color.orange) + } + } } } } From ee337a5313de4679fce09e709450948ca842c041 Mon Sep 17 00:00:00 2001 From: talksik Date: Mon, 20 Dec 2021 16:13:40 -0800 Subject: [PATCH 12/18] Update FindFriendsView.swift --- nirvana-ios/Views/Contacts/FindFriendsView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nirvana-ios/Views/Contacts/FindFriendsView.swift b/nirvana-ios/Views/Contacts/FindFriendsView.swift index fc20d93..b091afe 100644 --- a/nirvana-ios/Views/Contacts/FindFriendsView.swift +++ b/nirvana-ios/Views/Contacts/FindFriendsView.swift @@ -57,7 +57,7 @@ struct ListContactRow: View { var body: some View { if contact.isExisting { // add to circle HStack(alignment: .center, spacing: 0) { - Image(contact.user?.avatar ?? "") + Image(contact.user?.avatar ?? Avatars.avatarSystemNames[1]) .resizable() .scaledToFit() .clipShape(Circle()) From 5400ea8d9725024063d423561ef5def044c10825 Mon Sep 17 00:00:00 2001 From: talksik Date: Mon, 20 Dec 2021 16:43:31 -0800 Subject: [PATCH 13/18] adding texting ability --- nirvana-ios/Services/AuthSessionStore.swift | 6 ++++++ nirvana-ios/Views/Contacts/FindFriendsView.swift | 14 +++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/nirvana-ios/Services/AuthSessionStore.swift b/nirvana-ios/Services/AuthSessionStore.swift index 0cf764d..33cda4a 100644 --- a/nirvana-ios/Services/AuthSessionStore.swift +++ b/nirvana-ios/Services/AuthSessionStore.swift @@ -143,6 +143,12 @@ final class AuthSessionStore: ObservableObject, SessionStore { } } } + + // TODO: listener for getting user's sent and received messages + + // TODO: listener for getting user's circle members + + } else { // if we don't have a user, set our session to nil self.user = nil diff --git a/nirvana-ios/Views/Contacts/FindFriendsView.swift b/nirvana-ios/Views/Contacts/FindFriendsView.swift index b091afe..4022e3a 100644 --- a/nirvana-ios/Views/Contacts/FindFriendsView.swift +++ b/nirvana-ios/Views/Contacts/FindFriendsView.swift @@ -20,7 +20,7 @@ struct FindFriendsView: View { var body: some View { NavigationView { - // list with search bar + // TODO: add search bar + have secondary sort List { ForEach(contactsVM.contacts.sorted { $0.isExisting && !$1.isExisting }) { contact in ListContactRow(contact: contact) @@ -47,6 +47,8 @@ struct FindFriendsView_Previews: PreviewProvider { } } + + struct ListContactRow: View { var contact: ContactsViewModelContact @@ -56,6 +58,7 @@ struct ListContactRow: View { var body: some View { if contact.isExisting { // add to circle + // TODO: check if this contact is already in user's circle HStack(alignment: .center, spacing: 0) { Image(contact.user?.avatar ?? Avatars.avatarSystemNames[1]) .resizable() @@ -99,6 +102,15 @@ struct ListContactRow: View { Button { print("inviting user now") // text message to him/her + + if contact.cnPhoneNumber != nil { + let sms: String = "sms://\(contact.cnPhoneNumber)&body=Join me on Nirvana! I sent you a message there! https://usenirvana.com" + let strUrl: String = sms.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)! + + UIApplication.shared.open(URL(string: strUrl)!, options: [:], completionHandler: nil) + } else { + print("phone number is nil of contact") + } } label: { Label("Invite", systemImage: "paperplane") .font(.title2) From f7b8126a2612870787ea09c613c39af798b69b47 Mon Sep 17 00:00:00 2001 From: talksik Date: Mon, 20 Dec 2021 16:52:07 -0800 Subject: [PATCH 14/18] adding in last name for easier understanding of the user --- nirvana-ios/Views/Contacts/ContactsViewModel.swift | 2 +- nirvana-ios/Views/Contacts/FindFriendsView.swift | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/nirvana-ios/Views/Contacts/ContactsViewModel.swift b/nirvana-ios/Views/Contacts/ContactsViewModel.swift index f892a6d..2ce7539 100644 --- a/nirvana-ios/Views/Contacts/ContactsViewModel.swift +++ b/nirvana-ios/Views/Contacts/ContactsViewModel.swift @@ -55,7 +55,7 @@ class ContactsViewModel : ObservableObject { 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 + let contactDisplayName = contact.givenName + " " + contact.familyName // strip out nondigits // add or keep country code diff --git a/nirvana-ios/Views/Contacts/FindFriendsView.swift b/nirvana-ios/Views/Contacts/FindFriendsView.swift index 4022e3a..6cc7b86 100644 --- a/nirvana-ios/Views/Contacts/FindFriendsView.swift +++ b/nirvana-ios/Views/Contacts/FindFriendsView.swift @@ -17,7 +17,6 @@ struct FindFriendsView: View { @State private var searchQuery: String = "" - var body: some View { NavigationView { // TODO: add search bar + have secondary sort From 4c5f8e6985cac12580c4ac2fa74753d71d4d1dd6 Mon Sep 17 00:00:00 2001 From: talksik Date: Mon, 20 Dec 2021 17:23:06 -0800 Subject: [PATCH 15/18] adding custom sorting method and all and works fine with search and all now --- .../Views/Contacts/ContactsViewModel.swift | 11 +++++---- .../Views/Contacts/FindFriendsView.swift | 23 +++++++++++++------ 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/nirvana-ios/Views/Contacts/ContactsViewModel.swift b/nirvana-ios/Views/Contacts/ContactsViewModel.swift index 2ce7539..36eeebb 100644 --- a/nirvana-ios/Views/Contacts/ContactsViewModel.swift +++ b/nirvana-ios/Views/Contacts/ContactsViewModel.swift @@ -11,7 +11,7 @@ import SwiftUI class ContactsViewModel : ObservableObject { @Published var showPermissionAlert = false - @Published var contacts: [ContactsViewModelContact] = [] + @Published var contacts: [String: ContactsViewModelContact] = [:] private var firestoreService = FirestoreService() @@ -63,11 +63,11 @@ class ContactsViewModel : ObservableObject { var formattedNumber = cnPhoneNumber?.digits.suffix(10) // only show contacts if they have a phone number - if formattedNumber != nil { + if formattedNumber != nil && formattedNumber?.count ?? 0 > 9 { formattedNumber = "+1" + formattedNumber! // adding country code let contactNumber = String(formattedNumber!) - var contactVm = ContactsViewModelContact(cnName: contactDisplayName, cnPhoneNumber: contactNumber) + var contactVm = ContactsViewModelContact(cnName: contactDisplayName, cnPhoneNumber: contactNumber, sortingProp: contactDisplayName) // check if the contact is an existing user by phone number self.firestoreService.getUserByPhoneNumber(phoneNumber: contactNumber) {[weak self] returnedUser in @@ -75,13 +75,15 @@ class ContactsViewModel : ObservableObject { if returnedUser == nil { // do nothing, keep contactsVm object user property nil contactVm.isExisting = false + contactVm.sortingProp = contactVm.cnName } else { // adding user details if this contact is existing user + contactVm.sortingProp = "!" // adding for sorting purposes contactVm.user = returnedUser contactVm.isExisting = true } - self?.contacts.append(contactVm) + self?.contacts[contactVm.sortingProp] = contactVm } } } @@ -100,4 +102,5 @@ struct ContactsViewModelContact : Identifiable { var cnName: String var cnPhoneNumber: String var isExisting: Bool = false + var sortingProp: String } diff --git a/nirvana-ios/Views/Contacts/FindFriendsView.swift b/nirvana-ios/Views/Contacts/FindFriendsView.swift index 6cc7b86..3693d7c 100644 --- a/nirvana-ios/Views/Contacts/FindFriendsView.swift +++ b/nirvana-ios/Views/Contacts/FindFriendsView.swift @@ -16,15 +16,19 @@ struct FindFriendsView: View { @StateObject var contactsVM = ContactsViewModel() @State private var searchQuery: String = "" - + var body: some View { + NavigationView { // TODO: add search bar + have secondary sort List { - ForEach(contactsVM.contacts.sorted { $0.isExisting && !$1.isExisting }) { contact in - ListContactRow(contact: contact) + ForEach(searchItems, id: \.self) { key in + if let currContact = self.contactsVM.contacts[key] { + ListContactRow(contact: currContact) + } } } + .searchable(text: self.$searchQuery) .navigationTitle("Find Friends") .navigationBarItems(trailing: Button(action: { dismiss() @@ -32,10 +36,15 @@ struct FindFriendsView: View { Text("Cancel") })) } - .onAppear { - // organize contacts - // sort by has account and then show all other contacts - + } + + var searchItems: [String] { + let keys = (Array(self.contactsVM.contacts.keys) as [String]).sorted() + + if self.searchQuery.isEmpty { + return keys + } else { + return keys.filter { $0.contains(self.searchQuery) } } } } From 61d357875ab81e65eb8f96783764d008c9fb56c7 Mon Sep 17 00:00:00 2001 From: talksik Date: Mon, 20 Dec 2021 18:36:23 -0800 Subject: [PATCH 16/18] brute force working but just need to navigate user back to circle --- nirvana-ios.xcodeproj/project.pbxproj | 4 +++ nirvana-ios/Models/UserFriends.swift | 34 ++++++++++++++++++ .../Repositories/FirestoreService.swift | 21 ++++++++++- .../Views/AddBasicInfo/AddBasicInfoView.swift | 2 +- .../Views/Contacts/ContactsViewModel.swift | 9 +++++ .../Views/Contacts/FindFriendsView.swift | 35 ++++++++++++++----- 6 files changed, 94 insertions(+), 11 deletions(-) create mode 100644 nirvana-ios/Models/UserFriends.swift diff --git a/nirvana-ios.xcodeproj/project.pbxproj b/nirvana-ios.xcodeproj/project.pbxproj index 75335e9..66a97fa 100644 --- a/nirvana-ios.xcodeproj/project.pbxproj +++ b/nirvana-ios.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 8904DEC8277055E90071E6CA /* OnboardingTrioView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8904DEC7277055E90071E6CA /* OnboardingTrioView.swift */; }; + 89110714277166D6005797FA /* UserFriends.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89110713277166D6005797FA /* UserFriends.swift */; }; 891A15E127653A7000B26659 /* nirvana_iosApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891A15E027653A7000B26659 /* nirvana_iosApp.swift */; }; 891A15E327653A7000B26659 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891A15E227653A7000B26659 /* ContentView.swift */; }; 891A15E527653A7100B26659 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 891A15E427653A7100B26659 /* Assets.xcassets */; }; @@ -79,6 +80,7 @@ /* Begin PBXFileReference section */ 8904DEC7277055E90071E6CA /* OnboardingTrioView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingTrioView.swift; sourceTree = ""; }; + 89110713277166D6005797FA /* UserFriends.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserFriends.swift; sourceTree = ""; }; 891A15DD27653A7000B26659 /* nirvana-ios.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "nirvana-ios.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 891A15E027653A7000B26659 /* nirvana_iosApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = nirvana_iosApp.swift; sourceTree = ""; }; 891A15E227653A7000B26659 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; @@ -282,6 +284,7 @@ children = ( 89BDCDF02769E64200577829 /* Messages.swift */, 891A160D27657CEA00B26659 /* User.swift */, + 89110713277166D6005797FA /* UserFriends.swift */, ); path = Models; sourceTree = ""; @@ -530,6 +533,7 @@ 896CE7052770AE5D00DB474E /* InboxView.swift in Sources */, 891A160327656FC700B26659 /* HomeView.swift in Sources */, 896CE70927712CED00DB474E /* StringExtension.swift in Sources */, + 89110714277166D6005797FA /* UserFriends.swift in Sources */, 896CE70727711BAB00DB474E /* FindFriendsView.swift in Sources */, 891A160B2765732700B26659 /* HomeViewModel.swift in Sources */, 89BCABEB276D2A09009E9B10 /* PhoneVerificationView.swift in Sources */, diff --git a/nirvana-ios/Models/UserFriends.swift b/nirvana-ios/Models/UserFriends.swift new file mode 100644 index 0000000..b4ae1e8 --- /dev/null +++ b/nirvana-ios/Models/UserFriends.swift @@ -0,0 +1,34 @@ +// +// UserFriends.swift +// nirvana-ios +// +// Created by Arjun Patel on 12/20/21. +// + +import Foundation +import Firebase +import FirebaseFirestoreSwift + +enum UserFriendsState { + case active + case inactive +} + +struct UserFriends: Identifiable, Codable { + @DocumentID var id: String? = UUID().uuidString + var userId: String + var friendId: String + var isActive: Bool + + @ServerTimestamp var lastUpdatedTimestamp: Date? + @ServerTimestamp var createdTimestamp: Date? + + enum CodingKeys: String, CodingKey { + case id + case userId + case friendId + case isActive + case createdTimestamp + case lastUpdatedTimestamp + } +} diff --git a/nirvana-ios/Repositories/FirestoreService.swift b/nirvana-ios/Repositories/FirestoreService.swift index 625b3ba..5716083 100644 --- a/nirvana-ios/Repositories/FirestoreService.swift +++ b/nirvana-ios/Repositories/FirestoreService.swift @@ -7,13 +7,15 @@ import Foundation import Firebase +import FirebaseCore import FirebaseFirestore +import FirebaseFirestoreSwift class FirestoreService { enum Collection: String { case users = "users" case messages = "messages" - case user_friends = "user_friends" // associating a user to + case userFriends = "user_friends" // associating a user to } private var db = Firestore.firestore() @@ -103,4 +105,21 @@ class FirestoreService { return FieldValue.serverTimestamp() } + + + func createOrUpdateUserFriends(userFriend: UserFriends, completion: @escaping((_ state: ServiceState) -> ())) { + do { + if userFriend.id != nil { + let _ = try db.collection(Collection.userFriends.rawValue).addDocument(from: userFriend) + completion(ServiceState.success("created/updated userfriend in firestore service")) + } else { + completion(ServiceState.error(ServiceError(description: "No userfriend id given to firestore service"))) + } + } catch { + print("error in creating user friend \(error.localizedDescription)") + completion(ServiceState.error(ServiceError(description: error.localizedDescription))) + } + + } + } diff --git a/nirvana-ios/Views/AddBasicInfo/AddBasicInfoView.swift b/nirvana-ios/Views/AddBasicInfo/AddBasicInfoView.swift index 394168d..6bff78b 100644 --- a/nirvana-ios/Views/AddBasicInfo/AddBasicInfoView.swift +++ b/nirvana-ios/Views/AddBasicInfo/AddBasicInfoView.swift @@ -102,7 +102,7 @@ struct AddBasicInfoView: View { Spacer() - + // button to save information Button { print("attempting to save information") diff --git a/nirvana-ios/Views/Contacts/ContactsViewModel.swift b/nirvana-ios/Views/Contacts/ContactsViewModel.swift index 36eeebb..5968261 100644 --- a/nirvana-ios/Views/Contacts/ContactsViewModel.swift +++ b/nirvana-ios/Views/Contacts/ContactsViewModel.swift @@ -93,6 +93,15 @@ class ContactsViewModel : ObservableObject { } } + + func addOrActivateFriendToCircle(userId: String, friendId: String) { + // setting timestamps to nil to make sure that new server timestamp is set + var userFriend = UserFriends(userId: userId, friendId: friendId, isActive: true, lastUpdatedTimestamp: nil, createdTimestamp: nil) + + self.firestoreService.createOrUpdateUserFriends(userFriend: userFriend) {[weak self] res in + print(res) + } + } } diff --git a/nirvana-ios/Views/Contacts/FindFriendsView.swift b/nirvana-ios/Views/Contacts/FindFriendsView.swift index 3693d7c..a537f0d 100644 --- a/nirvana-ios/Views/Contacts/FindFriendsView.swift +++ b/nirvana-ios/Views/Contacts/FindFriendsView.swift @@ -7,6 +7,7 @@ import SwiftUI import Contacts +import NavigationStack @@ -24,7 +25,7 @@ struct FindFriendsView: View { List { ForEach(searchItems, id: \.self) { key in if let currContact = self.contactsVM.contacts[key] { - ListContactRow(contact: currContact) + ListContactRow(contactsVM: self.contactsVM, contact: currContact) } } } @@ -47,6 +48,8 @@ struct FindFriendsView: View { return keys.filter { $0.contains(self.searchQuery) } } } + + } struct FindFriendsView_Previews: PreviewProvider { @@ -55,14 +58,16 @@ struct FindFriendsView_Previews: PreviewProvider { } } - - struct ListContactRow: View { - var contact: ContactsViewModelContact + @EnvironmentObject var navigationStack : NavigationStack + @EnvironmentObject var authSessionStore: AuthSessionStore + + var contactsVM: ContactsViewModel + var contact:ContactsViewModelContact @State var showAlert = false - @State var alertText = "" - @State var alertMessage = "" + @State var alertText = "🌱Confirm Arjun into Your Circle?" + @State var alertMessage = "Note: You can have a maximium of 12 people in your circle and you have 5 swaps left!" var body: some View { if contact.isExisting { // add to circle @@ -81,9 +86,9 @@ struct ListContactRow: View { Spacer() Button { - print("adding contact to circle") - - //show alert if circle is full + print("showing alert now") + // TODO: show alert if circle is full + self.showAlert.toggle() } label: { Label("Add", systemImage: "plus.circle") @@ -91,6 +96,16 @@ struct ListContactRow: View { .foregroundColor(NirvanaColor.solidTeal) } } + .alert(self.alertText, isPresented: self.$showAlert) { + Button("Add \(contact.cnName)", role: ButtonRole.cancel) { + print("adding contact to circle") + // call method in vm to get it done, then navigate to the circle + self.contactsVM.addOrActivateFriendToCircle(userId: self.authSessionStore.user!.id!, friendId: (contact.user!.id)!) + + } + } message: { + Text(self.alertMessage) + } } else { // invite button to text the person HStack(alignment: .center, spacing: 0) { @@ -128,3 +143,5 @@ struct ListContactRow: View { } } } + + From aafe6dfff30725335b2601973b458f25cb6af445 Mon Sep 17 00:00:00 2001 From: talksik Date: Mon, 20 Dec 2021 18:48:02 -0800 Subject: [PATCH 17/18] everythings broken and unsmooth --- nirvana-ios/Repositories/FirestoreService.swift | 2 -- nirvana-ios/Views/Contacts/ContactsViewModel.swift | 1 + nirvana-ios/Views/Contacts/FindFriendsView.swift | 3 ++- nirvana-ios/Views/InnerCircle/InnerCircleView.swift | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/nirvana-ios/Repositories/FirestoreService.swift b/nirvana-ios/Repositories/FirestoreService.swift index 5716083..cd00ba7 100644 --- a/nirvana-ios/Repositories/FirestoreService.swift +++ b/nirvana-ios/Repositories/FirestoreService.swift @@ -62,8 +62,6 @@ class FirestoreService { 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) diff --git a/nirvana-ios/Views/Contacts/ContactsViewModel.swift b/nirvana-ios/Views/Contacts/ContactsViewModel.swift index 5968261..ea01d5a 100644 --- a/nirvana-ios/Views/Contacts/ContactsViewModel.swift +++ b/nirvana-ios/Views/Contacts/ContactsViewModel.swift @@ -81,6 +81,7 @@ class ContactsViewModel : ObservableObject { contactVm.sortingProp = "!" // adding for sorting purposes contactVm.user = returnedUser contactVm.isExisting = true + print("existing user: \(contactVm.cnName)") } self?.contacts[contactVm.sortingProp] = contactVm diff --git a/nirvana-ios/Views/Contacts/FindFriendsView.swift b/nirvana-ios/Views/Contacts/FindFriendsView.swift index a537f0d..2bb5542 100644 --- a/nirvana-ios/Views/Contacts/FindFriendsView.swift +++ b/nirvana-ios/Views/Contacts/FindFriendsView.swift @@ -97,11 +97,12 @@ struct ListContactRow: View { } } .alert(self.alertText, isPresented: self.$showAlert) { - Button("Add \(contact.cnName)", role: ButtonRole.cancel) { + Button("Add \(contact.cnName)") { print("adding contact to circle") // call method in vm to get it done, then navigate to the circle self.contactsVM.addOrActivateFriendToCircle(userId: self.authSessionStore.user!.id!, friendId: (contact.user!.id)!) + self.navigationStack.push(InnerCircleView()) } } message: { Text(self.alertMessage) diff --git a/nirvana-ios/Views/InnerCircle/InnerCircleView.swift b/nirvana-ios/Views/InnerCircle/InnerCircleView.swift index 9f7cf3a..fe62572 100644 --- a/nirvana-ios/Views/InnerCircle/InnerCircleView.swift +++ b/nirvana-ios/Views/InnerCircle/InnerCircleView.swift @@ -18,7 +18,7 @@ struct InnerCircleView: View { @EnvironmentObject var authSessionStore: AuthSessionStore @EnvironmentObject var navigationStack: NavigationStack - @State var sheetView: SheetView? = .contacts + @State var sheetView: SheetView? = nil let universalSize = UIScreen.main.bounds From 15d7ec45926ae314f32d681590ae90ba2c4d2a0d Mon Sep 17 00:00:00 2001 From: talksik Date: Mon, 20 Dec 2021 18:57:48 -0800 Subject: [PATCH 18/18] Update AuthSessionStore.swift --- nirvana-ios/Services/AuthSessionStore.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nirvana-ios/Services/AuthSessionStore.swift b/nirvana-ios/Services/AuthSessionStore.swift index 33cda4a..a6f4f77 100644 --- a/nirvana-ios/Services/AuthSessionStore.swift +++ b/nirvana-ios/Services/AuthSessionStore.swift @@ -121,18 +121,18 @@ final class AuthSessionStore: ObservableObject, SessionStore { func setupAuthListen() { // monitor authentication changes using firebase - self.handler = Auth.auth().addStateDidChangeListener { [weak self] res, user in + self.handler = Auth.auth().addStateDidChangeListener { [weak self] res, authUser in print("auth listener activated") guard let self = self else { return } - self.sessionState = user == nil ? SessionState.isLoggedOut : SessionState.isAuthenticated + self.sessionState = authUser == nil ? SessionState.isLoggedOut : SessionState.isAuthenticated // get the user from the auth table in firebase auth - if let uid = user?.uid { + if let uid = authUser?.uid { // if we have a user, create a new user model print("auth listener: Got user: \(uid)") - print("auth listener: phone number: \(user?.phoneNumber)") + print("auth listener: phone number: \(authUser?.phoneNumber)") // when we have a user get signed in, we can activate the listener for fetching the user's data to keep our auth session store always up to date for all of the ui self.firestoreService.getUserRealtime(userId: uid) {[weak self] realtimeUpdatedUser in