From 93dd2e92658b0f03e2053afadb3e50f260c14844 Mon Sep 17 00:00:00 2001 From: Patrick van Broeckhuijsen Date: Wed, 11 Jan 2023 22:01:39 +0100 Subject: [PATCH 1/8] Fix views for logout and ToolBar --- SinuS/SinuS/ContentView.swift | 2 +- .../AuthenticationStartView.swift | 37 ------ .../Views/Authentication/LoginView.swift | 123 ++++++++++++------ .../Views/Authentication/RegisterView.swift | 20 +++ SinuS/SinuS/Views/NavigateToView.swift | 8 ++ .../Views/Personal/ManageProfileView.swift | 5 +- 6 files changed, 115 insertions(+), 80 deletions(-) delete mode 100644 SinuS/SinuS/Views/Authentication/AuthenticationStartView.swift create mode 100644 SinuS/SinuS/Views/NavigateToView.swift diff --git a/SinuS/SinuS/ContentView.swift b/SinuS/SinuS/ContentView.swift index 1e4c9f9..bd5e2c9 100644 --- a/SinuS/SinuS/ContentView.swift +++ b/SinuS/SinuS/ContentView.swift @@ -14,7 +14,7 @@ struct ContentView: View { var body: some View { NavigationView { if KeychainWrapper.standard.string(forKey: "bearerToken") == nil { - AuthenticationStartView() + LoginView() } else { MenuView() } diff --git a/SinuS/SinuS/Views/Authentication/AuthenticationStartView.swift b/SinuS/SinuS/Views/Authentication/AuthenticationStartView.swift deleted file mode 100644 index e428f84..0000000 --- a/SinuS/SinuS/Views/Authentication/AuthenticationStartView.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// AuthenticationStartView.swift -// SinuS -// -// Created by Loe Hendriks on 06/11/2022. -// - -import SwiftUI - -struct AuthenticationStartView: View { - var body: some View { - NavigationView { - VStack { - - Spacer() - - // Login Button - NavigationLink(destination: LoginView(), label: { - MenuButton(image: Image(systemName: "person.badge.key.fill"), name: "Login") - }) - - // Register Button - NavigationLink(destination: RegisterView(), label: { - MenuButton(image: Image(systemName: "person.fill.badge.plus"), name: "Register") - }) - - Spacer() - } - } - } -} - -struct AutenticationStartView_Previews: PreviewProvider { - static var previews: some View { - AuthenticationStartView() - } -} diff --git a/SinuS/SinuS/Views/Authentication/LoginView.swift b/SinuS/SinuS/Views/Authentication/LoginView.swift index 98d663a..6e053eb 100644 --- a/SinuS/SinuS/Views/Authentication/LoginView.swift +++ b/SinuS/SinuS/Views/Authentication/LoginView.swift @@ -19,56 +19,97 @@ struct LoginView: View { var body: some View { VStack { - // Email - HStack { - Text("Email:") - Spacer() - TextField("", text: self.$email) - .disableAutocorrection(true) - .border(Color.white, width: 0.5) - .frame(width: 220) - }.padding(.horizontal).padding(.top) - - // Password - HStack { - Text("Password:") - Spacer() - SecureField("", text: self.$password) - .disableAutocorrection(true) - .border(Color.white, width: 0.5) - .frame(width: 220) - }.padding(.horizontal).padding(.top) - - // Login Button - Button("Login") { - let res = self.manager.login(email: self.email, password: self.password) - UserDefaults.standard.set(self.email, forKey: "email") - - if res == nil { - self.showAlert.toggle() - } else { - // Set global authentication token. - ContentView.AuthenticationToken = res!.success - let saveSuccessful: Bool = KeychainWrapper.standard.set(ContentView.AuthenticationToken, forKey: "bearerToken") - if !saveSuccessful { - print("Could not save bearerToken") + Spacer() + + VStack { + // Email + HStack { + Text("Email:") + Spacer() + TextField("", text: self.$email) + .disableAutocorrection(true) + .border(Color.white, width: 0.5) + .frame(width: 220) + }.padding(.horizontal).padding(.top) + + // Password + HStack { + Text("Password:") + Spacer() + SecureField("", text: self.$password) + .disableAutocorrection(true) + .border(Color.white, width: 0.5) + .frame(width: 220) + }.padding(.horizontal).padding(.top) + + // Login Button + Button("Login") { + let res = self.manager.login(email: self.email, password: self.password) + UserDefaults.standard.set(self.email, forKey: "email") + + if res == nil { + self.showAlert.toggle() + } else { + // Set global authentication token. + ContentView.AuthenticationToken = res!.success + let saveSuccessful: Bool = KeychainWrapper.standard.set(ContentView.AuthenticationToken, forKey: "bearerToken") + if !saveSuccessful { + print("Could not save bearerToken") + } + + self.pushActive = true } - self.pushActive = true } + .alert(isPresented: $showAlert) { + return Alert(title: Text("Failed to Login"), message: Text("Unable to log user: \(self.email) in"), dismissButton: .default(Text("OK"))) + } + .padding() } - .alert(isPresented: $showAlert) { - return Alert(title: Text("Failed to Login"), message: Text("Unable to log user: \(self.email) in"), dismissButton: .default(Text("OK"))) + .background(Style.AppColor) + .cornerRadius(5) + .shadow(radius: 5) + .padding() + .foregroundColor(.white) + NavigationLink(destination: RegisterView(), label: { + Text("Forgot password?") + }) + .foregroundColor(.black) + .padding() + + Spacer() + + VStack { + NavigationLink(destination: RegisterView(), label: { + MenuButton(image: Image(systemName: "person.fill.badge.plus"), name: "Register") + }) } .padding() + + } + .navigationBarBackButtonHidden(true) + .navigationBarTitleDisplayMode(.inline) + .toolbarBackground(Style.AppColor, for: .navigationBar) + .toolbarBackground(.visible, for: .navigationBar) + .toolbar { + ToolbarItem(placement: .principal) { + VStack { + HStack { + Image(systemName: "water.waves") + .resizable() + .frame(width: 25, height: 25) + .foregroundColor(.white) + .padding(.bottom) + Text("Love Waves") + .foregroundColor(.white) + .font(.system(size: 25)) + .padding(.bottom) + } + } + } } - .background(Style.AppColor) - .cornerRadius(5) - .shadow(radius: 5) - .padding() - .foregroundColor(.white) NavigationLink(destination: MenuView(), isActive: self.$pushActive) { diff --git a/SinuS/SinuS/Views/Authentication/RegisterView.swift b/SinuS/SinuS/Views/Authentication/RegisterView.swift index 5d716b6..c9e062c 100644 --- a/SinuS/SinuS/Views/Authentication/RegisterView.swift +++ b/SinuS/SinuS/Views/Authentication/RegisterView.swift @@ -94,6 +94,26 @@ struct RegisterView: View { .shadow(radius: 5) .padding() .foregroundColor(.white) + .navigationBarTitleDisplayMode(.inline) + .toolbarBackground(Style.AppColor, for: .navigationBar) + .toolbarBackground(.visible, for: .navigationBar) + .toolbar { + ToolbarItem(placement: .principal) { + VStack { + HStack { + Image(systemName: "water.waves") + .resizable() + .frame(width: 25, height: 25) + .foregroundColor(.white) + .padding(.bottom) + Text("Love Waves") + .foregroundColor(.white) + .font(.system(size: 25)) + .padding(.bottom) + } + } + } + } if self.showButton { NavigationLink(destination: MenuView(), label: { diff --git a/SinuS/SinuS/Views/NavigateToView.swift b/SinuS/SinuS/Views/NavigateToView.swift new file mode 100644 index 0000000..85129bb --- /dev/null +++ b/SinuS/SinuS/Views/NavigateToView.swift @@ -0,0 +1,8 @@ +// +// NavigateToView.swift +// SinuS +// +// Created by Patrick van Broeckhuijsen on 11/01/2023. +// + +import Foundation diff --git a/SinuS/SinuS/Views/Personal/ManageProfileView.swift b/SinuS/SinuS/Views/Personal/ManageProfileView.swift index 2cfb88c..d101c5a 100644 --- a/SinuS/SinuS/Views/Personal/ManageProfileView.swift +++ b/SinuS/SinuS/Views/Personal/ManageProfileView.swift @@ -6,6 +6,7 @@ // import SwiftUI +import SwiftKeychainWrapper struct ManageProfileView: View { let manager: DataManager @@ -21,8 +22,10 @@ struct ManageProfileView: View { HStack { Spacer() - NavigationLink(destination: AuthenticationStartView(), label: { + NavigationLink(destination: LoginView(), label: { MenuButton(image: Image(systemName: "figure.walk.departure"), name: "Logout") + }).simultaneousGesture(TapGesture().onEnded { + KeychainWrapper.standard.remove(forKey: "bearerToken") }) NavigationLink(destination: EditProfileView(gatherer: self.manager), label: { From 3c6a3735d6d0650281586df9c1485ae38a7e5173 Mon Sep 17 00:00:00 2001 From: Patrick van Broeckhuijsen Date: Wed, 11 Jan 2023 22:08:07 +0100 Subject: [PATCH 2/8] tagging release w.t.f. --- SinuS/SinuS.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SinuS/SinuS.xcodeproj/project.pbxproj b/SinuS/SinuS.xcodeproj/project.pbxproj index 1e4211a..15ccd79 100644 --- a/SinuS/SinuS.xcodeproj/project.pbxproj +++ b/SinuS/SinuS.xcodeproj/project.pbxproj @@ -18,7 +18,6 @@ 4A0B397B28E0846900D7EEC9 /* RelationStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A0B397A28E0846900D7EEC9 /* RelationStatusView.swift */; }; 4A15E00128C7C91C00422C05 /* ProfileButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A15E00028C7C91C00422C05 /* ProfileButton.swift */; }; 4A15E00328C7CD5300422C05 /* ProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A15E00228C7CD5300422C05 /* ProfileView.swift */; }; - 4A4C6D002917C2E4001DB4F7 /* AuthenticationStartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A4C6CFF2917C2E4001DB4F7 /* AuthenticationStartView.swift */; }; 4A4C6D032917C2F9001DB4F7 /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A4C6D022917C2F9001DB4F7 /* LoginView.swift */; }; 4A4C6D062917C30D001DB4F7 /* RegisterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A4C6D052917C30D001DB4F7 /* RegisterView.swift */; }; 4A4C6D082917CD95001DB4F7 /* AuthenticationResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A4C6D072917CD95001DB4F7 /* AuthenticationResult.swift */; }; @@ -51,6 +50,7 @@ CE6A64E629696C1C00DC47E5 /* SwiftKeychainWrapper in Frameworks */ = {isa = PBXBuildFile; productRef = CE6A64E529696C1C00DC47E5 /* SwiftKeychainWrapper */; }; CE89A8762969F93200300C9D /* ManageProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE89A8752969F93200300C9D /* ManageProfileView.swift */; }; CE89A87A296AF2D300300C9D /* LogHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE89A879296AF2D300300C9D /* LogHelper.swift */; }; + CEECA4FB296F4BFD00CA4496 /* NavigateToView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEECA4FA296F4BFD00CA4496 /* NavigateToView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -82,7 +82,6 @@ 4A0B397A28E0846900D7EEC9 /* RelationStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelationStatusView.swift; sourceTree = ""; }; 4A15E00028C7C91C00422C05 /* ProfileButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileButton.swift; sourceTree = ""; }; 4A15E00228C7CD5300422C05 /* ProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileView.swift; sourceTree = ""; }; - 4A4C6CFF2917C2E4001DB4F7 /* AuthenticationStartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationStartView.swift; sourceTree = ""; }; 4A4C6D022917C2F9001DB4F7 /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = ""; }; 4A4C6D052917C30D001DB4F7 /* RegisterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterView.swift; sourceTree = ""; }; 4A4C6D072917CD95001DB4F7 /* AuthenticationResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationResult.swift; sourceTree = ""; }; @@ -120,6 +119,7 @@ 4AD26FF428C7BFC10065FB01 /* DataGatherer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataGatherer.swift; sourceTree = ""; }; CE89A8752969F93200300C9D /* ManageProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManageProfileView.swift; sourceTree = ""; }; CE89A879296AF2D300300C9D /* LogHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogHelper.swift; sourceTree = ""; }; + CEECA4FA296F4BFD00CA4496 /* NavigateToView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigateToView.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -160,7 +160,6 @@ 4A4C6CFE2917C2A8001DB4F7 /* Authentication */ = { isa = PBXGroup; children = ( - 4A4C6CFF2917C2E4001DB4F7 /* AuthenticationStartView.swift */, 4A4C6D022917C2F9001DB4F7 /* LoginView.swift */, 4A4C6D052917C30D001DB4F7 /* RegisterView.swift */, ); @@ -314,6 +313,7 @@ 4A0B397128D3ABF100D7EEC9 /* SmallFrame.swift */, 4A0B397328D6044200D7EEC9 /* LineChart2.swift */, 4A0B397A28E0846900D7EEC9 /* RelationStatusView.swift */, + CEECA4FA296F4BFD00CA4496 /* NavigateToView.swift */, ); path = Views; sourceTree = ""; @@ -496,7 +496,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 4A4C6D002917C2E4001DB4F7 /* AuthenticationStartView.swift in Sources */, 4AC5B3E5296ADE0D003D819C /* TotalUserData.swift in Sources */, 4AD26FEB28BBAEA40065FB01 /* SinusData.swift in Sources */, 4AC5B3E1296AD6A4003D819C /* EditProfileView.swift in Sources */, @@ -524,6 +523,7 @@ 4A0B396C28D38F0700D7EEC9 /* MenuButton.swift in Sources */, 4A4C6D0D295D9E1B001DB4F7 /* FeedWaveGraphView.swift in Sources */, 4AC5B3DF296AD546003D819C /* Style.swift in Sources */, + CEECA4FB296F4BFD00CA4496 /* NavigateToView.swift in Sources */, 4A0B397228D3ABF200D7EEC9 /* SmallFrame.swift in Sources */, 4A0B397928E081CF00D7EEC9 /* RelationshipStatus.swift in Sources */, 4A4C6D082917CD95001DB4F7 /* AuthenticationResult.swift in Sources */, From a17230a9f64cdb4b7a2ea7f83d158ab95633d632 Mon Sep 17 00:00:00 2001 From: Patrick van Broeckhuijsen Date: Thu, 19 Jan 2023 21:19:06 +0100 Subject: [PATCH 3/8] Add proper authentication views --- .../ClickResetPasswordLinkView.swift | 48 +++++++ .../Authentication/ForgotPasswordView.swift | 79 ++++++++++++ .../Views/Authentication/LoginView.swift | 30 ++--- .../Views/Authentication/RegisterView.swift | 25 ++-- .../Authentication/ResetPasswordView.swift | 118 ++++++++++++++++++ .../Authentication/VerifyEmailView.swift | 48 +++++++ 6 files changed, 318 insertions(+), 30 deletions(-) create mode 100644 SinuS/SinuS/Views/Authentication/ClickResetPasswordLinkView.swift create mode 100644 SinuS/SinuS/Views/Authentication/ForgotPasswordView.swift create mode 100644 SinuS/SinuS/Views/Authentication/ResetPasswordView.swift create mode 100644 SinuS/SinuS/Views/Authentication/VerifyEmailView.swift diff --git a/SinuS/SinuS/Views/Authentication/ClickResetPasswordLinkView.swift b/SinuS/SinuS/Views/Authentication/ClickResetPasswordLinkView.swift new file mode 100644 index 0000000..c46163a --- /dev/null +++ b/SinuS/SinuS/Views/Authentication/ClickResetPasswordLinkView.swift @@ -0,0 +1,48 @@ +// +// ClickResetPasswordLinkView.swift +// SinuS +// +// Created by Patrick van Broeckhuijsen on 15/01/2023. +// + +import SwiftUI + +struct ClickResetPasswordLinkView: View { + var body: some View { + VStack { + Spacer() + + Text("Please click on the link sent to your email") + + Text("Go back") + + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + .toolbarBackground(Style.AppColor, for: .navigationBar) + .toolbarBackground(.visible, for: .navigationBar) + .toolbar { + ToolbarItem(placement: .principal) { + VStack { + HStack { + Image(systemName: "water.waves") + .resizable() + .frame(width: 25, height: 25) + .foregroundColor(.white) + .padding(.bottom) + Text("Love Waves") + .foregroundColor(.white) + .font(.system(size: 25)) + .padding(.bottom) + } + } + } + } + } +} + +struct ClickResetPasswordLinkView_Previews: PreviewProvider { + static var previews: some View { + ClickResetPasswordLinkView() + } +} diff --git a/SinuS/SinuS/Views/Authentication/ForgotPasswordView.swift b/SinuS/SinuS/Views/Authentication/ForgotPasswordView.swift new file mode 100644 index 0000000..1ca282e --- /dev/null +++ b/SinuS/SinuS/Views/Authentication/ForgotPasswordView.swift @@ -0,0 +1,79 @@ +// +// ForgotPasswordView.swift +// SinuS +// +// Created by Patrick van Broeckhuijsen on 12/01/2023. +// + +import SwiftUI + +struct ForgotPasswordView: View { + let manager = DataManager() + + @State private var email: String = UserDefaults.standard.string(forKey: "email") ?? "" + @State private var showAlert = false + @State private var nextView: Bool? = false + + var body: some View { + VStack { + // Email + HStack { + Text("Email") + Spacer() + TextField("", text: self.$email) + .disableAutocorrection(true) + .border(Color.white, width: 0.5) + .frame(width: 220) + }.padding(.horizontal).padding(.top) + + NavigationLink(destination: ClickResetPasswordLinkView(), tag: true, selection: self.$nextView) { EmptyView() } + + Button("Submit") { + let authenticationResult = self.manager.forgotPassword(email: self.email) + + if authenticationResult == nil { + self.showAlert.toggle() + } else { + UserDefaults.standard.set(self.email, forKey: "forgotPasswordEmail") + self.nextView = true + } + + } + .alert(isPresented: $showAlert) { + return Alert(title: Text("Error"), message: Text("Failed to request forgot password link for \(self.email)"), dismissButton: .default(Text("OK"))) + } + .padding() + } + .background(Style.AppColor) + .cornerRadius(5) + .shadow(radius: 5) + .padding() + .foregroundColor(.white) + .navigationBarTitleDisplayMode(.inline) + .toolbarBackground(Style.AppColor, for: .navigationBar) + .toolbarBackground(.visible, for: .navigationBar) + .toolbar { + ToolbarItem(placement: .principal) { + VStack { + HStack { + Image(systemName: "water.waves") + .resizable() + .frame(width: 25, height: 25) + .foregroundColor(.white) + .padding(.bottom) + Text("Love Waves") + .foregroundColor(.white) + .font(.system(size: 25)) + .padding(.bottom) + } + } + } + } + } +} + +struct ForgotPasswordView_Previews: PreviewProvider { + static var previews: some View { + ForgotPasswordView() + } +} diff --git a/SinuS/SinuS/Views/Authentication/LoginView.swift b/SinuS/SinuS/Views/Authentication/LoginView.swift index 6e053eb..7c37a26 100644 --- a/SinuS/SinuS/Views/Authentication/LoginView.swift +++ b/SinuS/SinuS/Views/Authentication/LoginView.swift @@ -11,8 +11,7 @@ import SwiftKeychainWrapper struct LoginView: View { let manager = DataManager() - // Tokens never expire so we can keep reusing the saved token - @State private var pushActive = false + @State private var showMenu: Bool? = false @State private var email: String = UserDefaults.standard.string(forKey: "email") ?? "" @State private var password: String = "" @State private var showAlert = false @@ -24,24 +23,26 @@ struct LoginView: View { VStack { // Email HStack { - Text("Email:") + Text("Email") Spacer() TextField("", text: self.$email) .disableAutocorrection(true) - .border(Color.white, width: 0.5) + .border(Color.white, width: 1) .frame(width: 220) }.padding(.horizontal).padding(.top) // Password HStack { - Text("Password:") + Text("Password") Spacer() SecureField("", text: self.$password) .disableAutocorrection(true) - .border(Color.white, width: 0.5) + .border(Color.white, width: 1) .frame(width: 220) }.padding(.horizontal).padding(.top) + NavigationLink(destination: MenuView(), tag: true, selection: self.$showMenu) { EmptyView() } + // Login Button Button("Login") { let res = self.manager.login(email: self.email, password: self.password) @@ -52,17 +53,21 @@ struct LoginView: View { } else { // Set global authentication token. ContentView.AuthenticationToken = res!.success - let saveSuccessful: Bool = KeychainWrapper.standard.set(ContentView.AuthenticationToken, forKey: "bearerToken") + let saveSuccessful: Bool = KeychainWrapper.standard.set( + ContentView.AuthenticationToken, + forKey: "bearerToken") if !saveSuccessful { print("Could not save bearerToken") } - self.pushActive = true + self.showMenu = true } } .alert(isPresented: $showAlert) { - return Alert(title: Text("Failed to Login"), message: Text("Unable to log user: \(self.email) in"), dismissButton: .default(Text("OK"))) + return Alert(title: Text("Failed to login"), + message: Text(self.email), + dismissButton: .default(Text("OK"))) } .padding() @@ -73,7 +78,7 @@ struct LoginView: View { .padding() .foregroundColor(.white) - NavigationLink(destination: RegisterView(), label: { + NavigationLink(destination: ForgotPasswordView(), label: { Text("Forgot password?") }) .foregroundColor(.black) @@ -110,11 +115,6 @@ struct LoginView: View { } } } - - NavigationLink(destination: MenuView(), - isActive: self.$pushActive) { - EmptyView() - }.hidden() } } diff --git a/SinuS/SinuS/Views/Authentication/RegisterView.swift b/SinuS/SinuS/Views/Authentication/RegisterView.swift index c9e062c..6a32667 100644 --- a/SinuS/SinuS/Views/Authentication/RegisterView.swift +++ b/SinuS/SinuS/Views/Authentication/RegisterView.swift @@ -16,16 +16,14 @@ struct RegisterView: View { @State private var password: String = "" @State private var confirmPassword: String = "" @State private var showAlert = false - - static var isPasswordCorrect: Bool = false - @State private var showButton = false + @State private var showMenu: Bool? = false var body: some View { VStack { // Name HStack { - Text("Name:") + Text("Name") Spacer() TextField("", text: self.$name) .disableAutocorrection(true) @@ -35,7 +33,7 @@ struct RegisterView: View { // Email HStack { - Text("Email:") + Text("Email") Spacer() TextField("", text: self.$email) .disableAutocorrection(true) @@ -45,7 +43,7 @@ struct RegisterView: View { // Password HStack { - Text("Password:") + Text("Password") Spacer() TextField("", text: self.$password) .disableAutocorrection(true) @@ -55,7 +53,7 @@ struct RegisterView: View { // Confirm password HStack { - Text("Confirm password:") + Text("Confirm password") Spacer() TextField("", text: self.$confirmPassword) .disableAutocorrection(true) @@ -63,6 +61,8 @@ struct RegisterView: View { .frame(width: 220) }.padding(.horizontal).padding(.top) + NavigationLink(destination: VerifyEmailView(), tag: true, selection: self.$showMenu) { EmptyView() } + // Register button Button("Register") { let authenticationResult = self.manager.register( @@ -76,11 +76,12 @@ struct RegisterView: View { } else { // Set global authentication token. ContentView.AuthenticationToken = authenticationResult!.success - let saveSuccessful: Bool = KeychainWrapper.standard.set(ContentView.AuthenticationToken, forKey: "bearerToken", isSynchronizable: true) + let saveSuccessful: Bool = KeychainWrapper.standard.set(ContentView.AuthenticationToken, forKey: "bearerToken") if !saveSuccessful { print("Could not save bearerToken") } - self.showButton.toggle() + + self.showMenu = true } } @@ -114,12 +115,6 @@ struct RegisterView: View { } } } - - if self.showButton { - NavigationLink(destination: MenuView(), label: { - MenuButton(image: Image(systemName: "lock.open"), name: "Enter") - }) - } } } diff --git a/SinuS/SinuS/Views/Authentication/ResetPasswordView.swift b/SinuS/SinuS/Views/Authentication/ResetPasswordView.swift new file mode 100644 index 0000000..d3ee468 --- /dev/null +++ b/SinuS/SinuS/Views/Authentication/ResetPasswordView.swift @@ -0,0 +1,118 @@ +// +// ResetPasswordView.swift +// SinuS +// +// Created by Patrick van Broeckhuijsen on 15/01/2023. +// + +import SwiftUI +import SwiftKeychainWrapper + +struct ResetPasswordView: View { + let manager = DataManager() + + @State private var token: String = "" + @State private var email: String = UserDefaults.standard.string(forKey: "forgotPasswordEmail") ?? "" + @State private var password: String = "" + @State private var confirmPassword: String = "" + @State private var showAlert = false + @State private var showLogin: Bool? = false + + var body: some View { + VStack { + if self.email != "" { + // Show email address of which reset password email was sent to + HStack { + Text("Email") + Spacer() + TextField("", text: self.$email) + .disabled(true) + .disableAutocorrection(true) + .border(Color.white, width: 0.5) + .frame(width: 220) + }.padding(.horizontal).padding(.top) + } + + // Password + HStack { + Text("New password") + Spacer() + TextField("", text: self.$password) + .disableAutocorrection(true) + .border(Color.white, width: 0.5) + .frame(width: 220) + }.padding(.horizontal).padding(.top) + + // Confirm password + HStack { + Text("Confirm password") + Spacer() + TextField("", text: self.$confirmPassword) + .disableAutocorrection(true) + .border(Color.white, width: 0.5) + .frame(width: 220) + }.padding(.horizontal).padding(.top) + + NavigationLink(destination: LoginView(), tag: true, selection: self.$showLogin) { EmptyView() } + + Button("Submit") { + let authenticationResult = self.manager.resetPassword( + token: self.token, + email: self.email, + password: self.password, + confirmPassword: self.confirmPassword) + + if authenticationResult == nil { + self.showAlert.toggle() + } else { + UserDefaults.standard.removeObject(forKey: "forgotPasswordEmail") + + // Set global authentication token. + ContentView.AuthenticationToken = authenticationResult!.success + let saveSuccessful: Bool = KeychainWrapper.standard.set(ContentView.AuthenticationToken, forKey: "bearerToken") + if !saveSuccessful { + print("Could not save bearerToken") + } + + self.showLogin = true + } + + } + .alert(isPresented: $showAlert) { + return Alert(title: Text("Failed to reset password"), message: Text("Unable to reset password: \(self.email)"), dismissButton: .default(Text("OK"))) + } + .padding() + } + .background(Style.AppColor) + .cornerRadius(5) + .shadow(radius: 5) + .padding() + .foregroundColor(.white) + .navigationBarTitleDisplayMode(.inline) + .toolbarBackground(Style.AppColor, for: .navigationBar) + .toolbarBackground(.visible, for: .navigationBar) + .toolbar { + ToolbarItem(placement: .principal) { + VStack { + HStack { + Image(systemName: "water.waves") + .resizable() + .frame(width: 25, height: 25) + .foregroundColor(.white) + .padding(.bottom) + Text("Love Waves") + .foregroundColor(.white) + .font(.system(size: 25)) + .padding(.bottom) + } + } + } + } + } +} + +struct ResetPasswordView_Previews: PreviewProvider { + static var previews: some View { + ResetPasswordView() + } +} diff --git a/SinuS/SinuS/Views/Authentication/VerifyEmailView.swift b/SinuS/SinuS/Views/Authentication/VerifyEmailView.swift new file mode 100644 index 0000000..5373335 --- /dev/null +++ b/SinuS/SinuS/Views/Authentication/VerifyEmailView.swift @@ -0,0 +1,48 @@ +// +// VerifyEmailView.swift +// SinuS +// +// Created by Patrick van Broeckhuijsen on 15/01/2023. +// + +import SwiftUI + +struct VerifyEmailView: View { + var body: some View { + VStack { + Spacer() + + Text("Please verify your email address by clicking on the link in your email") + + Text("Resend email") + + Spacer() + } + .navigationBarTitleDisplayMode(.inline) + .toolbarBackground(Style.AppColor, for: .navigationBar) + .toolbarBackground(.visible, for: .navigationBar) + .toolbar { + ToolbarItem(placement: .principal) { + VStack { + HStack { + Image(systemName: "water.waves") + .resizable() + .frame(width: 25, height: 25) + .foregroundColor(.white) + .padding(.bottom) + Text("Love Waves") + .foregroundColor(.white) + .font(.system(size: 25)) + .padding(.bottom) + } + } + } + } + } +} + +struct VerifyEmailView_Previews: PreviewProvider { + static var previews: some View { + VerifyEmailView() + } +} From 5b6f81db295d8399e3393958f2bded6b19793e0c Mon Sep 17 00:00:00 2001 From: Patrick van Broeckhuijsen Date: Thu, 19 Jan 2023 21:19:46 +0100 Subject: [PATCH 4/8] Add Forgot Password functionality to DataGatherer --- SinuS/SinuS/Data/DataGatherer.swift | 61 +++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/SinuS/SinuS/Data/DataGatherer.swift b/SinuS/SinuS/Data/DataGatherer.swift index fcb8073..541ca01 100644 --- a/SinuS/SinuS/Data/DataGatherer.swift +++ b/SinuS/SinuS/Data/DataGatherer.swift @@ -98,6 +98,67 @@ public class DataManager { return result } + public func forgotPassword(email: String) -> AuthenticationResult? { + let loginUrl = "https://lukassinus2.vanbroeckhuijsenvof.nl/api/forgot-password" + let parameters: [String: Any] = ["email": email] + let decoder = JSONDecoder() + var request = RestApiHelper.createRequest(type: "POST", url: loginUrl, auth: false) + + do { + request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted) + } catch let error { + print(error.localizedDescription) + return nil + } + + var result: AuthenticationResult? + let data = RestApiHelper.perfomRestCall(request: request) + + do { + result = try decoder.decode(AuthenticationResult.self, from: data!) + } catch { + let returnedData = (String(bytes: data!, encoding: .utf8) ?? "") + let errMsg = "Unable to process forgot password request: \(returnedData)" + self.logHelper.logMsg(level: "error", message: errMsg) + print(errMsg) + } + + return result + } + + public func resetPassword(token: String, email: String, password: String, confirmPassword: String) -> AuthenticationResult? { + let loginUrl = "https://lukassinus2.vanbroeckhuijsenvof.nl/api/reset-password" + let parameters: [String: Any] = [ + "token": token, + "email": email, + "password": password, + "password_confirmation": confirmPassword + ] + let decoder = JSONDecoder() + var request = RestApiHelper.createRequest(type: "POST", url: loginUrl, auth: false) + + do { + request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted) + } catch let error { + print(error.localizedDescription) + return nil + } + + var result: AuthenticationResult? + let data = RestApiHelper.perfomRestCall(request: request) + + do { + result = try decoder.decode(AuthenticationResult.self, from: data!) + } catch { + let returnedData = (String(bytes: data!, encoding: .utf8) ?? "") + let errMsg = "Unable to reset password: \(returnedData)" + self.logHelper.logMsg(level: "error", message: errMsg) + print(errMsg) + } + + return result + } + public func getCurrentUser() -> TotalUserData? { let url = "https://lukassinus2.vanbroeckhuijsenvof.nl/api/user" let decoder = JSONDecoder() From e40143450be9ac07f3ac5ed9864a3332d8d67f7e Mon Sep 17 00:00:00 2001 From: Patrick van Broeckhuijsen Date: Thu, 19 Jan 2023 21:20:09 +0100 Subject: [PATCH 5/8] Add proper title bar to MenuView --- SinuS/SinuS/Views/MenuView.swift | 36 +++++++++++++++++++------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/SinuS/SinuS/Views/MenuView.swift b/SinuS/SinuS/Views/MenuView.swift index f6fb27f..0ef1a5e 100644 --- a/SinuS/SinuS/Views/MenuView.swift +++ b/SinuS/SinuS/Views/MenuView.swift @@ -28,21 +28,6 @@ struct MenuView: View { var body: some View { let manager = DataManager() VStack { - HStack { - Spacer() - Image(systemName: "water.waves") - .resizable() - .frame(width: 25, height: 25) - .foregroundColor(.white) - .padding(.bottom) - Text("Love Waves") - .foregroundColor(.white) - .font(.system(size: 25)) - .padding(.bottom) - Spacer() - } - .background(Style.AppColor) - TabView(selection: self.$selection) { Group { FeedView(feedViewModel: self.feedViewModelExplore, gatherer: manager, onlyFollowing: false) @@ -67,6 +52,27 @@ struct MenuView: View { .toolbarColorScheme(.dark, for: .tabBar) } } + .navigationBarBackButtonHidden(true) + .navigationBarTitleDisplayMode(.inline) + .toolbarBackground(Style.AppColor, for: .navigationBar) + .toolbarBackground(.visible, for: .navigationBar) + .toolbar { + ToolbarItem(placement: .principal) { + VStack { + HStack { + Image(systemName: "water.waves") + .resizable() + .frame(width: 25, height: 25) + .foregroundColor(.white) + .padding(.bottom) + Text("Love Waves") + .foregroundColor(.white) + .font(.system(size: 25)) + .padding(.bottom) + } + } + } + } } } From 17931f806f389a85faa0c1f7ca891ccf4d851ba9 Mon Sep 17 00:00:00 2001 From: Patrick van Broeckhuijsen Date: Thu, 19 Jan 2023 21:20:32 +0100 Subject: [PATCH 6/8] Testing universal links --- SinuS/SinuS/ContentView.swift | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/SinuS/SinuS/ContentView.swift b/SinuS/SinuS/ContentView.swift index bd5e2c9..4f9d6d4 100644 --- a/SinuS/SinuS/ContentView.swift +++ b/SinuS/SinuS/ContentView.swift @@ -27,3 +27,24 @@ struct ContentView_Previews: PreviewProvider { ContentView() } } + +func application(_ application: UIApplication, + continue userActivity: NSUserActivity, + restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { + // Get URL components from the incoming user activity. + guard userActivity.activityType == NSUserActivityTypeBrowsingWeb, + let incomingURL = userActivity.webpageURL, + let components = NSURLComponents(url: incomingURL, resolvingAgainstBaseURL: true) else { + return false + } + + // Check for specific URL components that you need. + guard let path = components.path, + let params = components.queryItems else { + return false + } + print("path = \(path)") + + // Dispatch event to trigger another view + return true +} From 7342ceb08a416a83100a659d9ae79791b6f4e334 Mon Sep 17 00:00:00 2001 From: Patrick van Broeckhuijsen Date: Sat, 4 Feb 2023 14:24:23 +0100 Subject: [PATCH 7/8] Add updated project file --- SinuS/SinuS.xcodeproj/project.pbxproj | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/SinuS/SinuS.xcodeproj/project.pbxproj b/SinuS/SinuS.xcodeproj/project.pbxproj index 15ccd79..a2c3224 100644 --- a/SinuS/SinuS.xcodeproj/project.pbxproj +++ b/SinuS/SinuS.xcodeproj/project.pbxproj @@ -51,6 +51,10 @@ CE89A8762969F93200300C9D /* ManageProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE89A8752969F93200300C9D /* ManageProfileView.swift */; }; CE89A87A296AF2D300300C9D /* LogHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE89A879296AF2D300300C9D /* LogHelper.swift */; }; CEECA4FB296F4BFD00CA4496 /* NavigateToView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEECA4FA296F4BFD00CA4496 /* NavigateToView.swift */; }; + CEECA4FD29709E0F00CA4496 /* ForgotPasswordView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEECA4FC29709E0F00CA4496 /* ForgotPasswordView.swift */; }; + CEECA4FF2974534700CA4496 /* ResetPasswordView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEECA4FE2974534700CA4496 /* ResetPasswordView.swift */; }; + CEECA5012974665800CA4496 /* VerifyEmailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEECA5002974665800CA4496 /* VerifyEmailView.swift */; }; + CEECA50329748DA600CA4496 /* ClickResetPasswordLinkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEECA50229748DA600CA4496 /* ClickResetPasswordLinkView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -120,6 +124,11 @@ CE89A8752969F93200300C9D /* ManageProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManageProfileView.swift; sourceTree = ""; }; CE89A879296AF2D300300C9D /* LogHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogHelper.swift; sourceTree = ""; }; CEECA4FA296F4BFD00CA4496 /* NavigateToView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigateToView.swift; sourceTree = ""; }; + CEECA4FC29709E0F00CA4496 /* ForgotPasswordView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForgotPasswordView.swift; sourceTree = ""; }; + CEECA4FE2974534700CA4496 /* ResetPasswordView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordView.swift; sourceTree = ""; }; + CEECA5002974665800CA4496 /* VerifyEmailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerifyEmailView.swift; sourceTree = ""; }; + CEECA50229748DA600CA4496 /* ClickResetPasswordLinkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClickResetPasswordLinkView.swift; sourceTree = ""; }; + CEECA5042974928C00CA4496 /* SinuSRelease.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SinuSRelease.entitlements; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -162,6 +171,10 @@ children = ( 4A4C6D022917C2F9001DB4F7 /* LoginView.swift */, 4A4C6D052917C30D001DB4F7 /* RegisterView.swift */, + CEECA4FC29709E0F00CA4496 /* ForgotPasswordView.swift */, + CEECA4FE2974534700CA4496 /* ResetPasswordView.swift */, + CEECA5002974665800CA4496 /* VerifyEmailView.swift */, + CEECA50229748DA600CA4496 /* ClickResetPasswordLinkView.swift */, ); path = Authentication; sourceTree = ""; @@ -261,6 +274,7 @@ 4AD26FB828BBA5D40065FB01 /* SinuS */ = { isa = PBXGroup; children = ( + CEECA5042974928C00CA4496 /* SinuSRelease.entitlements */, 4AC5B3DD296AD537003D819C /* Style */, 4AD26FE928BBAE930065FB01 /* Data */, 4AD26FE428BBA8C40065FB01 /* Views */, @@ -496,6 +510,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + CEECA5012974665800CA4496 /* VerifyEmailView.swift in Sources */, + CEECA4FF2974534700CA4496 /* ResetPasswordView.swift in Sources */, 4AC5B3E5296ADE0D003D819C /* TotalUserData.swift in Sources */, 4AD26FEB28BBAEA40065FB01 /* SinusData.swift in Sources */, 4AC5B3E1296AD6A4003D819C /* EditProfileView.swift in Sources */, @@ -514,6 +530,7 @@ 4A0B397728E06E9600D7EEC9 /* SinusUserData.swift in Sources */, 4AD26FBC28BBA5D40065FB01 /* ContentView.swift in Sources */, 4A0B397428D6044300D7EEC9 /* LineChart2.swift in Sources */, + CEECA4FD29709E0F00CA4496 /* ForgotPasswordView.swift in Sources */, 4AC5B3D529698525003D819C /* PersonalView.swift in Sources */, 4A0B396A28D38DE000D7EEC9 /* MenuView.swift in Sources */, 4A4C6D062917C30D001DB4F7 /* RegisterView.swift in Sources */, @@ -532,6 +549,7 @@ 4AC5B3E3296ADB51003D819C /* UserData.swift in Sources */, 4AD26FBA28BBA5D40065FB01 /* SinuSApp.swift in Sources */, 4AC5B3D3296849DD003D819C /* RestApiHelper.swift in Sources */, + CEECA50329748DA600CA4496 /* ClickResetPasswordLinkView.swift in Sources */, 4AD26FF128C6773E0065FB01 /* FeedWaveView.swift in Sources */, 4AD26FED28C676C10065FB01 /* LineChart.swift in Sources */, 4A0B396E28D3935900D7EEC9 /* NewWaveView.swift in Sources */, @@ -691,9 +709,10 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"SinuS/Preview Content\""; - DEVELOPMENT_TEAM = 479GB76B7L; + DEVELOPMENT_TEAM = 27MSAG6A3N; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = SinuS/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 16.0; @@ -703,6 +722,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = LoeHen.SinuS; PRODUCT_NAME = "Love waves"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -713,9 +733,11 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = SinuS/SinuSRelease.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"SinuS/Preview Content\""; - DEVELOPMENT_TEAM = 479GB76B7L; + DEVELOPMENT_TEAM = 27MSAG6A3N; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = SinuS/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 16.0; @@ -725,6 +747,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = LoeHen.SinuS; PRODUCT_NAME = "Love waves"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; From 3c150f8259429e5729322055cb0777a69d37fd55 Mon Sep 17 00:00:00 2001 From: Loe Hendriks Date: Sat, 4 Feb 2023 15:03:45 +0100 Subject: [PATCH 8/8] explore view before authentication --- .../AuthenticationStartView.swift | 49 ++++++++++++++----- .../Views/Authentication/LoginView.swift | 20 ++------ SinuS/SinuS/Views/MenuView.swift | 36 ++++++++------ .../Views/Personal/ManageProfileView.swift | 8 +-- 4 files changed, 68 insertions(+), 45 deletions(-) diff --git a/SinuS/SinuS/Views/Authentication/AuthenticationStartView.swift b/SinuS/SinuS/Views/Authentication/AuthenticationStartView.swift index e428f84..0b511b7 100644 --- a/SinuS/SinuS/Views/Authentication/AuthenticationStartView.swift +++ b/SinuS/SinuS/Views/Authentication/AuthenticationStartView.swift @@ -8,23 +8,46 @@ import SwiftUI struct AuthenticationStartView: View { - var body: some View { - NavigationView { - VStack { + @State private var selection = Tab.feed - Spacer() + private var feedViewModelExplore: FeedViewModel - // Login Button - NavigationLink(destination: LoginView(), label: { - MenuButton(image: Image(systemName: "person.badge.key.fill"), name: "Login") - }) + private enum Tab: Hashable { + case feed + case login + case register + } - // Register Button - NavigationLink(destination: RegisterView(), label: { - MenuButton(image: Image(systemName: "person.fill.badge.plus"), name: "Register") - }) + init() { + self.feedViewModelExplore = FeedViewModel() + } + + var body: some View { + let manager = DataManager() - Spacer() + VStack { + TabView(selection: self.$selection) { + Group { + FeedView(feedViewModel: self.feedViewModelExplore, gatherer: manager, onlyFollowing: false) + .tabItem { + Label("Explore", systemImage: "network") + } + .tag(Tab.feed) + RegisterView() + .tabItem { + Label("Register", systemImage: "person.fill.badge.plus") + } + .tag(Tab.register) + LoginView() + .tabItem { + Label("Login", systemImage: "person.badge.key.fill") + } + .tag(Tab.login) + } + .toolbar(.visible, for: .tabBar) + .toolbarBackground(Style.AppColor, for: .tabBar) + .toolbarBackground(.visible, for: .tabBar) + .toolbarColorScheme(.dark, for: .tabBar) } } } diff --git a/SinuS/SinuS/Views/Authentication/LoginView.swift b/SinuS/SinuS/Views/Authentication/LoginView.swift index 48a42c9..d84e1f7 100644 --- a/SinuS/SinuS/Views/Authentication/LoginView.swift +++ b/SinuS/SinuS/Views/Authentication/LoginView.swift @@ -55,16 +55,6 @@ struct LoginView: View { print("Could not save bearerToken") } - // firebase login -// Auth.auth().signIn(withEmail: email, password: password) { (result, error) in -// print(result) -// if error != nil { -// print(error?.localizedDescription ?? "") -// } else { -// print("success") -// } -// } - self.pushActive = true } @@ -74,17 +64,17 @@ struct LoginView: View { } .padding() + + NavigationLink(destination: MenuView(), + isActive: self.$pushActive) { + EmptyView() + }.hidden() } .background(Style.AppColor) .cornerRadius(5) .shadow(radius: 5) .padding() .foregroundColor(.white) - - NavigationLink(destination: MenuView(), - isActive: self.$pushActive) { - EmptyView() - }.hidden() } } diff --git a/SinuS/SinuS/Views/MenuView.swift b/SinuS/SinuS/Views/MenuView.swift index f6fb27f..f4c389a 100644 --- a/SinuS/SinuS/Views/MenuView.swift +++ b/SinuS/SinuS/Views/MenuView.swift @@ -28,20 +28,6 @@ struct MenuView: View { var body: some View { let manager = DataManager() VStack { - HStack { - Spacer() - Image(systemName: "water.waves") - .resizable() - .frame(width: 25, height: 25) - .foregroundColor(.white) - .padding(.bottom) - Text("Love Waves") - .foregroundColor(.white) - .font(.system(size: 25)) - .padding(.bottom) - Spacer() - } - .background(Style.AppColor) TabView(selection: self.$selection) { Group { @@ -65,6 +51,28 @@ struct MenuView: View { .toolbarBackground(Style.AppColor, for: .tabBar) .toolbarBackground(.visible, for: .tabBar) .toolbarColorScheme(.dark, for: .tabBar) + + } + } + .navigationBarBackButtonHidden(true) + .navigationBarTitleDisplayMode(.inline) + .toolbarBackground(Style.AppColor, for: .navigationBar) + .toolbarBackground(.visible, for: .navigationBar) + .toolbar { + ToolbarItem(placement: .principal) { + VStack { + HStack { + Image(systemName: "water.waves") + .resizable() + .frame(width: 25, height: 25) + .foregroundColor(.white) + .padding(.bottom) + Text("Love Waves") + .foregroundColor(.white) + .font(.system(size: 25)) + .padding(.bottom) + } + } } } } diff --git a/SinuS/SinuS/Views/Personal/ManageProfileView.swift b/SinuS/SinuS/Views/Personal/ManageProfileView.swift index 2cfb88c..4f647fc 100644 --- a/SinuS/SinuS/Views/Personal/ManageProfileView.swift +++ b/SinuS/SinuS/Views/Personal/ManageProfileView.swift @@ -6,6 +6,7 @@ // import SwiftUI +import SwiftKeychainWrapper struct ManageProfileView: View { let manager: DataManager @@ -22,9 +23,10 @@ struct ManageProfileView: View { Spacer() NavigationLink(destination: AuthenticationStartView(), label: { - MenuButton(image: Image(systemName: "figure.walk.departure"), name: "Logout") - }) - + MenuButton(image: Image(systemName: "figure.walk.departure"), name: "Logout") + }).simultaneousGesture(TapGesture().onEnded { + KeychainWrapper.standard.remove(forKey: "bearerToken") + }) NavigationLink(destination: EditProfileView(gatherer: self.manager), label: { MenuButton(image: Image(systemName: "gearshape.fill"), name: "Edit") })