Prototype Refresh

This commit is contained in:
Stuart Breckenridge 2020-10-28 23:19:42 +08:00
parent 31607414f6
commit 3fdb0d1f04
No known key found for this signature in database
GPG Key ID: 802A426F493CA19C
6 changed files with 367 additions and 11 deletions

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="17505" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="17506" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="17505"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="17506"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -50,7 +50,7 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView distribution="fill" orientation="horizontal" alignment="centerY" spacing="17" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="iCD-Yx-4V5">
<rect key="frame" x="20" y="8" width="174" height="24"/>
<rect key="frame" x="20" y="8" width="133" height="24"/>
<subviews>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="KmN-Zk-TBU">
<rect key="frame" x="0.0" y="0.0" width="24" height="24"/>
@ -61,9 +61,9 @@
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="oGL-yl-27S"/>
</imageView>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="uyu-5W-IaW">
<rect key="frame" x="39" y="0.0" width="137" height="24"/>
<rect key="frame" x="39" y="4" width="96" height="16"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="iOW-VJ-bkx">
<font key="font" metaFont="system" size="20"/>
<font key="font" textStyle="body" name=".SFNS-Regular"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
@ -83,7 +83,7 @@
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="bevel" bezelStyle="rounded" alignment="center" imageScaling="proportionallyDown" inset="2" id="yf7-Ye-Pcd">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<font key="font" textStyle="body" name=".SFNS-Regular"/>
</buttonCell>
<connections>
<action selector="pressed:" target="EGi-CQ-lPc" id="2a9-Bp-K3K"/>

View File

@ -171,7 +171,6 @@ extension AccountsAddViewController: AccountsAddTableCellViewDelegate {
accountsReaderAPIWindowController.accountType = .theOldReader
accountsReaderAPIWindowController.runSheetOnWindow(self.view.window!)
accountsAddWindowController = accountsReaderAPIWindowController
}
}

View File

@ -8,12 +8,17 @@
import AppKit
import Account
import SwiftUI
import RSCore
final class AccountsPreferencesViewController: NSViewController {
@IBOutlet weak var tableView: NSTableView!
@IBOutlet weak var detailView: NSView!
@IBOutlet weak var deleteButton: NSButton!
var addAccountDelegate: AccountsPreferencesAddAccountDelegate?
private var sortedAccounts = [Account]()
@ -23,12 +28,13 @@ final class AccountsPreferencesViewController: NSViewController {
updateSortedAccounts()
tableView.delegate = self
tableView.dataSource = self
addAccountDelegate = self
NotificationCenter.default.addObserver(self, selector: #selector(displayNameDidChange(_:)), name: .DisplayNameDidChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(accountsDidChange(_:)), name: .UserDidAddAccount, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(accountsDidChange(_:)), name: .UserDidDeleteAccount, object: nil)
showController(AccountsAddViewController())
//showController(AccountsAddViewController())
// Fix tableView frame  for some reason IB wants it 1pt wider than the clip view. This leads to unwanted horizontal scrolling.
var rTable = tableView.frame
@ -37,8 +43,10 @@ final class AccountsPreferencesViewController: NSViewController {
}
@IBAction func addAccount(_ sender: Any) {
tableView.selectRowIndexes([], byExtendingSelection: false)
showController(AccountsAddViewController())
//tableView.selectRowIndexes([], byExtendingSelection: false)
let controller = NSHostingController(rootView: AddAccountsView(delegate: self))
controller.rootView.parent = controller
presentAsSheet(controller)
}
@IBAction func removeAccount(_ sender: Any) {
@ -62,7 +70,7 @@ final class AccountsPreferencesViewController: NSViewController {
if result == NSApplication.ModalResponse.alertFirstButtonReturn {
guard let self = self else { return }
AccountManager.shared.deleteAccount(self.sortedAccounts[self.tableView.selectedRow])
self.showController(AccountsAddViewController())
//self.showController(AccountsAddViewController())
}
}
@ -132,6 +140,106 @@ extension AccountsPreferencesViewController: NSTableViewDelegate {
}
// MARK: - AccountsPreferencesAddAccountDelegate
protocol AccountsPreferencesAddAccountDelegate {
func presentSheetForAccount(_ accountType: AccountType)
}
extension AccountsPreferencesViewController: AccountsPreferencesAddAccountDelegate {
func presentSheetForAccount(_ accountType: AccountType) {
switch accountType {
case .onMyMac:
let accountsAddLocalWindowController = AccountsAddLocalWindowController()
accountsAddLocalWindowController.runSheetOnWindow(self.view.window!)
//accountsAddWindowController = accountsAddLocalWindowController
case .cloudKit:
let accountsAddCloudKitWindowController = AccountsAddCloudKitWindowController()
accountsAddCloudKitWindowController.runSheetOnWindow(self.view.window!) { response in
if response == NSApplication.ModalResponse.OK {
//self.restrictAccounts()
//self.tableView.reloadData()
}
}
//accountsAddWindowController = accountsAddCloudKitWindowController
case .feedbin:
let accountsFeedbinWindowController = AccountsFeedbinWindowController()
accountsFeedbinWindowController.runSheetOnWindow(self.view.window!)
//accountsAddWindowController = accountsFeedbinWindowController
case .feedWrangler:
let accountsFeedWranglerWindowController = AccountsFeedWranglerWindowController()
accountsFeedWranglerWindowController.runSheetOnWindow(self.view.window!)
//accountsAddWindowController = accountsFeedWranglerWindowController
case .freshRSS:
let accountsReaderAPIWindowController = AccountsReaderAPIWindowController()
accountsReaderAPIWindowController.accountType = .freshRSS
accountsReaderAPIWindowController.runSheetOnWindow(self.view.window!)
//accountsAddWindowController = accountsReaderAPIWindowController
case .feedly:
let addAccount = OAuthAccountAuthorizationOperation(accountType: .feedly)
//addAccount.delegate = self
addAccount.presentationAnchor = self.view.window!
runAwaitingFeedlyLoginAlertModal(forLifetimeOf: addAccount)
MainThreadOperationQueue.shared.add(addAccount)
case .newsBlur:
let accountsNewsBlurWindowController = AccountsNewsBlurWindowController()
accountsNewsBlurWindowController.runSheetOnWindow(self.view.window!)
//accountsAddWindowController = accountsNewsBlurWindowController
case .inoreader:
let accountsReaderAPIWindowController = AccountsReaderAPIWindowController()
accountsReaderAPIWindowController.accountType = .inoreader
accountsReaderAPIWindowController.runSheetOnWindow(self.view.window!)
//accountsAddWindowController = accountsReaderAPIWindowController
case .bazQux:
let accountsReaderAPIWindowController = AccountsReaderAPIWindowController()
accountsReaderAPIWindowController.accountType = .bazQux
accountsReaderAPIWindowController.runSheetOnWindow(self.view.window!)
//accountsAddWindowController = accountsReaderAPIWindowController
case .theOldReader:
let accountsReaderAPIWindowController = AccountsReaderAPIWindowController()
accountsReaderAPIWindowController.accountType = .theOldReader
accountsReaderAPIWindowController.runSheetOnWindow(self.view.window!)
//accountsAddWindowController = accountsReaderAPIWindowController
}
}
private func runAwaitingFeedlyLoginAlertModal(forLifetimeOf operation: OAuthAccountAuthorizationOperation) {
let alert = NSAlert()
alert.alertStyle = .informational
alert.messageText = NSLocalizedString("Waiting for access to Feedly",
comment: "Alert title when adding a Feedly account and waiting for authorization from the user.")
alert.informativeText = NSLocalizedString("Your default web browser will open the Feedly login for you to authorize access.",
comment: "Alert informative text when adding a Feedly account and waiting for authorization from the user.")
alert.addButton(withTitle: NSLocalizedString("Cancel", comment: "Cancel"))
let attachedWindow = self.view.window!
alert.beginSheetModal(for: attachedWindow) { response in
if response == .alertFirstButtonReturn {
operation.cancel()
}
}
operation.completionBlock = { _ in
guard alert.window.isVisible else {
return
}
attachedWindow.endSheet(alert.window)
}
}
}
// MARK: - Private
private extension AccountsPreferencesViewController {
@ -155,3 +263,4 @@ private extension AccountsPreferencesViewController {
}
}

View File

@ -0,0 +1,241 @@
//
// AddAccountsView.swift
// NetNewsWire
//
// Created by Stuart Breckenridge on 28/10/20.
// Copyright © 2020 Ranchero Software. All rights reserved.
//
import SwiftUI
import Account
private enum AddAccountSections: Int, CaseIterable {
case local = 0
case icloud
case web
case selfhosted
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")
}
}
var sectionFooter: String {
switch self {
case .local:
return NSLocalizedString("This account does 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")
}
}
var sectionContent: [AccountType] {
switch self {
case .local:
return [.onMyMac]
case .icloud:
return [.cloudKit]
case .web:
return [.bazQux, .feedbin, .feedly, .feedWrangler, .inoreader, .newsBlur, .theOldReader]
case .selfhosted:
return [.freshRSS]
}
}
}
struct AddAccountsView: View {
weak var parent: NSHostingController<AddAccountsView>? // required because presentationMode.dismiss() doesn't work
var addAccountDelegate: AccountsPreferencesAddAccountDelegate?
init(delegate: AccountsPreferencesAddAccountDelegate?) {
self.addAccountDelegate = delegate
}
@State private var selectedAccount: AccountType = .onMyMac
var body: some View {
VStack(alignment: .leading, spacing: 8) {
Text("Choose an account type to add...")
.font(.headline)
.padding()
localAccount
icloudAccount
webAccounts
selfhostedAccounts
HStack {
Spacer()
if #available(OSX 11.0, *) {
Button(action: {
parent?.dismiss(nil)
}, label: {
Text("Cancel")
.accessibility(label: Text("Add Account"))
}).keyboardShortcut(.cancelAction)
} else {
Button(action: {
parent?.dismiss(nil)
}, label: {
Text("Cancel")
.accessibility(label: Text("Add Account"))
})
}
if #available(OSX 11.0, *) {
Button(action: {
addAccountDelegate?.presentSheetForAccount(selectedAccount)
parent?.dismiss(nil)
}, label: {
Text("Continue")
}).keyboardShortcut(.defaultAction)
} else {
Button(action: {
addAccountDelegate?.presentSheetForAccount(selectedAccount)
parent?.dismiss(nil)
}, label: {
Text("Continue")
})
}
}.padding([.top, .bottom], 4)
}
.pickerStyle(RadioGroupPickerStyle())
.fixedSize(horizontal: false, vertical: true)
.frame(width: 400)
.padding(12)
}
var localAccount: some View {
VStack(alignment: .leading) {
Text("Local")
.font(.headline)
.padding(.horizontal)
Picker(selection: $selectedAccount, label: Text(""), content: {
ForEach(AddAccountSections.local.sectionContent, id: \.self, content: { account in
HStack(alignment: .top) {
Image(nsImage: AppAssets.image(for: account)!)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 25, height: 25, alignment: .center)
.offset(CGSize(width: 0, height: -2.5))
VStack(alignment: .leading, spacing: 4) {
Text(account.localizedAccountName())
Text(AddAccountSections.local.sectionFooter).foregroundColor(.gray)
.font(.caption)
}
}
.tag(account)
})
})
.pickerStyle(RadioGroupPickerStyle())
}
}
var icloudAccount: some View {
VStack(alignment: .leading) {
Text("iCloud")
.font(.headline)
.padding(.horizontal)
Picker(selection: $selectedAccount, label: Text(""), content: {
ForEach(AddAccountSections.icloud.sectionContent, id: \.self, content: { account in
HStack(alignment: .top) {
Image(nsImage: AppAssets.image(for: account)!)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 25, height: 25, alignment: .center)
.offset(CGSize(width: 0, height: -5))
VStack(alignment: .leading, spacing: 4) {
Text(account.localizedAccountName())
Text(AddAccountSections.icloud.sectionFooter).foregroundColor(.gray)
.font(.caption)
}
}
.tag(account)
})
})
.disabled(isCloudInUse())
}
}
var webAccounts: some View {
VStack(alignment: .leading) {
Text("Web")
.font(.headline)
.padding(.horizontal)
Picker(selection: $selectedAccount, label: Text(""), content: {
ForEach(AddAccountSections.web.sectionContent.filter({ isRestricted($0) != true }), id: \.self, content: { account in
HStack(alignment: .center) {
Image(nsImage: AppAssets.image(for: account)!)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 25, height: 25, alignment: .center)
VStack(alignment: .leading) {
Text(account.localizedAccountName())
}
}
.tag(account)
})
})
}
}
var selfhostedAccounts: some View {
VStack(alignment: .leading) {
Text("Self-hosted")
.font(.headline)
.padding(.horizontal)
Picker(selection: $selectedAccount, label: Text(""), content: {
ForEach(AddAccountSections.selfhosted.sectionContent, id: \.self, content: { account in
HStack {
Image(nsImage: AppAssets.image(for: account)!)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 25, height: 25, alignment: .center)
Text(account.localizedAccountName())
}.tag(account)
})
})
Text("Web and self-hosted accounts sync across all signed-in devices.")
.font(.caption)
.padding(.leading, 62)
.foregroundColor(.gray)
}
}
private func isCloudInUse() -> Bool {
AccountManager.shared.accounts.contains(where: { $0.type == .cloudKit })
}
private func isRestricted(_ accountType: AccountType) -> Bool {
if AppDefaults.shared.isDeveloperBuild && (accountType == .feedly || accountType == .feedWrangler || accountType == .inoreader) {
return true
}
return false
}
}
struct AddAccountsView_Previews: PreviewProvider {
static var previews: some View {
AddAccountsView(delegate: nil)
}
}

View File

@ -41,6 +41,8 @@
177A0C2D25454AAB00D7EAF6 /* ReaderAPIAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 177A0C2C25454AAB00D7EAF6 /* ReaderAPIAccountViewController.swift */; };
17897ACA24C281A40014BA03 /* InspectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17897AC924C281A40014BA03 /* InspectorView.swift */; };
17897ACB24C281A40014BA03 /* InspectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17897AC924C281A40014BA03 /* InspectorView.swift */; };
178A9F9D2549449F00AB7E9D /* AddAccountsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 178A9F9C2549449F00AB7E9D /* AddAccountsView.swift */; };
178A9F9E2549449F00AB7E9D /* AddAccountsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 178A9F9C2549449F00AB7E9D /* AddAccountsView.swift */; };
17930ED424AF10EE00A9BA52 /* AddWebFeedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17930ED324AF10EE00A9BA52 /* AddWebFeedView.swift */; };
17930ED524AF10EE00A9BA52 /* AddWebFeedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17930ED324AF10EE00A9BA52 /* AddWebFeedView.swift */; };
1799E6A924C2F93F00511E91 /* InspectorPlatformModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1799E6A824C2F93F00511E91 /* InspectorPlatformModifier.swift */; };
@ -1468,6 +1470,7 @@
1776E88D24AC5F8A00E78166 /* AppDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDefaults.swift; sourceTree = "<group>"; };
177A0C2C25454AAB00D7EAF6 /* ReaderAPIAccountViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderAPIAccountViewController.swift; sourceTree = "<group>"; };
17897AC924C281A40014BA03 /* InspectorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InspectorView.swift; sourceTree = "<group>"; };
178A9F9C2549449F00AB7E9D /* AddAccountsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddAccountsView.swift; sourceTree = "<group>"; };
17930ED324AF10EE00A9BA52 /* AddWebFeedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddWebFeedView.swift; sourceTree = "<group>"; };
1799E6A824C2F93F00511E91 /* InspectorPlatformModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InspectorPlatformModifier.swift; sourceTree = "<group>"; };
1799E6CC24C320D600511E91 /* InspectorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InspectorModel.swift; sourceTree = "<group>"; };
@ -3345,6 +3348,7 @@
84C9FC6F22629E1200D921D6 /* Accounts */ = {
isa = PBXGroup;
children = (
178A9F9C2549449F00AB7E9D /* AddAccountsView.swift */,
84C9FC7222629E1200D921D6 /* AccountsPreferencesViewController.swift */,
51EF0F8D2279C9260050506E /* AccountsAdd.xib */,
51EF0F8F2279C9500050506E /* AccountsAddViewController.swift */,
@ -4948,6 +4952,7 @@
515A5108243D0CCD0089E588 /* TwitterFeedProvider-Extensions.swift in Sources */,
65ED402B235DEF6C0081F399 /* ImportOPMLWindowController.swift in Sources */,
65ED402C235DEF6C0081F399 /* TimelineTableView.swift in Sources */,
178A9F9E2549449F00AB7E9D /* AddAccountsView.swift in Sources */,
65ED402D235DEF6C0081F399 /* DetailStatusBarView.swift in Sources */,
65ED402E235DEF6C0081F399 /* MainWindowController+Scriptability.swift in Sources */,
65ED402F235DEF6C0081F399 /* PreferencesWindowController.swift in Sources */,
@ -5309,6 +5314,7 @@
84B99C9D1FAE83C600ECDEDB /* DeleteCommand.swift in Sources */,
849A97541ED9EAC0007D329B /* AddWebFeedWindowController.swift in Sources */,
5144EA40227A37EC00D19003 /* ImportOPMLWindowController.swift in Sources */,
178A9F9D2549449F00AB7E9D /* AddAccountsView.swift in Sources */,
51C4CFF024D37D1F00AF9874 /* Secrets.swift in Sources */,
849A976D1ED9EBC8007D329B /* TimelineTableView.swift in Sources */,
51333D1624685D2E00EB5C91 /* AddRedditFeedWindowController.swift in Sources */,

View File

@ -72,6 +72,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
debugAsWhichUser = "root"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"