// // SettingsGoogleReaderCompatibleAccountView.swift // NetNewsWire-iOS // // Created by Maurice Parker on 6/11/19. // Copyright © 2019 Ranchero Software. All rights reserved. // import SwiftUI import Combine import Account import RSWeb struct SettingsGoogleReaderCompatibleAccountView : View { @Environment(\.isPresented) private var isPresented @ObjectBinding var viewModel: ViewModel @State var busy: Bool = false @State var error: Text = Text("") var body: some View { NavigationView { List { Section(header: SettingsAccountLabelView(accountImage: "accountLocal", accountLabel: "Google Reader Compatible").padding() ) { HStack { Text("Email:") Divider() TextField($viewModel.email) .textContentType(.username) } HStack { Text("Password:") Divider() SecureField($viewModel.password) } HStack { Text("API URL:") Divider() TextField($viewModel.apiURL) .textContentType(.URL) } } Section(footer: HStack { Spacer() error.color(.red) Spacer() } ) { HStack { Spacer() Button(action: { self.addAccount() }) { if viewModel.isUpdate { Text("Update Account") } else { Text("Add Account") } } .disabled(!viewModel.isValid) Spacer() } } } .disabled(busy) .listStyle(.grouped) .navigationBarTitle(Text(""), displayMode: .inline) .navigationBarItems(leading: Button(action: { self.dismiss() }) { Text("Cancel") } ) } } private func addAccount() { busy = true error = Text("") let emailAddress = viewModel.email.trimmingCharacters(in: .whitespaces) let credentials = Credentials.googleBasicLogin(username: emailAddress, password: viewModel.password) guard let apiURL = URL(string: viewModel.apiURL) else { self.error = Text("Invalide API URL.") return } Account.validateCredentials(type: .googleReaderCompatible, credentials: credentials, endpoint: apiURL) { result in self.busy = false switch result { case .success(let authenticated): if (authenticated != nil) { var newAccount = false let workAccount: Account if self.viewModel.account == nil { workAccount = AccountManager.shared.createAccount(type: .googleReaderCompatible) newAccount = true } else { workAccount = self.viewModel.account! } do { do { try workAccount.removeBasicCredentials() } catch {} workAccount.endpointURL = apiURL try workAccount.storeCredentials(credentials) if newAccount { workAccount.refreshAll() { result in } } self.dismiss() } catch { self.error = Text("Keychain error while storing credentials.") } } else { self.error = Text("Invalid email/password combination.") } case .failure: self.error = Text("Network error. Try again later.") } } } private func dismiss() { isPresented?.value = false } class ViewModel: BindableObject { let didChange = PassthroughSubject() var account: Account? = nil init() { } init(account: Account) { self.account = account if case .basic(let username, let password) = try? account.retrieveBasicCredentials() { self.email = username self.password = password } } var email: String = "" { didSet { didChange.send(self) } } var password: String = "" { didSet { didChange.send(self) } } var apiURL: String = "" { didSet { didChange.send(self) } } var isUpdate: Bool { return account != nil } var isValid: Bool { return !email.isEmpty && !password.isEmpty } } } #if DEBUG struct SettingsGoogleReaderCompatibleAccountView_Previews : PreviewProvider { static var previews: some View { SettingsGoogleReaderCompatibleAccountView(viewModel: SettingsGoogleReaderCompatibleAccountView.ViewModel()) } } #endif