From 429ba1aed304f4111a1948832061b1e1e68da251 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Mon, 6 Apr 2020 21:06:42 -0500 Subject: [PATCH] Add Feed Providers preference pane. --- Frameworks/FeedProvider/FeedProvider.swift | 20 ++ .../FeedProvider.xcodeproj/project.pbxproj | 35 +++- Mac/AppAssets.swift | 4 + Mac/Base.lproj/Preferences.storyboard | 174 ++++++++++++++++-- .../FeedProviders/FeedProvidersAdd.xib | 109 +++++++++++ .../FeedProvidersAddTableCellView.swift | 16 ++ .../FeedProvidersAddViewController.swift | 141 ++++++++++++++ ...edProvidersPreferencesViewController.swift | 89 +++++++++ ...> PreferencesControlsBackgroundView.swift} | 4 +- ... PreferencesTableViewBackgroundView.swift} | 4 +- .../PreferencesWindowController.swift | 2 + .../Contents.json | 12 ++ .../feedProviderToolbar.imageset/globe.pdf | Bin 0 -> 7542 bytes .../Contents.json | 15 ++ .../feedProviderTwitter.imageset/twitter.pdf | Bin 0 -> 4237 bytes NetNewsWire.xcodeproj/project.pbxproj | 56 ++++-- 16 files changed, 651 insertions(+), 30 deletions(-) create mode 100644 Frameworks/FeedProvider/FeedProvider.swift create mode 100644 Mac/Preferences/FeedProviders/FeedProvidersAdd.xib create mode 100644 Mac/Preferences/FeedProviders/FeedProvidersAddTableCellView.swift create mode 100644 Mac/Preferences/FeedProviders/FeedProvidersAddViewController.swift create mode 100644 Mac/Preferences/FeedProviders/FeedProvidersPreferencesViewController.swift rename Mac/Preferences/{Accounts/AccountsControlsBackgroundView.swift => PreferencesControlsBackgroundView.swift} (93%) rename Mac/Preferences/{Accounts/AccountsTableViewBackgroundView.swift => PreferencesTableViewBackgroundView.swift} (81%) create mode 100644 Mac/Resources/Assets.xcassets/feedProviderToolbar.imageset/Contents.json create mode 100644 Mac/Resources/Assets.xcassets/feedProviderToolbar.imageset/globe.pdf create mode 100644 Mac/Resources/Assets.xcassets/feedProviderTwitter.imageset/Contents.json create mode 100644 Mac/Resources/Assets.xcassets/feedProviderTwitter.imageset/twitter.pdf diff --git a/Frameworks/FeedProvider/FeedProvider.swift b/Frameworks/FeedProvider/FeedProvider.swift new file mode 100644 index 000000000..8ce988d1e --- /dev/null +++ b/Frameworks/FeedProvider/FeedProvider.swift @@ -0,0 +1,20 @@ +// +// FeedProvider.swift +// FeedProvider +// +// Created by Maurice Parker on 4/6/20. +// Copyright © 2020 Ranchero Software, LLC. All rights reserved. +// + +import Foundation +import RSCore + +public enum FeedProviderType: Int, Codable { + // Raw values should not change since they’re stored. + case twitter = 1 +} + + +protocol FeedProvider { + +} diff --git a/Frameworks/FeedProvider/FeedProvider.xcodeproj/project.pbxproj b/Frameworks/FeedProvider/FeedProvider.xcodeproj/project.pbxproj index 949eb244d..1440e387b 100644 --- a/Frameworks/FeedProvider/FeedProvider.xcodeproj/project.pbxproj +++ b/Frameworks/FeedProvider/FeedProvider.xcodeproj/project.pbxproj @@ -13,8 +13,28 @@ 5110769E243BCF3A00D97C8C /* FeedProvider_project_debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 51107699243BCF3A00D97C8C /* FeedProvider_project_debug.xcconfig */; }; 5110769F243BCF3A00D97C8C /* FeedProvider_project.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 5110769A243BCF3A00D97C8C /* FeedProvider_project.xcconfig */; }; 511076EE243BD82A00D97C8C /* Articles.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 511076ED243BD82A00D97C8C /* Articles.framework */; }; + 51107722243BE0DA00D97C8C /* FeedProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51107721243BE0DA00D97C8C /* FeedProvider.swift */; }; + 51107724243BE11800D97C8C /* RSParser.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51107723243BE11800D97C8C /* RSParser.framework */; }; + 51107725243BE11800D97C8C /* RSParser.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 51107723243BE11800D97C8C /* RSParser.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 51107728243BE15D00D97C8C /* RSCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51107727243BE15D00D97C8C /* RSCore.framework */; }; + 51107729243BE15D00D97C8C /* RSCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 51107727243BE15D00D97C8C /* RSCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; /* End PBXBuildFile section */ +/* Begin PBXCopyFilesBuildPhase section */ + 51107726243BE11800D97C8C /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 51107729243BE15D00D97C8C /* RSCore.framework in Embed Frameworks */, + 51107725243BE11800D97C8C /* RSParser.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ 5110765F243BCE0400D97C8C /* FeedProvider.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FeedProvider.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 51107663243BCE0400D97C8C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -24,6 +44,9 @@ 51107699243BCF3A00D97C8C /* FeedProvider_project_debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = FeedProvider_project_debug.xcconfig; sourceTree = ""; }; 5110769A243BCF3A00D97C8C /* FeedProvider_project.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = FeedProvider_project.xcconfig; sourceTree = ""; }; 511076ED243BD82A00D97C8C /* Articles.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Articles.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 51107721243BE0DA00D97C8C /* FeedProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedProvider.swift; sourceTree = ""; }; + 51107723243BE11800D97C8C /* RSParser.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = RSParser.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 51107727243BE15D00D97C8C /* RSCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = RSCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -31,6 +54,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 51107728243BE15D00D97C8C /* RSCore.framework in Frameworks */, + 51107724243BE11800D97C8C /* RSParser.framework in Frameworks */, 511076EE243BD82A00D97C8C /* Articles.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -41,6 +66,7 @@ 51107655243BCE0400D97C8C = { isa = PBXGroup; children = ( + 51107721243BE0DA00D97C8C /* FeedProvider.swift */, 51107689243BCEB300D97C8C /* xcconfig */, 51107663243BCE0400D97C8C /* Info.plist */, 51107660243BCE0400D97C8C /* Products */, @@ -59,10 +85,10 @@ 51107689243BCEB300D97C8C /* xcconfig */ = { isa = PBXGroup; children = ( + 5110769A243BCF3A00D97C8C /* FeedProvider_project.xcconfig */, 51107699243BCF3A00D97C8C /* FeedProvider_project_debug.xcconfig */, 51107698243BCF3A00D97C8C /* FeedProvider_project_release.xcconfig */, 51107697243BCF3A00D97C8C /* FeedProvider_project_test.xcconfig */, - 5110769A243BCF3A00D97C8C /* FeedProvider_project.xcconfig */, 51107696243BCF3A00D97C8C /* FeedProvider_target.xcconfig */, ); path = xcconfig; @@ -71,6 +97,8 @@ 511076EC243BD82A00D97C8C /* Frameworks */ = { isa = PBXGroup; children = ( + 51107727243BE15D00D97C8C /* RSCore.framework */, + 51107723243BE11800D97C8C /* RSParser.framework */, 511076ED243BD82A00D97C8C /* Articles.framework */, ); name = Frameworks; @@ -98,6 +126,7 @@ 5110765C243BCE0400D97C8C /* Frameworks */, 5110765D243BCE0400D97C8C /* Resources */, 511076A2243BD2E600D97C8C /* Run Script: Verfiy No Build Settings */, + 51107726243BE11800D97C8C /* Embed Frameworks */, ); buildRules = ( ); @@ -115,10 +144,11 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 1140; - ORGANIZATIONNAME = "Vincode, Inc"; + ORGANIZATIONNAME = "Ranchero Software, LLC"; TargetAttributes = { 5110765E243BCE0400D97C8C = { CreatedOnToolsVersion = 11.4; + LastSwiftMigration = 1140; }; }; }; @@ -181,6 +211,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 51107722243BE0DA00D97C8C /* FeedProvider.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Mac/AppAssets.swift b/Mac/AppAssets.swift index 777438f2c..4ef1c1cc5 100644 --- a/Mac/AppAssets.swift +++ b/Mac/AppAssets.swift @@ -81,6 +81,10 @@ struct AppAssets { return RSImage(named: "faviconTemplateImage")! }() + static var feedProviderTwitter: RSImage = { + return RSImage(named: "feedProviderTwitter")! + }() + static var filterActive: RSImage = { return RSImage(named: "filterActive")! }() diff --git a/Mac/Base.lproj/Preferences.storyboard b/Mac/Base.lproj/Preferences.storyboard index 6b2ac07d5..e9aad2bd7 100644 --- a/Mac/Base.lproj/Preferences.storyboard +++ b/Mac/Base.lproj/Preferences.storyboard @@ -1,8 +1,7 @@ - + - - + @@ -375,7 +374,7 @@ - + @@ -385,17 +384,17 @@ - - + + - + - + - + @@ -403,7 +402,6 @@ - @@ -499,11 +497,11 @@ - + - + @@ -549,6 +547,158 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Mac/Preferences/FeedProviders/FeedProvidersAdd.xib b/Mac/Preferences/FeedProviders/FeedProvidersAdd.xib new file mode 100644 index 000000000..874bfa9e0 --- /dev/null +++ b/Mac/Preferences/FeedProviders/FeedProvidersAdd.xib @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Mac/Preferences/FeedProviders/FeedProvidersAddTableCellView.swift b/Mac/Preferences/FeedProviders/FeedProvidersAddTableCellView.swift new file mode 100644 index 000000000..8d0325832 --- /dev/null +++ b/Mac/Preferences/FeedProviders/FeedProvidersAddTableCellView.swift @@ -0,0 +1,16 @@ +// +// FeedProvidersAddTableCellView.swift +// NetNewsWire +// +// Created by Maurice Parker on 4/6/20. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import AppKit + +class FeedProvidersAddTableCellView: NSTableCellView { + + @IBOutlet weak var feedProviderImageView: NSImageView? + @IBOutlet weak var feedProviderNameLabel: NSTextField? + +} diff --git a/Mac/Preferences/FeedProviders/FeedProvidersAddViewController.swift b/Mac/Preferences/FeedProviders/FeedProvidersAddViewController.swift new file mode 100644 index 000000000..426037d96 --- /dev/null +++ b/Mac/Preferences/FeedProviders/FeedProvidersAddViewController.swift @@ -0,0 +1,141 @@ +// +// FeedProvidersAddViewController.swift +// NetNewsWire +// +// Created by Maurice Parker on 4/6/20. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import AppKit +import FeedProvider + +class FeedProvidersAddViewController: NSViewController { + + @IBOutlet weak var tableView: NSTableView! + + private var accountsAddWindowController: NSWindowController? + + #if DEBUG + private var addableFeedProviderTypes: [FeedProviderType] = [.twitter] + #else + private var addableFeedProviderTypes: [FeedProviderType] = [.twitter] + #endif + + init() { + super.init(nibName: "FeedProvidersAdd", bundle: nil) + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + } + + override func viewDidLoad() { + super.viewDidLoad() + tableView.dataSource = self + tableView.delegate = self + } + +} + +// MARK: - NSTableViewDataSource + +extension FeedProvidersAddViewController: NSTableViewDataSource { + + func numberOfRows(in tableView: NSTableView) -> Int { + return addableFeedProviderTypes.count + } + + func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? { + return nil + } +} + +// MARK: - NSTableViewDelegate + +extension FeedProvidersAddViewController: NSTableViewDelegate { + + private static let cellIdentifier = NSUserInterfaceItemIdentifier(rawValue: "AccountCell") + + func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { + + if let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "Cell"), owner: nil) as? FeedProvidersAddTableCellView { + switch addableFeedProviderTypes[row] { + case .twitter: + cell.feedProviderNameLabel?.stringValue = NSLocalizedString("Twitter", comment: "Twitter") + cell.feedProviderImageView?.image = AppAssets.feedProviderTwitter + } + return cell + } + return nil + } + + func tableViewSelectionDidChange(_ notification: Notification) { + + let selectedRow = tableView.selectedRow + guard selectedRow != -1 else { + return + } + +// switch addableAccountTypes[selectedRow] { +// 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! +// MainThreadOperationQueue.shared.add(addAccount) +// case .newsBlur: +// let accountsNewsBlurWindowController = AccountsNewsBlurWindowController() +// accountsNewsBlurWindowController.runSheetOnWindow(self.view.window!) +// accountsAddWindowController = accountsNewsBlurWindowController +// } + + tableView.selectRowIndexes([], byExtendingSelection: false) + + } + +} + +// MARK: OAuthAccountAuthorizationOperationDelegate + +//extension AccountsAddViewController: OAuthAccountAuthorizationOperationDelegate { +// +// func oauthAccountAuthorizationOperation(_ operation: OAuthAccountAuthorizationOperation, didCreate account: Account) { +// account.refreshAll { [weak self] result in +// switch result { +// case .success: +// break +// case .failure(let error): +// self?.presentError(error) +// } +// } +// } +// +// func oauthAccountAuthorizationOperation(_ operation: OAuthAccountAuthorizationOperation, didFailWith error: Error) { +// view.window?.presentError(error) +// } +//} diff --git a/Mac/Preferences/FeedProviders/FeedProvidersPreferencesViewController.swift b/Mac/Preferences/FeedProviders/FeedProvidersPreferencesViewController.swift new file mode 100644 index 000000000..d41b97df7 --- /dev/null +++ b/Mac/Preferences/FeedProviders/FeedProvidersPreferencesViewController.swift @@ -0,0 +1,89 @@ +// +// FeedProvidersPreferencesViewController.swift +// NetNewsWire +// +// Created by Maurice Parker on 4/6/20. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import AppKit + +final class FeedProvidersPreferencesViewController: NSViewController { + + @IBOutlet weak var tableView: NSTableView! + @IBOutlet weak var detailView: NSView! + @IBOutlet weak var deleteButton: NSButton! + + private var sortedAccounts = [String]() + + override func viewDidLoad() { + super.viewDidLoad() + + tableView.delegate = self + tableView.dataSource = self + + showController(FeedProvidersAddViewController()) + + // 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 + rTable.size.width = tableView.superview!.frame.size.width + tableView.frame = rTable + } + +} + +// MARK: - NSTableViewDataSource + +extension FeedProvidersPreferencesViewController: NSTableViewDataSource { + + func numberOfRows(in tableView: NSTableView) -> Int { + return sortedAccounts.count + } + + func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? { + return sortedAccounts[row] + } +} + +// MARK: - NSTableViewDelegate + +extension FeedProvidersPreferencesViewController: NSTableViewDelegate { + + private static let cellIdentifier = NSUserInterfaceItemIdentifier(rawValue: "AccountCell") + + func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { + if let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "Cell"), owner: nil) as? NSTableCellView { + let account = sortedAccounts[row] +// cell.textField?.stringValue = account.nameForDisplay +// cell.imageView?.image = account.smallIcon?.image + return cell + } + return nil + } + + func tableViewSelectionDidChange(_ notification: Notification) { + + + } + +} + +// MARK: - Private + +private extension FeedProvidersPreferencesViewController { + + func showController(_ controller: NSViewController) { + + if let controller = children.first { + children.removeAll() + controller.view.removeFromSuperview() + } + + addChild(controller) + controller.view.translatesAutoresizingMaskIntoConstraints = false + detailView.addSubview(controller.view) + detailView.addFullSizeConstraints(forSubview: controller.view) + + } + +} diff --git a/Mac/Preferences/Accounts/AccountsControlsBackgroundView.swift b/Mac/Preferences/PreferencesControlsBackgroundView.swift similarity index 93% rename from Mac/Preferences/Accounts/AccountsControlsBackgroundView.swift rename to Mac/Preferences/PreferencesControlsBackgroundView.swift index ef4489430..36353dd6b 100644 --- a/Mac/Preferences/Accounts/AccountsControlsBackgroundView.swift +++ b/Mac/Preferences/PreferencesControlsBackgroundView.swift @@ -1,5 +1,5 @@ // -// AccountsControlsBackgroundView.swift +// PreferencesControlsBackgroundView.swift // NetNewsWire // // Created by Brent Simmons on 3/18/19. @@ -9,7 +9,7 @@ import AppKit import RSCore -final class AccountsControlsBackgroundView: NSView { +final class PreferencesControlsBackgroundView: NSView { private let lightModeFillColor = NSColor(white: 0.97, alpha: 1.0) private let darkModeFillColor = NSColor(red: 0.32, green: 0.34, blue: 0.35, alpha: 1.0) diff --git a/Mac/Preferences/Accounts/AccountsTableViewBackgroundView.swift b/Mac/Preferences/PreferencesTableViewBackgroundView.swift similarity index 81% rename from Mac/Preferences/Accounts/AccountsTableViewBackgroundView.swift rename to Mac/Preferences/PreferencesTableViewBackgroundView.swift index 2c30b96b1..34548e429 100644 --- a/Mac/Preferences/Accounts/AccountsTableViewBackgroundView.swift +++ b/Mac/Preferences/PreferencesTableViewBackgroundView.swift @@ -1,5 +1,5 @@ // -// AccountsTableViewBackgroundView.swift +// PreferencesTableViewBackgroundView.swift // NetNewsWire // // Created by Brent Simmons on 3/19/19. @@ -8,7 +8,7 @@ import AppKit -final class AccountsTableViewBackgroundView: NSView { +final class PreferencesTableViewBackgroundView: NSView { let lightBorderColor = NSColor(white: 0.71, alpha: 1.0) let darkBorderColor = NSColor(red: 0.41, green: 0.43, blue: 0.44, alpha: 1.0) diff --git a/Mac/Preferences/PreferencesWindowController.swift b/Mac/Preferences/PreferencesWindowController.swift index 79570b50a..b13adbfd4 100644 --- a/Mac/Preferences/PreferencesWindowController.swift +++ b/Mac/Preferences/PreferencesWindowController.swift @@ -24,6 +24,7 @@ private struct PreferencesToolbarItemSpec { private struct ToolbarItemIdentifier { static let General = "General" static let Accounts = "Accounts" + static let FeedProvider = "FeedProvider" static let Advanced = "Advanced" } @@ -35,6 +36,7 @@ class PreferencesWindowController : NSWindowController, NSToolbarDelegate { var specs = [PreferencesToolbarItemSpec]() specs += [PreferencesToolbarItemSpec(identifierRawValue: ToolbarItemIdentifier.General, name: NSLocalizedString("General", comment: "Preferences"), imageName: NSImage.preferencesGeneralName)] specs += [PreferencesToolbarItemSpec(identifierRawValue: ToolbarItemIdentifier.Accounts, name: NSLocalizedString("Accounts", comment: "Preferences"), imageName: NSImage.userAccountsName)] + specs += [PreferencesToolbarItemSpec(identifierRawValue: ToolbarItemIdentifier.FeedProvider, name: NSLocalizedString("Providers", comment: "Preferences"), imageName: "feedProviderToolbar")] // Omit the Advanced Preferences for now because the Software Update related functionality is // forbidden/non-applicable, and we can rely upon Apple to some extent for crash reports. We diff --git a/Mac/Resources/Assets.xcassets/feedProviderToolbar.imageset/Contents.json b/Mac/Resources/Assets.xcassets/feedProviderToolbar.imageset/Contents.json new file mode 100644 index 000000000..79f849e65 --- /dev/null +++ b/Mac/Resources/Assets.xcassets/feedProviderToolbar.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "globe.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Mac/Resources/Assets.xcassets/feedProviderToolbar.imageset/globe.pdf b/Mac/Resources/Assets.xcassets/feedProviderToolbar.imageset/globe.pdf new file mode 100644 index 0000000000000000000000000000000000000000..2e2ffbf186cd7c33e0dce23a6d31f4a66dc463a6 GIT binary patch literal 7542 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 Nc`#{d#pNY1{|CIlI9LDx literal 0 HcmV?d00001 diff --git a/Mac/Resources/Assets.xcassets/feedProviderTwitter.imageset/Contents.json b/Mac/Resources/Assets.xcassets/feedProviderTwitter.imageset/Contents.json new file mode 100644 index 000000000..834100cda --- /dev/null +++ b/Mac/Resources/Assets.xcassets/feedProviderTwitter.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "twitter.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/Mac/Resources/Assets.xcassets/feedProviderTwitter.imageset/twitter.pdf b/Mac/Resources/Assets.xcassets/feedProviderTwitter.imageset/twitter.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e50de4443827d9570161cdd229c8d6ce640981e4 GIT binary patch literal 4237 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