Files
NetNewsWire/iOS/Settings/Accounts/AddAccountListView.swift

223 lines
6.3 KiB
Swift

//
// AddAccountListView.swift
// NetNewsWire-iOS
//
// Created by Stuart Breckenridge on 15/12/2022.
// Copyright © 2022 Ranchero Software. All rights reserved.
//
import SwiftUI
import Account
import RSCore
public final class AddAccountListViewModel: ObservableObject, OAuthAccountAuthorizationOperationDelegate {
@Published public var showAddAccountSheet: (Bool, accountType: AccountType) = (false, .onMyMac)
@Published public var showAddAccountError: (Error?, Bool) = (nil, false)
public var webAccountTypes: [AccountType] {
if AppDefaults.shared.isDeveloperBuild {
return [.bazQux, .feedbin, .feedly, .inoreader, .newsBlur, .theOldReader]
.filter({ $0.isDeveloperRestricted == false })
} else {
return [.bazQux, .feedbin, .feedly, .inoreader, .newsBlur, .theOldReader]
}
}
public var rootViewController: UIViewController? {
var currentKeyWindow: UIWindow? {
UIApplication.shared.connectedScenes
.filter { $0.activationState == .foregroundActive }
.map { $0 as? UIWindowScene }
.compactMap { $0 }
.first?.windows
.filter { $0.isKeyWindow }
.first
}
var rootViewController: UIViewController? {
currentKeyWindow?.rootViewController
}
return rootViewController
}
public func oauthAccountAuthorizationOperation(_ operation: OAuthAccountAuthorizationOperation, didCreate account: Account) {
account.refreshAll { [weak self] result in
switch result {
case .success:
break
case .failure(let error):
guard let viewController = self?.rootViewController else {
return
}
viewController.presentError(error)
}
}
}
public func oauthAccountAuthorizationOperation(_ operation: OAuthAccountAuthorizationOperation, didFailWith error: Error) {
showAddAccountError = (error, true)
}
}
struct AddAccountListView: View {
@Environment(\.dismiss) var dismiss
@StateObject private var viewModel = AddAccountListViewModel()
var body: some View {
NavigationView {
List {
localAccountSection
cloudKitSection
webAccountSection
selfHostedSection
}
.navigationTitle(Text("navigation.title.add-account", comment: "Add Account"))
.navigationBarTitleDisplayMode(.inline)
.listItemTint(.primary)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button(role: .cancel) {
dismiss()
} label: {
Text("button.title.cancel", comment: "Button title")
}
}
}
.sheet(isPresented: $viewModel.showAddAccountSheet.0) {
switch viewModel.showAddAccountSheet.accountType {
case .onMyMac:
LocalAddAccountView()
case .cloudKit:
CloudKitAddAccountView()
case .newsBlur:
NewsBlurAddAccountView()
case .freshRSS, .inoreader, .bazQux, .theOldReader:
ReaderAPIAddAccountView(accountType: viewModel.showAddAccountSheet.accountType, account: nil)
default:
Text(viewModel.showAddAccountSheet.accountType.localizedAccountName())
}
}
.alert(Text("alert.title.error", comment: "Error"),
isPresented: $viewModel.showAddAccountError.1,
actions: { },
message: {
Text(verbatim: "\(viewModel.showAddAccountError.0?.localizedDescription ?? "Unknown Error")")
})
.dismissOnAccountAdd()
}
}
var localAccountSection: some View {
Section {
Button {
viewModel.showAddAccountSheet = (true, .onMyMac)
} label: {
Label {
Text(verbatim: AccountType.onMyMac.localizedAccountName())
.foregroundColor(.primary)
} icon: {
Image(uiImage: AppAssets.image(for: .onMyMac)!)
.resizable()
.frame(width: 30, height: 30)
}
}
} header: {
Text("label.text.local-account", comment: "Local Account")
} footer: {
Text("label.text.local-account-explainer", comment: "Local accounts do not sync your feeds across devices")
}
}
var cloudKitSection: some View {
Section {
Button {
viewModel.showAddAccountSheet = (true, .cloudKit)
} label: {
Label {
Text(AccountType.cloudKit.localizedAccountName())
.foregroundColor(interactionDisabled(for: .cloudKit) ? .secondary : .primary)
} icon: {
Image(uiImage: AppAssets.image(for: .cloudKit)!)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 30, height: 30)
}
}
.disabled(interactionDisabled(for: .cloudKit))
} header: {
Text("label.text.cloudkit-account", comment: "iCloud")
} footer: {
Text("label.text.cloudkit-account-footer", comment: "Your iCloud account syncs your feeds across your Mac and iOS devices")
}
}
var webAccountSection: some View {
Section {
ForEach(viewModel.webAccountTypes, id: \.self) { webAccount in
Button {
if webAccount == .feedly {
let addAccount = OAuthAccountAuthorizationOperation(accountType: .feedly)
addAccount.delegate = viewModel
addAccount.presentationAnchor = viewModel.rootViewController?.view.window
MainThreadOperationQueue.shared.add(addAccount)
} else {
viewModel.showAddAccountSheet = (true, webAccount)
}
} label: {
Label {
Text(webAccount.localizedAccountName())
.foregroundColor(.primary)
} icon: {
Image(uiImage: AppAssets.image(for: webAccount)!)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 30, height: 30)
}
}
}
} header: {
Text("label.text.web-account", comment: "Web Account")
} footer: {
Text("label.text.web-account-explainer", comment: "Web accounts sync your feeds across all your devices")
}
}
var selfHostedSection: some View {
Section {
Button {
viewModel.showAddAccountSheet = (true, .freshRSS)
} label: {
Label {
Text(AccountType.freshRSS.localizedAccountName())
.foregroundColor(.primary)
} icon: {
Image(uiImage: AppAssets.image(for: .freshRSS)!)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 30, height: 30)
}
}
} header: {
Text("label.text.self-hosted-accounts", comment: "Self-Hosted Accounts")
} footer: {
Text("label.text.self-hosted-accounts-explainer", comment: "Self-hosted accounts sync your feeds across all your devices")
}
}
private func interactionDisabled(for accountType: AccountType) -> Bool {
if accountType == .cloudKit {
if AccountManager.shared.accounts.contains(where: { $0.type == .cloudKit }) {
return true
}
return AppDefaults.shared.isDeveloperBuild
}
return accountType.isDeveloperRestricted
}
}