Refactor account views and AccountModel

This commit is contained in:
Angelo Stavrow 2020-08-11 16:27:14 -04:00
parent 54d1d64e0e
commit 6dba087295
No known key found for this signature in database
GPG Key ID: 1A49C7064E060EEE
7 changed files with 63 additions and 65 deletions

View File

@ -1,70 +1,67 @@
import SwiftUI
struct AccountLoginView: View {
@State private var username: String = ""
@State private var password: String = ""
@State private var server: String = ""
@ObservedObject var account: AccountModel
@State private var isShowingAlert: Bool = false
@State private var alertMessage: String = ""
@Binding var accountModel: AccountModel
@Binding var isLoggedIn: Bool
@Binding var isLoggingIn: Bool
var body: some View {
VStack {
HStack {
Image(systemName: "person.circle")
.foregroundColor(.gray)
#if os(iOS)
TextField("Username", text: $username)
TextField("Username", text: $account.username)
.keyboardType(.emailAddress)
.autocapitalization(.none)
.disableAutocorrection(true)
.textFieldStyle(RoundedBorderTextFieldStyle())
#else
TextField("Username", text: $username)
TextField("Username", text: $account.username)
#endif
}
HStack {
Image(systemName: "lock.circle")
.foregroundColor(.gray)
#if os(iOS)
SecureField("Password", text: $password)
SecureField("Password", text: $account.password)
.autocapitalization(.none)
.disableAutocorrection(true)
.textFieldStyle(RoundedBorderTextFieldStyle())
#else
SecureField("Password", text: $password)
SecureField("Password", text: $account.password)
#endif
}
HStack {
Image(systemName: "link.circle")
.foregroundColor(.gray)
#if os(iOS)
TextField("Server URL", text: $server)
TextField("Server URL", text: $account.server)
.keyboardType(.URL)
.autocapitalization(.none)
.disableAutocorrection(true)
.textFieldStyle(RoundedBorderTextFieldStyle())
#else
TextField("Server URL", text: $server)
TextField("Server URL", text: $account.server)
#endif
}
Spacer()
if isLoggingIn {
if account.isLoggingIn {
ProgressView("Logging in...")
.padding()
} else {
Button(action: {
accountModel.login(
to: server,
as: username, password: password,
account.login(
to: account.server,
as: account.username, password: account.password,
completion: loginHandler
)
isLoggingIn = true
}, label: {
Text("Login")
}).disabled(isLoggedIn)
})
.disabled(account.isLoggedIn)
.padding()
}
}
.alert(isPresented: $isShowingAlert) {
@ -79,26 +76,18 @@ struct AccountLoginView: View {
func loginHandler(result: Result<UUID, AccountError>) {
do {
_ = try result.get()
isLoggedIn = true
isLoggingIn = false
} catch AccountError.serverNotFound {
alertMessage = """
The server could not be found. Please check that you've entered the information correctly and try again.
"""
isLoggedIn = false
isLoggingIn = false
isShowingAlert = true
} catch AccountError.invalidCredentials {
alertMessage = """
Invalid username or password. Please check that you've entered the information correctly and try again.
"""
isLoggedIn = false
isLoggingIn = false
isShowingAlert = true
} catch {
alertMessage = "An unknown error occurred. Please try again."
isLoggedIn = false
isLoggingIn = false
isShowingAlert = true
}
}
@ -106,20 +95,12 @@ The server could not be found. Please check that you've entered the information
struct AccountLoginView_LoggedOutPreviews: PreviewProvider {
static var previews: some View {
AccountLoginView(
accountModel: .constant(AccountModel()),
isLoggedIn: .constant(false),
isLoggingIn: .constant(false)
)
AccountLoginView(account: AccountModel())
}
}
struct AccountLoginView_LoggingInPreviews: PreviewProvider {
static var previews: some View {
AccountLoginView(
accountModel: .constant(AccountModel()),
isLoggedIn: .constant(false),
isLoggingIn: .constant(true)
)
AccountLoginView(account: AccountModel())
}
}

View File

@ -1,16 +1,14 @@
import SwiftUI
struct AccountLogoutView: View {
@Binding var accountModel: AccountModel
@Binding var isLoggedIn: Bool
@Binding var isLoggingIn: Bool
@ObservedObject var account: AccountModel
var body: some View {
VStack {
Spacer()
VStack {
Text("Logged in as \(accountModel.username ?? "UNKNOWN")")
Text("on \(accountModel.server ?? "UNKNOWN")")
Text("Logged in as \(account.username)")
Text("on \(account.server)")
}
Spacer()
Button(action: logoutHandler, label: {
@ -20,17 +18,12 @@ struct AccountLogoutView: View {
}
func logoutHandler() {
isLoggedIn = false
isLoggingIn = false
account.logout()
}
}
struct AccountLogoutView_Previews: PreviewProvider {
static var previews: some View {
AccountLogoutView(
accountModel: .constant(AccountModel()),
isLoggedIn: .constant(true),
isLoggingIn: .constant(false)
)
AccountLogoutView(account: AccountModel())
}
}

View File

@ -5,18 +5,21 @@ enum AccountError: Error {
case serverNotFound
}
struct AccountModel {
private(set) var id: UUID?
var username: String?
var password: String?
var server: String?
class AccountModel: ObservableObject {
@Published private(set) var id: UUID?
@Published private(set) var isLoggedIn: Bool = false
@Published private(set) var isLoggingIn: Bool = false
@Published var username: String = ""
@Published var password: String = ""
@Published var server: String = ""
mutating func login(
func login(
to server: String,
as username: String,
password: String,
completion: @escaping (Result<UUID, AccountError>) -> Void
) {
self.isLoggingIn = true
let result: Result<UUID, AccountError>
if server != validServer {
@ -34,10 +37,26 @@ struct AccountModel {
#if DEBUG
// Delay to simulate async network call
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.isLoggingIn = false
do {
_ = try result.get()
self.isLoggedIn = true
} catch {
self.isLoggedIn = false
}
completion(result)
}
#endif
}
func logout() {
id = nil
isLoggedIn = false
isLoggingIn = false
username = ""
password = ""
server = ""
}
}
#if DEBUG

View File

@ -1,25 +1,25 @@
import SwiftUI
struct AccountView: View {
@State private var accountModel = AccountModel()
@State private var isLoggingIn: Bool = false
@State private var isLoggedIn: Bool = false
@ObservedObject var account: AccountModel
var body: some View {
if isLoggedIn {
if account.isLoggedIn {
HStack {
Spacer()
AccountLogoutView(accountModel: $accountModel, isLoggedIn: $isLoggedIn, isLoggingIn: $isLoggingIn)
AccountLogoutView(account: account)
Spacer()
}
.padding()
} else {
AccountLoginView(accountModel: $accountModel, isLoggedIn: $isLoggedIn, isLoggingIn: $isLoggingIn)
AccountLoginView(account: account)
.padding()
}
}
}
struct AccountLogin_Previews: PreviewProvider {
static var previews: some View {
AccountView()
AccountView(account: AccountModel())
}
}

View File

@ -3,6 +3,7 @@ import SwiftUI
struct ContentView: View {
@ObservedObject var postStore: PostStore
@ObservedObject var preferences: PreferencesModel
@ObservedObject var account: AccountModel
var body: some View {
NavigationView {
@ -15,11 +16,12 @@ struct ContentView: View {
}
.environmentObject(postStore)
.environmentObject(preferences)
.environmentObject(account)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(postStore: testPostStore, preferences: PreferencesModel())
ContentView(postStore: testPostStore, preferences: PreferencesModel(), account: AccountModel())
}
}

View File

@ -3,6 +3,7 @@ import SwiftUI
@main
struct WriteFreely_MultiPlatformApp: App {
@StateObject private var preferences = PreferencesModel()
@StateObject private var account = AccountModel()
#if DEBUG
@StateObject private var store = testPostStore
@ -12,7 +13,7 @@ struct WriteFreely_MultiPlatformApp: App {
var body: some Scene {
WindowGroup {
ContentView(postStore: store, preferences: preferences)
ContentView(postStore: store, preferences: preferences, account: account)
.preferredColorScheme(preferences.preferredColorScheme)
}
@ -21,6 +22,7 @@ struct WriteFreely_MultiPlatformApp: App {
SettingsView(preferences: preferences)
.frame(minWidth: 300, maxWidth: 300, minHeight: 200, maxHeight: 200)
.padding()
.preferredColorScheme(preferences.preferredColorScheme)
}
#endif
}

View File

@ -2,6 +2,7 @@ import SwiftUI
struct SettingsView: View {
@EnvironmentObject var preferences: PreferencesModel
@EnvironmentObject var account: AccountModel
@Binding var isPresented: Bool
@ -10,7 +11,7 @@ struct SettingsView: View {
SettingsHeaderView(isPresented: $isPresented)
Form {
Section(header: Text("Login Details")) {
AccountView()
AccountView(account: account)
}
Section(header: Text("Appearance")) {
PreferencesView(preferences: preferences)