diff --git a/Multiplatform/Shared/Add/Add Account Models/AddAccountSignUp.swift b/Multiplatform/Shared/Add/Add Account Models/AddAccountSignUp.swift new file mode 100644 index 000000000..d2c11d5cd --- /dev/null +++ b/Multiplatform/Shared/Add/Add Account Models/AddAccountSignUp.swift @@ -0,0 +1,68 @@ +// +// AddAccountSignUp.swift +// NetNewsWire +// +// Created by Stuart Breckenridge on 06/12/2020. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import Foundation +import Account +#if os(iOS) +import UIKit +#endif + + +/// Helper functions common to most account services. +protocol AddAccountSignUp { + func presentSignUpOption(_ accountType: AccountType) +} + + +extension AddAccountSignUp { + func presentSignUpOption(_ accountType: AccountType) { + #if os(macOS) + switch accountType { + case .bazQux: + NSWorkspace.shared.open(URL(string: "https://bazqux.com")!) + case .feedbin: + NSWorkspace.shared.open(URL(string: "https://feedbin.com/signup")!) + case .feedly: + NSWorkspace.shared.open(URL(string: "https://feedly.com")!) + case .feedWrangler: + NSWorkspace.shared.open(URL(string: "https://feedwrangler.net/users/new")!) + case .freshRSS: + NSWorkspace.shared.open(URL(string: "https://freshrss.org")!) + case .inoreader: + NSWorkspace.shared.open(URL(string: "https://www.inoreader.com")!) + case .newsBlur: + NSWorkspace.shared.open(URL(string: "https://newsblur.com")!) + case .theOldReader: + NSWorkspace.shared.open(URL(string: "https://theoldreader.com")!) + default: + return + } + #else + switch accountType { + case .bazQux: + UIApplication.shared.open(URL(string: "https://bazqux.com")!, options: [UIApplication.OpenExternalURLOptionsKey.universalLinksOnly : false], completionHandler: nil) + case .feedbin: + UIApplication.shared.open(URL(string: "https://feedbin.com/signup")!, options: [:], completionHandler: nil) + case .feedly: + UIApplication.shared.open(URL(string: "https://feedly.com")!, options: [UIApplication.OpenExternalURLOptionsKey.universalLinksOnly : false], completionHandler: nil) + case .feedWrangler: + UIApplication.shared.open(URL(string: "https://feedwrangler.net/users/new")!, options: [UIApplication.OpenExternalURLOptionsKey.universalLinksOnly : false], completionHandler: nil) + case .freshRSS: + UIApplication.shared.open(URL(string: "https://freshrss.org")!, options: [UIApplication.OpenExternalURLOptionsKey.universalLinksOnly : false], completionHandler: nil) + case .inoreader: + UIApplication.shared.open(URL(string: "https://www.inoreader.com")!, options: [UIApplication.OpenExternalURLOptionsKey.universalLinksOnly : false], completionHandler: nil) + case .newsBlur: + UIApplication.shared.open(URL(string: "https://newsblur.com")!, options: [UIApplication.OpenExternalURLOptionsKey.universalLinksOnly : false], completionHandler: nil) + case .theOldReader: + UIApplication.shared.open(URL(string: "https://theoldreader.com")!, options: [UIApplication.OpenExternalURLOptionsKey.universalLinksOnly : false], completionHandler: nil) + default: + return + } + #endif + } +} diff --git a/Multiplatform/Shared/Add/Add Account Models/AddFeedWranglerViewModel.swift b/Multiplatform/Shared/Add/Add Account Models/AddFeedWranglerViewModel.swift new file mode 100644 index 000000000..f05ac68d1 --- /dev/null +++ b/Multiplatform/Shared/Add/Add Account Models/AddFeedWranglerViewModel.swift @@ -0,0 +1,70 @@ +// +// AddFeedWranglerViewModel.swift +// Multiplatform macOS +// +// Created by Stuart Breckenridge on 05/12/2020. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import SwiftUI +import Account +import RSCore +import RSWeb +import Secrets + +class AddFeedWranglerViewModel: ObservableObject, AddAccountSignUp { + @Published var isAuthenticating: Bool = false + @Published var accountUpdateError: AccountUpdateErrors = .none + @Published var showError: Bool = false + @Published var username: String = "" + @Published var password: String = "" + @Published var canDismiss: Bool = false + @Published var showPassword: Bool = false + + func authenticateFeedWrangler() { + + isAuthenticating = true + let credentials = Credentials(type: .feedWranglerBasic, username: username, secret: password) + + Account.validateCredentials(type: .feedWrangler, credentials: credentials) { result in + + + self.isAuthenticating = false + + switch result { + case .success(let validatedCredentials): + + guard let validatedCredentials = validatedCredentials else { + self.accountUpdateError = .invalidUsernamePassword + self.showError = true + return + } + + let account = AccountManager.shared.createAccount(type: .feedWrangler) + + do { + try account.removeCredentials(type: .feedWranglerBasic) + try account.removeCredentials(type: .feedWranglerToken) + try account.storeCredentials(credentials) + try account.storeCredentials(validatedCredentials) + self.canDismiss = true + account.refreshAll(completion: { result in + switch result { + case .success: + break + case .failure(let error): + self.accountUpdateError = .other(error: error) + self.showError = true + } + }) + } catch { + self.accountUpdateError = .keyChainError + self.showError = true + } + case .failure: + self.accountUpdateError = .networkError + self.showError = true + } + } + } +} diff --git a/Multiplatform/Shared/Add/Add Account Models/AddFeedbinViewModel.swift b/Multiplatform/Shared/Add/Add Account Models/AddFeedbinViewModel.swift new file mode 100644 index 000000000..a043fec28 --- /dev/null +++ b/Multiplatform/Shared/Add/Add Account Models/AddFeedbinViewModel.swift @@ -0,0 +1,68 @@ +// +// AddFeedbinViewModel.swift +// Multiplatform macOS +// +// Created by Stuart Breckenridge on 05/12/2020. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import SwiftUI +import Account +import RSCore +import RSWeb +import Secrets + +class AddFeedbinViewModel: ObservableObject, AddAccountSignUp { + @Published var isAuthenticating: Bool = false + @Published var accountUpdateError: AccountUpdateErrors = .none + @Published var showError: Bool = false + @Published var username: String = "" + @Published var password: String = "" + @Published var canDismiss: Bool = false + @Published var showPassword: Bool = false + + func authenticateFeedbin() { + isAuthenticating = true + let credentials = Credentials(type: .basic, username: username, secret: password) + + Account.validateCredentials(type: .feedbin, credentials: credentials) { result in + self.isAuthenticating = false + + switch result { + case .success(let validatedCredentials): + + guard let validatedCredentials = validatedCredentials else { + self.accountUpdateError = .invalidUsernamePassword + self.showError = true + return + } + + let account = AccountManager.shared.createAccount(type: .feedbin) + + do { + try account.removeCredentials(type: .basic) + try account.storeCredentials(validatedCredentials) + self.isAuthenticating = false + self.canDismiss = true + account.refreshAll(completion: { result in + switch result { + case .success: + break + case .failure(let error): + self.accountUpdateError = .other(error: error) + self.showError = true + } + }) + + } catch { + self.accountUpdateError = .keyChainError + self.showError = true + } + + case .failure: + self.accountUpdateError = .networkError + self.showError = true + } + } + } +} diff --git a/Multiplatform/Shared/Add/Add Account Models/AddFeedlyViewModel.swift b/Multiplatform/Shared/Add/Add Account Models/AddFeedlyViewModel.swift new file mode 100644 index 000000000..7312b2f61 --- /dev/null +++ b/Multiplatform/Shared/Add/Add Account Models/AddFeedlyViewModel.swift @@ -0,0 +1,67 @@ +// +// AddFeedlyViewModel.swift +// Multiplatform macOS +// +// Created by Stuart Breckenridge on 05/12/2020. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import SwiftUI +import Account +import RSCore +import RSWeb +import Secrets + +class AddFeedlyViewModel: ObservableObject, OAuthAccountAuthorizationOperationDelegate, AddAccountSignUp { + @Published var isAuthenticating: Bool = false + @Published var accountUpdateError: AccountUpdateErrors = .none + @Published var showError: Bool = false + @Published var username: String = "" + @Published var password: String = "" + + func authenticateFeedly() { + isAuthenticating = true + let addAccount = OAuthAccountAuthorizationOperation(accountType: .feedly) + addAccount.delegate = self + #if os(macOS) + addAccount.presentationAnchor = NSApplication.shared.windows.last + #else + addAccount.presentationAnchor = UIApplication.shared.windows.last + #endif + MainThreadOperationQueue.shared.add(addAccount) + } + + func oauthAccountAuthorizationOperation(_ operation: OAuthAccountAuthorizationOperation, didCreate account: Account) { + + isAuthenticating = false + + // macOS only: `ASWebAuthenticationSession` leaves the browser in the foreground. + // Ensure the app is in the foreground so the user can see their Feedly account load. + #if os(macOS) + NSApplication.shared.activate(ignoringOtherApps: true) + #endif + + account.refreshAll { [weak self] result in + switch result { + case .success: + break + case .failure(let error): + self?.accountUpdateError = .other(error: error) + self?.showError = true + } + } + } + + func oauthAccountAuthorizationOperation(_ operation: OAuthAccountAuthorizationOperation, didFailWith error: Error) { + isAuthenticating = false + + // macOS only: `ASWebAuthenticationSession` leaves the browser in the foreground. + // Ensure the app is in the foreground so the user can see the error. + #if os(macOS) + NSApplication.shared.activate(ignoringOtherApps: true) + #endif + + accountUpdateError = .other(error: error) + showError = true + } +} diff --git a/Multiplatform/Shared/Add/Add Account Models/AddNewsBlurViewModel.swift b/Multiplatform/Shared/Add/Add Account Models/AddNewsBlurViewModel.swift new file mode 100644 index 000000000..96f58b78f --- /dev/null +++ b/Multiplatform/Shared/Add/Add Account Models/AddNewsBlurViewModel.swift @@ -0,0 +1,71 @@ +// +// AddNewsBlurViewModel.swift +// Multiplatform macOS +// +// Created by Stuart Breckenridge on 05/12/2020. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import SwiftUI +import Account +import RSCore +import RSWeb +import Secrets + +class AddNewsBlurViewModel: ObservableObject, AddAccountSignUp { + @Published var isAuthenticating: Bool = false + @Published var accountUpdateError: AccountUpdateErrors = .none + @Published var showError: Bool = false + @Published var username: String = "" + @Published var password: String = "" + @Published var canDismiss: Bool = false + @Published var showPassword: Bool = false + + func authenticateNewsBlur() { + isAuthenticating = true + let credentials = Credentials(type: .newsBlurBasic, username: username, secret: password) + + Account.validateCredentials(type: .newsBlur, credentials: credentials) { result in + + self.isAuthenticating = false + + switch result { + case .success(let validatedCredentials): + + guard let validatedCredentials = validatedCredentials else { + self.accountUpdateError = .invalidUsernamePassword + self.showError = true + return + } + + let account = AccountManager.shared.createAccount(type: .newsBlur) + + do { + try account.removeCredentials(type: .newsBlurBasic) + try account.removeCredentials(type: .newsBlurSessionId) + try account.storeCredentials(credentials) + try account.storeCredentials(validatedCredentials) + self.canDismiss = true + account.refreshAll(completion: { result in + switch result { + case .success: + break + case .failure(let error): + self.accountUpdateError = .other(error: error) + self.showError = true + } + }) + + } catch { + self.accountUpdateError = .keyChainError + self.showError = true + } + + case .failure: + self.accountUpdateError = .networkError + self.showError = true + } + } + } + +} diff --git a/Multiplatform/Shared/Add/Add Account Models/AddReaderAPIViewModel.swift b/Multiplatform/Shared/Add/Add Account Models/AddReaderAPIViewModel.swift new file mode 100644 index 000000000..c6e67897f --- /dev/null +++ b/Multiplatform/Shared/Add/Add Account Models/AddReaderAPIViewModel.swift @@ -0,0 +1,122 @@ +// +// AddReaderAPIViewModel.swift +// Multiplatform macOS +// +// Created by Stuart Breckenridge on 05/12/2020. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import SwiftUI +import Account +import RSCore +import RSWeb +import Secrets + +class AddReaderAPIViewModel: ObservableObject, AddAccountSignUp { + @Published var isAuthenticating: Bool = false + @Published var accountUpdateError: AccountUpdateErrors = .none + @Published var showError: Bool = false + @Published var username: String = "" + @Published var password: String = "" + @Published var apiUrl: String = "" + @Published var canDismiss: Bool = false + @Published var showPassword: Bool = false + + func authenticateReaderAccount(_ accountType: AccountType) { + isAuthenticating = true + + let credentials = Credentials(type: .readerBasic, username: username, secret: password) + + if accountType == .freshRSS { + Account.validateCredentials(type: accountType, credentials: credentials, endpoint: URL(string: apiUrl)!) { result in + + self.isAuthenticating = false + + switch result { + case .success(let validatedCredentials): + + guard let validatedCredentials = validatedCredentials else { + self.accountUpdateError = .invalidUsernamePassword + self.showError = true + return + } + + let account = AccountManager.shared.createAccount(type: .freshRSS) + + do { + try account.removeCredentials(type: .readerBasic) + try account.removeCredentials(type: .readerAPIKey) + try account.storeCredentials(credentials) + try account.storeCredentials(validatedCredentials) + self.canDismiss = true + account.refreshAll(completion: { result in + switch result { + case .success: + break + case .failure(let error): + self.accountUpdateError = .other(error: error) + self.showError = true + } + }) + + } catch { + self.accountUpdateError = .keyChainError + self.showError = true + } + + case .failure: + self.accountUpdateError = .networkError + self.showError = true + } + } + } + + else { + + Account.validateCredentials(type: accountType, credentials: credentials) { result in + + self.isAuthenticating = false + + switch result { + case .success(let validatedCredentials): + + guard let validatedCredentials = validatedCredentials else { + self.accountUpdateError = .invalidUsernamePassword + self.showError = true + return + } + + let account = AccountManager.shared.createAccount(type: .freshRSS) + + do { + try account.removeCredentials(type: .readerBasic) + try account.removeCredentials(type: .readerAPIKey) + try account.storeCredentials(credentials) + try account.storeCredentials(validatedCredentials) + self.canDismiss = true + account.refreshAll(completion: { result in + switch result { + case .success: + break + case .failure(let error): + self.accountUpdateError = .other(error: error) + self.showError = true + } + }) + + } catch { + self.accountUpdateError = .keyChainError + self.showError = true + } + + case .failure: + self.accountUpdateError = .networkError + self.showError = true + } + } + + } + + } + +} diff --git a/Multiplatform/Shared/Add/Add Account Sheets/AddCloudKitAccountView.swift b/Multiplatform/Shared/Add/Add Account Sheets/AddCloudKitAccountView.swift new file mode 100644 index 000000000..b7ee03318 --- /dev/null +++ b/Multiplatform/Shared/Add/Add Account Sheets/AddCloudKitAccountView.swift @@ -0,0 +1,134 @@ +// +// AddCloudKitAccountView.swift +// Multiplatform macOS +// +// Created by Stuart Breckenridge on 03/12/2020. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import SwiftUI +import Account + +struct AddCloudKitAccountView: View { + + @Environment (\.presentationMode) var presentationMode + + var body: some View { + + #if os(macOS) + macBody + #else + NavigationView { + iosBody + } + #endif + + } + + #if os(iOS) + var iosBody: some View { + List { + Section(header: formHeader, footer: formFooter, content: { + Button(action: { + _ = AccountManager.shared.createAccount(type: .cloudKit) + presentationMode.wrappedValue.dismiss() + }, label: { + HStack { + Spacer() + Text("Add Account") + Spacer() + } + }).disabled(AccountManager.shared.activeAccounts.filter({ $0.type == .cloudKit }).count > 0) + }) + }.navigationBarItems(leading: + Button(action: { + presentationMode.wrappedValue.dismiss() + }, label: { + Text("Cancel") + }) + ) + .navigationBarTitleDisplayMode(.inline) + .navigationTitle(Text(AccountType.cloudKit.localizedAccountName())) + .listStyle(InsetGroupedListStyle()) + } + #endif + + #if os(macOS) + var macBody: some View { + VStack { + HStack(spacing: 16) { + VStack(alignment: .leading) { + AccountType.cloudKit.image() + .resizable() + .frame(width: 50, height: 50) + Spacer() + } + VStack(alignment: .leading, spacing: 8) { + Text("Sign in to your iCloud account.") + .font(.headline) + + Text("This account syncs across your Mac and iOS devices using your iCloud account.") + .foregroundColor(.secondary) + .font(.callout) + .lineLimit(2) + .padding(.top, 4) + + Spacer() + HStack(spacing: 8) { + Spacer() + Button(action: { + presentationMode.wrappedValue.dismiss() + }, label: { + Text("Cancel") + .frame(width: 60) + }).keyboardShortcut(.cancelAction) + + Button(action: { + _ = AccountManager.shared.createAccount(type: .cloudKit) + presentationMode.wrappedValue.dismiss() + }, label: { + Text("Create") + .frame(width: 60) + }) + .keyboardShortcut(.defaultAction) + .disabled(AccountManager.shared.activeAccounts.filter({ $0.type == .cloudKit }).count > 0) + } + } + } + } + .padding() + .frame(minWidth: 400, maxWidth: 400, maxHeight: 150) + } + #endif + + var formHeader: some View { + HStack { + Spacer() + VStack(alignment: .center) { + AccountType.cloudKit.image() + .resizable() + .frame(width: 50, height: 50) + } + Spacer() + }.padding(.vertical) + } + + var formFooter: some View { + HStack { + Spacer() + VStack(spacing: 8) { + Text("This account syncs across your Mac and iOS devices using your iCloud account.").foregroundColor(.secondary) + } + .multilineTextAlignment(.center) + .font(.caption) + Spacer() + + }.padding(.vertical) + } +} + +struct AddCloudKitAccountView_Previews: PreviewProvider { + static var previews: some View { + AddCloudKitAccountView() + } +} diff --git a/Multiplatform/Shared/Add/Add Account Sheets/AddFeedWranglerAccountView.swift b/Multiplatform/Shared/Add/Add Account Sheets/AddFeedWranglerAccountView.swift new file mode 100644 index 000000000..4e21a994a --- /dev/null +++ b/Multiplatform/Shared/Add/Add Account Sheets/AddFeedWranglerAccountView.swift @@ -0,0 +1,216 @@ +// +// AddFeedWranglerAccountView.swift +// Multiplatform macOS +// +// Created by Stuart Breckenridge on 03/12/2020. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import SwiftUI +import Account +import RSCore +import RSWeb +import Secrets + + +struct AddFeedWranglerAccountView: View { + + @Environment (\.presentationMode) var presentationMode + @StateObject private var model = AddFeedWranglerViewModel() + + var body: some View { + #if os(macOS) + macBody + #else + NavigationView { + iosBody + } + #endif + } + + + #if os(iOS) + var iosBody: some View { + List { + Section(header: formHeader, content: { + TextField("Email", text: $model.username) + if model.showPassword == false { + ZStack { + HStack { + SecureField("Password", text: $model.password) + Spacer() + Image(systemName: "eye.fill") + .foregroundColor(.accentColor) + .onTapGesture { + model.showPassword = true + } + } + } + } + else { + ZStack { + HStack { + TextField("Password", text: $model.password) + Spacer() + Image(systemName: "eye.slash.fill") + .foregroundColor(.accentColor) + .onTapGesture { + model.showPassword = false + } + } + } + } + + }) + + Section(footer: formFooter, content: { + Button(action: { + model.authenticateFeedWrangler() + }, label: { + HStack { + Spacer() + Text("Add Account") + Spacer() + } + }).disabled(model.username.isEmpty || model.password.isEmpty) + }) + + } + .navigationBarItems(leading: + Button(action: { + presentationMode.wrappedValue.dismiss() + }, label: { + Text("Cancel") + })) + .listStyle(InsetGroupedListStyle()) + .navigationBarTitleDisplayMode(.inline) + .navigationTitle(Text("Feed Wrangler")) + .alert(isPresented: $model.showError, content: { + Alert(title: Text("Sign In Error"), message: Text(model.accountUpdateError.description), dismissButton: .cancel(Text("Dismiss"))) + }) + .onReceive(model.$canDismiss, perform: { value in + if value == true { + presentationMode.wrappedValue.dismiss() + } + }) + } + #endif + + #if os(macOS) + var macBody: some View { + VStack { + HStack(spacing: 16) { + VStack(alignment: .leading) { + AccountType.feedWrangler.image() + .resizable() + .frame(width: 50, height: 50) + Spacer() + } + VStack(alignment: .leading, spacing: 8) { + Text("Sign in to your Feed Wrangler account.") + .font(.headline) + HStack { + Text("Don't have a Feed Wrangler account?") + .font(.callout) + Button(action: { + model.presentSignUpOption(.feedWrangler) + }, label: { + Text("Sign up here.").font(.callout) + }).buttonStyle(LinkButtonStyle()) + } + + HStack { + VStack(alignment: .trailing, spacing: 14) { + Text("Email") + Text("Password") + } + VStack(spacing: 8) { + TextField("me@email.com", text: $model.username) + SecureField("•••••••••••", text: $model.password) + } + } + + Text("Your username and password will be encrypted and stored in Keychain.") + .foregroundColor(.secondary) + .font(.callout) + .lineLimit(2) + .padding(.top, 4) + + Spacer() + HStack(spacing: 8) { + Spacer() + ProgressView() + .scaleEffect(CGSize(width: 0.5, height: 0.5)) + .hidden(!model.isAuthenticating) + Button(action: { + presentationMode.wrappedValue.dismiss() + }, label: { + Text("Cancel") + .frame(width: 60) + }).keyboardShortcut(.cancelAction) + + Button(action: { + model.authenticateFeedWrangler() + }, label: { + Text("Sign In") + .frame(width: 60) + }) + .keyboardShortcut(.defaultAction) + .disabled(model.username.isEmpty || model.password.isEmpty) + } + } + } + } + .padding() + .frame(minWidth: 400, maxWidth: 400, minHeight: 230, maxHeight: 260) + .textFieldStyle(RoundedBorderTextFieldStyle()) + .alert(isPresented: $model.showError, content: { + Alert(title: Text("Sign In Error"), message: Text(model.accountUpdateError.description), dismissButton: .cancel()) + }) + .onReceive(model.$canDismiss, perform: { value in + if value == true { + presentationMode.wrappedValue.dismiss() + } + }) + } + #endif + + var formHeader: some View { + HStack { + Spacer() + VStack(alignment: .center) { + AccountType.feedWrangler.image() + .resizable() + .frame(width: 50, height: 50) + } + Spacer() + }.padding(.vertical) + } + + var formFooter: some View { + HStack { + Spacer() + VStack(spacing: 8) { + Text("Sign in to your Feed Wrangler account and sync your subscriptions across your devices. Your username and password and password will be encrypted and stored in Keychain.").foregroundColor(.secondary) + Text("Don't have a Feed Wrangler account?").foregroundColor(.secondary) + Button(action: { + model.presentSignUpOption(.feedWrangler) + }, label: { + Text("Sign Up Here").foregroundColor(.blue).multilineTextAlignment(.center) + }) + ProgressView().hidden(!model.isAuthenticating) + } + .multilineTextAlignment(.center) + .font(.caption2) + Spacer() + + }.padding(.vertical) + } + +} + +struct AddFeedWranglerAccountView_Previews: PreviewProvider { + static var previews: some View { + AddFeedWranglerAccountView() + } +} diff --git a/Multiplatform/Shared/Add/Add Account Sheets/AddFeedbinAccountView.swift b/Multiplatform/Shared/Add/Add Account Sheets/AddFeedbinAccountView.swift new file mode 100644 index 000000000..032898816 --- /dev/null +++ b/Multiplatform/Shared/Add/Add Account Sheets/AddFeedbinAccountView.swift @@ -0,0 +1,214 @@ +// +// AddFeedbinAccountView.swift +// Multiplatform macOS +// +// Created by Stuart Breckenridge on 02/12/2020. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import SwiftUI +import Account +import RSCore +import RSWeb +import Secrets + +struct AddFeedbinAccountView: View { + + @Environment (\.presentationMode) var presentationMode + @StateObject private var model = AddFeedbinViewModel() + + var body: some View { + #if os(macOS) + macBody + #else + NavigationView { + iosBody + } + #endif + } + + #if os(iOS) + var iosBody: some View { + List { + Section(header: formHeader, content: { + TextField("Email", text: $model.username) + if model.showPassword == false { + ZStack { + HStack { + SecureField("Password", text: $model.password) + Spacer() + Image(systemName: "eye.fill") + .foregroundColor(.accentColor) + .onTapGesture { + model.showPassword = true + } + } + } + } + else { + ZStack { + HStack { + TextField("Password", text: $model.password) + Spacer() + Image(systemName: "eye.slash.fill") + .foregroundColor(.accentColor) + .onTapGesture { + model.showPassword = false + } + } + } + } + + }) + + Section(footer: formFooter, content: { + Button(action: { + model.authenticateFeedbin() + }, label: { + HStack { + Spacer() + Text("Add Account") + Spacer() + } + }).disabled(model.username.isEmpty || model.password.isEmpty) + }) + + } + .navigationBarItems(leading: + Button(action: { + presentationMode.wrappedValue.dismiss() + }, label: { + Text("Cancel") + })) + .listStyle(InsetGroupedListStyle()) + .navigationBarTitleDisplayMode(.inline) + .navigationTitle(Text("Feedbin")) + .alert(isPresented: $model.showError, content: { + Alert(title: Text("Sign In Error"), message: Text(model.accountUpdateError.description), dismissButton: .cancel(Text("Dismiss"))) + }) + .onReceive(model.$canDismiss, perform: { value in + if value == true { + presentationMode.wrappedValue.dismiss() + } + }) + } + #endif + + #if os(macOS) + var macBody: some View { + VStack { + HStack(spacing: 16) { + VStack(alignment: .leading) { + AccountType.feedbin.image() + .frame(width: 50, height: 50) + Spacer() + } + VStack(alignment: .leading, spacing: 8) { + Text("Sign in to your Feedbin account.") + .font(.headline) + HStack { + Text("Don't have a Feedbin account?") + .font(.callout) + Button(action: { + model.presentSignUpOption(.feedbin) + }, label: { + Text("Sign up here.").font(.callout) + }).buttonStyle(LinkButtonStyle()) + } + + HStack { + VStack(alignment: .trailing, spacing: 14) { + Text("Email") + Text("Password") + } + VStack(spacing: 8) { + TextField("me@email.com", text: $model.username) + SecureField("•••••••••••", text: $model.password) + } + } + + Text("Your username and password will be encrypted and stored in Keychain.") + .foregroundColor(.secondary) + .font(.callout) + .lineLimit(2) + .padding(.top, 4) + + Spacer() + HStack(spacing: 8) { + Spacer() + ProgressView() + .scaleEffect(CGSize(width: 0.5, height: 0.5)) + .hidden(!model.isAuthenticating) + Button(action: { + presentationMode.wrappedValue.dismiss() + }, label: { + Text("Cancel") + .frame(width: 60) + }).keyboardShortcut(.cancelAction) + + Button(action: { + model.authenticateFeedbin() + }, label: { + Text("Sign In") + .frame(width: 60) + }) + .keyboardShortcut(.defaultAction) + .disabled(model.username.isEmpty || model.password.isEmpty) + } + } + } + } + .padding() + .frame(minWidth: 400, maxWidth: 400, minHeight: 230, maxHeight: 260) + .textFieldStyle(RoundedBorderTextFieldStyle()) + .alert(isPresented: $model.showError, content: { + Alert(title: Text("Sign In Error"), message: Text(model.accountUpdateError.description), dismissButton: .cancel()) + }) + .onReceive(model.$canDismiss, perform: { value in + if value == true { + presentationMode.wrappedValue.dismiss() + } + }) + } + #endif + + var formHeader: some View { + HStack { + Spacer() + VStack(alignment: .center) { + AccountType.feedbin.image() + .resizable() + .frame(width: 50, height: 50) + } + Spacer() + }.padding(.vertical) + } + + var formFooter: some View { + HStack { + Spacer() + VStack(spacing: 8) { + Text("Sign in to your Feedbin account and sync your subscriptions across your devices. Your username and password and password will be encrypted and stored in Keychain.").foregroundColor(.secondary) + Text("Don't have a Feedbin account?").foregroundColor(.secondary) + Button(action: { + model.presentSignUpOption(.feedbin) + }, label: { + Text("Sign Up Here").foregroundColor(.blue).multilineTextAlignment(.center) + }) + ProgressView().hidden(!model.isAuthenticating) + } + .multilineTextAlignment(.center) + .font(.caption2) + Spacer() + + }.padding(.vertical) + } + + +} + +struct AddFeedbinAccountView_Previews: PreviewProvider { + static var previews: some View { + AddFeedbinAccountView() + } +} diff --git a/Multiplatform/Shared/Add/Add Account Sheets/AddFeedlyAccountView.swift b/Multiplatform/Shared/Add/Add Account Sheets/AddFeedlyAccountView.swift new file mode 100644 index 000000000..0fc0f7e90 --- /dev/null +++ b/Multiplatform/Shared/Add/Add Account Sheets/AddFeedlyAccountView.swift @@ -0,0 +1,149 @@ +// +// AddFeedlyAccountView.swift +// Multiplatform macOS +// +// Created by Stuart Breckenridge on 05/12/2020. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import SwiftUI +import Account +import RSCore +import RSWeb +import Secrets + +struct AddFeedlyAccountView: View { + + @Environment (\.presentationMode) var presentationMode + @StateObject private var model = AddFeedlyViewModel() + + var body: some View { + #if os(macOS) + macBody + #else + NavigationView { + iosBody + } + #endif + } + + + #if os(iOS) + var iosBody: some View { + List { + Section(header: formHeader, footer: formFooter, content: { + Button(action: { + model.authenticateFeedly() + }, label: { + HStack { + Spacer() + Text("Add Account") + Spacer() + } + }) + }) + }.navigationBarItems(leading: + Button(action: { + presentationMode.wrappedValue.dismiss() + }, label: { + Text("Cancel") + }) + ) + .navigationBarTitleDisplayMode(.inline) + .navigationTitle(Text(AccountType.feedly.localizedAccountName())) + .listStyle(InsetGroupedListStyle()) + + } + #endif + + #if os(macOS) + var macBody: some View { + VStack { + HStack(spacing: 16) { + VStack(alignment: .leading) { + AccountType.feedly.image() + .resizable() + .frame(width: 50, height: 50) + Spacer() + } + VStack(alignment: .leading, spacing: 8) { + Text("Sign in to your Feedly account.") + .font(.headline) + HStack { + Text("Don't have a Feedly account?") + .font(.callout) + Button(action: { + model.presentSignUpOption(.feedly) + }, label: { + Text("Sign up here.").font(.callout) + }).buttonStyle(LinkButtonStyle()) + } + + Spacer() + HStack(spacing: 8) { + Spacer() + Button(action: { + presentationMode.wrappedValue.dismiss() + }, label: { + Text("Cancel") + .frame(width: 60) + }).keyboardShortcut(.cancelAction) + + Button(action: { + model.authenticateFeedly() + presentationMode.wrappedValue.dismiss() + }, label: { + Text("Sign In") + .frame(width: 60) + }) + .keyboardShortcut(.defaultAction) + .disabled(AccountManager.shared.activeAccounts.filter({ $0.type == .cloudKit }).count > 0) + } + } + } + } + .padding() + .frame(minWidth: 400, maxWidth: 400, maxHeight: 150) + .alert(isPresented: $model.showError, content: { + Alert(title: Text("Sign In Error"), message: Text(model.accountUpdateError.description), dismissButton: .cancel()) + }) + } + #endif + + var formHeader: some View { + HStack { + Spacer() + VStack(alignment: .center) { + AccountType.feedly.image() + .resizable() + .frame(width: 50, height: 50) + } + Spacer() + }.padding(.vertical) + } + + var formFooter: some View { + HStack { + Spacer() + VStack(spacing: 8) { + Text("Sign in to your Feedly account and sync your subscriptions across your devices. Your username and password will be encrypted and stored in Keychain.\n\nDon't have an Feedly account?").foregroundColor(.secondary) + Button(action: { + model.presentSignUpOption(.feedly) + }, label: { + Text("Sign Up Here").foregroundColor(.blue).multilineTextAlignment(.center) + }) + } + .multilineTextAlignment(.center) + .font(.caption) + Spacer() + + }.padding(.vertical) + } + +} + +struct AddFeedlyAccountView_Previews: PreviewProvider { + static var previews: some View { + AddFeedlyAccountView() + } +} diff --git a/Multiplatform/Shared/Add/Add Account Sheets/AddLocalAccountView.swift b/Multiplatform/Shared/Add/Add Account Sheets/AddLocalAccountView.swift new file mode 100644 index 000000000..034ca07d3 --- /dev/null +++ b/Multiplatform/Shared/Add/Add Account Sheets/AddLocalAccountView.swift @@ -0,0 +1,140 @@ +// +// AddLocalAccountView.swift +// Multiplatform macOS +// +// Created by Stuart Breckenridge on 02/12/2020. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import SwiftUI +import Account +import RSCore + +struct AddLocalAccountView: View { + + @State private var newAccountName: String = "" + @Environment (\.presentationMode) var presentationMode + + var body: some View { + #if os(macOS) + macBody + #else + NavigationView { + iosBody + } + #endif + } + + #if os(iOS) + var iosBody: some View { + List { + Section(header: formHeader, content: { + TextField("Account Name", text: $newAccountName) + }) + + Section(footer: formFooter, content: { + Button(action: { + let newAccount = AccountManager.shared.createAccount(type: .onMyMac) + newAccount.name = newAccountName + presentationMode.wrappedValue.dismiss() + }, label: { + HStack { + Spacer() + Text("Add Account") + Spacer() + } + }) + }) + }.navigationBarItems(leading: + Button(action: { + presentationMode.wrappedValue.dismiss() + }, label: { + Text("Cancel") + }) + ) + .navigationBarTitleDisplayMode(.inline) + .navigationTitle(Text(AccountType.onMyMac.localizedAccountName())) + .listStyle(InsetGroupedListStyle()) + } + #endif + + #if os(macOS) + var macBody: some View { + VStack { + HStack(spacing: 16) { + VStack(alignment: .leading) { + AccountType.onMyMac.image() + .resizable() + .frame(width: 50, height: 50) + Spacer() + } + VStack(alignment: .leading, spacing: 8) { + Text("Create a local account on your Mac.") + .font(.headline) + Text("Local accounts store their data on your Mac. They do not sync across your devices.") + .font(.callout) + .foregroundColor(.secondary) + HStack { + Text("Name: ") + TextField("Account Name", text: $newAccountName) + }.padding(.top, 8) + Spacer() + HStack(spacing: 8) { + Spacer() + Button(action: { + presentationMode.wrappedValue.dismiss() + }, label: { + Text("Cancel") + .frame(width: 60) + }).keyboardShortcut(.cancelAction) + + Button(action: { + let newAccount = AccountManager.shared.createAccount(type: .onMyMac) + newAccount.name = newAccountName + presentationMode.wrappedValue.dismiss() + }, label: { + Text("Create") + .frame(width: 60) + }).keyboardShortcut(.defaultAction) + } + } + } + } + .padding() + .frame(minWidth: 400, maxWidth: 400, minHeight: 230, maxHeight: 260) + .textFieldStyle(RoundedBorderTextFieldStyle()) + } + #endif + + var formHeader: some View { + HStack { + Spacer() + VStack(alignment: .center) { + AccountType.onMyMac.image() + .resizable() + .frame(width: 50, height: 50) + } + Spacer() + }.padding(.vertical) + } + + var formFooter: some View { + HStack { + Spacer() + VStack(spacing: 8) { + Text("Local accounts do not sync your subscriptions across devices.").foregroundColor(.secondary) + } + .multilineTextAlignment(.center) + .font(.caption) + Spacer() + + }.padding(.vertical) + } + +} + +struct AddLocalAccount_Previews: PreviewProvider { + static var previews: some View { + AddLocalAccountView() + } +} diff --git a/Multiplatform/Shared/Add/Add Account Sheets/AddNewsBlurAccountView.swift b/Multiplatform/Shared/Add/Add Account Sheets/AddNewsBlurAccountView.swift new file mode 100644 index 000000000..dc6783589 --- /dev/null +++ b/Multiplatform/Shared/Add/Add Account Sheets/AddNewsBlurAccountView.swift @@ -0,0 +1,212 @@ +// +// AddNewsBlurAccountView.swift +// Multiplatform macOS +// +// Created by Stuart Breckenridge on 03/12/2020. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import SwiftUI +import Account +import RSCore +import RSWeb +import Secrets + +struct AddNewsBlurAccountView: View { + + @Environment (\.presentationMode) var presentationMode + @StateObject private var model = AddNewsBlurViewModel() + + var body: some View { + #if os(macOS) + macBody + #else + NavigationView { + iosBody + } + #endif + } + + #if os(iOS) + var iosBody: some View { + List { + Section(header: formHeader, content: { + TextField("Email", text: $model.username) + if model.showPassword == false { + ZStack { + HStack { + SecureField("Password", text: $model.password) + Spacer() + Image(systemName: "eye.fill") + .foregroundColor(.accentColor) + .onTapGesture { + model.showPassword = true + } + } + } + } + else { + ZStack { + HStack { + TextField("Password", text: $model.password) + Spacer() + Image(systemName: "eye.slash.fill") + .foregroundColor(.accentColor) + .onTapGesture { + model.showPassword = false + } + } + } + } + + }) + + Section(footer: formFooter, content: { + Button(action: { + model.authenticateNewsBlur() + }, label: { + HStack { + Spacer() + Text("Add Account") + Spacer() + } + }).disabled(model.username.isEmpty || model.password.isEmpty) + }) + + } + .navigationBarItems(leading: + Button(action: { + presentationMode.wrappedValue.dismiss() + }, label: { + Text("Cancel") + })) + .listStyle(InsetGroupedListStyle()) + .navigationBarTitleDisplayMode(.inline) + .navigationTitle(Text("NewsBlur")) + .alert(isPresented: $model.showError, content: { + Alert(title: Text("Sign In Error"), message: Text(model.accountUpdateError.description), dismissButton: .cancel(Text("Dismiss"))) + }) + .onReceive(model.$canDismiss, perform: { value in + if value == true { + presentationMode.wrappedValue.dismiss() + } + }) + } + #endif + + #if os(macOS) + var macBody: some View { + VStack { + HStack(spacing: 16) { + VStack(alignment: .leading) { + AccountType.newsBlur.image() + .frame(width: 50, height: 50) + Spacer() + } + VStack(alignment: .leading, spacing: 8) { + Text("Sign in to your NewsBlur account.") + .font(.headline) + HStack { + Text("Don't have a NewsBlur account?") + .font(.callout) + Button(action: { + model.presentSignUpOption(.newsBlur) + }, label: { + Text("Sign up here.").font(.callout) + }).buttonStyle(LinkButtonStyle()) + } + + HStack { + VStack(alignment: .trailing, spacing: 14) { + Text("Email") + Text("Password") + } + VStack(spacing: 8) { + TextField("me@email.com", text: $model.username) + SecureField("•••••••••••", text: $model.password) + } + } + + Text("Your username and password will be encrypted and stored in Keychain.") + .foregroundColor(.secondary) + .font(.callout) + .lineLimit(2) + .padding(.top, 4) + + Spacer() + HStack(spacing: 8) { + Spacer() + ProgressView() + .scaleEffect(CGSize(width: 0.5, height: 0.5)) + .hidden(!model.isAuthenticating) + Button(action: { + presentationMode.wrappedValue.dismiss() + }, label: { + Text("Cancel") + .frame(width: 60) + }).keyboardShortcut(.cancelAction) + + Button(action: { + model.authenticateNewsBlur() + }, label: { + Text("Sign In") + .frame(width: 60) + }) + .keyboardShortcut(.defaultAction) + .disabled(model.username.isEmpty || model.password.isEmpty) + } + } + } + } + .padding() + .frame(minWidth: 400, maxWidth: 400, minHeight: 230, maxHeight: 260) + .textFieldStyle(RoundedBorderTextFieldStyle()) + .alert(isPresented: $model.showError, content: { + Alert(title: Text("Sign In Error"), message: Text(model.accountUpdateError.description), dismissButton: .cancel()) + }) + .onReceive(model.$canDismiss, perform: { value in + if value == true { + presentationMode.wrappedValue.dismiss() + } + }) + } + #endif + + var formHeader: some View { + HStack { + Spacer() + VStack(alignment: .center) { + AccountType.newsBlur.image() + .resizable() + .frame(width: 50, height: 50) + } + Spacer() + }.padding(.vertical) + } + + var formFooter: some View { + HStack { + Spacer() + VStack(spacing: 8) { + Text("Sign in to your NewsBlur account and sync your subscriptions across your devices. Your username and password and password will be encrypted and stored in Keychain.").foregroundColor(.secondary) + Text("Don't have a NewsBlur account?").foregroundColor(.secondary) + Button(action: { + model.presentSignUpOption(.newsBlur) + }, label: { + Text("Sign Up Here").foregroundColor(.blue).multilineTextAlignment(.center) + }) + ProgressView().hidden(!model.isAuthenticating) + } + .multilineTextAlignment(.center) + .font(.caption2) + Spacer() + + }.padding(.vertical) + } +} + +struct AddNewsBlurAccountView_Previews: PreviewProvider { + static var previews: some View { + AddNewsBlurAccountView() + } +} diff --git a/Multiplatform/Shared/Add/Add Account Sheets/AddReaderAPIAccountView.swift b/Multiplatform/Shared/Add/Add Account Sheets/AddReaderAPIAccountView.swift new file mode 100644 index 000000000..53359633a --- /dev/null +++ b/Multiplatform/Shared/Add/Add Account Sheets/AddReaderAPIAccountView.swift @@ -0,0 +1,247 @@ +// +// AddReaderAPIAccountView.swift +// Multiplatform macOS +// +// Created by Stuart Breckenridge on 03/12/2020. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import SwiftUI +import Account +import RSCore +import RSWeb +import Secrets + +struct AddReaderAPIAccountView: View { + + @Environment (\.presentationMode) var presentationMode + @StateObject private var model = AddReaderAPIViewModel() + public var accountType: AccountType + + var body: some View { + #if os(macOS) + macBody + #else + NavigationView { + iosBody + } + #endif + } + + #if os(iOS) + var iosBody: some View { + List { + Section(header: formHeader, content: { + TextField("Email", text: $model.username) + if model.showPassword == false { + ZStack { + HStack { + SecureField("Password", text: $model.password) + Spacer() + Image(systemName: "eye.fill") + .foregroundColor(.accentColor) + .onTapGesture { + model.showPassword = true + } + } + } + } + else { + ZStack { + HStack { + TextField("Password", text: $model.password) + Spacer() + Image(systemName: "eye.slash.fill") + .foregroundColor(.accentColor) + .onTapGesture { + model.showPassword = false + } + } + } + } + if accountType == .freshRSS { + TextField("API URL", text: $model.apiUrl) + } + + }) + + Section(footer: formFooter, content: { + Button(action: { + model.authenticateReaderAccount(accountType) + }, label: { + HStack { + Spacer() + Text("Add Account") + Spacer() + } + }).disabled(createDisabled()) + }) + + } + .navigationBarItems(leading: + Button(action: { + presentationMode.wrappedValue.dismiss() + }, label: { + Text("Cancel") + })) + .listStyle(InsetGroupedListStyle()) + .navigationBarTitleDisplayMode(.inline) + .navigationTitle(Text(accountType.localizedAccountName())) + .alert(isPresented: $model.showError, content: { + Alert(title: Text("Sign In Error"), message: Text(model.accountUpdateError.description), dismissButton: .cancel(Text("Dismiss"))) + }) + .onReceive(model.$canDismiss, perform: { value in + if value == true { + presentationMode.wrappedValue.dismiss() + } + }) + } + #endif + + #if os(macOS) + var macBody: some View { + VStack { + HStack(spacing: 16) { + VStack(alignment: .leading) { + accountType.image() + .resizable() + .frame(width: 50, height: 50) + Spacer() + } + VStack(alignment: .leading, spacing: 8) { + Text("Sign in to your \(accountType.localizedAccountName()) account.") + .font(.headline) + HStack { + if accountType == .freshRSS { + Text("Don't have a \(accountType.localizedAccountName()) instance?") + .font(.callout) + } else { + Text("Don't have an \(accountType.localizedAccountName()) account?") + .font(.callout) + } + Button(action: { + model.presentSignUpOption(accountType) + }, label: { + Text(accountType == .freshRSS ? "Find out more." : "Sign up here.").font(.callout) + }).buttonStyle(LinkButtonStyle()) + } + + HStack { + VStack(alignment: .trailing, spacing: 14) { + Text("Email") + Text("Password") + if accountType == .freshRSS { + Text("API URL") + } + } + VStack(spacing: 8) { + TextField("me@email.com", text: $model.username) + SecureField("•••••••••••", text: $model.password) + if accountType == .freshRSS { + TextField("https://myfreshrss.rocks", text: $model.apiUrl) + } + } + } + + Text("Your username and password will be encrypted and stored in Keychain.") + .foregroundColor(.secondary) + .font(.callout) + .lineLimit(2) + .padding(.top, 4) + + Spacer() + HStack(spacing: 8) { + Spacer() + ProgressView() + .scaleEffect(CGSize(width: 0.5, height: 0.5)) + .hidden(!model.isAuthenticating) + Button(action: { + presentationMode.wrappedValue.dismiss() + }, label: { + Text("Cancel") + .frame(width: 60) + }).keyboardShortcut(.cancelAction) + + Button(action: { + model.authenticateReaderAccount(accountType) + }, label: { + Text("Sign In") + .frame(width: 60) + }) + .keyboardShortcut(.defaultAction) + .disabled(createDisabled()) + } + } + } + } + .padding() + .frame(width: 400, height: height()) + .textFieldStyle(RoundedBorderTextFieldStyle()) + .alert(isPresented: $model.showError, content: { + Alert(title: Text("Sign In Error"), message: Text(model.accountUpdateError.description), dismissButton: .cancel()) + }) + .onReceive(model.$canDismiss, perform: { value in + if value == true { + presentationMode.wrappedValue.dismiss() + } + }) + } + #endif + + + + + func createDisabled() -> Bool { + if accountType == .freshRSS { + return model.username.isEmpty || model.password.isEmpty || !model.apiUrl.mayBeURL + } + return model.username.isEmpty || model.password.isEmpty + } + + func height() -> CGFloat { + if accountType == .freshRSS { + return 260 + } + return 230 + } + + var formHeader: some View { + HStack { + Spacer() + VStack(alignment: .center) { + accountType.image() + .resizable() + .frame(width: 50, height: 50) + } + Spacer() + }.padding(.vertical) + } + + var formFooter: some View { + HStack { + Spacer() + VStack(spacing: 8) { + Text("Sign in to your \(accountType.localizedAccountName()) account and sync your subscriptions across your devices. Your username and password and password will be encrypted and stored in Keychain.").foregroundColor(.secondary) + Text("Don't have a \(accountType.localizedAccountName()) instance?").foregroundColor(.secondary) + Button(action: { + model.presentSignUpOption(accountType) + }, label: { + Text("Sign Up Here").foregroundColor(.blue).multilineTextAlignment(.center) + }) + ProgressView().hidden(!model.isAuthenticating) + } + .multilineTextAlignment(.center) + .font(.caption2) + Spacer() + + }.padding(.vertical) + } + +} + +struct AddReaderAPIAccountView_Previews: PreviewProvider { + static var previews: some View { + AddReaderAPIAccountView(accountType: .freshRSS) + //AddReaderAPIAccountView(accountType: .inoreader) + } +} diff --git a/Multiplatform/Shared/Add/Add Account Sheets/Authentication.swift b/Multiplatform/Shared/Add/Add Account Sheets/Authentication.swift new file mode 100644 index 000000000..026f7ab4f --- /dev/null +++ b/Multiplatform/Shared/Add/Add Account Sheets/Authentication.swift @@ -0,0 +1,13 @@ +// +// Authentication.swift +// Multiplatform macOS +// +// Created by Stuart Breckenridge on 05/12/2020. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import Foundation + +protocol AccountUpdater { + var authenticationError: AccountUpdateErrors { get set } +} diff --git a/Multiplatform/Shared/AppAssets.swift b/Multiplatform/Shared/AppAssets.swift index 244c5fb87..fca390e06 100644 --- a/Multiplatform/Shared/AppAssets.swift +++ b/Multiplatform/Shared/AppAssets.swift @@ -18,40 +18,53 @@ struct AppAssets { }() #endif + static var accountBazQux: RSImage! = { + return RSImage(named: "accountBazQux") + }() + + static var accountLocalMacImage: RSImage! = { - return RSImage(named: "AccountLocalMac") + return RSImage(named: "accountLocalMac") }() static var accountLocalPadImage: RSImage = { - return RSImage(named: "AccountLocalPad")! + return RSImage(named: "accountLocalPad")! }() static var accountLocalPhoneImage: RSImage = { - return RSImage(named: "AccountLocalPhone")! + return RSImage(named: "accountLocalPhone")! }() static var accountCloudKitImage: RSImage = { - return RSImage(named: "AccountCloudKit")! + return RSImage(named: "accountCloudKit")! }() static var accountFeedbinImage: RSImage = { - return RSImage(named: "AccountFeedbin")! + return RSImage(named: "accountFeedbin")! }() static var accountFeedlyImage: RSImage = { - return RSImage(named: "AccountFeedly")! + return RSImage(named: "accountFeedly")! }() static var accountFeedWranglerImage: RSImage = { - return RSImage(named: "AccountFeedWrangler")! + return RSImage(named: "accountFeedWrangler")! }() static var accountFreshRSSImage: RSImage = { - return RSImage(named: "AccountFreshRSS")! + return RSImage(named: "accountFreshRSS")! + }() + + static var accountInoreader: RSImage! = { + return RSImage(named: "accountInoreader") }() static var accountNewsBlurImage: RSImage = { - return RSImage(named: "AccountNewsBlur")! + return RSImage(named: "accountNewsBlur")! + }() + + static var accountTheOldReader: RSImage! = { + return RSImage(named: "accountTheOldReader") }() static var addMenuImage: Image = { @@ -325,6 +338,8 @@ struct AppAssets { return AppAssets.accountLocalPhoneImage } #endif + case .bazQux: + return AppAssets.accountBazQux case .cloudKit: return AppAssets.accountCloudKitImage case .feedbin: @@ -337,6 +352,11 @@ struct AppAssets { return AppAssets.accountFreshRSSImage case .newsBlur: return AppAssets.accountNewsBlurImage + case .inoreader: + return AppAssets.accountInoreader + case .theOldReader: + return AppAssets.accountTheOldReader + } } diff --git a/Multiplatform/Shared/Assets.xcassets/AccountCloudKit.imageset/Contents.json b/Multiplatform/Shared/Assets.xcassets/AccountCloudKit.imageset/Contents.json index fc07d2975..b2f51e691 100644 --- a/Multiplatform/Shared/Assets.xcassets/AccountCloudKit.imageset/Contents.json +++ b/Multiplatform/Shared/Assets.xcassets/AccountCloudKit.imageset/Contents.json @@ -1,7 +1,17 @@ { "images" : [ { - "filename" : "icloud.pdf", + "filename" : "icloud-any.pdf", + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "icloud-dark.pdf", "idiom" : "universal" } ], @@ -10,6 +20,6 @@ "version" : 1 }, "properties" : { - "template-rendering-intent" : "template" + "template-rendering-intent" : "original" } } diff --git a/Multiplatform/Shared/Assets.xcassets/AccountCloudKit.imageset/icloud-any.pdf b/Multiplatform/Shared/Assets.xcassets/AccountCloudKit.imageset/icloud-any.pdf new file mode 100644 index 000000000..79ba7e3eb Binary files /dev/null and b/Multiplatform/Shared/Assets.xcassets/AccountCloudKit.imageset/icloud-any.pdf differ diff --git a/Multiplatform/Shared/Assets.xcassets/AccountCloudKit.imageset/icloud-dark.pdf b/Multiplatform/Shared/Assets.xcassets/AccountCloudKit.imageset/icloud-dark.pdf new file mode 100644 index 000000000..e876337ac Binary files /dev/null and b/Multiplatform/Shared/Assets.xcassets/AccountCloudKit.imageset/icloud-dark.pdf differ diff --git a/Multiplatform/Shared/Assets.xcassets/AccountFeedWrangler.imageset/Contents.json b/Multiplatform/Shared/Assets.xcassets/AccountFeedWrangler.imageset/Contents.json index 5e337ee42..f7b68151c 100644 --- a/Multiplatform/Shared/Assets.xcassets/AccountFeedWrangler.imageset/Contents.json +++ b/Multiplatform/Shared/Assets.xcassets/AccountFeedWrangler.imageset/Contents.json @@ -1,8 +1,52 @@ { "images" : [ { - "filename" : "outline-512.png", - "idiom" : "universal" + "filename" : "feedwranger-any-slice.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "feedwranger-dark-slice.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "feedwranger-any-slice@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "feedwranger-dark-slice@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "feedwranger-any-slice@3x.png", + "idiom" : "universal", + "scale" : "3x" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "feedwranger-dark-slice@3x.png", + "idiom" : "universal", + "scale" : "3x" } ], "info" : { @@ -10,6 +54,6 @@ "version" : 1 }, "properties" : { - "template-rendering-intent" : "template" + "template-rendering-intent" : "original" } } diff --git a/Multiplatform/Shared/Assets.xcassets/AccountFeedWrangler.imageset/feedwranger-any-slice.png b/Multiplatform/Shared/Assets.xcassets/AccountFeedWrangler.imageset/feedwranger-any-slice.png new file mode 100644 index 000000000..a04e07f9a Binary files /dev/null and b/Multiplatform/Shared/Assets.xcassets/AccountFeedWrangler.imageset/feedwranger-any-slice.png differ diff --git a/Multiplatform/Shared/Assets.xcassets/AccountFeedWrangler.imageset/feedwranger-any-slice@2x.png b/Multiplatform/Shared/Assets.xcassets/AccountFeedWrangler.imageset/feedwranger-any-slice@2x.png new file mode 100644 index 000000000..dd25a60ae Binary files /dev/null and b/Multiplatform/Shared/Assets.xcassets/AccountFeedWrangler.imageset/feedwranger-any-slice@2x.png differ diff --git a/Multiplatform/Shared/Assets.xcassets/AccountFeedWrangler.imageset/feedwranger-any-slice@3x.png b/Multiplatform/Shared/Assets.xcassets/AccountFeedWrangler.imageset/feedwranger-any-slice@3x.png new file mode 100644 index 000000000..1fceca03d Binary files /dev/null and b/Multiplatform/Shared/Assets.xcassets/AccountFeedWrangler.imageset/feedwranger-any-slice@3x.png differ diff --git a/Multiplatform/Shared/Assets.xcassets/AccountFeedWrangler.imageset/feedwranger-dark-slice.png b/Multiplatform/Shared/Assets.xcassets/AccountFeedWrangler.imageset/feedwranger-dark-slice.png new file mode 100644 index 000000000..ff1990102 Binary files /dev/null and b/Multiplatform/Shared/Assets.xcassets/AccountFeedWrangler.imageset/feedwranger-dark-slice.png differ diff --git a/Multiplatform/Shared/Assets.xcassets/AccountFeedWrangler.imageset/feedwranger-dark-slice@2x.png b/Multiplatform/Shared/Assets.xcassets/AccountFeedWrangler.imageset/feedwranger-dark-slice@2x.png new file mode 100644 index 000000000..e2e52edb5 Binary files /dev/null and b/Multiplatform/Shared/Assets.xcassets/AccountFeedWrangler.imageset/feedwranger-dark-slice@2x.png differ diff --git a/Multiplatform/Shared/Assets.xcassets/AccountFeedWrangler.imageset/feedwranger-dark-slice@3x.png b/Multiplatform/Shared/Assets.xcassets/AccountFeedWrangler.imageset/feedwranger-dark-slice@3x.png new file mode 100644 index 000000000..e1640465a Binary files /dev/null and b/Multiplatform/Shared/Assets.xcassets/AccountFeedWrangler.imageset/feedwranger-dark-slice@3x.png differ diff --git a/Multiplatform/Shared/Assets.xcassets/AccountFeedWrangler.imageset/outline-512.png b/Multiplatform/Shared/Assets.xcassets/AccountFeedWrangler.imageset/outline-512.png deleted file mode 100644 index f7d29faa1..000000000 Binary files a/Multiplatform/Shared/Assets.xcassets/AccountFeedWrangler.imageset/outline-512.png and /dev/null differ diff --git a/Multiplatform/Shared/Assets.xcassets/AccountFeedbin.imageset/Contents.json b/Multiplatform/Shared/Assets.xcassets/AccountFeedbin.imageset/Contents.json index 3495fe8ef..1b0780896 100644 --- a/Multiplatform/Shared/Assets.xcassets/AccountFeedbin.imageset/Contents.json +++ b/Multiplatform/Shared/Assets.xcassets/AccountFeedbin.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "feedbin-logo.pdf", + "filename" : "feedbin.pdf", "idiom" : "universal" } ], @@ -11,6 +11,6 @@ }, "properties" : { "preserves-vector-representation" : true, - "template-rendering-intent" : "template" + "template-rendering-intent" : "original" } } diff --git a/Multiplatform/Shared/Assets.xcassets/AccountFeedbin.imageset/feedbin-logo.pdf b/Multiplatform/Shared/Assets.xcassets/AccountFeedbin.imageset/feedbin-logo.pdf deleted file mode 100644 index de686614a..000000000 Binary files a/Multiplatform/Shared/Assets.xcassets/AccountFeedbin.imageset/feedbin-logo.pdf and /dev/null differ diff --git a/Multiplatform/Shared/Assets.xcassets/AccountFeedbin.imageset/feedbin.pdf b/Multiplatform/Shared/Assets.xcassets/AccountFeedbin.imageset/feedbin.pdf new file mode 100644 index 000000000..8892e9db6 Binary files /dev/null and b/Multiplatform/Shared/Assets.xcassets/AccountFeedbin.imageset/feedbin.pdf differ diff --git a/Multiplatform/Shared/Assets.xcassets/AccountFeedly.imageset/Contents.json b/Multiplatform/Shared/Assets.xcassets/AccountFeedly.imageset/Contents.json index 4034be795..236ba8fa6 100644 --- a/Multiplatform/Shared/Assets.xcassets/AccountFeedly.imageset/Contents.json +++ b/Multiplatform/Shared/Assets.xcassets/AccountFeedly.imageset/Contents.json @@ -1,7 +1,17 @@ { "images" : [ { - "filename" : "accountFeedly.pdf", + "filename" : "feedly-logo-any.pdf", + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "feedly-logo-dark.pdf", "idiom" : "universal" } ], @@ -10,6 +20,6 @@ "version" : 1 }, "properties" : { - "template-rendering-intent" : "template" + "template-rendering-intent" : "original" } } diff --git a/Multiplatform/Shared/Assets.xcassets/AccountFeedly.imageset/feedly-logo-any.pdf b/Multiplatform/Shared/Assets.xcassets/AccountFeedly.imageset/feedly-logo-any.pdf new file mode 100644 index 000000000..e1ccaab94 Binary files /dev/null and b/Multiplatform/Shared/Assets.xcassets/AccountFeedly.imageset/feedly-logo-any.pdf differ diff --git a/Multiplatform/Shared/Assets.xcassets/AccountFeedly.imageset/feedly-logo-dark.pdf b/Multiplatform/Shared/Assets.xcassets/AccountFeedly.imageset/feedly-logo-dark.pdf new file mode 100644 index 000000000..f287b271b Binary files /dev/null and b/Multiplatform/Shared/Assets.xcassets/AccountFeedly.imageset/feedly-logo-dark.pdf differ diff --git a/Multiplatform/Shared/Assets.xcassets/AccountFreshRSS.imageset/Contents.json b/Multiplatform/Shared/Assets.xcassets/AccountFreshRSS.imageset/Contents.json index 64a29ab45..f71a580b8 100644 --- a/Multiplatform/Shared/Assets.xcassets/AccountFreshRSS.imageset/Contents.json +++ b/Multiplatform/Shared/Assets.xcassets/AccountFreshRSS.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "accountFreshRSS.pdf", + "filename" : "FreshRSS.pdf", "idiom" : "universal" } ], @@ -10,6 +10,6 @@ "version" : 1 }, "properties" : { - "template-rendering-intent" : "template" + "template-rendering-intent" : "original" } } diff --git a/Multiplatform/Shared/Assets.xcassets/AccountFreshRSS.imageset/FreshRSS.pdf b/Multiplatform/Shared/Assets.xcassets/AccountFreshRSS.imageset/FreshRSS.pdf new file mode 100644 index 000000000..d9ba3f3ea Binary files /dev/null and b/Multiplatform/Shared/Assets.xcassets/AccountFreshRSS.imageset/FreshRSS.pdf differ diff --git a/Multiplatform/Shared/Assets.xcassets/AccountLocalMac.imageset/mac.pdf b/Multiplatform/Shared/Assets.xcassets/AccountLocalMac.imageset/mac.pdf deleted file mode 100644 index 7262b2c97..000000000 Binary files a/Multiplatform/Shared/Assets.xcassets/AccountLocalMac.imageset/mac.pdf and /dev/null differ diff --git a/Multiplatform/Shared/Assets.xcassets/AccountLocalPad.imageset/Contents.json b/Multiplatform/Shared/Assets.xcassets/AccountLocalPad.imageset/Contents.json index d9272e8cb..e072222a1 100644 --- a/Multiplatform/Shared/Assets.xcassets/AccountLocalPad.imageset/Contents.json +++ b/Multiplatform/Shared/Assets.xcassets/AccountLocalPad.imageset/Contents.json @@ -1,7 +1,17 @@ { "images" : [ { - "filename" : "ipad.pdf", + "filename" : "ipad-any-slice.pdf", + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "ipad-dark-slice.pdf", "idiom" : "universal" } ], @@ -11,6 +21,6 @@ }, "properties" : { "preserves-vector-representation" : true, - "template-rendering-intent" : "template" + "template-rendering-intent" : "original" } } diff --git a/Multiplatform/Shared/Assets.xcassets/AccountLocalPad.imageset/ipad-any-slice.pdf b/Multiplatform/Shared/Assets.xcassets/AccountLocalPad.imageset/ipad-any-slice.pdf new file mode 100644 index 000000000..91665fa1b Binary files /dev/null and b/Multiplatform/Shared/Assets.xcassets/AccountLocalPad.imageset/ipad-any-slice.pdf differ diff --git a/Multiplatform/Shared/Assets.xcassets/AccountLocalPad.imageset/ipad-dark-slice.pdf b/Multiplatform/Shared/Assets.xcassets/AccountLocalPad.imageset/ipad-dark-slice.pdf new file mode 100644 index 000000000..9091a096b Binary files /dev/null and b/Multiplatform/Shared/Assets.xcassets/AccountLocalPad.imageset/ipad-dark-slice.pdf differ diff --git a/Multiplatform/Shared/Assets.xcassets/AccountLocalPad.imageset/ipad.pdf b/Multiplatform/Shared/Assets.xcassets/AccountLocalPad.imageset/ipad.pdf deleted file mode 100644 index a74725c7d..000000000 Binary files a/Multiplatform/Shared/Assets.xcassets/AccountLocalPad.imageset/ipad.pdf and /dev/null differ diff --git a/Multiplatform/Shared/Assets.xcassets/AccountLocalPhone.imageset/Contents.json b/Multiplatform/Shared/Assets.xcassets/AccountLocalPhone.imageset/Contents.json index b5a4070e5..04d21c05f 100644 --- a/Multiplatform/Shared/Assets.xcassets/AccountLocalPhone.imageset/Contents.json +++ b/Multiplatform/Shared/Assets.xcassets/AccountLocalPhone.imageset/Contents.json @@ -1,7 +1,17 @@ { "images" : [ { - "filename" : "phone.pdf", + "filename" : "iphone-any-slice.pdf", + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "iphone-dark-slice.pdf", "idiom" : "universal" } ], @@ -11,6 +21,6 @@ }, "properties" : { "preserves-vector-representation" : true, - "template-rendering-intent" : "template" + "template-rendering-intent" : "original" } } diff --git a/Multiplatform/Shared/Assets.xcassets/AccountLocalPhone.imageset/iphone-any-slice.pdf b/Multiplatform/Shared/Assets.xcassets/AccountLocalPhone.imageset/iphone-any-slice.pdf new file mode 100644 index 000000000..f36056970 Binary files /dev/null and b/Multiplatform/Shared/Assets.xcassets/AccountLocalPhone.imageset/iphone-any-slice.pdf differ diff --git a/Multiplatform/Shared/Assets.xcassets/AccountLocalPhone.imageset/iphone-dark-slice.pdf b/Multiplatform/Shared/Assets.xcassets/AccountLocalPhone.imageset/iphone-dark-slice.pdf new file mode 100644 index 000000000..cf2247077 Binary files /dev/null and b/Multiplatform/Shared/Assets.xcassets/AccountLocalPhone.imageset/iphone-dark-slice.pdf differ diff --git a/Multiplatform/Shared/Assets.xcassets/AccountLocalPhone.imageset/phone.pdf b/Multiplatform/Shared/Assets.xcassets/AccountLocalPhone.imageset/phone.pdf deleted file mode 100644 index f068353d1..000000000 Binary files a/Multiplatform/Shared/Assets.xcassets/AccountLocalPhone.imageset/phone.pdf and /dev/null differ diff --git a/Multiplatform/Shared/Assets.xcassets/AccountNewsBlur.imageset/Contents.json b/Multiplatform/Shared/Assets.xcassets/AccountNewsBlur.imageset/Contents.json index 9b23ec7d3..a73c591f6 100644 --- a/Multiplatform/Shared/Assets.xcassets/AccountNewsBlur.imageset/Contents.json +++ b/Multiplatform/Shared/Assets.xcassets/AccountNewsBlur.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "newsblur-512.png", + "filename" : "Newsblur-any.pdf", "idiom" : "universal" } ], @@ -10,6 +10,6 @@ "version" : 1 }, "properties" : { - "template-rendering-intent" : "template" + "template-rendering-intent" : "original" } } diff --git a/Multiplatform/Shared/Assets.xcassets/AccountNewsBlur.imageset/Newsblur-any.pdf b/Multiplatform/Shared/Assets.xcassets/AccountNewsBlur.imageset/Newsblur-any.pdf new file mode 100644 index 000000000..216dc4f8a Binary files /dev/null and b/Multiplatform/Shared/Assets.xcassets/AccountNewsBlur.imageset/Newsblur-any.pdf differ diff --git a/Multiplatform/Shared/Assets.xcassets/AccountNewsBlur.imageset/newsblur-512.png b/Multiplatform/Shared/Assets.xcassets/AccountNewsBlur.imageset/newsblur-512.png deleted file mode 100644 index 5fab67691..000000000 Binary files a/Multiplatform/Shared/Assets.xcassets/AccountNewsBlur.imageset/newsblur-512.png and /dev/null differ diff --git a/Multiplatform/Shared/Assets.xcassets/AccountLocalMac.imageset/Contents.json b/Multiplatform/Shared/Assets.xcassets/accountBazQux.imageset/Contents.json similarity index 53% rename from Multiplatform/Shared/Assets.xcassets/AccountLocalMac.imageset/Contents.json rename to Multiplatform/Shared/Assets.xcassets/accountBazQux.imageset/Contents.json index 2b1ddc334..25d8387f8 100644 --- a/Multiplatform/Shared/Assets.xcassets/AccountLocalMac.imageset/Contents.json +++ b/Multiplatform/Shared/Assets.xcassets/accountBazQux.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "mac.pdf", + "filename" : "bazqux-any.pdf", "idiom" : "universal" } ], @@ -10,6 +10,7 @@ "version" : 1 }, "properties" : { - "template-rendering-intent" : "template" + "preserves-vector-representation" : true, + "template-rendering-intent" : "original" } } diff --git a/Multiplatform/Shared/Assets.xcassets/accountBazQux.imageset/bazqux-any.pdf b/Multiplatform/Shared/Assets.xcassets/accountBazQux.imageset/bazqux-any.pdf new file mode 100644 index 000000000..d13a0defd Binary files /dev/null and b/Multiplatform/Shared/Assets.xcassets/accountBazQux.imageset/bazqux-any.pdf differ diff --git a/Multiplatform/Shared/Assets.xcassets/accountInoreader.imageset/Contents.json b/Multiplatform/Shared/Assets.xcassets/accountInoreader.imageset/Contents.json new file mode 100644 index 000000000..8711b150a --- /dev/null +++ b/Multiplatform/Shared/Assets.xcassets/accountInoreader.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "inoreader_logo-any.pdf", + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "inoreader_logo-dark.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true, + "template-rendering-intent" : "original" + } +} diff --git a/Multiplatform/Shared/Assets.xcassets/accountInoreader.imageset/inoreader_logo-any.pdf b/Multiplatform/Shared/Assets.xcassets/accountInoreader.imageset/inoreader_logo-any.pdf new file mode 100644 index 000000000..4c5befe74 Binary files /dev/null and b/Multiplatform/Shared/Assets.xcassets/accountInoreader.imageset/inoreader_logo-any.pdf differ diff --git a/Multiplatform/Shared/Assets.xcassets/accountInoreader.imageset/inoreader_logo-dark.pdf b/Multiplatform/Shared/Assets.xcassets/accountInoreader.imageset/inoreader_logo-dark.pdf new file mode 100644 index 000000000..2ab5d34dd Binary files /dev/null and b/Multiplatform/Shared/Assets.xcassets/accountInoreader.imageset/inoreader_logo-dark.pdf differ diff --git a/Multiplatform/Shared/Assets.xcassets/accountLocal.imageset/Contents.json b/Multiplatform/Shared/Assets.xcassets/accountLocal.imageset/Contents.json new file mode 100644 index 000000000..63f3b392e --- /dev/null +++ b/Multiplatform/Shared/Assets.xcassets/accountLocal.imageset/Contents.json @@ -0,0 +1,25 @@ +{ + "images" : [ + { + "filename" : "localAccountLight.pdf", + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "localAccountDark-1.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/Multiplatform/Shared/Assets.xcassets/AccountFreshRSS.imageset/accountFreshRSS.pdf b/Multiplatform/Shared/Assets.xcassets/accountLocal.imageset/localAccountDark-1.pdf similarity index 68% rename from Multiplatform/Shared/Assets.xcassets/AccountFreshRSS.imageset/accountFreshRSS.pdf rename to Multiplatform/Shared/Assets.xcassets/accountLocal.imageset/localAccountDark-1.pdf index 1ff98e115..584b84f4a 100644 Binary files a/Multiplatform/Shared/Assets.xcassets/AccountFreshRSS.imageset/accountFreshRSS.pdf and b/Multiplatform/Shared/Assets.xcassets/accountLocal.imageset/localAccountDark-1.pdf differ diff --git a/Multiplatform/Shared/Assets.xcassets/AccountCloudKit.imageset/icloud.pdf b/Multiplatform/Shared/Assets.xcassets/accountLocal.imageset/localAccountLight.pdf similarity index 67% rename from Multiplatform/Shared/Assets.xcassets/AccountCloudKit.imageset/icloud.pdf rename to Multiplatform/Shared/Assets.xcassets/accountLocal.imageset/localAccountLight.pdf index 74406f4cb..d3d3d40e2 100644 Binary files a/Multiplatform/Shared/Assets.xcassets/AccountCloudKit.imageset/icloud.pdf and b/Multiplatform/Shared/Assets.xcassets/accountLocal.imageset/localAccountLight.pdf differ diff --git a/Multiplatform/Shared/Assets.xcassets/accountLocalMac.imageset/Contents.json b/Multiplatform/Shared/Assets.xcassets/accountLocalMac.imageset/Contents.json new file mode 100644 index 000000000..63f3b392e --- /dev/null +++ b/Multiplatform/Shared/Assets.xcassets/accountLocalMac.imageset/Contents.json @@ -0,0 +1,25 @@ +{ + "images" : [ + { + "filename" : "localAccountLight.pdf", + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "localAccountDark-1.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/Multiplatform/Shared/Assets.xcassets/AccountFeedly.imageset/accountFeedly.pdf b/Multiplatform/Shared/Assets.xcassets/accountLocalMac.imageset/localAccountDark-1.pdf similarity index 64% rename from Multiplatform/Shared/Assets.xcassets/AccountFeedly.imageset/accountFeedly.pdf rename to Multiplatform/Shared/Assets.xcassets/accountLocalMac.imageset/localAccountDark-1.pdf index 907e486bc..584b84f4a 100644 Binary files a/Multiplatform/Shared/Assets.xcassets/AccountFeedly.imageset/accountFeedly.pdf and b/Multiplatform/Shared/Assets.xcassets/accountLocalMac.imageset/localAccountDark-1.pdf differ diff --git a/Multiplatform/Shared/Assets.xcassets/accountLocalMac.imageset/localAccountLight.pdf b/Multiplatform/Shared/Assets.xcassets/accountLocalMac.imageset/localAccountLight.pdf new file mode 100644 index 000000000..d3d3d40e2 Binary files /dev/null and b/Multiplatform/Shared/Assets.xcassets/accountLocalMac.imageset/localAccountLight.pdf differ diff --git a/Multiplatform/Shared/Assets.xcassets/accountTheOldReader.imageset/Contents.json b/Multiplatform/Shared/Assets.xcassets/accountTheOldReader.imageset/Contents.json new file mode 100644 index 000000000..231c33ab0 --- /dev/null +++ b/Multiplatform/Shared/Assets.xcassets/accountTheOldReader.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "oldreader-icon-any.pdf", + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "oldreader-icon-dark.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true, + "template-rendering-intent" : "original" + } +} diff --git a/Multiplatform/Shared/Assets.xcassets/accountTheOldReader.imageset/oldreader-icon-any.pdf b/Multiplatform/Shared/Assets.xcassets/accountTheOldReader.imageset/oldreader-icon-any.pdf new file mode 100644 index 000000000..05b0003b1 Binary files /dev/null and b/Multiplatform/Shared/Assets.xcassets/accountTheOldReader.imageset/oldreader-icon-any.pdf differ diff --git a/Multiplatform/Shared/Assets.xcassets/accountTheOldReader.imageset/oldreader-icon-dark.pdf b/Multiplatform/Shared/Assets.xcassets/accountTheOldReader.imageset/oldreader-icon-dark.pdf new file mode 100644 index 000000000..dfe4ce8b4 Binary files /dev/null and b/Multiplatform/Shared/Assets.xcassets/accountTheOldReader.imageset/oldreader-icon-dark.pdf differ diff --git a/Multiplatform/iOS/Settings/Accounts/SettingsAddAccountView.swift b/Multiplatform/iOS/Settings/Accounts/SettingsAddAccountView.swift index a42caeb0f..c8855409e 100644 --- a/Multiplatform/iOS/Settings/Accounts/SettingsAddAccountView.swift +++ b/Multiplatform/iOS/Settings/Accounts/SettingsAddAccountView.swift @@ -27,15 +27,21 @@ struct SettingsAddAccountView: View { } .listStyle(InsetGroupedListStyle()) .sheet(isPresented: $model.isAddPresented) { - switch model.selectedAccountType { + switch model.selectedAccountType! { case .onMyMac: - SettingsLocalAccountView() - case .feedbin, .feedWrangler, .newsBlur, .freshRSS: - SettingsCredentialsAccountView(accountType: model.selectedAccountType!) + AddLocalAccountView() + case .feedbin: + AddFeedbinAccountView() case .cloudKit: - SettingsCloudKitAccountView() + AddCloudKitAccountView() + case .feedWrangler: + AddFeedWranglerAccountView() + case .newsBlur: + AddNewsBlurAccountView() + case .feedly: + AddFeedlyAccountView() default: - EmptyView() + AddReaderAPIAccountView(accountType: model.selectedAccountType!) } } .navigationBarTitle(Text("Add Account"), displayMode: .inline) diff --git a/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Account Preferences/AccountsPreferencesModel.swift b/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Account Preferences/AccountsPreferencesModel.swift index 69d7bf34b..b3853d473 100644 --- a/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Account Preferences/AccountsPreferencesModel.swift +++ b/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Account Preferences/AccountsPreferencesModel.swift @@ -10,12 +10,22 @@ import Foundation import Account import Combine -class AccountsPreferencesModel: ObservableObject { +public enum AccountConfigurationSheets: Equatable { + case addAccountPicker, addSelectedAccount(AccountType), credentials, none - enum AccountConfigurationSheets { - case add, credentials, none + public static func == (lhs: AccountConfigurationSheets, rhs: AccountConfigurationSheets) -> Bool { + switch (lhs, rhs) { + case (let .addSelectedAccount(lhsType), let .addSelectedAccount(rhsType)): + return lhsType == rhsType + default: + return false + } } +} + +public class AccountsPreferencesModel: ObservableObject { + // Selected Account public private(set) var account: Account? @@ -57,7 +67,7 @@ class AccountsPreferencesModel: ObservableObject { @Published var showSheet: Bool = false @Published var sheetToShow: AccountConfigurationSheets = .none { didSet { - showSheet = sheetToShow != .none + if sheetToShow == .none { showSheet = false } else { showSheet = true } } } @Published var showDeleteConfirmation: Bool = false diff --git a/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Account Preferences/AccountsPreferencesView.swift b/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Account Preferences/AccountsPreferencesView.swift index 67236d1c7..bd72a621c 100644 --- a/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Account Preferences/AccountsPreferencesView.swift +++ b/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Account Preferences/AccountsPreferencesView.swift @@ -29,14 +29,29 @@ struct AccountsPreferencesView: View { onDismiss: { viewModel.sheetToShow = .none }, content: { switch viewModel.sheetToShow { - case .add: - AddAccountView(preferencesModel: viewModel) - .frame(width: 300, height: 200) - .padding() + case .addAccountPicker: + AddAccountView(accountToAdd: $viewModel.sheetToShow) case .credentials: EditAccountCredentialsView(viewModel: viewModel) case .none: EmptyView() + case .addSelectedAccount(let type): + switch type { + case .onMyMac: + AddLocalAccountView() + case .feedbin: + AddFeedbinAccountView() + case .cloudKit: + AddCloudKitAccountView() + case .feedWrangler: + AddFeedWranglerAccountView() + case .newsBlur: + AddNewsBlurAccountView() + case .feedly: + AddFeedlyAccountView() + default: + AddReaderAPIAccountView(accountType: type) + } } }) .alert(isPresented: $viewModel.showDeleteConfirmation, content: { @@ -71,7 +86,7 @@ struct AccountsPreferencesView: View { Divider() HStack(alignment: .center, spacing: 4) { Button(action: { - viewModel.sheetToShow = .add + viewModel.sheetToShow = .addAccountPicker }, label: { Image(systemName: "plus") .font(.title) diff --git a/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Account Preferences/Add Account/AddAccountModel.swift b/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Account Preferences/Add Account/AddAccountModel.swift deleted file mode 100644 index 21074d617..000000000 --- a/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Account Preferences/Add Account/AddAccountModel.swift +++ /dev/null @@ -1,307 +0,0 @@ -// -// AddAccountModel.swift -// Multiplatform macOS -// -// Created by Stuart Breckenridge on 13/7/20. -// Copyright © 2020 Ranchero Software. All rights reserved. -// - -import Foundation -import Account -import RSWeb -import Secrets -import RSCore - -class AddAccountModel: ObservableObject { - - #if DEBUG - let addableAccountTypes: [AccountType] = [.onMyMac, .feedbin, .feedly, .feedWrangler, .freshRSS, .cloudKit, .newsBlur] - #else - let addableAccountTypes: [AccountType] = [.onMyMac, .feedbin, .feedly] - #endif - - // Add Accounts - @Published var selectedAddAccount: AccountType = .onMyMac - @Published var userName: String = "" - @Published var password: String = "" - @Published var apiUrl: String = "" - @Published var newLocalAccountName: String = "" - @Published var accountIsAuthenticating: Bool = false - @Published var addAccountError: AccountUpdateErrors = .none { - didSet { - if addAccountError == .none { - showError = false - } else { - showError = true - } - } - } - @Published var showError: Bool = false - @Published var accountAdded: Bool = false - - func resetUserEntries() { - userName = "" - password = "" - newLocalAccountName = "" - apiUrl = "" - } - - func authenticateAccount() { - switch selectedAddAccount { - case .onMyMac: - addLocalAccount() - case .cloudKit: - authenticateCloudKit() - case .feedbin: - authenticateFeedbin() - case .feedWrangler: - authenticateFeedWrangler() - case .freshRSS: - authenticateFreshRSS() - case .feedly: - authenticateFeedly() - case .newsBlur: - authenticateNewsBlur() - } - } - -} - -// MARK:- Authentication APIs - -extension AddAccountModel { - - private func addLocalAccount() { - let account = AccountManager.shared.createAccount(type: .onMyMac) - account.name = newLocalAccountName - accountAdded = true - } - - private func authenticateFeedbin() { - accountIsAuthenticating = true - let credentials = Credentials(type: .basic, username: userName, secret: password) - - Account.validateCredentials(type: .feedbin, credentials: credentials) { [weak self] result in - - guard let self = self else { return } - - self.accountIsAuthenticating = false - - switch result { - case .success(let validatedCredentials): - - guard let validatedCredentials = validatedCredentials else { - self.addAccountError = .invalidUsernamePassword - return - } - - let account = AccountManager.shared.createAccount(type: .feedbin) - - do { - try account.removeCredentials(type: .basic) - try account.storeCredentials(validatedCredentials) - self.accountAdded = true - account.refreshAll(completion: { result in - switch result { - case .success: - break - case .failure(let error): - self.addAccountError = .other(error: error) - } - }) - - } catch { - self.addAccountError = .keyChainError - } - - case .failure: - self.addAccountError = .networkError - } - - } - - } - - private func authenticateFeedWrangler() { - - accountIsAuthenticating = true - let credentials = Credentials(type: .feedWranglerBasic, username: userName, secret: password) - - Account.validateCredentials(type: .feedWrangler, credentials: credentials) { [weak self] result in - - guard let self = self else { return } - - self.accountIsAuthenticating = false - - switch result { - case .success(let validatedCredentials): - - guard let validatedCredentials = validatedCredentials else { - self.addAccountError = .invalidUsernamePassword - return - } - - let account = AccountManager.shared.createAccount(type: .feedWrangler) - - do { - try account.removeCredentials(type: .feedWranglerBasic) - try account.removeCredentials(type: .feedWranglerToken) - try account.storeCredentials(credentials) - try account.storeCredentials(validatedCredentials) - self.accountAdded = true - account.refreshAll(completion: { result in - switch result { - case .success: - break - case .failure(let error): - self.addAccountError = .other(error: error) - } - }) - - } catch { - self.addAccountError = .keyChainError - } - - case .failure: - self.addAccountError = .networkError - } - } - } - - private func authenticateNewsBlur() { - accountIsAuthenticating = true - let credentials = Credentials(type: .newsBlurBasic, username: userName, secret: password) - - Account.validateCredentials(type: .newsBlur, credentials: credentials) { [weak self] result in - - guard let self = self else { return } - - self.accountIsAuthenticating = false - - switch result { - case .success(let validatedCredentials): - - guard let validatedCredentials = validatedCredentials else { - self.addAccountError = .invalidUsernamePassword - return - } - - let account = AccountManager.shared.createAccount(type: .newsBlur) - - do { - try account.removeCredentials(type: .newsBlurBasic) - try account.removeCredentials(type: .newsBlurSessionId) - try account.storeCredentials(credentials) - try account.storeCredentials(validatedCredentials) - self.accountAdded = true - account.refreshAll(completion: { result in - switch result { - case .success: - break - case .failure(let error): - self.addAccountError = .other(error: error) - } - }) - - } catch { - self.addAccountError = .keyChainError - } - - case .failure: - self.addAccountError = .networkError - } - } - - } - - private func authenticateFreshRSS() { - accountIsAuthenticating = true - let credentials = Credentials(type: .readerBasic, username: userName, secret: password) - - Account.validateCredentials(type: .freshRSS, credentials: credentials, endpoint: URL(string: apiUrl)!) { [weak self] result in - - guard let self = self else { return } - - self.accountIsAuthenticating = false - - switch result { - case .success(let validatedCredentials): - - guard let validatedCredentials = validatedCredentials else { - self.addAccountError = .invalidUsernamePassword - return - } - - let account = AccountManager.shared.createAccount(type: .freshRSS) - - do { - try account.removeCredentials(type: .readerBasic) - try account.removeCredentials(type: .readerAPIKey) - try account.storeCredentials(credentials) - try account.storeCredentials(validatedCredentials) - self.accountAdded = true - account.refreshAll(completion: { result in - switch result { - case .success: - break - case .failure(let error): - self.addAccountError = .other(error: error) - } - }) - - } catch { - self.addAccountError = .keyChainError - } - - case .failure: - self.addAccountError = .networkError - } - } - } - - private func authenticateCloudKit() { - let _ = AccountManager.shared.createAccount(type: .cloudKit) - self.accountAdded = true - } - - private func authenticateFeedly() { - accountIsAuthenticating = true - let addAccount = OAuthAccountAuthorizationOperation(accountType: .feedly) - addAccount.delegate = self - addAccount.presentationAnchor = NSApplication.shared.windows.last - MainThreadOperationQueue.shared.add(addAccount) - } - -} - -// MARK:- OAuthAccountAuthorizationOperationDelegate -extension AddAccountModel: OAuthAccountAuthorizationOperationDelegate { - func oauthAccountAuthorizationOperation(_ operation: OAuthAccountAuthorizationOperation, didCreate account: Account) { - - accountIsAuthenticating = false - accountAdded = true - - // macOS only: `ASWebAuthenticationSession` leaves the browser in the foreground. - // Ensure the app is in the foreground so the user can see their Feedly account load. - NSApplication.shared.activate(ignoringOtherApps: true) - - account.refreshAll { [weak self] result in - switch result { - case .success: - break - case .failure(let error): - self?.addAccountError = .other(error: error) - } - } - } - - func oauthAccountAuthorizationOperation(_ operation: OAuthAccountAuthorizationOperation, didFailWith error: Error) { - accountIsAuthenticating = false - - // macOS only: `ASWebAuthenticationSession` leaves the browser in the foreground. - // Ensure the app is in the foreground so the user can see the error. - NSApplication.shared.activate(ignoringOtherApps: true) - - addAccountError = .other(error: error) - } -} diff --git a/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Account Preferences/Add Account/AddAccountPickerRow.swift b/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Account Preferences/Add Account/AddAccountPickerRow.swift deleted file mode 100644 index 23366ac85..000000000 --- a/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Account Preferences/Add Account/AddAccountPickerRow.swift +++ /dev/null @@ -1,49 +0,0 @@ -// -// AddAccountPickerRow.swift -// Multiplatform macOS -// -// Created by Stuart Breckenridge on 13/7/20. -// Copyright © 2020 Ranchero Software. All rights reserved. -// - -import SwiftUI -import Account - -struct AddAccountPickerRow: View { - - var accountType: AccountType - - var body: some View { - HStack { -// if let img = AppAssets.image(for: accountType) { -// Image(rsImage: img) -// .resizable() -// .aspectRatio(contentMode: .fit) -// .frame(width: 15, height: 15) -// } - - switch accountType { - case .onMyMac: - Text(Account.defaultLocalAccountName) - case .cloudKit: - Text("iCloud") - case .feedbin: - Text("Feedbin") - case .feedWrangler: - Text("FeedWrangler") - case .freshRSS: - Text("FreshRSS") - case .feedly: - Text("Feedly") - case .newsBlur: - Text("NewsBlur") - } - } - } -} - -struct AddAccountPickerRow_Previews: PreviewProvider { - static var previews: some View { - AddAccountPickerRow(accountType: .onMyMac) - } -} diff --git a/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Account Preferences/Add Account/AddAccountView.swift b/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Account Preferences/Add Account/AddAccountView.swift index 026aa0671..3a95b9f83 100644 --- a/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Account Preferences/Add Account/AddAccountView.swift +++ b/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Account Preferences/Add Account/AddAccountView.swift @@ -1,150 +1,274 @@ // // AddAccountView.swift -// Multiplatform macOS +// NetNewsWire // -// Created by Stuart Breckenridge on 13/7/20. +// Created by Stuart Breckenridge on 28/10/20. // Copyright © 2020 Ranchero Software. All rights reserved. // import SwiftUI import Account +enum AddAccountSections: Int, CaseIterable { + case local = 0 + case icloud + case web + case selfhosted + case allOrdered + + var sectionHeader: String { + switch self { + case .local: + return NSLocalizedString("Local", comment: "Local Account") + case .icloud: + return NSLocalizedString("iCloud", comment: "iCloud Account") + case .web: + return NSLocalizedString("Web", comment: "Web Account") + case .selfhosted: + return NSLocalizedString("Self-hosted", comment: "Self hosted Account") + case .allOrdered: + return "" + } + } + + var sectionFooter: String { + switch self { + case .local: + return NSLocalizedString("Local accounts do not sync subscriptions across devices.", comment: "Local Account") + case .icloud: + return NSLocalizedString("Use your iCloud account to sync your subscriptions across your iOS and macOS devices.", comment: "iCloud Account") + case .web: + return NSLocalizedString("Web accounts sync your subscriptions across all your devices.", comment: "Web Account") + case .selfhosted: + return NSLocalizedString("Self-hosted accounts sync your subscriptions across all your devices.", comment: "Self hosted Account") + case .allOrdered: + return "" + } + } + + var sectionContent: [AccountType] { + switch self { + case .local: + return [.onMyMac] + case .icloud: + return [.cloudKit] + case .web: + #if DEBUG + return [.bazQux, .feedbin, .feedly, .feedWrangler, .inoreader, .newsBlur, .theOldReader] + #else + return [.bazQux, .feedbin, .feedly, .feedWrangler, .inoreader, .newsBlur, .theOldReader] + #endif + case .selfhosted: + return [.freshRSS] + case .allOrdered: + return AddAccountSections.local.sectionContent + + AddAccountSections.icloud.sectionContent + + AddAccountSections.web.sectionContent + + AddAccountSections.selfhosted.sectionContent + } + } +} + struct AddAccountView: View { - @Environment(\.presentationMode) private var presentationMode - @ObservedObject var preferencesModel: AccountsPreferencesModel - @StateObject private var viewModel = AddAccountModel() - + @State private var selectedAccount: AccountType = .onMyMac + @Binding public var accountToAdd: AccountConfigurationSheets + @Environment(\.presentationMode) var presentationMode + var body: some View { + VStack(alignment: .leading, spacing: 8) { + Text("Choose an account type to add...") + .font(.headline) + .padding() - Form { - Text("Add an Account").font(.headline) + localAccount + icloudAccount + webAccounts + selfhostedAccounts - Picker("Account Type", - selection: $viewModel.selectedAddAccount, - content: { - ForEach(0.. Bool { + AccountManager.shared.accounts.contains(where: { $0.type == .cloudKit }) } - var userNamePasswordAndAPIUrlView: some View { - Group { - TextField("Email", text: $viewModel.userName) - SecureField("Password", text: $viewModel.password) - TextField("API URL", text: $viewModel.apiUrl) - }.textFieldStyle(RoundedBorderTextFieldStyle()) - } - - var oAuthView: some View { - Group { - Text("Click Authenticate") - }.textFieldStyle(RoundedBorderTextFieldStyle()) - } - - -} -struct AddAccountView_Previews: PreviewProvider { - static var previews: some View { - AddAccountView(preferencesModel: AccountsPreferencesModel()) + private func isRestricted(_ accountType: AccountType) -> Bool { + if AppDefaults.shared.isDeveloperBuild && (accountType == .feedly || accountType == .feedWrangler || accountType == .inoreader) { + return true + } + return false } } + + diff --git a/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Account Preferences/Edit Account/EditAccountCredentialsModel.swift b/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Account Preferences/Edit Account/EditAccountCredentialsModel.swift index 28e5c10ea..a96b8e27e 100644 --- a/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Account Preferences/Edit Account/EditAccountCredentialsModel.swift +++ b/Multiplatform/macOS/Preferences/Preference Panes/Accounts/Account Preferences/Edit Account/EditAccountCredentialsModel.swift @@ -42,9 +42,15 @@ class EditAccountCredentialsModel: ObservableObject { case .feedly: updateFeedly(account) case .freshRSS: - updateFreshRSS(account) + updateReaderAccount(account) case .newsBlur: updateNewsblur(account) + case .inoreader: + updateReaderAccount(account) + case .bazQux: + updateReaderAccount(account) + case .theOldReader: + updateReaderAccount(account) } } @@ -168,11 +174,11 @@ extension EditAccountCredentialsModel { MainThreadOperationQueue.shared.add(updateAccount) } - func updateFreshRSS(_ account: Account) { + func updateReaderAccount(_ account: Account) { accountIsUpdatingCredentials = true let credentials = Credentials(type: .readerBasic, username: userName, secret: password) - Account.validateCredentials(type: .freshRSS, credentials: credentials) { [weak self] result in + Account.validateCredentials(type: account.type, credentials: credentials) { [weak self] result in guard let self = self else { return } diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 80dfb74f4..57305f1ba 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -28,12 +28,46 @@ 172199C924AB228900A31D04 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 172199C824AB228900A31D04 /* SettingsView.swift */; }; 172199ED24AB2E0100A31D04 /* SafariView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 172199EC24AB2E0100A31D04 /* SafariView.swift */; }; 172199F124AB716900A31D04 /* SidebarToolbarModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 172199F024AB716900A31D04 /* SidebarToolbarModifier.swift */; }; + 17241249257B8A8A00ACCEBC /* AddFeedlyAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17241248257B8A8A00ACCEBC /* AddFeedlyAccountView.swift */; }; + 1724126A257BBEBB00ACCEBC /* AddFeedbinViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17241269257BBEBB00ACCEBC /* AddFeedbinViewModel.swift */; }; + 17241278257BBEE700ACCEBC /* AddFeedlyViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17241277257BBEE700ACCEBC /* AddFeedlyViewModel.swift */; }; + 17241280257BBF3E00ACCEBC /* AddFeedWranglerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1724127F257BBF3E00ACCEBC /* AddFeedWranglerViewModel.swift */; }; + 17241288257BBF7000ACCEBC /* AddNewsBlurViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17241287257BBF7000ACCEBC /* AddNewsBlurViewModel.swift */; }; + 17241290257BBFAD00ACCEBC /* AddReaderAPIViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1724128F257BBFAD00ACCEBC /* AddReaderAPIViewModel.swift */; }; + 1724129D257BC01C00ACCEBC /* AddNewsBlurViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17241287257BBF7000ACCEBC /* AddNewsBlurViewModel.swift */; }; + 1724129E257BC01C00ACCEBC /* AddReaderAPIViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1724128F257BBFAD00ACCEBC /* AddReaderAPIViewModel.swift */; }; + 1724129F257BC01C00ACCEBC /* AddFeedlyAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17241248257B8A8A00ACCEBC /* AddFeedlyAccountView.swift */; }; + 172412A0257BC01C00ACCEBC /* AddFeedWranglerAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF98E2AF2578AA5C00F18944 /* AddFeedWranglerAccountView.swift */; }; + 172412A1257BC01C00ACCEBC /* AddReaderAPIAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF98E2C52578AD1B00F18944 /* AddReaderAPIAccountView.swift */; }; + 172412A2257BC01C00ACCEBC /* AddLocalAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17386B792577C4BF0014C8B2 /* AddLocalAccountView.swift */; }; + 172412A3257BC01C00ACCEBC /* AddNewsBlurAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF98E2BD2578AC0000F18944 /* AddNewsBlurAccountView.swift */; }; + 172412A4257BC01C00ACCEBC /* AddFeedlyViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17241277257BBEE700ACCEBC /* AddFeedlyViewModel.swift */; }; + 172412A5257BC01C00ACCEBC /* AddCloudKitAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF98E2992578A73A00F18944 /* AddCloudKitAccountView.swift */; }; + 172412A6257BC01C00ACCEBC /* AddFeedbinViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17241269257BBEBB00ACCEBC /* AddFeedbinViewModel.swift */; }; + 172412A7257BC01C00ACCEBC /* AddFeedbinAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17386BC32577CC600014C8B2 /* AddFeedbinAccountView.swift */; }; + 172412A8257BC01C00ACCEBC /* AddFeedWranglerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1724127F257BBF3E00ACCEBC /* AddFeedWranglerViewModel.swift */; }; + 172412AF257BC0C300ACCEBC /* AccountType+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 173A64162547BE0900267F6E /* AccountType+Helpers.swift */; }; 1727B39924C1368D00A4DBDC /* LayoutPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1727B39824C1368D00A4DBDC /* LayoutPreferencesView.swift */; }; 1729529324AA1CAA00D65E66 /* AccountsPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1729529024AA1CAA00D65E66 /* AccountsPreferencesView.swift */; }; 1729529424AA1CAA00D65E66 /* AdvancedPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1729529124AA1CAA00D65E66 /* AdvancedPreferencesView.swift */; }; 1729529524AA1CAA00D65E66 /* GeneralPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1729529224AA1CAA00D65E66 /* GeneralPreferencesView.swift */; }; 1729529724AA1CD000D65E66 /* MacPreferencePanes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1729529624AA1CD000D65E66 /* MacPreferencePanes.swift */; }; 1729529B24AA1FD200D65E66 /* MacSearchField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1729529A24AA1FD200D65E66 /* MacSearchField.swift */; }; + 17386B5E2577BC820014C8B2 /* AccountType+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 173A64162547BE0900267F6E /* AccountType+Helpers.swift */; }; + 17386B6C2577BD820014C8B2 /* RSSparkle in Frameworks */ = {isa = PBXBuildFile; productRef = 17386B6B2577BD820014C8B2 /* RSSparkle */; }; + 17386B7A2577C4BF0014C8B2 /* AddLocalAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17386B792577C4BF0014C8B2 /* AddLocalAccountView.swift */; }; + 17386B952577C6240014C8B2 /* RSCore in Frameworks */ = {isa = PBXBuildFile; productRef = 17386B942577C6240014C8B2 /* RSCore */; }; + 17386B962577C6240014C8B2 /* RSCore in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 17386B942577C6240014C8B2 /* RSCore */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 17386B982577C6240014C8B2 /* RSTree in Frameworks */ = {isa = PBXBuildFile; productRef = 17386B972577C6240014C8B2 /* RSTree */; }; + 17386B992577C6240014C8B2 /* RSTree in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 17386B972577C6240014C8B2 /* RSTree */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 17386B9B2577C6240014C8B2 /* RSWeb in Frameworks */ = {isa = PBXBuildFile; productRef = 17386B9A2577C6240014C8B2 /* RSWeb */; }; + 17386B9C2577C6240014C8B2 /* RSWeb in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 17386B9A2577C6240014C8B2 /* RSWeb */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 17386B9E2577C6240014C8B2 /* RSDatabase in Frameworks */ = {isa = PBXBuildFile; productRef = 17386B9D2577C6240014C8B2 /* RSDatabase */; }; + 17386B9F2577C6240014C8B2 /* RSDatabase in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 17386B9D2577C6240014C8B2 /* RSDatabase */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 17386BA42577C6240014C8B2 /* RSParser in Frameworks */ = {isa = PBXBuildFile; productRef = 17386BA32577C6240014C8B2 /* RSParser */; }; + 17386BA52577C6240014C8B2 /* RSParser in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 17386BA32577C6240014C8B2 /* RSParser */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 17386BB62577C7340014C8B2 /* RSCoreResources in Frameworks */ = {isa = PBXBuildFile; productRef = 17386BB52577C7340014C8B2 /* RSCoreResources */; }; + 17386BC42577CC600014C8B2 /* AddFeedbinAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17386BC32577CC600014C8B2 /* AddFeedbinAccountView.swift */; }; 173A64172547BE0900267F6E /* AccountType+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 173A64162547BE0900267F6E /* AccountType+Helpers.swift */; }; 173A642C2547BE9600267F6E /* AccountType+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 173A64162547BE0900267F6E /* AccountType+Helpers.swift */; }; 175942AA24AD533200585066 /* RefreshInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCE4226F4DFA0010922C /* RefreshInterval.swift */; }; @@ -60,8 +94,6 @@ 1768147B2564BE5400D98635 /* widget-sample.json in Resources */ = {isa = PBXBuildFile; fileRef = 1768147A2564BE5400D98635 /* widget-sample.json */; }; 1769E32224BC5925000E1E8E /* AccountsPreferencesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1769E32124BC5925000E1E8E /* AccountsPreferencesModel.swift */; }; 1769E32524BC5A65000E1E8E /* AddAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1769E32424BC5A65000E1E8E /* AddAccountView.swift */; }; - 1769E32724BC5B6C000E1E8E /* AddAccountModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1769E32624BC5B6C000E1E8E /* AddAccountModel.swift */; }; - 1769E32924BCAFC7000E1E8E /* AddAccountPickerRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1769E32824BCAFC7000E1E8E /* AddAccountPickerRow.swift */; }; 1769E32B24BCB030000E1E8E /* ConfiguredAccountRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1769E32A24BCB030000E1E8E /* ConfiguredAccountRow.swift */; }; 1769E32D24BD20A0000E1E8E /* AccountDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1769E32C24BD20A0000E1E8E /* AccountDetailView.swift */; }; 1769E33024BD6271000E1E8E /* EditAccountCredentialsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1769E32F24BD6271000E1E8E /* EditAccountCredentialsView.swift */; }; @@ -95,6 +127,8 @@ 17D0682C2564F47E00C0B37E /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 17D0682B2564F47E00C0B37E /* Localizable.stringsdict */; }; 17D232A824AFF10A0005F075 /* AddWebFeedModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17D232A724AFF10A0005F075 /* AddWebFeedModel.swift */; }; 17D232A924AFF10A0005F075 /* AddWebFeedModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17D232A724AFF10A0005F075 /* AddWebFeedModel.swift */; }; + 17D3CEE3257C4D2300E74939 /* AddAccountSignUp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17D3CEE2257C4D2300E74939 /* AddAccountSignUp.swift */; }; + 17D3CEE4257C4D2300E74939 /* AddAccountSignUp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17D3CEE2257C4D2300E74939 /* AddAccountSignUp.swift */; }; 17D5F17124B0BC6700375168 /* SidebarToolbarModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17D5F17024B0BC6700375168 /* SidebarToolbarModel.swift */; }; 17D5F17224B0BC6700375168 /* SidebarToolbarModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17D5F17024B0BC6700375168 /* SidebarToolbarModel.swift */; }; 17D5F19524B0C1DD00375168 /* SidebarToolbarModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 172199F024AB716900A31D04 /* SidebarToolbarModifier.swift */; }; @@ -1085,6 +1119,10 @@ D5F4EDB720074D6500B9E363 /* WebFeed+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F4EDB620074D6500B9E363 /* WebFeed+Scriptability.swift */; }; D5F4EDB920074D7C00B9E363 /* Folder+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F4EDB820074D7C00B9E363 /* Folder+Scriptability.swift */; }; DD82AB0A231003F6002269DF /* SharingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD82AB09231003F6002269DF /* SharingTests.swift */; }; + DF98E29A2578A73A00F18944 /* AddCloudKitAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF98E2992578A73A00F18944 /* AddCloudKitAccountView.swift */; }; + DF98E2B02578AA5C00F18944 /* AddFeedWranglerAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF98E2AF2578AA5C00F18944 /* AddFeedWranglerAccountView.swift */; }; + DF98E2BE2578AC0000F18944 /* AddNewsBlurAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF98E2BD2578AC0000F18944 /* AddNewsBlurAccountView.swift */; }; + DF98E2C62578AD1B00F18944 /* AddReaderAPIAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF98E2C52578AD1B00F18944 /* AddReaderAPIAccountView.swift */; }; FA80C11724B0728000974098 /* AddFolderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA80C11624B0728000974098 /* AddFolderView.swift */; }; FA80C11824B0728000974098 /* AddFolderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA80C11624B0728000974098 /* AddFolderView.swift */; }; FA80C13E24B072AA00974098 /* AddFolderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA80C13D24B072AA00974098 /* AddFolderModel.swift */; }; @@ -1228,6 +1266,11 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( + 17386BA52577C6240014C8B2 /* RSParser in Embed Frameworks */, + 17386B9F2577C6240014C8B2 /* RSDatabase in Embed Frameworks */, + 17386B9C2577C6240014C8B2 /* RSWeb in Embed Frameworks */, + 17386B962577C6240014C8B2 /* RSCore in Embed Frameworks */, + 17386B992577C6240014C8B2 /* RSTree in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -1331,12 +1374,20 @@ 172199C824AB228900A31D04 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; 172199EC24AB2E0100A31D04 /* SafariView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariView.swift; sourceTree = ""; }; 172199F024AB716900A31D04 /* SidebarToolbarModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarToolbarModifier.swift; sourceTree = ""; }; + 17241248257B8A8A00ACCEBC /* AddFeedlyAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddFeedlyAccountView.swift; sourceTree = ""; }; + 17241269257BBEBB00ACCEBC /* AddFeedbinViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddFeedbinViewModel.swift; sourceTree = ""; }; + 17241277257BBEE700ACCEBC /* AddFeedlyViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddFeedlyViewModel.swift; sourceTree = ""; }; + 1724127F257BBF3E00ACCEBC /* AddFeedWranglerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddFeedWranglerViewModel.swift; sourceTree = ""; }; + 17241287257BBF7000ACCEBC /* AddNewsBlurViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddNewsBlurViewModel.swift; sourceTree = ""; }; + 1724128F257BBFAD00ACCEBC /* AddReaderAPIViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddReaderAPIViewModel.swift; sourceTree = ""; }; 1727B39824C1368D00A4DBDC /* LayoutPreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutPreferencesView.swift; sourceTree = ""; }; 1729529024AA1CAA00D65E66 /* AccountsPreferencesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountsPreferencesView.swift; sourceTree = ""; }; 1729529124AA1CAA00D65E66 /* AdvancedPreferencesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedPreferencesView.swift; sourceTree = ""; }; 1729529224AA1CAA00D65E66 /* GeneralPreferencesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneralPreferencesView.swift; sourceTree = ""; }; 1729529624AA1CD000D65E66 /* MacPreferencePanes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MacPreferencePanes.swift; sourceTree = ""; }; 1729529A24AA1FD200D65E66 /* MacSearchField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacSearchField.swift; sourceTree = ""; }; + 17386B792577C4BF0014C8B2 /* AddLocalAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddLocalAccountView.swift; sourceTree = ""; }; + 17386BC32577CC600014C8B2 /* AddFeedbinAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddFeedbinAccountView.swift; sourceTree = ""; }; 173A64162547BE0900267F6E /* AccountType+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AccountType+Helpers.swift"; sourceTree = ""; }; 176813B62564B9F800D98635 /* WidgetData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetData.swift; sourceTree = ""; }; 176813BD2564BA2800D98635 /* WidgetDataEncoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetDataEncoder.swift; sourceTree = ""; }; @@ -1359,8 +1410,6 @@ 176814822564C02A00D98635 /* NetNewsWire_iOS_WidgetExtension.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = NetNewsWire_iOS_WidgetExtension.entitlements; sourceTree = ""; }; 1769E32124BC5925000E1E8E /* AccountsPreferencesModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsPreferencesModel.swift; sourceTree = ""; }; 1769E32424BC5A65000E1E8E /* AddAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddAccountView.swift; sourceTree = ""; }; - 1769E32624BC5B6C000E1E8E /* AddAccountModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddAccountModel.swift; sourceTree = ""; }; - 1769E32824BCAFC7000E1E8E /* AddAccountPickerRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddAccountPickerRow.swift; sourceTree = ""; }; 1769E32A24BCB030000E1E8E /* ConfiguredAccountRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfiguredAccountRow.swift; sourceTree = ""; }; 1769E32C24BD20A0000E1E8E /* AccountDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountDetailView.swift; sourceTree = ""; }; 1769E32F24BD6271000E1E8E /* EditAccountCredentialsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditAccountCredentialsView.swift; sourceTree = ""; }; @@ -1377,6 +1426,7 @@ 17B223DB24AC24D2001E4592 /* TimelineLayoutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineLayoutView.swift; sourceTree = ""; }; 17D0682B2564F47E00C0B37E /* Localizable.stringsdict */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; path = Localizable.stringsdict; sourceTree = ""; }; 17D232A724AFF10A0005F075 /* AddWebFeedModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddWebFeedModel.swift; sourceTree = ""; }; + 17D3CEE2257C4D2300E74939 /* AddAccountSignUp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddAccountSignUp.swift; sourceTree = ""; }; 17D5F17024B0BC6700375168 /* SidebarToolbarModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarToolbarModel.swift; sourceTree = ""; }; 17E4DBD524BFC53E00FE462A /* AdvancedPreferencesModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedPreferencesModel.swift; sourceTree = ""; }; 3B3A328B238B820900314204 /* FeedWranglerAccountViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedWranglerAccountViewController.swift; sourceTree = ""; }; @@ -1913,6 +1963,10 @@ D5F4EDB620074D6500B9E363 /* WebFeed+Scriptability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WebFeed+Scriptability.swift"; sourceTree = ""; }; D5F4EDB820074D7C00B9E363 /* Folder+Scriptability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Folder+Scriptability.swift"; sourceTree = ""; }; DD82AB09231003F6002269DF /* SharingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SharingTests.swift; sourceTree = ""; }; + DF98E2992578A73A00F18944 /* AddCloudKitAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddCloudKitAccountView.swift; sourceTree = ""; }; + DF98E2AF2578AA5C00F18944 /* AddFeedWranglerAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddFeedWranglerAccountView.swift; sourceTree = ""; }; + DF98E2BD2578AC0000F18944 /* AddNewsBlurAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddNewsBlurAccountView.swift; sourceTree = ""; }; + DF98E2C52578AD1B00F18944 /* AddReaderAPIAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddReaderAPIAccountView.swift; sourceTree = ""; }; FA80C11624B0728000974098 /* AddFolderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddFolderView.swift; sourceTree = ""; }; FA80C13D24B072AA00974098 /* AddFolderModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddFolderModel.swift; sourceTree = ""; }; FF3ABF09232599450074C542 /* ArticleSorterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleSorterTests.swift; sourceTree = ""; }; @@ -1983,9 +2037,16 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 17386BA42577C6240014C8B2 /* RSParser in Frameworks */, + 17386B952577C6240014C8B2 /* RSCore in Frameworks */, + 17386B6C2577BD820014C8B2 /* RSSparkle in Frameworks */, 516B695B24D2F28600B5702F /* Account in Frameworks */, + 17386B9B2577C6240014C8B2 /* RSWeb in Frameworks */, + 17386B9E2577C6240014C8B2 /* RSDatabase in Frameworks */, + 17386BB62577C7340014C8B2 /* RSCoreResources in Frameworks */, 51E498B124A806A400B667CB /* CloudKit.framework in Frameworks */, 51E498B324A806AA00B667CB /* WebKit.framework in Frameworks */, + 17386B982577C6240014C8B2 /* RSTree in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2076,6 +2137,19 @@ path = Settings; sourceTree = ""; }; + 17241268257BBE7B00ACCEBC /* Add Account Models */ = { + isa = PBXGroup; + children = ( + 17241269257BBEBB00ACCEBC /* AddFeedbinViewModel.swift */, + 17241277257BBEE700ACCEBC /* AddFeedlyViewModel.swift */, + 1724127F257BBF3E00ACCEBC /* AddFeedWranglerViewModel.swift */, + 17241287257BBF7000ACCEBC /* AddNewsBlurViewModel.swift */, + 1724128F257BBFAD00ACCEBC /* AddReaderAPIViewModel.swift */, + 17D3CEE2257C4D2300E74939 /* AddAccountSignUp.swift */, + ); + path = "Add Account Models"; + sourceTree = ""; + }; 1727B37624C1365300A4DBDC /* Viewing */ = { isa = PBXGroup; children = ( @@ -2104,6 +2178,20 @@ path = "Preference Panes"; sourceTree = ""; }; + 17386B812577C4C60014C8B2 /* Add Account Sheets */ = { + isa = PBXGroup; + children = ( + 17386B792577C4BF0014C8B2 /* AddLocalAccountView.swift */, + DF98E2992578A73A00F18944 /* AddCloudKitAccountView.swift */, + 17386BC32577CC600014C8B2 /* AddFeedbinAccountView.swift */, + 17241248257B8A8A00ACCEBC /* AddFeedlyAccountView.swift */, + DF98E2AF2578AA5C00F18944 /* AddFeedWranglerAccountView.swift */, + DF98E2BD2578AC0000F18944 /* AddNewsBlurAccountView.swift */, + DF98E2C52578AD1B00F18944 /* AddReaderAPIAccountView.swift */, + ); + path = "Add Account Sheets"; + sourceTree = ""; + }; 176813A22564B9D100D98635 /* Widget */ = { isa = PBXGroup; children = ( @@ -2190,9 +2278,7 @@ 1769E32324BC5A50000E1E8E /* Add Account */ = { isa = PBXGroup; children = ( - 1769E32624BC5B6C000E1E8E /* AddAccountModel.swift */, 1769E32424BC5A65000E1E8E /* AddAccountView.swift */, - 1769E32824BCAFC7000E1E8E /* AddAccountPickerRow.swift */, ); path = "Add Account"; sourceTree = ""; @@ -2236,6 +2322,8 @@ 17930ED324AF10EE00A9BA52 /* AddWebFeedView.swift */, FA80C13D24B072AA00974098 /* AddFolderModel.swift */, FA80C11624B0728000974098 /* AddFolderView.swift */, + 17241268257BBE7B00ACCEBC /* Add Account Models */, + 17386B812577C4C60014C8B2 /* Add Account Sheets */, ); path = Add; sourceTree = ""; @@ -3666,6 +3754,13 @@ name = "Multiplatform macOS"; packageProductDependencies = ( 516B695A24D2F28600B5702F /* Account */, + 17386B6B2577BD820014C8B2 /* RSSparkle */, + 17386B942577C6240014C8B2 /* RSCore */, + 17386B972577C6240014C8B2 /* RSTree */, + 17386B9A2577C6240014C8B2 /* RSWeb */, + 17386B9D2577C6240014C8B2 /* RSDatabase */, + 17386BA32577C6240014C8B2 /* RSParser */, + 17386BB52577C7340014C8B2 /* RSCoreResources */, ); productName = macOS; productReference = 51C0514424A77DF800194D5E /* NetNewsWire.app */; @@ -4391,6 +4486,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 172412A6257BC01C00ACCEBC /* AddFeedbinViewModel.swift in Sources */, 17D5F17124B0BC6700375168 /* SidebarToolbarModel.swift in Sources */, 51E4995924A873F900B667CB /* ErrorHandler.swift in Sources */, 51392D1B24AC19A000BE0D35 /* SidebarExpandedContainers.swift in Sources */, @@ -4409,11 +4505,13 @@ 51E4997224A8784300B667CB /* DefaultFeedsImporter.swift in Sources */, 1704053424E5985A00A00787 /* SceneNavigationModel.swift in Sources */, 514E6C0924AD39AD00AC6F6E /* ArticleIconImageLoader.swift in Sources */, + 172412A2257BC01C00ACCEBC /* AddLocalAccountView.swift in Sources */, 6594CA3B24AF6F2A005C7D7C /* OPMLExporter.swift in Sources */, FA80C13E24B072AA00974098 /* AddFolderModel.swift in Sources */, 5177470624B2910300EB0F74 /* ArticleToolbarModifier.swift in Sources */, 51919FAF24AA8EFA00541E64 /* SidebarItemView.swift in Sources */, 514E6BDA24ACEA0400AC6F6E /* TimelineItemView.swift in Sources */, + 172412A1257BC01C00ACCEBC /* AddReaderAPIAccountView.swift in Sources */, 5177471624B37D9700EB0F74 /* ArticleIconSchemeHandler.swift in Sources */, FA80C11724B0728000974098 /* AddFolderView.swift in Sources */, 51E4990D24A808C500B667CB /* RSHTMLMetadata+Extension.swift in Sources */, @@ -4450,6 +4548,7 @@ 51E4996924A8760C00B667CB /* ArticleStylesManager.swift in Sources */, 5177471E24B387E100EB0F74 /* ImageTransition.swift in Sources */, 51E498F324A8085D00B667CB /* PseudoFeed.swift in Sources */, + 172412A5257BC01C00ACCEBC /* AddCloudKitAccountView.swift in Sources */, 65ACE48424B4779B003AE06A /* SettingsAddAccountView.swift in Sources */, 51A5769624AE617200078888 /* ArticleContainerView.swift in Sources */, 5181C5AD24AF89B1002E0F70 /* PreferredColorSchemeModifier.swift in Sources */, @@ -4459,14 +4558,17 @@ 51E4991D24A8092100B667CB /* NSAttributedString+NetNewsWire.swift in Sources */, 65082A2F24C72AC8009FA994 /* SettingsCredentialsAccountView.swift in Sources */, 51A8FFED24CA0CF400F41F1D /* WIthLatestFrom.swift in Sources */, + 1724129E257BC01C00ACCEBC /* AddReaderAPIViewModel.swift in Sources */, 51E499FD24A9137600B667CB /* SidebarModel.swift in Sources */, 5181C66224B0C326002E0F70 /* SettingsModel.swift in Sources */, 51E4995324A8734D00B667CB /* RedditFeedProvider-Extensions.swift in Sources */, 5177471024B3029400EB0F74 /* ArticleViewController.swift in Sources */, + 17D3CEE3257C4D2300E74939 /* AddAccountSignUp.swift in Sources */, 65082A5224C72B88009FA994 /* SettingsCredentialsAccountModel.swift in Sources */, 172199C924AB228900A31D04 /* SettingsView.swift in Sources */, 51B8BCC224C25C3E00360B00 /* SidebarContextMenu.swift in Sources */, 51A8005124CC453C00F41F1D /* ReplaySubject.swift in Sources */, + 172412A7257BC01C00ACCEBC /* AddFeedbinAccountView.swift in Sources */, 17D232A824AFF10A0005F075 /* AddWebFeedModel.swift in Sources */, 51B80EB824BD1F8B00C6C32D /* ActivityViewController.swift in Sources */, 51E4994224A8713C00B667CB /* ArticleStatusSyncTimer.swift in Sources */, @@ -4484,6 +4586,7 @@ 51E4993124A8676400B667CB /* FetchRequestOperation.swift in Sources */, 51E4992624A80AAB00B667CB /* AppAssets.swift in Sources */, 514E6C0624AD2B5F00AC6F6E /* Image-Extensions.swift in Sources */, + 172412AF257BC0C300ACCEBC /* AccountType+Helpers.swift in Sources */, 51E4995624A8734D00B667CB /* TwitterFeedProvider-Extensions.swift in Sources */, 5125E6CA24AE461D002A7562 /* TimelineLayoutView.swift in Sources */, 51E4996824A8760C00B667CB /* ArticleStyle.swift in Sources */, @@ -4494,8 +4597,10 @@ 5177470E24B2FF6F00EB0F74 /* ArticleView.swift in Sources */, 5171B4F624B7BABA00FB8D3B /* MarkStatusCommand.swift in Sources */, 65422D1724B75CD1008A2FA2 /* SettingsAddAccountModel.swift in Sources */, + 172412A3257BC01C00ACCEBC /* AddNewsBlurAccountView.swift in Sources */, 5177471424B37D4000EB0F74 /* PreloadedWebView.swift in Sources */, 51B80EDD24BD296700C6C32D /* ArticleActivityItemSource.swift in Sources */, + 1724129D257BC01C00ACCEBC /* AddNewsBlurViewModel.swift in Sources */, 17897ACA24C281A40014BA03 /* InspectorView.swift in Sources */, 517B2EBC24B3E62A001AC46C /* WrapperScriptMessageHandler.swift in Sources */, 51919FB324AAB97900541E64 /* FeedIconImageLoader.swift in Sources */, @@ -4515,6 +4620,7 @@ 5177471A24B3863000EB0F74 /* WebViewProvider.swift in Sources */, 51E4992124A8095000B667CB /* RSImage-Extensions.swift in Sources */, 51A8001224CA0FC700F41F1D /* Sink.swift in Sources */, + 172412A8257BC01C00ACCEBC /* AddFeedWranglerViewModel.swift in Sources */, 51E4990324A808BB00B667CB /* FaviconDownloader.swift in Sources */, 172199ED24AB2E0100A31D04 /* SafariView.swift in Sources */, 65ACE48624B477C9003AE06A /* SettingsAccountLabelView.swift in Sources */, @@ -4529,14 +4635,17 @@ 51C0515E24A77DF800194D5E /* MainApp.swift in Sources */, 51919FF724AB8B7700541E64 /* TimelineView.swift in Sources */, 51E4993D24A870F800B667CB /* UserNotificationManager.swift in Sources */, + 172412A0257BC01C00ACCEBC /* AddFeedWranglerAccountView.swift in Sources */, 5177470324B2657F00EB0F74 /* TimelineToolbarModifier.swift in Sources */, 51B80EDF24BD298900C6C32D /* TitleActivityItemSource.swift in Sources */, 51E4991524A808FF00B667CB /* ArticleStringFormatter.swift in Sources */, 51919FEE24AB85E400541E64 /* TimelineContainerView.swift in Sources */, 653A4E7924BCA5BB00EF2D7F /* SettingsCloudKitAccountView.swift in Sources */, + 1724129F257BC01C00ACCEBC /* AddFeedlyAccountView.swift in Sources */, 51E4995724A8734D00B667CB /* ExtensionPoint.swift in Sources */, 51A8002D24CC451500F41F1D /* ShareReplay.swift in Sources */, 51B8BCE624C25F7C00360B00 /* TimelineContextMenu.swift in Sources */, + 172412A4257BC01C00ACCEBC /* AddFeedlyViewModel.swift in Sources */, 1776E88E24AC5F8A00E78166 /* AppDefaults.swift in Sources */, 51E4991124A808DE00B667CB /* SmallIconProvider.swift in Sources */, ); @@ -4564,6 +4673,7 @@ 51B54AB624B5B33C0014348B /* WebViewController.swift in Sources */, 51E4994B24A8734C00B667CB /* SendToMicroBlogCommand.swift in Sources */, 51E4996F24A8764C00B667CB /* ActivityType.swift in Sources */, + 17386BC42577CC600014C8B2 /* AddFeedbinAccountView.swift in Sources */, 51E4994E24A8734C00B667CB /* SendToMarsEditCommand.swift in Sources */, 51919FB024AA8EFA00541E64 /* SidebarItemView.swift in Sources */, 1769E33624BD9621000E1E8E /* EditAccountCredentialsModel.swift in Sources */, @@ -4573,6 +4683,7 @@ 17E4DBD624BFC53E00FE462A /* AdvancedPreferencesModel.swift in Sources */, 5177470724B2910300EB0F74 /* ArticleToolbarModifier.swift in Sources */, FA80C11824B0728000974098 /* AddFolderView.swift in Sources */, + 17386B7A2577C4BF0014C8B2 /* AddLocalAccountView.swift in Sources */, 51E4996C24A8762D00B667CB /* ExtractedArticle.swift in Sources */, 51E4990824A808C300B667CB /* RSHTMLMetadata+Extension.swift in Sources */, 51919FF824AB8B7700541E64 /* TimelineView.swift in Sources */, @@ -4583,6 +4694,7 @@ 514E6C0724AD2B5F00AC6F6E /* Image-Extensions.swift in Sources */, 51E4994D24A8734C00B667CB /* ExtensionPointIdentifer.swift in Sources */, 51C65AFD24CCB2C9008EB3BD /* TimelineItems.swift in Sources */, + DF98E2BE2578AC0000F18944 /* AddNewsBlurAccountView.swift in Sources */, 51B54A6724B549FE0014348B /* ArticleIconSchemeHandler.swift in Sources */, 51E4992224A8095600B667CB /* URL-Extensions.swift in Sources */, 51E4990424A808C300B667CB /* WebFeedIconDownloader.swift in Sources */, @@ -4595,12 +4707,13 @@ 51B80F4224BE588200C6C32D /* SharingServicePickerDelegate.swift in Sources */, 51E4990624A808C300B667CB /* ImageDownloader.swift in Sources */, 51E4994F24A8734C00B667CB /* TwitterFeedProvider-Extensions.swift in Sources */, + 17241280257BBF3E00ACCEBC /* AddFeedWranglerViewModel.swift in Sources */, 51E498CA24A8085D00B667CB /* SmartFeedDelegate.swift in Sources */, + DF98E2B02578AA5C00F18944 /* AddFeedWranglerAccountView.swift in Sources */, 5177470A24B2F87600EB0F74 /* SidebarListStyleModifier.swift in Sources */, 1769E33824BD97CB000E1E8E /* AccountUpdateErrors.swift in Sources */, 51E4990524A808C300B667CB /* FeaturedImageDownloader.swift in Sources */, 5181C5AE24AF89B1002E0F70 /* PreferredColorSchemeModifier.swift in Sources */, - 1769E32924BCAFC7000E1E8E /* AddAccountPickerRow.swift in Sources */, 1769E32224BC5925000E1E8E /* AccountsPreferencesModel.swift in Sources */, 51E4991624A8090300B667CB /* ArticleUtilities.swift in Sources */, 51919FF224AB864A00541E64 /* TimelineModel.swift in Sources */, @@ -4622,17 +4735,21 @@ 51E498FC24A808BA00B667CB /* FaviconURLFinder.swift in Sources */, 51E4991C24A8092000B667CB /* NSAttributedString+NetNewsWire.swift in Sources */, 1769E32B24BCB030000E1E8E /* ConfiguredAccountRow.swift in Sources */, + DF98E2C62578AD1B00F18944 /* AddReaderAPIAccountView.swift in Sources */, FF64D0E824AF53EE0084080A /* RefreshProgressModel.swift in Sources */, 51E499D924A912C200B667CB /* SceneModel.swift in Sources */, 51919FB424AAB97900541E64 /* FeedIconImageLoader.swift in Sources */, 1769E32524BC5A65000E1E8E /* AddAccountView.swift in Sources */, 51E4994A24A8734C00B667CB /* ExtensionPointManager.swift in Sources */, 514E6C0324AD29A300AC6F6E /* TimelineItemStatusView.swift in Sources */, + 1724126A257BBEBB00ACCEBC /* AddFeedbinViewModel.swift in Sources */, 51B54A6524B549B20014348B /* WrapperScriptMessageHandler.swift in Sources */, 51E4996D24A8762D00B667CB /* ArticleExtractor.swift in Sources */, 1704053524E5985A00A00787 /* SceneNavigationModel.swift in Sources */, + 17241278257BBEE700ACCEBC /* AddFeedlyViewModel.swift in Sources */, 51E4994024A8713B00B667CB /* AccountRefreshTimer.swift in Sources */, 51E49A0424A91FF600B667CB /* SceneNavigationView.swift in Sources */, + 17241290257BBFAD00ACCEBC /* AddReaderAPIViewModel.swift in Sources */, 51E498CC24A8085D00B667CB /* SearchFeedDelegate.swift in Sources */, 51E498C824A8085D00B667CB /* SmartFeedsController.swift in Sources */, 175942AB24AD533200585066 /* RefreshInterval.swift in Sources */, @@ -4641,8 +4758,10 @@ 514E6C0A24AD39AD00AC6F6E /* ArticleIconImageLoader.swift in Sources */, 51E4995024A8734C00B667CB /* ExtensionPoint.swift in Sources */, 51E4990E24A808CC00B667CB /* HTMLMetadataDownloader.swift in Sources */, + DF98E29A2578A73A00F18944 /* AddCloudKitAccountView.swift in Sources */, 51E498FB24A808BA00B667CB /* FaviconGenerator.swift in Sources */, 17D5F19524B0C1DD00375168 /* SidebarToolbarModifier.swift in Sources */, + 17241288257BBF7000ACCEBC /* AddNewsBlurViewModel.swift in Sources */, 51E4996724A8760B00B667CB /* ArticleStylesManager.swift in Sources */, 1729529B24AA1FD200D65E66 /* MacSearchField.swift in Sources */, 51408B7F24A9EC6F0073CF4E /* SidebarItem.swift in Sources */, @@ -4659,6 +4778,7 @@ 51B54B6724B6A7960014348B /* WebStatusBarView.swift in Sources */, 51E4993E24A870F900B667CB /* UserNotificationManager.swift in Sources */, 51E4992E24A8676300B667CB /* FetchRequestQueue.swift in Sources */, + 17386B5E2577BC820014C8B2 /* AccountType+Helpers.swift in Sources */, 51E498CF24A8085D00B667CB /* SmartFeed.swift in Sources */, 51E4990724A808C300B667CB /* AuthorAvatarDownloader.swift in Sources */, 51E4997424A8784400B667CB /* DefaultFeedsImporter.swift in Sources */, @@ -4680,12 +4800,13 @@ 514E6C0024AD255D00AC6F6E /* PreviewArticles.swift in Sources */, 51C4CFF424D37D1F00AF9874 /* Secrets.swift in Sources */, 1729529524AA1CAA00D65E66 /* GeneralPreferencesView.swift in Sources */, - 1769E32724BC5B6C000E1E8E /* AddAccountModel.swift in Sources */, 1729529424AA1CAA00D65E66 /* AdvancedPreferencesView.swift in Sources */, 5177470424B2657F00EB0F74 /* TimelineToolbarModifier.swift in Sources */, 51A8001324CA0FC700F41F1D /* Sink.swift in Sources */, + 17241249257B8A8A00ACCEBC /* AddFeedlyAccountView.swift in Sources */, 51E4992D24A8676300B667CB /* FetchRequestOperation.swift in Sources */, 51E4992424A8098400B667CB /* SmartFeedPasteboardWriter.swift in Sources */, + 17D3CEE4257C4D2300E74939 /* AddAccountSignUp.swift in Sources */, 51E4991424A808FF00B667CB /* ArticleStringFormatter.swift in Sources */, 51B54A6624B549CB0014348B /* PreloadedWebView.swift in Sources */, 51E4991024A808DE00B667CB /* SmallIconProvider.swift in Sources */, @@ -5843,6 +5964,41 @@ package = 17192AD82567B3D500AAEACA /* XCRemoteSwiftPackageReference "Sparkle-Binary" */; productName = RSSparkle; }; + 17386B6B2577BD820014C8B2 /* RSSparkle */ = { + isa = XCSwiftPackageProductDependency; + package = 17192AD82567B3D500AAEACA /* XCRemoteSwiftPackageReference "Sparkle-Binary" */; + productName = RSSparkle; + }; + 17386B942577C6240014C8B2 /* RSCore */ = { + isa = XCSwiftPackageProductDependency; + package = 5102AE4324D17E820050839C /* XCRemoteSwiftPackageReference "RSCore" */; + productName = RSCore; + }; + 17386B972577C6240014C8B2 /* RSTree */ = { + isa = XCSwiftPackageProductDependency; + package = 510ECA4024D1DCD0001C31A6 /* XCRemoteSwiftPackageReference "RSTree" */; + productName = RSTree; + }; + 17386B9A2577C6240014C8B2 /* RSWeb */ = { + isa = XCSwiftPackageProductDependency; + package = 51383A3024D1F90E0027E272 /* XCRemoteSwiftPackageReference "RSWeb" */; + productName = RSWeb; + }; + 17386B9D2577C6240014C8B2 /* RSDatabase */ = { + isa = XCSwiftPackageProductDependency; + package = 51B0DF0D24D24E3B000AD99E /* XCRemoteSwiftPackageReference "RSDatabase" */; + productName = RSDatabase; + }; + 17386BA32577C6240014C8B2 /* RSParser */ = { + isa = XCSwiftPackageProductDependency; + package = 51B0DF2324D2C7FA000AD99E /* XCRemoteSwiftPackageReference "RSParser" */; + productName = RSParser; + }; + 17386BB52577C7340014C8B2 /* RSCoreResources */ = { + isa = XCSwiftPackageProductDependency; + package = 5102AE4324D17E820050839C /* XCRemoteSwiftPackageReference "RSCore" */; + productName = RSCoreResources; + }; 17A1597B24E3DEDD005DA32A /* RSCore */ = { isa = XCSwiftPackageProductDependency; package = 5102AE4324D17E820050839C /* XCRemoteSwiftPackageReference "RSCore" */; diff --git a/Shared/AccountType+Helpers.swift b/Shared/AccountType+Helpers.swift index fe61b9043..4b7ccb3cc 100644 --- a/Shared/AccountType+Helpers.swift +++ b/Shared/AccountType+Helpers.swift @@ -59,7 +59,16 @@ extension AccountType { func image() -> Image { switch self { case .onMyMac: + // If it's the multiplatform app, the asset catalog contains assets for + #if os(macOS) return Image("accountLocal") + #else + if UIDevice.current.userInterfaceIdiom == .pad { + return Image("accountLocalPad") + } else { + return Image("accountLocalPhone") + } + #endif case .bazQux: return Image("accountBazQux") case .cloudKit: diff --git a/iOS/Add/Add.storyboard b/iOS/Add/Add.storyboard index 3e86949aa..ca335bf36 100644 --- a/iOS/Add/Add.storyboard +++ b/iOS/Add/Add.storyboard @@ -1,9 +1,9 @@ - + - +