Skip to content

Commit

Permalink
SignIn screen, now in SwiftUI
Browse files Browse the repository at this point in the history
took the opportunity to modernize the screen a bit
background color of yellow, loading indicator
and twaek the version shown in dark mode
  • Loading branch information
krugerk committed Dec 6, 2024
1 parent 745cf98 commit 60cb3da
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 8 deletions.
4 changes: 4 additions & 0 deletions BeeSwift.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
9B2488422D030E5100E610E0 /* SignInView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B2488412D030E5100E610E0 /* SignInView.swift */; };
9B8CA57D24B120CA009C86C2 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9B8CA57C24B120CA009C86C2 /* LaunchScreen.storyboard */; };
A10D4E931B07948500A72D29 /* DatapointsTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A10D4E921B07948500A72D29 /* DatapointsTableView.swift */; };
A10DC2DF207BFCBA00FB7B3A /* RemoveHKMetricViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A10DC2DE207BFCBA00FB7B3A /* RemoveHKMetricViewController.swift */; };
Expand Down Expand Up @@ -217,6 +218,7 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
9B2488412D030E5100E610E0 /* SignInView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInView.swift; sourceTree = "<group>"; };
9B8CA57C24B120CA009C86C2 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
A10D4E921B07948500A72D29 /* DatapointsTableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatapointsTableView.swift; sourceTree = "<group>"; };
A10DC2DE207BFCBA00FB7B3A /* RemoveHKMetricViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveHKMetricViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -492,6 +494,7 @@
E43BEA832A036A9C00FC3A38 /* LogReader.swift */,
A196CB201AE4142F00B90A3E /* Main.storyboard */,
A1453B3E1AEDFCC8006F48DA /* SignInViewController.swift */,
9B2488412D030E5100E610E0 /* SignInView.swift */,
);
path = BeeSwift;
sourceTree = "<group>";
Expand Down Expand Up @@ -1024,6 +1027,7 @@
A10DC2DF207BFCBA00FB7B3A /* RemoveHKMetricViewController.swift in Sources */,
E412DAE12B86A8F70099E483 /* GoalImageView.swift in Sources */,
A1619EA41BEECC1500E14B3A /* EditDefaultNotificationsViewController.swift in Sources */,
9B2488422D030E5100E610E0 /* SignInView.swift in Sources */,
A149B3701AEF528C00F19A09 /* SettingsViewController.swift in Sources */,
E46DC80F2AA58DF20059FDFE /* PullToRefreshHint.swift in Sources */,
A1E618E21E78158700D8ED93 /* HealthKitConfigViewController.swift in Sources */,
Expand Down
45 changes: 37 additions & 8 deletions BeeSwift/Gallery/GalleryViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -207,11 +207,19 @@ class GalleryViewController: UIViewController, UICollectionViewDelegateFlowLayou
}
}

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)

if !ServiceLocator.currentUserManager.signedIn(context: ServiceLocator.persistentContainer.viewContext) {
presentSignInScreen()
}
}

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

if !ServiceLocator.currentUserManager.signedIn(context: ServiceLocator.persistentContainer.viewContext) {
let signInVC = SignInViewController()
signInVC.modalPresentationStyle = .fullScreen
self.present(signInVC, animated: true, completion: nil)
presentSignInScreen()
} else {
self.updateGoals()
self.fetchGoals()
Expand Down Expand Up @@ -269,15 +277,34 @@ class GalleryViewController: UIViewController, UICollectionViewDelegateFlowLayou
}

@objc func handleSignOut() {
logger.debug("\(#function)")

self.goals = []
self.filteredGoals = []
self.collectionView?.reloadData()
if self.presentedViewController != nil {
if type(of: self.presentedViewController!) == SignInViewController.self { return }

presentSignInScreen()
}


private var isSignInViewBeingPresented: Bool {
guard let presentedViewController else { return false }

return type(of: presentedViewController) == UIHostingController<SignInView>.self
}


private func presentSignInScreen() {
let shallPresentSignIn = presentedViewController == nil || !isSignInViewBeingPresented

guard shallPresentSignIn else {
logger.debug("\(#function) - already presenting sign in; not presenting it yet again")
return
}
let signInVC = SignInViewController()
signInVC.modalPresentationStyle = .fullScreen
self.present(signInVC, animated: true, completion: nil)

let hostingVC = UIHostingController(rootView: SignInView())
hostingVC.modalPresentationStyle = .fullScreen
self.present(hostingVC, animated: true)
}

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
Expand Down Expand Up @@ -501,3 +528,5 @@ class GalleryViewController: UIViewController, UICollectionViewDelegateFlowLayou
}
}


import SwiftUI
131 changes: 131 additions & 0 deletions BeeSwift/SignInView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// Part of BeeSwift. Copyright Beeminder

import SwiftUI
import BeeKit

struct SignInView: View {
@StateObject private var viewModel = SignInViewModel()
@State private var showingFailedSignInAlert = false
@State private var showingMissingDataAlert = false
@Environment(\.dismiss) private var dismiss

var body: some View {
ZStack {
Color.yellow
.opacity(0.8)
.ignoresSafeArea()

HStack(alignment: .center) {

VStack(alignment: .center, spacing: 15) {
Spacer()

Image("website_logo_mid")
.resizable()
.scaledToFit()
.frame(maxWidth: 200)
.padding(.bottom)

VStack(spacing: 15) {
TextField("Email or username", text: $viewModel.email)
.textFieldStyle(RoundedBorderTextFieldStyle())
.textInputAutocapitalization(.never)
.autocorrectionDisabled()
.keyboardType(.emailAddress)
.textContentType(.emailAddress)
.submitLabel(.next)

SecureField("Password", text: $viewModel.password)
.textFieldStyle(RoundedBorderTextFieldStyle())
.textInputAutocapitalization(.never)
.submitLabel(.done)

Button(action: signIn) {
Text("Sign In")
.font(.system(size: 20))
.foregroundColor(.white)
.frame(maxWidth: .infinity)
.frame(height: 44)
}
.background(Color("BeeminderGray"))
.cornerRadius(8)
.disabled(viewModel.isLoading)
}
.frame(maxWidth: .infinity)
.padding(.horizontal, 40)

Spacer()
Spacer()
Spacer()
}
.padding()

}
.alert("Could not sign in", isPresented: $showingFailedSignInAlert) {
Button("OK", role: .cancel) { }
} message: {
Text("Invalid credentials")
}
.alert("Incomplete Account Details", isPresented: $showingMissingDataAlert) {
Button("OK", role: .cancel) { }
} message: {
Text("Username and Password are required")
}
.onReceive(NotificationCenter.default.publisher(for: Notification.Name(CurrentUserManager.failedSignInNotificationName))) { _ in
viewModel.isLoading = false
showingFailedSignInAlert = true
}
.onReceive(NotificationCenter.default.publisher(for: Notification.Name(CurrentUserManager.signedInNotificationName))) { _ in
viewModel.isLoading = false
dismiss()
}
}
.overlay {
if viewModel.isLoading {
ProgressView()
.scaleEffect(1.5)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.black.opacity(0.2))
}
}
}

private func signIn() {
guard !viewModel.email.trimmingCharacters(in: .whitespaces).isEmpty,
!viewModel.password.isEmpty else {
showingMissingDataAlert = true
return
}

Task {
await viewModel.signIn()
}
}
}

@MainActor
class SignInViewModel: ObservableObject {
@Published var email = ""
@Published var password = ""
@Published var isLoading = false

func signIn() async {
isLoading = true

// Delay the task by 3 seconds:
do {
try await Task.sleep(nanoseconds: 3_000_000_000)
} catch {
print("canceled early")
}

await ServiceLocator.currentUserManager.signInWithEmail(
email.trimmingCharacters(in: .whitespaces),
password: password
)
}
}

#Preview {
SignInView()
}

0 comments on commit 60cb3da

Please sign in to comment.