Refactor login/logout to implement WriteFreely package

This commit is contained in:
Angelo Stavrow 2020-08-18 17:20:16 -04:00
parent d402ccd472
commit 0c20fea0e6
No known key found for this signature in database
GPG Key ID: 1A49C7064E060EEE
8 changed files with 91 additions and 89 deletions

View File

@ -1,65 +1,66 @@
import SwiftUI
struct AccountLoginView: View {
@ObservedObject var account: AccountModel
@EnvironmentObject var model: WriteFreelyModel
@State private var isShowingAlert: Bool = false
@State private var alertMessage: String = ""
@State private var username: String = ""
@State private var password: String = ""
@State private var server: String = ""
var body: some View {
VStack {
HStack {
Image(systemName: "person.circle")
.foregroundColor(.gray)
#if os(iOS)
TextField("Username", text: $account.username)
TextField("Username", text: $username)
.autocapitalization(.none)
.disableAutocorrection(true)
.textFieldStyle(RoundedBorderTextFieldStyle())
#else
TextField("Username", text: $account.username)
TextField("Username", text: $username)
#endif
}
HStack {
Image(systemName: "lock.circle")
.foregroundColor(.gray)
#if os(iOS)
SecureField("Password", text: $account.password)
SecureField("Password", text: $password)
.autocapitalization(.none)
.disableAutocorrection(true)
.textFieldStyle(RoundedBorderTextFieldStyle())
#else
SecureField("Password", text: $account.password)
SecureField("Password", text: $password)
#endif
}
HStack {
Image(systemName: "link.circle")
.foregroundColor(.gray)
#if os(iOS)
TextField("Server URL", text: $account.server)
TextField("Server URL", text: $server)
.keyboardType(.URL)
.autocapitalization(.none)
.disableAutocorrection(true)
.textFieldStyle(RoundedBorderTextFieldStyle())
#else
TextField("Server URL", text: $account.server)
TextField("Server URL", text: $server)
#endif
}
Spacer()
if account.isLoggingIn {
if model.isLoggingIn {
ProgressView("Logging in...")
.padding()
} else {
Button(action: {
account.login(
to: account.server,
as: account.username, password: account.password,
completion: loginHandler
model.login(
to: URL(string: server)!,
as: username, password: password
)
}, label: {
Text("Login")
})
.disabled(account.isLoggedIn)
.disabled(model.account.isLoggedIn)
.padding()
}
}
@ -99,6 +100,7 @@ struct AccountLoginView: View {
struct AccountLoginView_Previews: PreviewProvider {
static var previews: some View {
AccountLoginView(account: AccountModel())
AccountLoginView()
.environmentObject(WriteFreelyModel())
}
}

View File

@ -1,14 +1,14 @@
import SwiftUI
struct AccountLogoutView: View {
@ObservedObject var account: AccountModel
@EnvironmentObject var model: WriteFreelyModel
var body: some View {
VStack {
Spacer()
VStack {
Text("Logged in as \(account.username)")
Text("on \(account.server)")
Text("Logged in as \(model.account.user?.username ?? "Anonymous")")
Text("on \(model.account.server)")
}
Spacer()
Button(action: logoutHandler, label: {
@ -18,12 +18,13 @@ struct AccountLogoutView: View {
}
func logoutHandler() {
account.logout()
model.logout()
}
}
struct AccountLogoutView_Previews: PreviewProvider {
static var previews: some View {
AccountLogoutView(account: AccountModel())
AccountLogoutView()
.environmentObject(WriteFreelyModel())
}
}

View File

@ -1,4 +1,5 @@
import Foundation
import WriteFreely
enum AccountError: Error {
case invalidPassword
@ -6,66 +7,18 @@ enum AccountError: Error {
case serverNotFound
}
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 = ""
struct AccountModel {
var server: String = ""
private(set) var user: WFUser?
private(set) var isLoggedIn: Bool = false
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 {
result = .failure(.serverNotFound)
} else if username != validCredentials["username"] {
result = .failure(.usernameNotFound)
} else if password != validCredentials["password"] {
result = .failure(.invalidPassword)
} else {
self.id = UUID()
self.username = username
self.password = password
self.server = server
result = .success(self.id!)
}
#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
mutating func login(_ user: WFUser) {
self.user = user
self.isLoggedIn = true
}
func logout() {
id = nil
isLoggedIn = false
isLoggingIn = false
username = ""
password = ""
server = ""
mutating func logout() {
self.user = nil
self.isLoggedIn = false
}
}
#if DEBUG
let validCredentials = [
"username": "test-writer",
"password": "12345"
]
let validServer = "https://test.server.url"
#endif

View File

@ -1,18 +1,18 @@
import SwiftUI
struct AccountView: View {
@ObservedObject var account: AccountModel
@EnvironmentObject var model: WriteFreelyModel
var body: some View {
if account.isLoggedIn {
if model.account.isLoggedIn {
HStack {
Spacer()
AccountLogoutView(account: account)
AccountLogoutView()
Spacer()
}
.padding()
} else {
AccountLoginView(account: account)
AccountLoginView()
.padding()
}
}
@ -20,6 +20,7 @@ struct AccountView: View {
struct AccountLogin_Previews: PreviewProvider {
static var previews: some View {
AccountView(account: AccountModel())
AccountView()
.environmentObject(WriteFreelyModel())
}
}

View File

@ -1,4 +1,5 @@
import Foundation
import WriteFreely
// MARK: - WriteFreelyModel
@ -7,6 +8,9 @@ class WriteFreelyModel: ObservableObject {
@Published var preferences = PreferencesModel()
@Published var store = PostStore()
@Published var post: Post?
@Published var isLoggingIn: Bool = false
private var client: WFClient?
init() {
#if DEBUG
@ -18,5 +22,44 @@ class WriteFreelyModel: ObservableObject {
// MARK: - WriteFreelyModel API
extension WriteFreelyModel {
// API goes here
func login(
to server: URL,
as username: String,
password: String
) {
isLoggingIn = true
account.server = server.absoluteString
client = WFClient(for: server)
client?.login(username: username, password: password, completion: loginHandler)
}
func logout () {
guard let loggedInClient = client else { return }
loggedInClient.logout(completion: logoutHandler)
}
}
private extension WriteFreelyModel {
func loginHandler(result: Result<WFUser, Error>) {
isLoggingIn = false
do {
let user = try result.get()
account.login(user)
dump(user)
} catch {
dump(error)
}
}
func logoutHandler(result: Result<Bool, Error>) {
do {
let loggedOut = try result.get()
if loggedOut {
client = nil
account.logout()
}
} catch {
dump(error)
}
}
}

View File

@ -18,7 +18,8 @@ struct WriteFreely_MultiPlatformApp: App {
#if os(macOS)
Settings {
TabView(selection: $selectedTab) {
MacAccountView(account: model.account)
MacAccountView()
.environmentObject(model)
.tabItem {
Image(systemName: "person.crop.circle")
Text("Account")

View File

@ -10,7 +10,7 @@ struct SettingsView: View {
SettingsHeaderView(isPresented: $isPresented)
Form {
Section(header: Text("Login Details")) {
AccountView(account: model.account)
AccountView()
}
Section(header: Text("Appearance")) {
PreferencesView(preferences: model.preferences)

View File

@ -1,12 +1,12 @@
import SwiftUI
struct MacAccountView: View {
@ObservedObject var account: AccountModel
@EnvironmentObject var model: WriteFreelyModel
var body: some View {
Form {
Section(header: Text("Login Details")) {
AccountView(account: account)
AccountView()
}
}
}
@ -14,6 +14,7 @@ struct MacAccountView: View {
struct MacAccountView_Previews: PreviewProvider {
static var previews: some View {
MacAccountView(account: AccountModel())
MacAccountView()
.environmentObject(WriteFreelyModel())
}
}