mirror of
https://github.com/Ranchero-Software/NetNewsWire
synced 2025-08-12 06:26:36 +00:00
Continue removing ExtensionPoint code.
This commit is contained in:
@@ -24,7 +24,6 @@ final class AppDefaults {
|
||||
struct Key {
|
||||
static let firstRunDate = "firstRunDate"
|
||||
static let windowState = "windowState"
|
||||
static let activeExtensionPointIDs = "activeExtensionPointIDs"
|
||||
static let lastImageCacheFlushDate = "lastImageCacheFlushDate"
|
||||
static let sidebarFontSize = "sidebarFontSize"
|
||||
static let timelineFontSize = "timelineFontSize"
|
||||
@@ -86,15 +85,6 @@ final class AppDefaults {
|
||||
}
|
||||
}
|
||||
|
||||
var activeExtensionPointIDs: [[AnyHashable : AnyHashable]]? {
|
||||
get {
|
||||
return UserDefaults.standard.object(forKey: Key.activeExtensionPointIDs) as? [[AnyHashable : AnyHashable]]
|
||||
}
|
||||
set {
|
||||
UserDefaults.standard.set(newValue, forKey: Key.activeExtensionPointIDs)
|
||||
}
|
||||
}
|
||||
|
||||
var lastImageCacheFlushDate: Date? {
|
||||
get {
|
||||
return AppDefaults.date(for: Key.lastImageCacheFlushDate)
|
||||
|
||||
@@ -123,7 +123,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
|
||||
SecretsManager.provider = Secrets()
|
||||
AccountManager.shared = AccountManager(accountsFolder: Platform.dataSubfolder(forApplication: nil, folderName: "Accounts")!)
|
||||
ArticleThemesManager.shared = ArticleThemesManager(folderPath: Platform.dataSubfolder(forApplication: nil, folderName: "Themes")!)
|
||||
FeedProviderManager.shared.delegate = ExtensionPointManager.shared
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(unreadCountDidChange(_:)), name: .UnreadCountDidChange, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(inspectableObjectsDidChange(_:)), name: .InspectableObjectsDidChange, object: nil)
|
||||
|
||||
@@ -523,16 +523,16 @@
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="7UM-iq-OLB" customClass="PreferencesTableViewBackgroundView" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="44" width="180" height="214"/>
|
||||
<rect key="frame" x="20" y="44" width="180" height="212"/>
|
||||
<subviews>
|
||||
<scrollView borderType="none" autohidesScrollers="YES" horizontalLineScroll="26" horizontalPageScroll="10" verticalLineScroll="26" verticalPageScroll="10" hasHorizontalScroller="NO" horizontalScrollElasticity="none" translatesAutoresizingMaskIntoConstraints="NO" id="PaF-du-r3c">
|
||||
<rect key="frame" x="1" y="1" width="178" height="212"/>
|
||||
<rect key="frame" x="1" y="1" width="178" height="210"/>
|
||||
<clipView key="contentView" id="cil-Gq-akO">
|
||||
<rect key="frame" x="0.0" y="0.0" width="178" height="212"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="178" height="210"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" tableStyle="fullWidth" columnReordering="NO" columnSelection="YES" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" rowHeight="24" viewBased="YES" id="aTp-KR-y6b">
|
||||
<rect key="frame" x="0.0" y="0.0" width="178" height="212"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="178" height="210"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<size key="intercellSpacing" width="3" height="2"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
@@ -639,7 +639,7 @@
|
||||
<rect key="frame" x="83" y="20" width="117" height="24"/>
|
||||
</customView>
|
||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="Y7D-xQ-wep">
|
||||
<rect key="frame" x="208" y="20" width="222" height="238"/>
|
||||
<rect key="frame" x="208" y="20" width="222" height="236"/>
|
||||
</customView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
@@ -685,160 +685,6 @@
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-44" y="27"/>
|
||||
</scene>
|
||||
<!--Extension Point Preferences View Controller-->
|
||||
<scene sceneID="2Q8-nu-xsg">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="Extensions" id="K4Z-qS-hrR" customClass="ExtensionPointPreferencesViewController" customModule="NetNewsWire" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" misplaced="YES" id="Jpa-aD-PZF">
|
||||
<rect key="frame" x="0.0" y="0.0" width="450" height="307"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="pjs-G4-byk" customClass="PreferencesTableViewBackgroundView" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="44" width="180" height="214"/>
|
||||
<subviews>
|
||||
<scrollView borderType="none" autohidesScrollers="YES" horizontalLineScroll="26" horizontalPageScroll="10" verticalLineScroll="26" verticalPageScroll="10" hasHorizontalScroller="NO" horizontalScrollElasticity="none" translatesAutoresizingMaskIntoConstraints="NO" id="29T-r2-ckC">
|
||||
<rect key="frame" x="1" y="1" width="178" height="212"/>
|
||||
<clipView key="contentView" id="dXw-GY-TP8">
|
||||
<rect key="frame" x="0.0" y="0.0" width="178" height="212"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" tableStyle="fullWidth" columnReordering="NO" columnSelection="YES" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" rowHeight="24" viewBased="YES" id="dfn-Vn-oDp">
|
||||
<rect key="frame" x="0.0" y="0.0" width="178" height="212"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<size key="intercellSpacing" width="3" height="2"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
||||
<tableColumns>
|
||||
<tableColumn width="146" minWidth="40" maxWidth="1000" id="jBM-96-TEB">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="uax-iF-gzP">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView identifier="Cell" id="xQs-6E-Kpy">
|
||||
<rect key="frame" x="1" y="1" width="155" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="kmG-vw-CbN">
|
||||
<rect key="frame" x="6" y="-4" width="16" height="27"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="16" id="qC6-Mb-6EQ"/>
|
||||
<constraint firstAttribute="width" constant="16" id="yi0-bd-XJq"/>
|
||||
</constraints>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="NSActionTemplate" id="OVD-Jo-TXU"/>
|
||||
</imageView>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsExpansionToolTips="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6cr-cB-qAN">
|
||||
<rect key="frame" x="26" y="1" width="125" height="16"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="goO-QG-kk7">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="6cr-cB-qAN" firstAttribute="centerY" secondItem="xQs-6E-Kpy" secondAttribute="centerY" id="5Zo-fV-HYU"/>
|
||||
<constraint firstItem="kmG-vw-CbN" firstAttribute="leading" secondItem="xQs-6E-Kpy" secondAttribute="leading" constant="6" id="Ap0-bW-xsi"/>
|
||||
<constraint firstAttribute="trailing" secondItem="6cr-cB-qAN" secondAttribute="trailing" constant="6" id="O9X-RU-yVU"/>
|
||||
<constraint firstItem="kmG-vw-CbN" firstAttribute="centerY" secondItem="xQs-6E-Kpy" secondAttribute="centerY" id="a9O-2C-ez9"/>
|
||||
<constraint firstItem="6cr-cB-qAN" firstAttribute="leading" secondItem="kmG-vw-CbN" secondAttribute="trailing" constant="6" id="yfP-7k-Uyb"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<outlet property="imageView" destination="kmG-vw-CbN" id="Ktw-eT-QtE"/>
|
||||
<outlet property="textField" destination="6cr-cB-qAN" id="7Cb-o3-IeP"/>
|
||||
</connections>
|
||||
</tableCellView>
|
||||
</prototypeCellViews>
|
||||
</tableColumn>
|
||||
</tableColumns>
|
||||
</tableView>
|
||||
</subviews>
|
||||
</clipView>
|
||||
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="0n8-KN-h13">
|
||||
<rect key="frame" x="-100" y="-100" width="118" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="t4w-hp-8WD">
|
||||
<rect key="frame" x="224" y="17" width="15" height="102"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
</scrollView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="180" id="0gU-oR-pQf"/>
|
||||
<constraint firstAttribute="bottom" secondItem="29T-r2-ckC" secondAttribute="bottom" constant="1" id="BMY-9E-vH2"/>
|
||||
<constraint firstAttribute="trailing" secondItem="29T-r2-ckC" secondAttribute="trailing" constant="1" id="dAW-1i-3iD"/>
|
||||
<constraint firstItem="29T-r2-ckC" firstAttribute="top" secondItem="pjs-G4-byk" secondAttribute="top" constant="1" id="tAi-6L-Tjj"/>
|
||||
<constraint firstItem="29T-r2-ckC" firstAttribute="leading" secondItem="pjs-G4-byk" secondAttribute="leading" constant="1" id="wXE-ze-ubv"/>
|
||||
</constraints>
|
||||
</customView>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="JA2-UT-8DR">
|
||||
<rect key="frame" x="20" y="19" width="32" height="26"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="24" id="Qnm-eZ-2KJ"/>
|
||||
<constraint firstAttribute="width" constant="32" id="ZQY-kS-9lY"/>
|
||||
</constraints>
|
||||
<buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSAddTemplate" imagePosition="only" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" inset="2" id="xk0-JH-jr9">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="enableExtensionPoints:" target="K4Z-qS-hrR" id="Jlk-S5-Kam"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="jfX-DL-TXs">
|
||||
<rect key="frame" x="51" y="19" width="32" height="26"/>
|
||||
<buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSRemoveTemplate" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" enabled="NO" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="4FB-KH-Ton">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="disableExtensionPoint:" target="K4Z-qS-hrR" id="Red-pz-FUE"/>
|
||||
</connections>
|
||||
</button>
|
||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="sak-nS-Xfu" customClass="PreferencesControlsBackgroundView" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="83" y="20" width="117" height="24"/>
|
||||
</customView>
|
||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="N1N-pE-gBL">
|
||||
<rect key="frame" x="208" y="20" width="222" height="238"/>
|
||||
</customView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="JA2-UT-8DR" firstAttribute="leading" secondItem="Jpa-aD-PZF" secondAttribute="leading" constant="20" symbolic="YES" id="0PA-e9-b64"/>
|
||||
<constraint firstAttribute="bottom" secondItem="jfX-DL-TXs" secondAttribute="bottom" constant="20" symbolic="YES" id="2V0-KT-vWv"/>
|
||||
<constraint firstItem="pjs-G4-byk" firstAttribute="top" secondItem="Jpa-aD-PZF" secondAttribute="top" constant="20" symbolic="YES" id="4j8-1U-WiI"/>
|
||||
<constraint firstItem="sak-nS-Xfu" firstAttribute="trailing" secondItem="pjs-G4-byk" secondAttribute="trailing" id="9u7-Nb-S9f"/>
|
||||
<constraint firstAttribute="bottom" secondItem="JA2-UT-8DR" secondAttribute="bottom" constant="20" symbolic="YES" id="Ebi-1b-c4r"/>
|
||||
<constraint firstItem="jfX-DL-TXs" firstAttribute="width" secondItem="JA2-UT-8DR" secondAttribute="width" id="Ilb-x9-dYo"/>
|
||||
<constraint firstItem="pjs-G4-byk" firstAttribute="leading" secondItem="Jpa-aD-PZF" secondAttribute="leading" constant="20" symbolic="YES" id="JGH-r5-Umj"/>
|
||||
<constraint firstItem="JA2-UT-8DR" firstAttribute="top" secondItem="pjs-G4-byk" secondAttribute="bottom" id="JhX-tK-MxJ"/>
|
||||
<constraint firstAttribute="trailing" secondItem="N1N-pE-gBL" secondAttribute="trailing" constant="20" symbolic="YES" id="MaO-sk-c4U"/>
|
||||
<constraint firstItem="sak-nS-Xfu" firstAttribute="height" secondItem="jfX-DL-TXs" secondAttribute="height" id="Nnu-tE-a42"/>
|
||||
<constraint firstItem="jfX-DL-TXs" firstAttribute="leading" secondItem="JA2-UT-8DR" secondAttribute="trailing" constant="-1" id="T2Z-VL-HDw"/>
|
||||
<constraint firstItem="N1N-pE-gBL" firstAttribute="leading" secondItem="pjs-G4-byk" secondAttribute="trailing" constant="8" symbolic="YES" id="TkH-1v-Rt4"/>
|
||||
<constraint firstItem="sak-nS-Xfu" firstAttribute="leading" secondItem="jfX-DL-TXs" secondAttribute="trailing" id="YNy-26-lR2"/>
|
||||
<constraint firstItem="N1N-pE-gBL" firstAttribute="top" secondItem="Jpa-aD-PZF" secondAttribute="top" constant="20" symbolic="YES" id="Z4D-bk-Smx"/>
|
||||
<constraint firstItem="sak-nS-Xfu" firstAttribute="bottom" secondItem="jfX-DL-TXs" secondAttribute="bottom" id="ofz-UJ-8BL"/>
|
||||
<constraint firstItem="JA2-UT-8DR" firstAttribute="height" secondItem="jfX-DL-TXs" secondAttribute="height" id="vOo-mW-auf"/>
|
||||
<constraint firstAttribute="bottom" secondItem="N1N-pE-gBL" secondAttribute="bottom" constant="20" symbolic="YES" id="vyg-BP-5bk"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="deleteButton" destination="jfX-DL-TXs" id="gT1-Dt-vZL"/>
|
||||
<outlet property="detailView" destination="N1N-pE-gBL" id="PYj-cW-fz1"/>
|
||||
<outlet property="tableView" destination="dfn-Vn-oDp" id="heh-fs-Tqr"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<customObject id="Cne-wm-w1Q" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-36" y="931"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="NSActionTemplate" width="20" height="20"/>
|
||||
|
||||
@@ -27,12 +27,14 @@ import RSCore
|
||||
}
|
||||
|
||||
static func customSharingServices(for items: [Any]) -> [NSSharingService] {
|
||||
let customServices = ExtensionPointManager.shared.activeSendToCommands.compactMap { (sendToCommand) -> NSSharingService? in
|
||||
let customServices: [SendToCommand] = [SendToMarsEditCommand(), SendToMicroBlogCommand()]
|
||||
|
||||
return customServices.compactMap { (sendToCommand) -> NSSharingService? in
|
||||
|
||||
guard let object = items.first else {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
guard sendToCommand.canSendObject(object, selectedText: nil) else {
|
||||
return nil
|
||||
}
|
||||
@@ -42,6 +44,5 @@ import RSCore
|
||||
sendToCommand.sendObject(object, selectedText: nil)
|
||||
}
|
||||
}
|
||||
return customServices
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21701" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21701"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="ExtensionPointDetailViewController" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<connections>
|
||||
<outlet property="descriptionLabel" destination="tK2-QL-hvM" id="5jU-Vz-6us"/>
|
||||
<outlet property="imageView" destination="I6P-Q2-DtA" id="mBe-xk-jOe"/>
|
||||
<outlet property="titleLabel" destination="d0R-Cs-axs" id="axb-bi-iwe"/>
|
||||
<outlet property="view" destination="988-TV-aJt" id="cUJ-Ez-XiC"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<tabView id="988-TV-aJt">
|
||||
<rect key="frame" x="0.0" y="0.0" width="346" height="300"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
<tabViewItems>
|
||||
<tabViewItem label="Extension" identifier="" id="k6A-mz-zOF">
|
||||
<view key="view" id="jT6-Hh-gWM">
|
||||
<rect key="frame" x="10" y="33" width="326" height="254"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<stackView distribution="fill" orientation="horizontal" alignment="bottom" spacing="19" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Z8D-OO-XZd">
|
||||
<rect key="frame" x="85" y="208" width="157" height="30"/>
|
||||
<subviews>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="I6P-Q2-DtA">
|
||||
<rect key="frame" x="0.0" y="0.0" width="28" height="28"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="28" id="HqU-9L-bqb"/>
|
||||
<constraint firstAttribute="height" constant="28" id="bpI-uD-bzZ"/>
|
||||
</constraints>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyUpOrDown" image="NSAdvanced" id="iCo-JD-zZy"/>
|
||||
</imageView>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="d0R-Cs-axs">
|
||||
<rect key="frame" x="45" y="0.0" width="114" height="30"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" title="Extension" id="CGj-bV-rXW">
|
||||
<font key="font" metaFont="system" size="26"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
<visibilityPriorities>
|
||||
<integer value="1000"/>
|
||||
<integer value="1000"/>
|
||||
</visibilityPriorities>
|
||||
<customSpacing>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
</customSpacing>
|
||||
</stackView>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" textCompletion="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tK2-QL-hvM">
|
||||
<rect key="frame" x="31" y="176" width="264" height="16"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="260" id="GRp-qY-UP1"/>
|
||||
</constraints>
|
||||
<textFieldCell key="cell" selectable="YES" allowsUndo="NO" alignment="left" allowsEditingTextAttributes="YES" id="7dt-TS-iHM">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="tK2-QL-hvM" firstAttribute="top" secondItem="Z8D-OO-XZd" secondAttribute="bottom" constant="16" id="3Ww-vg-yg7"/>
|
||||
<constraint firstItem="Z8D-OO-XZd" firstAttribute="top" secondItem="jT6-Hh-gWM" secondAttribute="top" constant="16" id="3hP-9H-3IX"/>
|
||||
<constraint firstItem="tK2-QL-hvM" firstAttribute="centerX" secondItem="jT6-Hh-gWM" secondAttribute="centerX" id="7ik-M6-Wmx"/>
|
||||
<constraint firstItem="Z8D-OO-XZd" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="jT6-Hh-gWM" secondAttribute="leading" constant="8" id="U8D-q2-eyi"/>
|
||||
<constraint firstItem="Z8D-OO-XZd" firstAttribute="centerX" secondItem="jT6-Hh-gWM" secondAttribute="centerX" id="XZC-Yp-uT5"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="Z8D-OO-XZd" secondAttribute="trailing" constant="8" id="pok-cn-NFH"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</tabViewItem>
|
||||
</tabViewItems>
|
||||
<point key="canvasLocation" x="-195" y="110"/>
|
||||
</tabView>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="NSAdvanced" width="32" height="32"/>
|
||||
</resources>
|
||||
</document>
|
||||
@@ -1,51 +0,0 @@
|
||||
//
|
||||
// EnableExtensionPointHelpView.swift
|
||||
// NetNewsWire
|
||||
//
|
||||
// Created by Stuart Breckenridge on 4/11/20.
|
||||
// Copyright © 2020 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import AppKit
|
||||
import SwiftUI
|
||||
import RSCore
|
||||
|
||||
struct EnableExtensionPointHelpView: View {
|
||||
|
||||
var extensionPoints: [ExtensionPoint.Type] {
|
||||
let types = ExtensionPointManager.shared.availableExtensionPointTypes.filter({ $0 is SendToCommand.Type }) +
|
||||
ExtensionPointManager.shared.availableExtensionPointTypes.filter({ !($0 is SendToCommand.Type) })
|
||||
return types
|
||||
}
|
||||
var helpText: String
|
||||
weak var preferencesController: ExtensionPointPreferencesViewController?
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
HStack {
|
||||
ForEach(0..<extensionPoints.count, id: \.self, content: { i in
|
||||
Button(action: {
|
||||
preferencesController?.enableExtensionPointFromSelection(extensionPoints[i])
|
||||
}, label: {
|
||||
Image(nsImage: extensionPoints[i].image)
|
||||
.resizable()
|
||||
.frame(width: 20, height: 20, alignment: .center)
|
||||
})
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
})
|
||||
|
||||
if ExtensionPointManager.shared.availableExtensionPointTypes.count == 0 {
|
||||
Image("markUnread")
|
||||
.resizable()
|
||||
.renderingMode(.template)
|
||||
.frame(width: 30, height: 30, alignment: .center)
|
||||
.foregroundColor(.green)
|
||||
}
|
||||
}
|
||||
|
||||
Text(helpText)
|
||||
.multilineTextAlignment(.center)
|
||||
.padding(.top, 8)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,172 +0,0 @@
|
||||
//
|
||||
// EnableExtensionPointView.swift
|
||||
// NetNewsWire
|
||||
//
|
||||
// Created by Maurice Parker on 10/30/20.
|
||||
// Copyright © 2020 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import AppKit
|
||||
import SwiftUI
|
||||
import RSCore
|
||||
|
||||
|
||||
struct EnableExtensionPointView: View {
|
||||
|
||||
weak var parent: NSHostingController<EnableExtensionPointView>? // required because presentationMode.dismiss() doesn't work
|
||||
weak var enabler: ExtensionPointPreferencesEnabler?
|
||||
@State private var extensionPointTypeName = ""
|
||||
private var selectedType: ExtensionPoint.Type?
|
||||
|
||||
init(enabler: ExtensionPointPreferencesEnabler?, selectedType: ExtensionPoint.Type?) {
|
||||
self.enabler = enabler
|
||||
self.selectedType = selectedType
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text("label.text.choose-extension-to-add", comment: "Choose an extension to add...")
|
||||
.font(.headline)
|
||||
.padding()
|
||||
|
||||
feedProviderExtensionPoints
|
||||
sendToCommandExtensionPoints
|
||||
|
||||
HStack(spacing: 12) {
|
||||
Spacer()
|
||||
Button(action: {
|
||||
parent?.dismiss(nil)
|
||||
}, label: {
|
||||
Text("button.title.cancel", comment: "Cancel")
|
||||
.frame(width: 80)
|
||||
})
|
||||
.help("Cancel")
|
||||
.keyboardShortcut(.cancelAction)
|
||||
|
||||
Button(action: {
|
||||
enabler?.enable(typeFromName(extensionPointTypeName))
|
||||
parent?.dismiss(nil)
|
||||
}, label: {
|
||||
Text("Continue")
|
||||
.frame(width: 80)
|
||||
})
|
||||
.help("Add Extension")
|
||||
.keyboardShortcut(.defaultAction)
|
||||
.disabled(disableContinue())
|
||||
}
|
||||
.padding(.top, 12)
|
||||
.padding(.bottom, 4)
|
||||
}
|
||||
.pickerStyle(RadioGroupPickerStyle())
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.frame(width: 420)
|
||||
.padding()
|
||||
.onAppear {
|
||||
if selectedType != nil {
|
||||
extensionPointTypeName = String(describing: selectedType!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var feedProviderExtensionPoints: some View {
|
||||
VStack(alignment: .leading) {
|
||||
let extensionPointTypeNames = Self.feedProviderExtensionPointTypes.map { String(describing: $0) }
|
||||
if extensionPointTypeNames.count > 0 {
|
||||
Text("label.text.feed-provider", comment: "Feed Provider")
|
||||
.font(.headline)
|
||||
.padding(.horizontal)
|
||||
|
||||
Picker(selection: $extensionPointTypeName, label: Text(""), content: {
|
||||
ForEach(extensionPointTypeNames, id: \.self, content: { extensionPointTypeName in
|
||||
let extensionPointType = typeFromName(extensionPointTypeName)
|
||||
HStack(alignment: .center) {
|
||||
Image(nsImage: extensionPointType.image)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 25, height: 25, alignment: .center)
|
||||
.padding(.leading, 4)
|
||||
|
||||
|
||||
Text(extensionPointType.title)
|
||||
}
|
||||
.tag(extensionPointTypeName)
|
||||
})
|
||||
})
|
||||
.pickerStyle(RadioGroupPickerStyle())
|
||||
.offset(x: 7.5, y: 0)
|
||||
|
||||
Text("label.text.feed-provider-explainer", comment: "An extension that makes websites appear to provide RSS feeds for their content.")
|
||||
.foregroundColor(.gray)
|
||||
.font(.caption)
|
||||
.padding(.horizontal)
|
||||
.onAppear {
|
||||
if extensionPointTypeName.count == 0 {
|
||||
self.extensionPointTypeName = extensionPointTypeNames.first!
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var sendToCommandExtensionPoints: some View {
|
||||
VStack(alignment: .leading) {
|
||||
let extensionPointTypeNames = Self.sendToCommandExtensionPointTypes.map { String(describing: $0) }
|
||||
if extensionPointTypeNames.count > 0 {
|
||||
Text("label.text.third-party-integration", comment: "Third-Party Integration")
|
||||
.font(.headline)
|
||||
.padding(.horizontal)
|
||||
.padding(.top, 8)
|
||||
|
||||
Picker(selection: $extensionPointTypeName, label: Text(""), content: {
|
||||
ForEach(extensionPointTypeNames, id: \.self, content: { extensionPointTypeName in
|
||||
let extensionPointType = typeFromName(extensionPointTypeName)
|
||||
HStack(alignment: .center) {
|
||||
Image(nsImage: extensionPointType.image)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 25, height: 25, alignment: .center)
|
||||
.padding(.leading, 4)
|
||||
|
||||
|
||||
Text(extensionPointType.title)
|
||||
}
|
||||
.tag(extensionPointTypeName)
|
||||
})
|
||||
})
|
||||
.pickerStyle(RadioGroupPickerStyle())
|
||||
.offset(x: 7.5, y: 0)
|
||||
|
||||
Text("label.text.share-extension-explainer", comment: "An extension that enables a share menu item that passes article data to a third-party application.")
|
||||
.foregroundColor(.gray)
|
||||
.font(.caption)
|
||||
.padding(.horizontal)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static var sendToCommandExtensionPointTypes: [ExtensionPoint.Type] {
|
||||
return ExtensionPointManager.shared.availableExtensionPointTypes.filter({ $0 is SendToCommand.Type })
|
||||
}
|
||||
|
||||
static var feedProviderExtensionPointTypes: [ExtensionPoint.Type] {
|
||||
return ExtensionPointManager.shared.availableExtensionPointTypes.filter({ !($0 is SendToCommand.Type) })
|
||||
}
|
||||
|
||||
func typeFromName(_ name: String) -> ExtensionPoint.Type {
|
||||
for type in ExtensionPointManager.shared.possibleExtensionPointTypes {
|
||||
if name == String(describing: type) {
|
||||
return type
|
||||
}
|
||||
}
|
||||
fatalError()
|
||||
}
|
||||
|
||||
func disableContinue() -> Bool {
|
||||
ExtensionPointManager.shared.availableExtensionPointTypes.count == 0 || extensionPointTypeName.count == 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
//
|
||||
// ExtensionPointDetailViewController.swift
|
||||
// NetNewsWire
|
||||
//
|
||||
// Created by Maurice Parker on 4/8/20.
|
||||
// Copyright © 2020 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
@MainActor class ExtensionPointDetailViewController: NSViewController {
|
||||
|
||||
@IBOutlet weak var imageView: NSImageView!
|
||||
@IBOutlet weak var titleLabel: NSTextField!
|
||||
@IBOutlet weak var descriptionLabel: NSTextField!
|
||||
|
||||
private var extensionPointWindowController: NSWindowController?
|
||||
private var extensionPoint: ExtensionPoint?
|
||||
|
||||
init(extensionPoint: ExtensionPoint) {
|
||||
super.init(nibName: "ExtensionPointDetail", bundle: nil)
|
||||
self.extensionPoint = extensionPoint
|
||||
}
|
||||
|
||||
public required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
guard let extensionPoint = extensionPoint else { return }
|
||||
imageView.image = extensionPoint.image
|
||||
titleLabel.stringValue = extensionPoint.title
|
||||
descriptionLabel.attributedStringValue = extensionPoint.description
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
//
|
||||
// ExtensionPointEnableWindowController.swift
|
||||
// NetNewsWire
|
||||
//
|
||||
// Created by Maurice Parker on 4/8/20.
|
||||
// Copyright © 2020 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
import AuthenticationServices
|
||||
import OAuthSwift
|
||||
import Secrets
|
||||
|
||||
@MainActor class ExtensionPointEnableWindowController: NSWindowController {
|
||||
|
||||
@IBOutlet weak var imageView: NSImageView!
|
||||
@IBOutlet weak var titleLabel: NSTextField!
|
||||
@IBOutlet weak var descriptionLabel: NSTextField!
|
||||
@IBOutlet weak var enableButton: NSButton!
|
||||
|
||||
private weak var hostWindow: NSWindow?
|
||||
|
||||
private var callbackURL: URL? = nil
|
||||
private var oauth: OAuthSwift?
|
||||
|
||||
var extensionPointType: ExtensionPoint.Type?
|
||||
|
||||
convenience init() {
|
||||
self.init(windowNibName: NSNib.Name("ExtensionPointEnable"))
|
||||
}
|
||||
|
||||
override func windowDidLoad() {
|
||||
super.windowDidLoad()
|
||||
guard let extensionPointType = extensionPointType else { return }
|
||||
|
||||
imageView.image = extensionPointType.image
|
||||
titleLabel.stringValue = extensionPointType.title
|
||||
descriptionLabel.attributedStringValue = extensionPointType.description
|
||||
}
|
||||
|
||||
// MARK: API
|
||||
|
||||
func runSheetOnWindow(_ hostWindow: NSWindow) {
|
||||
self.hostWindow = hostWindow
|
||||
hostWindow.beginSheet(window!)
|
||||
}
|
||||
|
||||
// MARK: Actions
|
||||
|
||||
@IBAction func cancel(_ sender: Any) {
|
||||
hostWindow!.endSheet(window!, returnCode: NSApplication.ModalResponse.cancel)
|
||||
}
|
||||
|
||||
@IBAction func enable(_ sender: Any) {
|
||||
guard let extensionPointType = extensionPointType else { return }
|
||||
|
||||
enableButton.isEnabled = false
|
||||
|
||||
if let oauth1 = extensionPointType as? OAuth1SwiftProvider.Type {
|
||||
enableOauth1(oauth1)
|
||||
} else if let oauth2 = extensionPointType as? OAuth2SwiftProvider.Type {
|
||||
enableOauth2(oauth2)
|
||||
} else {
|
||||
ExtensionPointManager.shared.activateExtensionPoint(extensionPointType) { result in
|
||||
if case .failure(let error) = result {
|
||||
self.presentError(error)
|
||||
}
|
||||
self.hostWindow!.endSheet(self.window!, returnCode: NSApplication.ModalResponse.OK)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ExtensionPointEnableWindowController: OAuthSwiftURLHandlerType {
|
||||
|
||||
public func handle(_ url: URL) {
|
||||
let session = ASWebAuthenticationSession(url: url, callbackURLScheme: callbackURL!.scheme, completionHandler: { (url, error) in
|
||||
if let callbackedURL = url {
|
||||
OAuth1Swift.handle(url: callbackedURL)
|
||||
}
|
||||
|
||||
guard let error = error else { return }
|
||||
|
||||
self.oauth?.cancel()
|
||||
self.oauth = nil
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.hostWindow!.endSheet(self.window!, returnCode: NSApplication.ModalResponse.OK)
|
||||
}
|
||||
|
||||
if case ASWebAuthenticationSessionError.canceledLogin = error {
|
||||
print("Login cancelled.")
|
||||
} else {
|
||||
NSApplication.shared.presentError(error)
|
||||
}
|
||||
})
|
||||
|
||||
session.presentationContextProvider = self
|
||||
if !session.start() {
|
||||
print("Session failed to start!!!")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
extension ExtensionPointEnableWindowController: ASWebAuthenticationPresentationContextProviding {
|
||||
|
||||
public func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
|
||||
return hostWindow!
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private extension ExtensionPointEnableWindowController {
|
||||
|
||||
func enableOauth1(_ provider: OAuth1SwiftProvider.Type) {
|
||||
callbackURL = provider.callbackURL
|
||||
|
||||
let oauth1 = provider.oauth1Swift
|
||||
self.oauth = oauth1
|
||||
oauth1.authorizeURLHandler = self
|
||||
|
||||
oauth1.authorize(withCallbackURL: callbackURL!) { [weak self] result in
|
||||
guard let self = self, let extensionPointType = self.extensionPointType else { return }
|
||||
|
||||
switch result {
|
||||
case .success(let tokenSuccess):
|
||||
ExtensionPointManager.shared.activateExtensionPoint(extensionPointType, tokenSuccess: tokenSuccess) { result in
|
||||
if case .failure(let error) = result {
|
||||
self.presentError(error)
|
||||
}
|
||||
self.hostWindow!.endSheet(self.window!, returnCode: NSApplication.ModalResponse.OK)
|
||||
}
|
||||
case .failure(let oauthSwiftError):
|
||||
self.presentError(oauthSwiftError)
|
||||
}
|
||||
|
||||
self.oauth?.cancel()
|
||||
self.oauth = nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func enableOauth2(_ provider: OAuth2SwiftProvider.Type) {
|
||||
callbackURL = provider.callbackURL
|
||||
|
||||
let oauth2 = provider.oauth2Swift
|
||||
self.oauth = oauth2
|
||||
oauth2.authorizeURLHandler = self
|
||||
|
||||
let oauth2Vars = provider.oauth2Vars
|
||||
|
||||
oauth2.authorize(withCallbackURL: callbackURL!, scope: oauth2Vars.scope, state: oauth2Vars.state, parameters: oauth2Vars.params) { [weak self] result in
|
||||
guard let self = self, let extensionPointType = self.extensionPointType else { return }
|
||||
|
||||
switch result {
|
||||
case .success(let tokenSuccess):
|
||||
ExtensionPointManager.shared.activateExtensionPoint(extensionPointType, tokenSuccess: tokenSuccess) { result in
|
||||
if case .failure(let error) = result {
|
||||
self.presentError(error)
|
||||
}
|
||||
self.hostWindow!.endSheet(self.window!, returnCode: NSApplication.ModalResponse.OK)
|
||||
}
|
||||
case .failure(let oauthSwiftError):
|
||||
self.presentError(oauthSwiftError)
|
||||
}
|
||||
|
||||
self.oauth?.cancel()
|
||||
self.oauth = nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,324 +0,0 @@
|
||||
//
|
||||
// ExtensionsPreferencesViewController.swift
|
||||
// NetNewsWire
|
||||
//
|
||||
// Created by Maurice Parker on 4/6/20.
|
||||
// Copyright © 2020 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import AppKit
|
||||
import SwiftUI
|
||||
import AuthenticationServices
|
||||
import OAuthSwift
|
||||
import Secrets
|
||||
|
||||
protocol ExtensionPointPreferencesEnabler: AnyObject {
|
||||
func enable(_ extensionPointType: ExtensionPoint.Type)
|
||||
}
|
||||
|
||||
@MainActor final class ExtensionPointPreferencesViewController: NSViewController {
|
||||
|
||||
@IBOutlet weak var tableView: NSTableView!
|
||||
@IBOutlet weak var detailView: NSView!
|
||||
@IBOutlet weak var deleteButton: NSButton!
|
||||
|
||||
private var activeExtensionPoints = [ExtensionPoint]()
|
||||
private var callbackURL: URL? = nil
|
||||
private var oauth: OAuthSwift?
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
tableView.delegate = self
|
||||
tableView.dataSource = self
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(activeExtensionPointsDidChange(_:)), name: .ActiveExtensionPointsDidChange, object: nil)
|
||||
|
||||
// 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
|
||||
|
||||
showDefaultView()
|
||||
|
||||
}
|
||||
|
||||
@IBAction func enableExtensionPoints(_ sender: Any) {
|
||||
let controller = NSHostingController(rootView: EnableExtensionPointView(enabler: self, selectedType: nil))
|
||||
controller.rootView.parent = controller
|
||||
presentAsSheet(controller)
|
||||
}
|
||||
|
||||
func enableExtensionPointFromSelection(_ selection: ExtensionPoint.Type) {
|
||||
let controller = NSHostingController(rootView: EnableExtensionPointView(enabler: self, selectedType: selection))
|
||||
controller.rootView.parent = controller
|
||||
presentAsSheet(controller)
|
||||
}
|
||||
|
||||
@IBAction func disableExtensionPoint(_ sender: Any) {
|
||||
guard tableView.selectedRow != -1 else {
|
||||
return
|
||||
}
|
||||
|
||||
let extensionPoint = activeExtensionPoints[tableView.selectedRow]
|
||||
|
||||
let alert = NSAlert()
|
||||
alert.alertStyle = .warning
|
||||
let prompt = NSLocalizedString("alert.title.deactivate-extension.%@", comment: "Deactivate “%@“?")
|
||||
alert.messageText = String(format: prompt, extensionPoint.title)
|
||||
alert.informativeText = NSLocalizedString("alert.message.cannot-undo-action", comment: "You can't undo this action.")
|
||||
|
||||
alert.addButton(withTitle: NSLocalizedString("button.title.deactivate", comment: "Deactivate Extension"))
|
||||
alert.addButton(withTitle: NSLocalizedString("button.title.cancel", comment: "Cancel Deactivate Extension"))
|
||||
|
||||
alert.beginSheetModal(for: view.window!) { [weak self] result in
|
||||
if result == NSApplication.ModalResponse.alertFirstButtonReturn {
|
||||
ExtensionPointManager.shared.deactivateExtensionPoint(extensionPoint.extensionPointID)
|
||||
self?.hideController()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - NSTableViewDataSource
|
||||
|
||||
extension ExtensionPointPreferencesViewController: NSTableViewDataSource {
|
||||
|
||||
func numberOfRows(in tableView: NSTableView) -> Int {
|
||||
return activeExtensionPoints.count
|
||||
}
|
||||
|
||||
func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {
|
||||
return activeExtensionPoints[row]
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - NSTableViewDelegate
|
||||
|
||||
extension ExtensionPointPreferencesViewController: 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 extensionPoint = activeExtensionPoints[row]
|
||||
cell.textField?.stringValue = extensionPoint.title
|
||||
cell.imageView?.image = extensionPoint.image
|
||||
return cell
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func tableViewSelectionDidChange(_ notification: Notification) {
|
||||
|
||||
let selectedRow = tableView.selectedRow
|
||||
if tableView.selectedRow == -1 {
|
||||
deleteButton.isEnabled = false
|
||||
hideController()
|
||||
return
|
||||
} else {
|
||||
deleteButton.isEnabled = true
|
||||
}
|
||||
|
||||
let extensionPoint = activeExtensionPoints[selectedRow]
|
||||
let controller = ExtensionPointDetailViewController(extensionPoint: extensionPoint)
|
||||
showController(controller)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: ExtensionPointPreferencesViewController
|
||||
|
||||
extension ExtensionPointPreferencesViewController: ExtensionPointPreferencesEnabler {
|
||||
|
||||
func enable(_ extensionPointType: ExtensionPoint.Type) {
|
||||
if let oauth1 = extensionPointType as? OAuth1SwiftProvider.Type {
|
||||
enableOauth1(oauth1, extensionPointType: extensionPointType)
|
||||
} else if let oauth2 = extensionPointType as? OAuth2SwiftProvider.Type {
|
||||
enableOauth2(oauth2, extensionPointType: extensionPointType)
|
||||
} else {
|
||||
ExtensionPointManager.shared.activateExtensionPoint(extensionPointType) { result in
|
||||
if case .failure(let error) = result {
|
||||
self.presentError(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ExtensionPointPreferencesViewController: OAuthSwiftURLHandlerType {
|
||||
|
||||
public func handle(_ url: URL) {
|
||||
let session = ASWebAuthenticationSession(url: url, callbackURLScheme: callbackURL!.scheme, completionHandler: { (url, error) in
|
||||
if let callbackedURL = url {
|
||||
OAuth1Swift.handle(url: callbackedURL)
|
||||
}
|
||||
|
||||
guard let error = error else { return }
|
||||
|
||||
self.oauth?.cancel()
|
||||
self.oauth = nil
|
||||
|
||||
if case ASWebAuthenticationSessionError.canceledLogin = error {
|
||||
print("Login cancelled.")
|
||||
} else {
|
||||
NSApplication.shared.presentError(error)
|
||||
}
|
||||
})
|
||||
|
||||
session.presentationContextProvider = self
|
||||
if !session.start() {
|
||||
print("Session failed to start!!!")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
extension ExtensionPointPreferencesViewController: ASWebAuthenticationPresentationContextProviding {
|
||||
|
||||
public func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
|
||||
return view.window!
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private extension ExtensionPointPreferencesViewController {
|
||||
|
||||
@objc func activeExtensionPointsDidChange(_ note: Notification) {
|
||||
showDefaultView()
|
||||
}
|
||||
|
||||
func showDefaultView() {
|
||||
activeExtensionPoints = Array(ExtensionPointManager.shared.activeExtensionPoints.values).sorted(by: { $0.title < $1.title })
|
||||
tableView.reloadData()
|
||||
|
||||
if tableView.selectedRow == -1 {
|
||||
var helpText = ""
|
||||
if ExtensionPointManager.shared.availableExtensionPointTypes.count == 0 {
|
||||
helpText = NSLocalizedString("label.text.added-all-extensions", comment: "You've added all available extensions.")
|
||||
}
|
||||
else if activeExtensionPoints.count == 0 {
|
||||
helpText = NSLocalizedString("label.text.add-extension", comment: "Add an extension by clicking the + button.")
|
||||
} else {
|
||||
helpText = NSLocalizedString("label.text.select-or-add-extension", comment: "Select an extension or add a new extension by clicking the + button.")
|
||||
}
|
||||
|
||||
if let controller = children.first {
|
||||
children.removeAll()
|
||||
controller.view.removeFromSuperview()
|
||||
}
|
||||
|
||||
let textHostingController = NSHostingController(rootView: EnableExtensionPointHelpView(helpText: helpText, preferencesController: self))
|
||||
addChild(textHostingController)
|
||||
textHostingController.view.translatesAutoresizingMaskIntoConstraints = false
|
||||
detailView.addSubview(textHostingController.view)
|
||||
detailView.addConstraints([
|
||||
NSLayoutConstraint(item: textHostingController.view, attribute: .top, relatedBy: .equal, toItem: detailView, attribute: .top, multiplier: 1, constant: 1),
|
||||
NSLayoutConstraint(item: textHostingController.view, attribute: .bottom, relatedBy: .equal, toItem: detailView, attribute: .bottom, multiplier: 1, constant: -deleteButton.frame.height),
|
||||
NSLayoutConstraint(item: textHostingController.view, attribute: .width, relatedBy: .equal, toItem: detailView, attribute: .width, multiplier: 1, constant: 1)
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
func showController(_ controller: NSViewController) {
|
||||
hideController()
|
||||
|
||||
addChild(controller)
|
||||
controller.view.translatesAutoresizingMaskIntoConstraints = false
|
||||
detailView.addSubview(controller.view)
|
||||
detailView.addFullSizeConstraints(forSubview: controller.view)
|
||||
}
|
||||
|
||||
func hideController() {
|
||||
if let controller = children.first {
|
||||
children.removeAll()
|
||||
controller.view.removeFromSuperview()
|
||||
}
|
||||
|
||||
if tableView.selectedRow == -1 {
|
||||
var helpText = ""
|
||||
if ExtensionPointManager.shared.availableExtensionPointTypes.count == 0 {
|
||||
helpText = NSLocalizedString("label.text.added-all-extensions", comment: "You've added all available extensions.")
|
||||
}
|
||||
else if activeExtensionPoints.count == 0 {
|
||||
helpText = NSLocalizedString("label.text.add-extension", comment: "Add an extension by clicking the + button.")
|
||||
} else {
|
||||
helpText = NSLocalizedString("label.text.select-or-add-extension", comment: "Select an extension or add a new extension by clicking the + button.")
|
||||
}
|
||||
|
||||
let textHostingController = NSHostingController(rootView: EnableExtensionPointHelpView(helpText: helpText, preferencesController: self))
|
||||
addChild(textHostingController)
|
||||
textHostingController.view.translatesAutoresizingMaskIntoConstraints = false
|
||||
detailView.addSubview(textHostingController.view)
|
||||
detailView.addConstraints([
|
||||
NSLayoutConstraint(item: textHostingController.view, attribute: .top, relatedBy: .equal, toItem: detailView, attribute: .top, multiplier: 1, constant: 1),
|
||||
NSLayoutConstraint(item: textHostingController.view, attribute: .bottom, relatedBy: .equal, toItem: detailView, attribute: .bottom, multiplier: 1, constant: -deleteButton.frame.height),
|
||||
NSLayoutConstraint(item: textHostingController.view, attribute: .width, relatedBy: .equal, toItem: detailView, attribute: .width, multiplier: 1, constant: 1)
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
func enableOauth1(_ provider: OAuth1SwiftProvider.Type, extensionPointType: ExtensionPoint.Type) {
|
||||
callbackURL = provider.callbackURL
|
||||
|
||||
let oauth1 = provider.oauth1Swift
|
||||
self.oauth = oauth1
|
||||
oauth1.authorizeURLHandler = self
|
||||
|
||||
oauth1.authorize(withCallbackURL: callbackURL!) { [weak self] result in
|
||||
guard let self = self else { return }
|
||||
|
||||
switch result {
|
||||
case .success(let tokenSuccess):
|
||||
ExtensionPointManager.shared.activateExtensionPoint(extensionPointType, tokenSuccess: tokenSuccess) { result in
|
||||
if case .failure(let error) = result {
|
||||
self.presentError(error)
|
||||
}
|
||||
}
|
||||
case .failure(let oauthSwiftError):
|
||||
self.presentError(oauthSwiftError)
|
||||
}
|
||||
|
||||
self.oauth?.cancel()
|
||||
self.oauth = nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func enableOauth2(_ provider: OAuth2SwiftProvider.Type, extensionPointType: ExtensionPoint.Type) {
|
||||
callbackURL = provider.callbackURL
|
||||
|
||||
let oauth2 = provider.oauth2Swift
|
||||
self.oauth = oauth2
|
||||
oauth2.authorizeURLHandler = self
|
||||
|
||||
let oauth2Vars = provider.oauth2Vars
|
||||
|
||||
oauth2.authorize(withCallbackURL: callbackURL!, scope: oauth2Vars.scope, state: oauth2Vars.state, parameters: oauth2Vars.params) { [weak self] result in
|
||||
guard let self = self else { return }
|
||||
|
||||
switch result {
|
||||
case .success(let tokenSuccess):
|
||||
ExtensionPointManager.shared.activateExtensionPoint(extensionPointType, tokenSuccess: tokenSuccess) { result in
|
||||
if case .failure(let error) = result {
|
||||
self.presentError(error)
|
||||
}
|
||||
}
|
||||
case .failure(let oauthSwiftError):
|
||||
self.presentError(oauthSwiftError)
|
||||
}
|
||||
|
||||
self.oauth?.cancel()
|
||||
self.oauth = nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "Extension"; ObjectID = "CGj-bV-rXW"; */
|
||||
"CGj-bV-rXW.title" = "Extension";
|
||||
|
||||
/* Class = "NSTabViewItem"; label = "Extension"; ObjectID = "k6A-mz-zOF"; */
|
||||
"k6A-mz-zOF.label" = "Extension";
|
||||
@@ -1,6 +0,0 @@
|
||||
/* Class = "NSTextFieldCell"; title = "Extension"; ObjectID = "CGj-bV-rXW"; */
|
||||
"CGj-bV-rXW.title" = "扩展";
|
||||
|
||||
/* Class = "NSTabViewItem"; label = "Extension"; ObjectID = "k6A-mz-zOF"; */
|
||||
"k6A-mz-zOF.label" = "扩展";
|
||||
|
||||
@@ -24,7 +24,6 @@ private struct PreferencesToolbarItemSpec {
|
||||
private struct ToolbarItemIdentifier {
|
||||
static let General = "General"
|
||||
static let Accounts = "Accounts"
|
||||
static let Extensions = "Extensions"
|
||||
static let Advanced = "Advanced"
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user