Make the default-aggregator popup work in the preferences window. Fix #444.
This commit is contained in:
parent
03d615f8ef
commit
4d90ed022f
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="14313.13.2" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="mPU-HG-I4u">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="mPU-HG-I4u">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14313.13.2"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14460.31"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
|
@ -76,17 +76,18 @@
|
|||
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="cSu-T2-Jby">
|
||||
<rect key="frame" x="198" y="45" width="212" height="25"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="push" title="This doesn’t work yet" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="bEy-Qx-Grl" id="Dyk-WN-XOo">
|
||||
<popUpButtonCell key="cell" type="push" title="NetNewsWire" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="bEy-Qx-Grl" id="Dyk-WN-XOo" userLabel="Popup">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="menu"/>
|
||||
<menu key="menu" id="8PF-kj-u99">
|
||||
<items>
|
||||
<menuItem title="This doesn’t work yet" state="on" id="bEy-Qx-Grl"/>
|
||||
<menuItem title="Item 2" id="ZB8-D2-BS4"/>
|
||||
<menuItem title="Item 3" id="aSx-R2-4eg"/>
|
||||
<menuItem title="NetNewsWire" state="on" id="bEy-Qx-Grl"/>
|
||||
</items>
|
||||
</menu>
|
||||
</popUpButtonCell>
|
||||
<connections>
|
||||
<action selector="rssReaderPopupDidChangeValue:" target="iuH-lz-18x" id="pyX-Bp-ws0"/>
|
||||
</connections>
|
||||
</popUpButton>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Wsb-Lr-8Q7">
|
||||
<rect key="frame" x="118" y="20" width="76" height="17"/>
|
||||
|
|
|
@ -12,55 +12,167 @@ import RSCore
|
|||
final class GeneralPreferencesViewController: NSViewController {
|
||||
|
||||
@IBOutlet var defaultRSSReaderPopup: NSPopUpButton!
|
||||
static let feedURLScheme = "feed:"
|
||||
static let feedsURLScheme = "feeds:"
|
||||
private var rssReaderInfo = RSSReaderInfo()
|
||||
|
||||
public override init(nibName nibNameOrNil: NSNib.Name?, bundle nibBundleOrNil: Bundle?) {
|
||||
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
|
||||
commonInit()
|
||||
}
|
||||
|
||||
public required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
commonInit()
|
||||
}
|
||||
|
||||
override func viewWillAppear() {
|
||||
updateRSSReaderPopup()
|
||||
super.viewWillAppear()
|
||||
updateUI()
|
||||
}
|
||||
|
||||
// MARK: - Notifications
|
||||
|
||||
@objc func applicationWillBecomeActive(_ note: Notification) {
|
||||
updateUI()
|
||||
}
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@IBAction func rssReaderPopupDidChangeValue(_ sender: Any?) {
|
||||
guard let menuItem = defaultRSSReaderPopup.selectedItem else {
|
||||
return
|
||||
}
|
||||
guard let bundleID = menuItem.representedObject as? String else {
|
||||
return
|
||||
}
|
||||
registerAppWithBundleID(bundleID)
|
||||
updateUI()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private extension GeneralPreferencesViewController {
|
||||
|
||||
func updateRSSReaderPopup() {
|
||||
let rssReaders = fetchRSSReaders()
|
||||
print(rssReaders)
|
||||
func commonInit() {
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(applicationWillBecomeActive(_:)), name: NSApplication.willBecomeActiveNotification, object: nil)
|
||||
}
|
||||
|
||||
func fetchRSSReaders() -> Set<RSSReader> {
|
||||
let defaultRSSReaderBundleID = NSWorkspace.shared.defaultAppBundleID(forURLScheme: GeneralPreferencesViewController.feedURLScheme)
|
||||
let rssReaderBundleIDs = NSWorkspace.shared.bundleIDsForApps(forURLScheme: GeneralPreferencesViewController.feedURLScheme)
|
||||
func updateUI() {
|
||||
rssReaderInfo = RSSReaderInfo()
|
||||
updateRSSReaderPopup()
|
||||
}
|
||||
|
||||
var allReaders = Set<RSSReader>()
|
||||
if let defaultRSSReaderBundleID = defaultRSSReaderBundleID, let defaultReader = RSSReader(bundleID: defaultRSSReaderBundleID, isDefaultReader: true) {
|
||||
allReaders.insert(defaultReader)
|
||||
func updateRSSReaderPopup() {
|
||||
// Top item should always be: NetNewsWire (this app)
|
||||
// Additional items should be sorted alphabetically.
|
||||
// Any older versions of NetNewsWire should be listed as: NetNewsWire (old version)
|
||||
|
||||
let menu = NSMenu(title: "RSS Readers")
|
||||
|
||||
let netNewsWireBundleID = Bundle.main.bundleIdentifier!
|
||||
let thisAppParentheticalComment = NSLocalizedString("(this app)", comment: "Preferences default RSS Reader popup")
|
||||
let thisAppName = "NetNewsWire \(thisAppParentheticalComment)"
|
||||
let netNewsWireMenuItem = NSMenuItem(title: thisAppName, action: nil, keyEquivalent: "")
|
||||
netNewsWireMenuItem.representedObject = netNewsWireBundleID
|
||||
menu.addItem(netNewsWireMenuItem)
|
||||
|
||||
let readersToList = rssReaderInfo.rssReaders.filter { $0.bundleID != netNewsWireBundleID }
|
||||
let sortedReaders = readersToList.sorted { (reader1, reader2) -> Bool in
|
||||
return reader1.nameMinusAppSuffix.localizedStandardCompare(reader2.nameMinusAppSuffix) == .orderedAscending
|
||||
}
|
||||
rssReaderBundleIDs.forEach { (bundleID) in
|
||||
let isDefault = bundleID == defaultRSSReaderBundleID
|
||||
if let reader = RSSReader(bundleID: bundleID, isDefaultReader: isDefault) {
|
||||
allReaders.insert(reader)
|
||||
|
||||
let oldVersionParentheticalComment = NSLocalizedString("(old version)", comment: "Preferences default RSS Reader popup")
|
||||
for rssReader in sortedReaders {
|
||||
var appName = rssReader.nameMinusAppSuffix
|
||||
if appName.contains("NetNewsWire") {
|
||||
appName = "\(appName) \(oldVersionParentheticalComment)"
|
||||
}
|
||||
let menuItem = NSMenuItem(title: appName, action: nil, keyEquivalent: "")
|
||||
menuItem.representedObject = rssReader.bundleID
|
||||
menu.addItem(menuItem)
|
||||
}
|
||||
|
||||
defaultRSSReaderPopup.menu = menu
|
||||
|
||||
func insertAndSelectNoneMenuItem() {
|
||||
let noneTitle = NSLocalizedString("None", comment: "Preferences default RSS Reader popup")
|
||||
let menuItem = NSMenuItem(title: noneTitle, action: nil, keyEquivalent: "")
|
||||
defaultRSSReaderPopup.menu!.insertItem(menuItem, at: 0)
|
||||
defaultRSSReaderPopup.selectItem(at: 0)
|
||||
}
|
||||
|
||||
guard let defaultRSSReaderBundleID = rssReaderInfo.defaultRSSReaderBundleID else {
|
||||
insertAndSelectNoneMenuItem()
|
||||
return
|
||||
}
|
||||
|
||||
for menuItem in defaultRSSReaderPopup.menu!.items {
|
||||
guard let bundleID = menuItem.representedObject as? String else {
|
||||
continue
|
||||
}
|
||||
if bundleID == defaultRSSReaderBundleID {
|
||||
defaultRSSReaderPopup.select(menuItem)
|
||||
return
|
||||
}
|
||||
}
|
||||
return allReaders
|
||||
|
||||
insertAndSelectNoneMenuItem()
|
||||
}
|
||||
|
||||
func registerAppWithBundleID(_ bundleID: String) {
|
||||
NSWorkspace.shared.setDefaultAppBundleID(forURLScheme: "feed", to: bundleID)
|
||||
NSWorkspace.shared.setDefaultAppBundleID(forURLScheme: "feeds", to: bundleID)
|
||||
}
|
||||
}
|
||||
|
||||
private final class RSSReader: Hashable {
|
||||
|
||||
// MARK: - RSSReaderInfo
|
||||
|
||||
private struct RSSReaderInfo {
|
||||
|
||||
let defaultRSSReaderBundleID: String?
|
||||
let rssReaders: Set<RSSReader>
|
||||
static let feedURLScheme = "feed:"
|
||||
|
||||
init() {
|
||||
let defaultRSSReaderBundleID = NSWorkspace.shared.defaultAppBundleID(forURLScheme: RSSReaderInfo.feedURLScheme)
|
||||
self.defaultRSSReaderBundleID = defaultRSSReaderBundleID
|
||||
self.rssReaders = RSSReaderInfo.fetchRSSReaders(defaultRSSReaderBundleID)
|
||||
}
|
||||
|
||||
static func fetchRSSReaders(_ defaultRSSReaderBundleID: String?) -> Set<RSSReader> {
|
||||
let rssReaderBundleIDs = NSWorkspace.shared.bundleIDsForApps(forURLScheme: feedURLScheme)
|
||||
|
||||
var rssReaders = Set<RSSReader>()
|
||||
if let defaultRSSReaderBundleID = defaultRSSReaderBundleID, let defaultReader = RSSReader(bundleID: defaultRSSReaderBundleID) {
|
||||
rssReaders.insert(defaultReader)
|
||||
}
|
||||
rssReaderBundleIDs.forEach { (bundleID) in
|
||||
if let reader = RSSReader(bundleID: bundleID) {
|
||||
rssReaders.insert(reader)
|
||||
}
|
||||
}
|
||||
return rssReaders
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - RSSReader
|
||||
|
||||
private struct RSSReader: Hashable {
|
||||
|
||||
let bundleID: String
|
||||
let name: String
|
||||
let nameMinusAppSuffix: String
|
||||
let path: String
|
||||
let isDefaultReader: Bool
|
||||
|
||||
init?(bundleID: String, isDefaultReader: Bool) {
|
||||
init?(bundleID: String) {
|
||||
guard let path = NSWorkspace.shared.absolutePathForApplication(withBundleIdentifier: bundleID) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
self.path = path
|
||||
self.bundleID = bundleID
|
||||
self.isDefaultReader = isDefaultReader
|
||||
|
||||
let name = (path as NSString).lastPathComponent
|
||||
self.name = name
|
||||
|
|
Loading…
Reference in New Issue