Implemented the add feed functionality on the feed directory window. Issue #105

This commit is contained in:
Maurice Parker 2018-09-12 22:23:23 -05:00
parent 586d10bfa4
commit ab8ef65962
5 changed files with 188 additions and 76 deletions

View File

@ -8,6 +8,7 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
519B8D332143397200FA689C /* SharingServiceDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519B8D322143397200FA689C /* SharingServiceDelegate.swift */; }; 519B8D332143397200FA689C /* SharingServiceDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519B8D322143397200FA689C /* SharingServiceDelegate.swift */; };
51EC114C2149FE3300B296E3 /* FolderTreeMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EC114B2149FE3300B296E3 /* FolderTreeMenu.swift */; };
6581C73820CED60100F4AD34 /* SafariExtensionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6581C73720CED60100F4AD34 /* SafariExtensionHandler.swift */; }; 6581C73820CED60100F4AD34 /* SafariExtensionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6581C73720CED60100F4AD34 /* SafariExtensionHandler.swift */; };
6581C73A20CED60100F4AD34 /* SafariExtensionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6581C73920CED60100F4AD34 /* SafariExtensionViewController.swift */; }; 6581C73A20CED60100F4AD34 /* SafariExtensionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6581C73920CED60100F4AD34 /* SafariExtensionViewController.swift */; };
6581C73D20CED60100F4AD34 /* SafariExtensionViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6581C73B20CED60100F4AD34 /* SafariExtensionViewController.xib */; }; 6581C73D20CED60100F4AD34 /* SafariExtensionViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6581C73B20CED60100F4AD34 /* SafariExtensionViewController.xib */; };
@ -480,6 +481,7 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
519B8D322143397200FA689C /* SharingServiceDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharingServiceDelegate.swift; sourceTree = "<group>"; }; 519B8D322143397200FA689C /* SharingServiceDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharingServiceDelegate.swift; sourceTree = "<group>"; };
51EC114B2149FE3300B296E3 /* FolderTreeMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = FolderTreeMenu.swift; path = AddFeed/FolderTreeMenu.swift; sourceTree = "<group>"; };
6581C73320CED60000F4AD34 /* Subscribe to Feed.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Subscribe to Feed.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; 6581C73320CED60000F4AD34 /* Subscribe to Feed.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Subscribe to Feed.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
6581C73420CED60100F4AD34 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 6581C73420CED60100F4AD34 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
6581C73720CED60100F4AD34 /* SafariExtensionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariExtensionHandler.swift; sourceTree = "<group>"; }; 6581C73720CED60100F4AD34 /* SafariExtensionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariExtensionHandler.swift; sourceTree = "<group>"; };
@ -952,6 +954,7 @@
849A97511ED9EAC0007D329B /* AddFeedController.swift */, 849A97511ED9EAC0007D329B /* AddFeedController.swift */,
849A97521ED9EAC0007D329B /* AddFeedWindowController.swift */, 849A97521ED9EAC0007D329B /* AddFeedWindowController.swift */,
849A97A01ED9F180007D329B /* InitialFeedDownloader.swift */, 849A97A01ED9F180007D329B /* InitialFeedDownloader.swift */,
51EC114B2149FE3300B296E3 /* FolderTreeMenu.swift */,
849A97A11ED9F180007D329B /* FolderTreeControllerDelegate.swift */, 849A97A11ED9F180007D329B /* FolderTreeControllerDelegate.swift */,
); );
name = "Add Feed"; name = "Add Feed";
@ -1528,8 +1531,8 @@
ORGANIZATIONNAME = "Ranchero Software"; ORGANIZATIONNAME = "Ranchero Software";
TargetAttributes = { TargetAttributes = {
6581C73220CED60000F4AD34 = { 6581C73220CED60000F4AD34 = {
DevelopmentTeam = M8L2WTLA8W; DevelopmentTeam = SHJK2V3AJG;
ProvisioningStyle = Manual; ProvisioningStyle = Automatic;
}; };
840D617B2029031C009BC708 = { 840D617B2029031C009BC708 = {
CreatedOnToolsVersion = 9.3; CreatedOnToolsVersion = 9.3;
@ -1550,12 +1553,12 @@
}; };
849C645F1ED37A5D003D8FC0 = { 849C645F1ED37A5D003D8FC0 = {
CreatedOnToolsVersion = 8.2.1; CreatedOnToolsVersion = 8.2.1;
DevelopmentTeam = M8L2WTLA8W; DevelopmentTeam = SHJK2V3AJG;
ProvisioningStyle = Manual; ProvisioningStyle = Automatic;
}; };
849C64701ED37A5D003D8FC0 = { 849C64701ED37A5D003D8FC0 = {
CreatedOnToolsVersion = 8.2.1; CreatedOnToolsVersion = 8.2.1;
DevelopmentTeam = 9C84TZ7Q6Z; DevelopmentTeam = SHJK2V3AJG;
ProvisioningStyle = Automatic; ProvisioningStyle = Automatic;
TestTargetID = 849C645F1ED37A5D003D8FC0; TestTargetID = 849C645F1ED37A5D003D8FC0;
}; };
@ -2005,6 +2008,7 @@
84B99C691FAE36B800ECDEDB /* FeedListFolder.swift in Sources */, 84B99C691FAE36B800ECDEDB /* FeedListFolder.swift in Sources */,
84411E711FE5FBFA004B527F /* SmallIconProvider.swift in Sources */, 84411E711FE5FBFA004B527F /* SmallIconProvider.swift in Sources */,
844B5B591FE9FE4F00C7C76A /* SidebarKeyboardDelegate.swift in Sources */, 844B5B591FE9FE4F00C7C76A /* SidebarKeyboardDelegate.swift in Sources */,
51EC114C2149FE3300B296E3 /* FolderTreeMenu.swift in Sources */,
849A97A31ED9F180007D329B /* FolderTreeControllerDelegate.swift in Sources */, 849A97A31ED9F180007D329B /* FolderTreeControllerDelegate.swift in Sources */,
84A1500320048D660046AD9A /* SendToCommand.swift in Sources */, 84A1500320048D660046AD9A /* SendToCommand.swift in Sources */,
845A29091FC74B8E007B49E3 /* SingleFaviconDownloader.swift in Sources */, 845A29091FC74B8E007B49E3 /* SingleFaviconDownloader.swift in Sources */,

View File

@ -1,15 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="14092" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="z5E-aV-xMb"> <document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="14313.13.2" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="z5E-aV-xMb">
<dependencies> <dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14092"/> <deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14313.13.2"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies> </dependencies>
<scenes> <scenes>
<!--Window Controller--> <!--Window Controller-->
<scene sceneID="joN-Oe-nep"> <scene sceneID="joN-Oe-nep">
<objects> <objects>
<windowController showSeguePresentationStyle="single" id="z5E-aV-xMb" customClass="FeedListWindowController" customModule="Evergreen" customModuleProvider="target" sceneMemberID="viewController"> <windowController showSeguePresentationStyle="single" id="z5E-aV-xMb" customClass="FeedListWindowController" customModule="NetNewsWire" customModuleProvider="target" sceneMemberID="viewController">
<window key="window" identifier="feedDirectoryWindow" title="Feed Directory" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" tabbingMode="disallowed" id="Ty3-Oi-cUp"> <window key="window" identifier="feedDirectoryWindow" title="Feed Directory" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" tabbingMode="disallowed" id="Ty3-Oi-cUp">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/> <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="425" y="461" width="300" height="600"/> <rect key="contentRect" x="425" y="461" width="300" height="600"/>
@ -32,25 +33,25 @@
<!--Feed List View Controller--> <!--Feed List View Controller-->
<scene sceneID="TKm-CD-zMs"> <scene sceneID="TKm-CD-zMs">
<objects> <objects>
<viewController id="QX3-Wg-cdZ" customClass="FeedListViewController" customModule="Evergreen" customModuleProvider="target" sceneMemberID="viewController"> <viewController id="QX3-Wg-cdZ" customClass="FeedListViewController" customModule="NetNewsWire" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" id="vp3-VV-Mzw"> <view key="view" id="vp3-VV-Mzw">
<rect key="frame" x="0.0" y="0.0" width="328" height="300"/> <rect key="frame" x="0.0" y="0.0" width="328" height="300"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<scrollView borderType="none" autohidesScrollers="YES" horizontalLineScroll="27" horizontalPageScroll="10" verticalLineScroll="27" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rir-se-YCO"> <scrollView borderType="none" autohidesScrollers="YES" horizontalLineScroll="27" horizontalPageScroll="10" verticalLineScroll="27" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rir-se-YCO">
<rect key="frame" x="0.0" y="32" width="328" height="268"/> <rect key="frame" x="0.0" y="67" width="328" height="233"/>
<clipView key="contentView" drawsBackground="NO" id="vli-sv-HLg"> <clipView key="contentView" drawsBackground="NO" id="vli-sv-HLg">
<rect key="frame" x="0.0" y="0.0" width="328" height="268"/> <rect key="frame" x="0.0" y="0.0" width="328" height="233"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" autosaveColumns="NO" rowHeight="24" rowSizeStyle="medium" viewBased="YES" floatsGroupRows="NO" indentationPerLevel="27" outlineTableColumn="Ytm-dS-0WJ" id="Hxu-8i-6rp" customClass="FeedListOutlineView" customModule="Evergreen" customModuleProvider="target"> <outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" autosaveColumns="NO" rowHeight="24" rowSizeStyle="medium" viewBased="YES" floatsGroupRows="NO" indentationPerLevel="27" outlineTableColumn="Ytm-dS-0WJ" id="Hxu-8i-6rp" customClass="FeedListOutlineView" customModule="NetNewsWire" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="328" height="268"/> <rect key="frame" x="0.0" y="0.0" width="328" height="233"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<size key="intercellSpacing" width="2" height="3"/> <size key="intercellSpacing" width="2" height="3"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/> <color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns> <tableColumns>
<tableColumn identifier="" width="326" minWidth="16" maxWidth="1000" id="Ytm-dS-0WJ"> <tableColumn width="326" minWidth="16" maxWidth="1000" id="Ytm-dS-0WJ">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border"> <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
<font key="font" metaFont="smallSystem"/> <font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/> <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
@ -81,7 +82,7 @@
<outlet property="textField" destination="vm6-1A-a5G" id="Ygp-YV-bUa"/> <outlet property="textField" destination="vm6-1A-a5G" id="Ygp-YV-bUa"/>
</connections> </connections>
</tableCellView> </tableCellView>
<tableCellView identifier="FeedListCell" id="M2x-Bb-n1x" customClass="SidebarCell" customModule="Evergreen" customModuleProvider="target"> <tableCellView identifier="FeedListCell" id="M2x-Bb-n1x" customClass="SidebarCell" customModule="NetNewsWire" customModuleProvider="target">
<rect key="frame" x="1" y="21" width="326" height="17"/> <rect key="frame" x="1" y="21" width="326" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
@ -120,21 +121,24 @@
<constraint firstAttribute="width" relation="lessThanOrEqual" constant="512" id="9NC-nE-xTp"/> <constraint firstAttribute="width" relation="lessThanOrEqual" constant="512" id="9NC-nE-xTp"/>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="240" id="ldQ-7U-jou"/> <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="240" id="ldQ-7U-jou"/>
</constraints> </constraints>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="X3r-hu-K2f"> <scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="X3r-hu-K2f">
<rect key="frame" x="-100" y="-100" width="285" height="16"/> <rect key="frame" x="-100" y="-100" width="285" height="16"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
</scroller> </scroller>
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="Qg7-sg-Bly"> <scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="Qg7-sg-Bly">
<rect key="frame" x="224" y="17" width="15" height="102"/> <rect key="frame" x="224" y="17" width="15" height="102"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
</scroller> </scroller>
</scrollView> </scrollView>
<customView horizontalHuggingPriority="1000" horizontalCompressionResistancePriority="1000" translatesAutoresizingMaskIntoConstraints="NO" id="xKq-9P-ibo"> <customView horizontalHuggingPriority="1000" horizontalCompressionResistancePriority="1000" translatesAutoresizingMaskIntoConstraints="NO" id="xKq-9P-ibo">
<rect key="frame" x="20" y="0.0" width="288" height="32"/> <rect key="frame" x="20" y="0.0" width="288" height="67"/>
<subviews> <subviews>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Bv8-Eq-0cT"> <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Bv8-Eq-0cT">
<rect key="frame" x="20" y="3" width="120" height="25"/> <rect key="frame" x="220" y="7" width="60" height="23"/>
<buttonCell key="cell" type="roundTextured" title="Add to Feeds" bezelStyle="texturedRounded" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="0gj-Cw-KCE"> <constraints>
<constraint firstAttribute="width" constant="60" id="koV-lZ-YjH"/>
</constraints>
<buttonCell key="cell" type="roundTextured" title="Add" bezelStyle="texturedRounded" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="0gj-Cw-KCE">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/> <font key="font" metaFont="system"/>
</buttonCell> </buttonCell>
@ -142,8 +146,30 @@
<action selector="addToFeeds:" target="MKk-xD-0Fh" id="43Z-VU-PTO"/> <action selector="addToFeeds:" target="MKk-xD-0Fh" id="43Z-VU-PTO"/>
</connections> </connections>
</button> </button>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Y7Q-9h-CQt">
<rect key="frame" x="57" y="5" width="158" height="25"/>
<popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="mdb-2T-Agc" id="v51-oe-wo7">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="Wos-y0-k5e">
<items>
<menuItem title="Item 1" state="on" id="mdb-2T-Agc"/>
<menuItem title="Item 2" id="Ynb-dc-srr"/>
<menuItem title="Item 3" id="g5j-fH-Vn8"/>
</items>
</menu>
</popUpButtonCell>
</popUpButton>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="F1T-Qb-TlD">
<rect key="frame" x="6" y="10" width="47" height="17"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Folder:" id="4xq-Sg-pQF">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Ohy-a3-XkT"> <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Ohy-a3-XkT">
<rect key="frame" x="148" y="3" width="120" height="25"/> <rect key="frame" x="84" y="36" width="120" height="23"/>
<buttonCell key="cell" type="roundTextured" title="Open Home Page" bezelStyle="texturedRounded" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="hom-If-fbd"> <buttonCell key="cell" type="roundTextured" title="Open Home Page" bezelStyle="texturedRounded" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="hom-If-fbd">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/> <font key="font" metaFont="system"/>
@ -154,29 +180,33 @@
</button> </button>
</subviews> </subviews>
<constraints> <constraints>
<constraint firstItem="Ohy-a3-XkT" firstAttribute="width" secondItem="Bv8-Eq-0cT" secondAttribute="width" id="1Kl-sg-GHU"/> <constraint firstItem="Bv8-Eq-0cT" firstAttribute="leading" secondItem="Y7Q-9h-CQt" secondAttribute="trailing" constant="8" id="CRG-dw-kiJ"/>
<constraint firstItem="Ohy-a3-XkT" firstAttribute="leading" secondItem="Bv8-Eq-0cT" secondAttribute="trailing" constant="8" symbolic="YES" id="5Og-09-12P"/> <constraint firstAttribute="bottom" secondItem="Y7Q-9h-CQt" secondAttribute="bottom" constant="8" id="Lgt-k2-AWs"/>
<constraint firstItem="Ohy-a3-XkT" firstAttribute="centerY" secondItem="xKq-9P-ibo" secondAttribute="centerY" id="7Yu-Ab-dfe"/> <constraint firstItem="Y7Q-9h-CQt" firstAttribute="leading" secondItem="F1T-Qb-TlD" secondAttribute="trailing" constant="8" id="Sfd-Fz-kr1"/>
<constraint firstAttribute="trailing" secondItem="Ohy-a3-XkT" secondAttribute="trailing" constant="20" symbolic="YES" id="ACJ-M3-QR1"/> <constraint firstItem="Y7Q-9h-CQt" firstAttribute="top" secondItem="Ohy-a3-XkT" secondAttribute="bottom" constant="8" id="TfX-Nt-esZ"/>
<constraint firstItem="Bv8-Eq-0cT" firstAttribute="leading" secondItem="xKq-9P-ibo" secondAttribute="leading" constant="20" symbolic="YES" id="Iph-MK-E6k"/> <constraint firstItem="Ohy-a3-XkT" firstAttribute="top" secondItem="xKq-9P-ibo" secondAttribute="top" constant="8" id="V9t-1t-Krq"/>
<constraint firstAttribute="height" constant="32" id="dH4-pR-OmT"/> <constraint firstItem="Ohy-a3-XkT" firstAttribute="centerX" secondItem="xKq-9P-ibo" secondAttribute="centerX" id="gFQ-Mg-YTf"/>
<constraint firstItem="Bv8-Eq-0cT" firstAttribute="centerY" secondItem="xKq-9P-ibo" secondAttribute="centerY" id="qgr-sL-IFQ"/> <constraint firstAttribute="trailing" secondItem="Bv8-Eq-0cT" secondAttribute="trailing" constant="8" id="gTK-Pb-nd1"/>
<constraint firstAttribute="bottom" secondItem="Bv8-Eq-0cT" secondAttribute="bottom" constant="8" id="oXN-5G-MYC"/>
<constraint firstItem="F1T-Qb-TlD" firstAttribute="centerY" secondItem="Y7Q-9h-CQt" secondAttribute="centerY" id="ohA-kz-Fc0"/>
<constraint firstItem="F1T-Qb-TlD" firstAttribute="leading" secondItem="xKq-9P-ibo" secondAttribute="leading" constant="8" id="oph-Aa-L1K"/>
</constraints> </constraints>
</customView> </customView>
</subviews> </subviews>
<constraints> <constraints>
<constraint firstAttribute="bottom" secondItem="xKq-9P-ibo" secondAttribute="bottom" id="2cb-L2-JEt"/> <constraint firstAttribute="bottom" secondItem="xKq-9P-ibo" secondAttribute="bottom" id="2cb-L2-JEt"/>
<constraint firstAttribute="trailing" secondItem="rir-se-YCO" secondAttribute="trailing" id="7WI-u5-sU6"/> <constraint firstAttribute="trailing" secondItem="rir-se-YCO" secondAttribute="trailing" id="7WI-u5-sU6"/>
<constraint firstItem="xKq-9P-ibo" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="vp3-VV-Mzw" secondAttribute="leading" constant="20" symbolic="YES" id="I6a-ro-vaw"/> <constraint firstItem="xKq-9P-ibo" firstAttribute="leading" secondItem="vp3-VV-Mzw" secondAttribute="leading" constant="20" symbolic="YES" id="I6a-ro-vaw"/>
<constraint firstItem="rir-se-YCO" firstAttribute="top" secondItem="vp3-VV-Mzw" secondAttribute="top" id="Koo-lp-EvO"/> <constraint firstItem="rir-se-YCO" firstAttribute="top" secondItem="vp3-VV-Mzw" secondAttribute="top" id="Koo-lp-EvO"/>
<constraint firstItem="xKq-9P-ibo" firstAttribute="centerX" secondItem="vp3-VV-Mzw" secondAttribute="centerX" id="Mv4-A4-oeJ"/> <constraint firstItem="xKq-9P-ibo" firstAttribute="centerX" secondItem="vp3-VV-Mzw" secondAttribute="centerX" id="Mv4-A4-oeJ"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="xKq-9P-ibo" secondAttribute="trailing" constant="20" symbolic="YES" id="TYr-VP-3lc"/> <constraint firstAttribute="trailing" secondItem="xKq-9P-ibo" secondAttribute="trailing" constant="20" symbolic="YES" id="TYr-VP-3lc"/>
<constraint firstItem="xKq-9P-ibo" firstAttribute="top" secondItem="rir-se-YCO" secondAttribute="bottom" id="WN7-F2-8Cn"/> <constraint firstItem="xKq-9P-ibo" firstAttribute="top" secondItem="rir-se-YCO" secondAttribute="bottom" id="WN7-F2-8Cn"/>
<constraint firstItem="rir-se-YCO" firstAttribute="leading" secondItem="vp3-VV-Mzw" secondAttribute="leading" id="bGY-bf-MdA"/> <constraint firstItem="rir-se-YCO" firstAttribute="leading" secondItem="vp3-VV-Mzw" secondAttribute="leading" id="bGY-bf-MdA"/>
</constraints> </constraints>
</view> </view>
<connections> <connections>
<outlet property="addToFeedsButton" destination="Bv8-Eq-0cT" id="ZD6-YN-9oa"/> <outlet property="addToFeedsButton" destination="Bv8-Eq-0cT" id="ZD6-YN-9oa"/>
<outlet property="folderPopupButton" destination="Y7Q-9h-CQt" id="OLi-Wx-HDj"/>
<outlet property="openHomePageButton" destination="Ohy-a3-XkT" id="G55-UY-RQ8"/> <outlet property="openHomePageButton" destination="Ohy-a3-XkT" id="G55-UY-RQ8"/>
<outlet property="outlineView" destination="Hxu-8i-6rp" id="Hm2-on-0JP"/> <outlet property="outlineView" destination="Hxu-8i-6rp" id="Hm2-on-0JP"/>
</connections> </connections>

View File

@ -7,6 +7,7 @@
// //
import AppKit import AppKit
import Account
import RSTree import RSTree
import RSCore import RSCore
@ -22,10 +23,12 @@ struct FeedListUserInfoKey {
final class FeedListViewController: NSViewController { final class FeedListViewController: NSViewController {
@IBOutlet var outlineView: NSOutlineView! @IBOutlet weak var outlineView: NSOutlineView!
@IBOutlet var openHomePageButton: NSButton! @IBOutlet weak var openHomePageButton: NSButton!
@IBOutlet var addToFeedsButton: NSButton! @IBOutlet weak var addToFeedsButton: NSButton!
@IBOutlet weak var folderPopupButton: NSPopUpButton!
fileprivate var folderTreeController: TreeController?
private var sidebarCellAppearance: SidebarCellAppearance! private var sidebarCellAppearance: SidebarCellAppearance!
private let treeControllerDelegate = FeedListTreeControllerDelegate() private let treeControllerDelegate = FeedListTreeControllerDelegate()
lazy var treeController: TreeController = { lazy var treeController: TreeController = {
@ -51,16 +54,24 @@ final class FeedListViewController: NSViewController {
sidebarCellAppearance = SidebarCellAppearance(theme: appDelegate.currentTheme, fontSize: AppDefaults.shared.sidebarFontSize) sidebarCellAppearance = SidebarCellAppearance(theme: appDelegate.currentTheme, fontSize: AppDefaults.shared.sidebarFontSize)
NotificationCenter.default.addObserver(self, selector: #selector(faviconDidBecomeAvailable(_:)), name: .FaviconDidBecomeAvailable, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(faviconDidBecomeAvailable(_:)), name: .FaviconDidBecomeAvailable, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(childrenDidChange(_:)), name: .ChildrenDidChange, object: nil)
outlineView.needsLayout = true outlineView.needsLayout = true
updateUI()
updateFolderMenu()
updateButtons()
} }
// MARK: - Notifications // MARK: - Notifications
@objc func faviconDidBecomeAvailable(_ note: Notification) { @objc func faviconDidBecomeAvailable(_ note: Notification) {
configureAvailableCells() configureAvailableCells()
} }
@objc func childrenDidChange(_ note: Notification) {
updateFolderMenu()
}
} }
// MARK: Actions // MARK: Actions
@ -77,6 +88,51 @@ extension FeedListViewController {
@IBAction func addToFeeds(_ sender: Any?) { @IBAction func addToFeeds(_ sender: Any?) {
guard let container = folderPopupButton.selectedItem?.representedObject as? Container else {
assertionFailure("Expected the folderPopupButton to have a container.")
return
}
var account: Account?
var folder: Folder?
if container is Folder {
folder = (container as! Folder)
account = folder!.account
} else {
account = (container as! Account)
}
for selectedObject in selectedObjects {
guard let feedListFeed = selectedObject as? FeedListFeed else {
continue
}
if account!.hasFeed(withURL: feedListFeed.url) {
continue
}
guard let feed = account!.createFeed(with: feedListFeed.nameForDisplay, editedName: nil, url: feedListFeed.url) else {
continue
}
guard let url = URL(string: feedListFeed.url) else {
assertionFailure("Malformed URL string: \(feedListFeed.url).")
continue
}
if account!.addFeed(feed, to: folder) {
NotificationCenter.default.post(name: .UserDidAddFeed, object: self, userInfo: [UserInfoKey.feed: feed])
}
InitialFeedDownloader.download(url) { (parsedFeed) in
if let parsedFeed = parsedFeed {
account!.update(feed, with: parsedFeed, {})
}
}
}
} }
} }
@ -124,8 +180,8 @@ extension FeedListViewController: NSOutlineViewDelegate {
func outlineViewSelectionDidChange(_ notification: Notification) { func outlineViewSelectionDidChange(_ notification: Notification) {
updateUI() updateButtons()
let selectedRow = self.outlineView.selectedRow let selectedRow = self.outlineView.selectedRow
if selectedRow < 0 || selectedRow == NSNotFound { if selectedRow < 0 || selectedRow == NSNotFound {
@ -211,11 +267,15 @@ private extension FeedListViewController {
NotificationCenter.default.post(name: .FeedListSidebarSelectionDidChange, object: self, userInfo: userInfo) NotificationCenter.default.post(name: .FeedListSidebarSelectionDidChange, object: self, userInfo: userInfo)
} }
func updateUI() { func updateFolderMenu() {
updateButtons() let rootNode = Node(representedObject: AccountManager.shared.localAccount, parent: nil)
rootNode.canHaveChildNodes = true
folderTreeController = TreeController(delegate: FolderTreeControllerDelegate(), rootNode: rootNode)
folderPopupButton.menu = FolderTreeMenu.createFolderPopupMenu(with: folderTreeController!.rootNode)
} }
func updateButtons() { func updateButtons() {
let objects = selectedObjects let objects = selectedObjects
@ -223,10 +283,12 @@ private extension FeedListViewController {
if objects.isEmpty { if objects.isEmpty {
openHomePageButton.isEnabled = false openHomePageButton.isEnabled = false
addToFeedsButton.isEnabled = false addToFeedsButton.isEnabled = false
folderPopupButton.isEnabled = false
return return
} }
addToFeedsButton.isEnabled = true addToFeedsButton.isEnabled = true
folderPopupButton.isEnabled = true
if let _ = singleSelectedHomePageURL() { if let _ = singleSelectedHomePageURL() {
openHomePageButton.isEnabled = true openHomePageButton.isEnabled = true

View File

@ -68,7 +68,7 @@ class AddFeedWindowController : NSWindowController {
nameTextField.stringValue = initialName nameTextField.stringValue = initialName
} }
folderPopupButton.menu = createFolderPopupMenu() folderPopupButton.menu = FolderTreeMenu.createFolderPopupMenu(with: folderTreeController.rootNode)
updateUI() updateUI()
} }
@ -139,35 +139,4 @@ private extension AddFeedWindowController {
return folderPopupButton.selectedItem?.representedObject as? Container return folderPopupButton.selectedItem?.representedObject as? Container
} }
func createFolderPopupMenu() -> NSMenu {
let menu = NSMenu(title: "Folders")
let menuItem = NSMenuItem(title: NSLocalizedString("Top Level", comment: "Add Feed Sheet"), action: nil, keyEquivalent: "")
menuItem.representedObject = folderTreeController.rootNode.representedObject
menu.addItem(menuItem)
let childNodes = folderTreeController.rootNode.childNodes
addFolderItemsToMenuWithNodes(menu: menu, nodes: childNodes, indentationLevel: 1)
return menu
}
func addFolderItemsToMenuWithNodes(menu: NSMenu, nodes: [Node], indentationLevel: Int) {
nodes.forEach { (oneNode) in
if let nameProvider = oneNode.representedObject as? DisplayNameProvider {
let menuItem = NSMenuItem(title: nameProvider.nameForDisplay, action: nil, keyEquivalent: "")
menuItem.indentationLevel = indentationLevel
menuItem.representedObject = oneNode.representedObject
menu.addItem(menuItem)
if oneNode.numberOfChildNodes > 0 {
addFolderItemsToMenuWithNodes(menu: menu, nodes: oneNode.childNodes, indentationLevel: indentationLevel + 1)
}
}
}
}
} }

View File

@ -0,0 +1,47 @@
//
// FolderTreeMenu.swift
// NetNewsWire
//
// Created by Maurice Parker on 9/12/18.
// Copyright © 2018 Ranchero Software, LLC. All rights reserved.
//
import AppKit
import RSCore
import RSTree
class FolderTreeMenu {
static func createFolderPopupMenu(with rootNode: Node) -> NSMenu {
let menu = NSMenu(title: "Folders")
let menuItem = NSMenuItem(title: NSLocalizedString("Top Level", comment: "Add Feed Sheet"), action: nil, keyEquivalent: "")
menuItem.representedObject = rootNode.representedObject
menu.addItem(menuItem)
let childNodes = rootNode.childNodes
addFolderItemsToMenuWithNodes(menu: menu, nodes: childNodes, indentationLevel: 1)
return menu
}
private static func addFolderItemsToMenuWithNodes(menu: NSMenu, nodes: [Node], indentationLevel: Int) {
nodes.forEach { (oneNode) in
if let nameProvider = oneNode.representedObject as? DisplayNameProvider {
let menuItem = NSMenuItem(title: nameProvider.nameForDisplay, action: nil, keyEquivalent: "")
menuItem.indentationLevel = indentationLevel
menuItem.representedObject = oneNode.representedObject
menu.addItem(menuItem)
if oneNode.numberOfChildNodes > 0 {
addFolderItemsToMenuWithNodes(menu: menu, nodes: oneNode.childNodes, indentationLevel: indentationLevel + 1)
}
}
}
}
}