Add FreshRSS add account back into settings

This commit is contained in:
Maurice Parker 2019-09-14 15:15:13 -05:00
parent 5c59427e90
commit 157bd57c5e
4 changed files with 73 additions and 69 deletions

View File

@ -7,6 +7,7 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
510BD15D232D765D002692E4 /* SettingsReaderAPIAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 557EE1A522B6F4E1004206FA /* SettingsReaderAPIAccountView.swift */; };
51126DA4225FDE2F00722696 /* RSImage-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51126DA3225FDE2F00722696 /* RSImage-Extensions.swift */; }; 51126DA4225FDE2F00722696 /* RSImage-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51126DA3225FDE2F00722696 /* RSImage-Extensions.swift */; };
5115CAF42266301400B21BCE /* AddContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51121B5A22661FEF00BC0EC1 /* AddContainerViewController.swift */; }; 5115CAF42266301400B21BCE /* AddContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51121B5A22661FEF00BC0EC1 /* AddContainerViewController.swift */; };
511D43CF231FA62200FB1562 /* DetailKeyboardShortcuts.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5127B237222B4849006D641D /* DetailKeyboardShortcuts.plist */; }; 511D43CF231FA62200FB1562 /* DetailKeyboardShortcuts.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5127B237222B4849006D641D /* DetailKeyboardShortcuts.plist */; };
@ -2651,6 +2652,7 @@
514B7C8323205EFB00BAC947 /* RootSplitViewController.swift in Sources */, 514B7C8323205EFB00BAC947 /* RootSplitViewController.swift in Sources */,
5152E0F923248F6200E5C7AD /* SettingsLocalAccountView.swift in Sources */, 5152E0F923248F6200E5C7AD /* SettingsLocalAccountView.swift in Sources */,
FF3ABF162325AF5D0074C542 /* ArticleSorter.swift in Sources */, FF3ABF162325AF5D0074C542 /* ArticleSorter.swift in Sources */,
510BD15D232D765D002692E4 /* SettingsReaderAPIAccountView.swift in Sources */,
51C4525C226508DF00C03939 /* String-Extensions.swift in Sources */, 51C4525C226508DF00C03939 /* String-Extensions.swift in Sources */,
51C452792265091600C03939 /* MasterTimelineTableViewCell.swift in Sources */, 51C452792265091600C03939 /* MasterTimelineTableViewCell.swift in Sources */,
51C452852265093600C03939 /* FlattenedAccountFolderPickerData.swift in Sources */, 51C452852265093600C03939 /* FlattenedAccountFolderPickerData.swift in Sources */,

View File

@ -20,6 +20,9 @@ struct SettingsAddAccountView : View {
NavigationLink(destination: SettingsFeedbinAccountView(viewModel: SettingsFeedbinAccountView.ViewModel())) { NavigationLink(destination: SettingsFeedbinAccountView(viewModel: SettingsFeedbinAccountView.ViewModel())) {
SettingsAccountLabelView(accountImage: "accountFeedbin", accountLabel: "Feedbin") SettingsAccountLabelView(accountImage: "accountFeedbin", accountLabel: "Feedbin")
} }
NavigationLink(destination: SettingsReaderAPIAccountView(viewModel: SettingsReaderAPIAccountView.ViewModel(accountType: .freshRSS))) {
SettingsAccountLabelView(accountImage: "accountFreshRSS", accountLabel: "Fresh RSS")
}
} }
.navigationBarTitle(Text("Add Account"), displayMode: .inline) .navigationBarTitle(Text("Add Account"), displayMode: .inline)
} }

View File

@ -14,7 +14,7 @@ import RSWeb
struct SettingsDetailAccountView : View { struct SettingsDetailAccountView : View {
@Environment(\.presentationMode) var presentation @Environment(\.presentationMode) var presentation
@ObservedObject var viewModel: ViewModel @ObservedObject var viewModel: ViewModel
@State private var isFeedbinCredentialsPresented = false @State private var accountType: AccountType = nil
@State private var isDeleteAlertPresented = false @State private var isDeleteAlertPresented = false
var body: some View { var body: some View {
@ -32,15 +32,20 @@ struct SettingsDetailAccountView : View {
HStack { HStack {
Spacer() Spacer()
Button(action: { Button(action: {
self.isFeedbinCredentialsPresented.toggle() self.accountType = self.viewModel.account.type
}) { }) {
Text("Credentials") Text("Credentials")
} }
Spacer() Spacer()
} }
} }
.sheet(isPresented: $isFeedbinCredentialsPresented) { .sheet(item: $accountType) { type in
self.settingsFeedbinAccountView if type == .feedbin {
self.settingsFeedbinAccountView
}
if type == .freshRSS {
self.settingsReaderAPIAccountView
}
} }
} }
if viewModel.isDeletable { if viewModel.isDeletable {
@ -74,6 +79,11 @@ struct SettingsDetailAccountView : View {
return SettingsFeedbinAccountView(viewModel: feedbinViewModel) return SettingsFeedbinAccountView(viewModel: feedbinViewModel)
} }
var settingsReaderAPIAccountView: SettingsReaderAPIAccountView {
let readerAPIModel = SettingsReaderAPIAccountView.ViewModel(account: viewModel.account)
return SettingsReaderAPIAccountView(viewModel: readerAPIModel)
}
class ViewModel: ObservableObject { class ViewModel: ObservableObject {
let objectWillChange = ObservableObjectPublisher() let objectWillChange = ObservableObjectPublisher()

View File

@ -12,74 +12,61 @@ import Account
import RSWeb import RSWeb
struct SettingsReaderAPIAccountView : View { struct SettingsReaderAPIAccountView : View {
@Environment(\.isPresented) private var isPresented @Environment(\.presentationMode) var presentation
@ObjectBinding var viewModel: ViewModel @ObservedObject var viewModel: ViewModel
@State var busy: Bool = false @State var busy: Bool = false
@State var error: Text = Text("") @State var error: String = ""
var body: some View { var body: some View {
NavigationView { Form {
List { Section(header:
Section(header: HStack {
SettingsAccountLabelView(accountImage: "accountFreshRSS", accountLabel: "FreshRSS").padding() Spacer()
) { SettingsAccountLabelView(accountImage: "accountFreshRSS", accountLabel: "FreshRSS")
HStack { .padding()
Text("Email:") .layoutPriority(1.0)
Divider() Spacer()
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 { TextField("Email", text: $viewModel.email).textContentType(.username)
Spacer() SecureField("Password", text: $viewModel.password)
error.color(.red) TextField("API URL:", text: $viewModel.apiURL).textContentType(.URL)
Spacer() }
}
) { Section(footer:
HStack { HStack {
Spacer() Spacer()
Button(action: { self.addAccount() }) { Text(verbatim: error).foregroundColor(.red)
if viewModel.isUpdate { Spacer()
Text("Update Account") }
} else { ) {
Text("Add Account") HStack {
} Spacer()
Button(action: { self.addAccount() }) {
if viewModel.isUpdate {
Text("Update Account")
} else {
Text("Add Account")
} }
.disabled(!viewModel.isValid)
Spacer()
} }
.disabled(!viewModel.isValid)
Spacer()
} }
} }
.disabled(busy)
.listStyle(.grouped)
.navigationBarTitle(Text(""), displayMode: .inline)
.navigationBarItems(leading:
Button(action: { self.dismiss() }) { Text("Cancel") }
)
} }
// .disabled(busy)
} }
private func addAccount() { private func addAccount() {
busy = true busy = true
error = Text("") error = ""
let emailAddress = viewModel.email.trimmingCharacters(in: .whitespaces) let emailAddress = viewModel.email.trimmingCharacters(in: .whitespaces)
let credentials = Credentials.readerAPIBasicLogin(username: emailAddress, password: viewModel.password) let credentials = Credentials.readerAPIBasicLogin(username: emailAddress, password: viewModel.password)
guard let apiURL = URL(string: viewModel.apiURL) else { guard let apiURL = URL(string: viewModel.apiURL) else {
self.error = Text("Invalide API URL.") self.error = "Invalid API URL."
return return
} }
@ -118,15 +105,15 @@ struct SettingsReaderAPIAccountView : View {
self.dismiss() self.dismiss()
} catch { } catch {
self.error = Text("Keychain error while storing credentials.") self.error = "Keychain error while storing credentials."
} }
} else { } else {
self.error = Text("Invalid email/password combination.") self.error = "Invalid email/password combination."
} }
case .failure: case .failure:
self.error = Text("Network error. Try again later.") self.error = "Network error. Try again later."
} }
} }
@ -134,11 +121,12 @@ struct SettingsReaderAPIAccountView : View {
} }
private func dismiss() { private func dismiss() {
isPresented?.value = false presentation.wrappedValue.dismiss()
} }
class ViewModel: BindableObject { class ViewModel: ObservableObject {
let didChange = PassthroughSubject<ViewModel, Never>()
let objectWillChange = ObservableObjectPublisher()
var accountType: AccountType var accountType: AccountType
var account: Account? = nil var account: Account? = nil
@ -146,28 +134,29 @@ struct SettingsReaderAPIAccountView : View {
self.accountType = accountType self.accountType = accountType
} }
init(accountType: AccountType, account: Account) { init(account: Account) {
self.account = account self.account = account
self.accountType = accountType self.accountType = account.type
if case .basic(let username, let password) = try? account.retrieveCredentials() { if case .readerAPIBasicLogin(let username, let password) = try? account.retrieveCredentials() {
self.email = username self.email = username
self.password = password self.password = password
self.apiURL = account.endpointURL?.absoluteString ?? ""
} }
} }
var email: String = "" { var email: String = "" {
didSet { willSet {
didChange.send(self) objectWillChange.send()
} }
} }
var password: String = "" { var password: String = "" {
didSet { willSet {
didChange.send(self) objectWillChange.send()
} }
} }
var apiURL: String = "" { var apiURL: String = "" {
didSet { willSet {
didChange.send(self) objectWillChange.send()
} }
} }
var isUpdate: Bool { var isUpdate: Bool {