This commit is contained in:
Brent Simmons 2018-08-21 08:57:26 -07:00
commit 8e36459209
12 changed files with 528 additions and 2 deletions

View File

@ -7,6 +7,12 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
6581C73820CED60100F4AD34 /* SafariExtensionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6581C73720CED60100F4AD34 /* SafariExtensionHandler.swift */; };
6581C73A20CED60100F4AD34 /* SafariExtensionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6581C73920CED60100F4AD34 /* SafariExtensionViewController.swift */; };
6581C73D20CED60100F4AD34 /* SafariExtensionViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6581C73B20CED60100F4AD34 /* SafariExtensionViewController.xib */; };
6581C74020CED60100F4AD34 /* evergreen-subscribe-to-feed.js in Resources */ = {isa = PBXBuildFile; fileRef = 6581C73F20CED60100F4AD34 /* evergreen-subscribe-to-feed.js */; };
6581C74220CED60100F4AD34 /* ToolbarItemIcon.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 6581C74120CED60100F4AD34 /* ToolbarItemIcon.pdf */; };
6581C74620CED60100F4AD34 /* Subscribe to Feed.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 6581C73320CED60000F4AD34 /* Subscribe to Feed.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
840D617F2029031C009BC708 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840D617E2029031C009BC708 /* AppDelegate.swift */; }; 840D617F2029031C009BC708 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840D617E2029031C009BC708 /* AppDelegate.swift */; };
840D61812029031C009BC708 /* MasterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840D61802029031C009BC708 /* MasterViewController.swift */; }; 840D61812029031C009BC708 /* MasterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840D61802029031C009BC708 /* MasterViewController.swift */; };
840D61832029031C009BC708 /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840D61822029031C009BC708 /* DetailViewController.swift */; }; 840D61832029031C009BC708 /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840D61822029031C009BC708 /* DetailViewController.swift */; };
@ -32,6 +38,8 @@
842E45E51ED8C6B7000A8B52 /* MainWindowSplitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842E45E41ED8C6B7000A8B52 /* MainWindowSplitView.swift */; }; 842E45E51ED8C6B7000A8B52 /* MainWindowSplitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842E45E41ED8C6B7000A8B52 /* MainWindowSplitView.swift */; };
842E45E71ED8C747000A8B52 /* DB5.plist in Resources */ = {isa = PBXBuildFile; fileRef = 842E45E61ED8C747000A8B52 /* DB5.plist */; }; 842E45E71ED8C747000A8B52 /* DB5.plist in Resources */ = {isa = PBXBuildFile; fileRef = 842E45E61ED8C747000A8B52 /* DB5.plist */; };
843A3B5620311E7700BF76EC /* FeedListOutlineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843A3B5520311E7700BF76EC /* FeedListOutlineView.swift */; }; 843A3B5620311E7700BF76EC /* FeedListOutlineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843A3B5520311E7700BF76EC /* FeedListOutlineView.swift */; };
8440C8AD2129F9F5002353D1 /* ArticlesDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 841D4D682106B3E100DD04E6 /* ArticlesDatabase.framework */; };
8440C8AE2129F9F5002353D1 /* ArticlesDatabase.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 841D4D682106B3E100DD04E6 /* ArticlesDatabase.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
84411E711FE5FBFA004B527F /* SmallIconProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84411E701FE5FBFA004B527F /* SmallIconProvider.swift */; }; 84411E711FE5FBFA004B527F /* SmallIconProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84411E701FE5FBFA004B527F /* SmallIconProvider.swift */; };
8444C8F21FED81840051386C /* OPMLExporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8444C8F11FED81840051386C /* OPMLExporter.swift */; }; 8444C8F21FED81840051386C /* OPMLExporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8444C8F11FED81840051386C /* OPMLExporter.swift */; };
844B5B591FE9FE4F00C7C76A /* SidebarKeyboardDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844B5B581FE9FE4F00C7C76A /* SidebarKeyboardDelegate.swift */; }; 844B5B591FE9FE4F00C7C76A /* SidebarKeyboardDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844B5B581FE9FE4F00C7C76A /* SidebarKeyboardDelegate.swift */; };
@ -253,6 +261,13 @@
remoteGlobalIDString = 844BEE5A1F0AB3C8004AB7CD; remoteGlobalIDString = 844BEE5A1F0AB3C8004AB7CD;
remoteInfo = Articles; remoteInfo = Articles;
}; };
8440C8AF2129F9F5002353D1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 841D4D5E2106B3E100DD04E6 /* ArticlesDatabase.xcodeproj */;
proxyType = 1;
remoteGlobalIDString = 844BEE361F0AB3AA004AB7CD;
remoteInfo = ArticlesDatabase;
};
846E77391F6EF5D700A165E2 /* PBXContainerItemProxy */ = { 846E77391F6EF5D700A165E2 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy; isa = PBXContainerItemProxy;
containerPortal = 846E77301F6EF5D600A165E2 /* Account.xcodeproj */; containerPortal = 846E77301F6EF5D600A165E2 /* Account.xcodeproj */;
@ -431,6 +446,17 @@
/* End PBXContainerItemProxy section */ /* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */ /* Begin PBXCopyFilesBuildPhase section */
6581C75720CED60100F4AD34 /* Embed App Extensions */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 13;
files = (
6581C74620CED60100F4AD34 /* Subscribe to Feed.appex in Embed App Extensions */,
);
name = "Embed App Extensions";
runOnlyForDeploymentPostprocessing = 0;
};
84B06F681ED37B9000F0B54B /* Embed Frameworks */ = { 84B06F681ED37B9000F0B54B /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase; isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@ -445,6 +471,7 @@
84C37FB620DD8DBB00CA8CF5 /* RSParser.framework in Embed Frameworks */, 84C37FB620DD8DBB00CA8CF5 /* RSParser.framework in Embed Frameworks */,
84C37FA620DD8D8400CA8CF5 /* RSCore.framework in Embed Frameworks */, 84C37FA620DD8D8400CA8CF5 /* RSCore.framework in Embed Frameworks */,
846E773E1F6EF67A00A165E2 /* Account.framework in Embed Frameworks */, 846E773E1F6EF67A00A165E2 /* Account.framework in Embed Frameworks */,
8440C8AE2129F9F5002353D1 /* ArticlesDatabase.framework in Embed Frameworks */,
841D4D6C2106B3ED00DD04E6 /* Articles.framework in Embed Frameworks */, 841D4D6C2106B3ED00DD04E6 /* Articles.framework in Embed Frameworks */,
); );
name = "Embed Frameworks"; name = "Embed Frameworks";
@ -477,6 +504,15 @@
/* End PBXCopyFilesBuildPhase section */ /* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
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; };
6581C73720CED60100F4AD34 /* SafariExtensionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariExtensionHandler.swift; sourceTree = "<group>"; };
6581C73920CED60100F4AD34 /* SafariExtensionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariExtensionViewController.swift; sourceTree = "<group>"; };
6581C73C20CED60100F4AD34 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/SafariExtensionViewController.xib; sourceTree = "<group>"; };
6581C73E20CED60100F4AD34 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
6581C73F20CED60100F4AD34 /* evergreen-subscribe-to-feed.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = "evergreen-subscribe-to-feed.js"; sourceTree = "<group>"; };
6581C74120CED60100F4AD34 /* ToolbarItemIcon.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = ToolbarItemIcon.pdf; sourceTree = "<group>"; };
6581C74320CED60100F4AD34 /* Subscribe_to_Feed.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Subscribe_to_Feed.entitlements; sourceTree = "<group>"; };
8403E75A201C4A79007F7246 /* FeedListKeyboardDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedListKeyboardDelegate.swift; sourceTree = "<group>"; }; 8403E75A201C4A79007F7246 /* FeedListKeyboardDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedListKeyboardDelegate.swift; sourceTree = "<group>"; };
840D617C2029031C009BC708 /* Evergreen.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Evergreen.app; sourceTree = BUILT_PRODUCTS_DIR; }; 840D617C2029031C009BC708 /* Evergreen.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Evergreen.app; sourceTree = BUILT_PRODUCTS_DIR; };
840D617E2029031C009BC708 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 840D617E2029031C009BC708 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
@ -672,6 +708,13 @@
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
6581C73020CED60000F4AD34 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
840D61792029031C009BC708 /* Frameworks */ = { 840D61792029031C009BC708 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@ -705,6 +748,7 @@
846E773D1F6EF67A00A165E2 /* Account.framework in Frameworks */, 846E773D1F6EF67A00A165E2 /* Account.framework in Frameworks */,
84C37FA520DD8D8400CA8CF5 /* RSCore.framework in Frameworks */, 84C37FA520DD8D8400CA8CF5 /* RSCore.framework in Frameworks */,
84FB9A2F1EDCD6C4003D53B9 /* Sparkle.framework in Frameworks */, 84FB9A2F1EDCD6C4003D53B9 /* Sparkle.framework in Frameworks */,
8440C8AD2129F9F5002353D1 /* ArticlesDatabase.framework in Frameworks */,
841D4D6B2106B3ED00DD04E6 /* Articles.framework in Frameworks */, 841D4D6B2106B3ED00DD04E6 /* Articles.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -719,6 +763,20 @@
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
6581C73620CED60100F4AD34 /* Safari Extension */ = {
isa = PBXGroup;
children = (
6581C73720CED60100F4AD34 /* SafariExtensionHandler.swift */,
6581C73920CED60100F4AD34 /* SafariExtensionViewController.swift */,
6581C73B20CED60100F4AD34 /* SafariExtensionViewController.xib */,
6581C73E20CED60100F4AD34 /* Info.plist */,
6581C73F20CED60100F4AD34 /* evergreen-subscribe-to-feed.js */,
6581C74120CED60100F4AD34 /* ToolbarItemIcon.pdf */,
6581C74320CED60100F4AD34 /* Subscribe_to_Feed.entitlements */,
);
path = "Safari Extension";
sourceTree = "<group>";
};
840D617D2029031C009BC708 /* Evergreen-iOS */ = { 840D617D2029031C009BC708 /* Evergreen-iOS */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -1090,6 +1148,7 @@
840D617D2029031C009BC708 /* Evergreen-iOS */, 840D617D2029031C009BC708 /* Evergreen-iOS */,
840D61942029031D009BC708 /* Evergreen-iOSTests */, 840D61942029031D009BC708 /* Evergreen-iOSTests */,
840D619F2029031E009BC708 /* Evergreen-iOSUITests */, 840D619F2029031E009BC708 /* Evergreen-iOSUITests */,
6581C73620CED60100F4AD34 /* Safari Extension */,
84FB9A2C1EDCD6A4003D53B9 /* Frameworks */, 84FB9A2C1EDCD6A4003D53B9 /* Frameworks */,
849C64741ED37A5D003D8FC0 /* EvergreenTests */, 849C64741ED37A5D003D8FC0 /* EvergreenTests */,
D5907CDA2002F084005947E5 /* xcconfig */, D5907CDA2002F084005947E5 /* xcconfig */,
@ -1114,6 +1173,7 @@
840D617C2029031C009BC708 /* Evergreen.app */, 840D617C2029031C009BC708 /* Evergreen.app */,
840D61912029031D009BC708 /* Evergreen-iOSTests.xctest */, 840D61912029031D009BC708 /* Evergreen-iOSTests.xctest */,
840D619C2029031D009BC708 /* Evergreen-iOSUITests.xctest */, 840D619C2029031D009BC708 /* Evergreen-iOSUITests.xctest */,
6581C73320CED60000F4AD34 /* Subscribe to Feed.appex */,
); );
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1278,6 +1338,7 @@
children = ( children = (
847752FE2008879500D93690 /* CoreServices.framework */, 847752FE2008879500D93690 /* CoreServices.framework */,
84FB9A2D1EDCD6B8003D53B9 /* Sparkle.framework */, 84FB9A2D1EDCD6B8003D53B9 /* Sparkle.framework */,
6581C73420CED60100F4AD34 /* Cocoa.framework */,
); );
name = Frameworks; name = Frameworks;
path = Evergreen/Extensions; path = Evergreen/Extensions;
@ -1358,6 +1419,23 @@
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
6581C73220CED60000F4AD34 /* Subscribe to Feed */ = {
isa = PBXNativeTarget;
buildConfigurationList = 6581C75620CED60100F4AD34 /* Build configuration list for PBXNativeTarget "Subscribe to Feed" */;
buildPhases = (
6581C72F20CED60000F4AD34 /* Sources */,
6581C73020CED60000F4AD34 /* Frameworks */,
6581C73120CED60000F4AD34 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "Subscribe to Feed";
productName = "Subscribe to Feed";
productReference = 6581C73320CED60000F4AD34 /* Subscribe to Feed.appex */;
productType = "com.apple.product-type.app-extension";
};
840D617B2029031C009BC708 /* Evergreen-iOS */ = { 840D617B2029031C009BC708 /* Evergreen-iOS */ = {
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 840D61A32029031E009BC708 /* Build configuration list for PBXNativeTarget "Evergreen-iOS" */; buildConfigurationList = 840D61A32029031E009BC708 /* Build configuration list for PBXNativeTarget "Evergreen-iOS" */;
@ -1420,6 +1498,7 @@
849C645E1ED37A5D003D8FC0 /* Resources */, 849C645E1ED37A5D003D8FC0 /* Resources */,
84C987A52000AC9E0066B150 /* ShellScript */, 84C987A52000AC9E0066B150 /* ShellScript */,
84B06F681ED37B9000F0B54B /* Embed Frameworks */, 84B06F681ED37B9000F0B54B /* Embed Frameworks */,
6581C75720CED60100F4AD34 /* Embed App Extensions */,
); );
buildRules = ( buildRules = (
); );
@ -1432,6 +1511,7 @@
84C37FB820DD8DBB00CA8CF5 /* PBXTargetDependency */, 84C37FB820DD8DBB00CA8CF5 /* PBXTargetDependency */,
84C37FC820DD8E1D00CA8CF5 /* PBXTargetDependency */, 84C37FC820DD8E1D00CA8CF5 /* PBXTargetDependency */,
841D4D6E2106B3ED00DD04E6 /* PBXTargetDependency */, 841D4D6E2106B3ED00DD04E6 /* PBXTargetDependency */,
8440C8B02129F9F5002353D1 /* PBXTargetDependency */,
); );
name = Evergreen; name = Evergreen;
productName = Evergreen; productName = Evergreen;
@ -1467,6 +1547,10 @@
LastUpgradeCheck = 0930; LastUpgradeCheck = 0930;
ORGANIZATIONNAME = "Ranchero Software"; ORGANIZATIONNAME = "Ranchero Software";
TargetAttributes = { TargetAttributes = {
6581C73220CED60000F4AD34 = {
DevelopmentTeam = M8L2WTLA8W;
ProvisioningStyle = Manual;
};
840D617B2029031C009BC708 = { 840D617B2029031C009BC708 = {
CreatedOnToolsVersion = 9.3; CreatedOnToolsVersion = 9.3;
DevelopmentTeam = 9C84TZ7Q6Z; DevelopmentTeam = 9C84TZ7Q6Z;
@ -1553,6 +1637,7 @@
840D617B2029031C009BC708 /* Evergreen-iOS */, 840D617B2029031C009BC708 /* Evergreen-iOS */,
840D61902029031D009BC708 /* Evergreen-iOSTests */, 840D61902029031D009BC708 /* Evergreen-iOSTests */,
840D619B2029031D009BC708 /* Evergreen-iOSUITests */, 840D619B2029031D009BC708 /* Evergreen-iOSUITests */,
6581C73220CED60000F4AD34 /* Subscribe to Feed */,
); );
}; };
/* End PBXProject section */ /* End PBXProject section */
@ -1708,6 +1793,16 @@
/* End PBXReferenceProxy section */ /* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */ /* Begin PBXResourcesBuildPhase section */
6581C73120CED60000F4AD34 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
6581C74220CED60100F4AD34 /* ToolbarItemIcon.pdf in Resources */,
6581C73D20CED60100F4AD34 /* SafariExtensionViewController.xib in Resources */,
6581C74020CED60100F4AD34 /* evergreen-subscribe-to-feed.js in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
840D617A2029031C009BC708 /* Resources */ = { 840D617A2029031C009BC708 /* Resources */ = {
isa = PBXResourcesBuildPhase; isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@ -1780,11 +1875,20 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "# See https://blog.curtisherbert.com/automated-build-numbers/\n\ngit=`sh /etc/profile; which git`\nbranch_name=`$git symbolic-ref HEAD | sed -e 's,.*/\\\\(.*\\\\),\\\\1,'`\ngit_count=`$git rev-list $branch_name |wc -l | sed 's/^ *//;s/ *$//'`\nsimple_branch_name=`$git rev-parse --abbrev-ref HEAD`\n\nbuild_number=\"$git_count\"\nif [ $CONFIGURATION != \"Release\" ]; then\nbuild_number+=\"-$simple_branch_name\"\nfi\n\nplist=\"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}\"\ndsym_plist=\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"\n\n/usr/libexec/PlistBuddy -c \"Set :CFBundleVersion $build_number\" \"$plist\"\nif [ -f \"$DSYM_INFO_PLIST\" ] ; then\n/usr/libexec/PlistBuddy -c \"Set :CFBundleVersion $build_number\" \"$dsym_plist\"\nfi"; shellScript = "# See https://blog.curtisherbert.com/automated-build-numbers/\n\ngit=`sh /etc/profile; which git`\nbranch_name=`$git symbolic-ref HEAD | sed -e 's,.*/\\\\(.*\\\\),\\\\1,'`\ngit_count=`$git rev-list $branch_name |wc -l | sed 's/^ *//;s/ *$//'`\nsimple_branch_name=`$git rev-parse --abbrev-ref HEAD`\n\nbuild_number=\"$git_count\"\nif [ $CONFIGURATION != \"Release\" ]; then\nbuild_number+=\"-$simple_branch_name\"\nfi\n\nplist=\"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}\"\ndsym_plist=\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"\n\n/usr/libexec/PlistBuddy -c \"Set :CFBundleVersion $build_number\" \"$plist\"\nif [ -f \"$DSYM_INFO_PLIST\" ] ; then\n/usr/libexec/PlistBuddy -c \"Set :CFBundleVersion $build_number\" \"$dsym_plist\"\nfi\n";
}; };
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */
6581C72F20CED60000F4AD34 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
6581C73A20CED60100F4AD34 /* SafariExtensionViewController.swift in Sources */,
6581C73820CED60100F4AD34 /* SafariExtensionHandler.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
840D61782029031C009BC708 /* Sources */ = { 840D61782029031C009BC708 /* Sources */ = {
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@ -1976,6 +2080,11 @@
name = Articles; name = Articles;
targetProxy = 841D4D6D2106B3ED00DD04E6 /* PBXContainerItemProxy */; targetProxy = 841D4D6D2106B3ED00DD04E6 /* PBXContainerItemProxy */;
}; };
8440C8B02129F9F5002353D1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = ArticlesDatabase;
targetProxy = 8440C8AF2129F9F5002353D1 /* PBXContainerItemProxy */;
};
846E77401F6EF67A00A165E2 /* PBXTargetDependency */ = { 846E77401F6EF67A00A165E2 /* PBXTargetDependency */ = {
isa = PBXTargetDependency; isa = PBXTargetDependency;
name = Account; name = Account;
@ -2019,6 +2128,14 @@
/* End PBXTargetDependency section */ /* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */ /* Begin PBXVariantGroup section */
6581C73B20CED60100F4AD34 /* SafariExtensionViewController.xib */ = {
isa = PBXVariantGroup;
children = (
6581C73C20CED60100F4AD34 /* Base */,
);
name = SafariExtensionViewController.xib;
sourceTree = "<group>";
};
840D61842029031C009BC708 /* Main.storyboard */ = { 840D61842029031C009BC708 /* Main.storyboard */ = {
isa = PBXVariantGroup; isa = PBXVariantGroup;
children = ( children = (
@ -2095,6 +2212,30 @@
/* End PBXVariantGroup section */ /* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */ /* Begin XCBuildConfiguration section */
6581C74720CED60100F4AD34 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = D5907CE02002F0FA005947E5 /* Evergreen_target.xcconfig */;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = "Safari Extension/Subscribe_to_Feed.entitlements";
INFOPLIST_FILE = "Safari Extension/Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = "com.ranchero.Evergreen.Subscribe-to-Feed";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
};
name = Debug;
};
6581C74820CED60100F4AD34 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = D5907CE02002F0FA005947E5 /* Evergreen_target.xcconfig */;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = "Safari Extension/Subscribe_to_Feed.entitlements";
INFOPLIST_FILE = "Safari Extension/Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = "com.ranchero.Evergreen.Subscribe-to-Feed";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
};
name = Release;
};
840D61A42029031E009BC708 /* Debug */ = { 840D61A42029031E009BC708 /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
@ -2545,6 +2686,15 @@
/* End XCBuildConfiguration section */ /* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */ /* Begin XCConfigurationList section */
6581C75620CED60100F4AD34 /* Build configuration list for PBXNativeTarget "Subscribe to Feed" */ = {
isa = XCConfigurationList;
buildConfigurations = (
6581C74720CED60100F4AD34 /* Debug */,
6581C74820CED60100F4AD34 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
840D61A32029031E009BC708 /* Build configuration list for PBXNativeTarget "Evergreen-iOS" */ = { 840D61A32029031E009BC708 /* Build configuration list for PBXNativeTarget "Evergreen-iOS" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (

View File

@ -38,7 +38,7 @@ class UnreadIndicatorView: NSView {
override func draw(_ dirtyRect: NSRect) { override func draw(_ dirtyRect: NSRect) {
if #available(OSX 10.14, *) { if #available(OSX 10.14, *) {
let color = isEmphasized && isSelected ? NSColor.white : NSColor.controlAccent let color = isEmphasized && isSelected ? NSColor.white : NSColor.controlAccentColor
color.setFill() color.setFill()
} else { } else {
let color = isEmphasized && isSelected ? NSColor.white : NSColor.systemBlue let color = isEmphasized && isSelected ? NSColor.white : NSColor.systemBlue

View File

@ -343,6 +343,7 @@
844BEE701F0AB3C9004AB7CD /* Debug */ = { 844BEE701F0AB3C9004AB7CD /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
MACOSX_DEPLOYMENT_TARGET = 10.13; MACOSX_DEPLOYMENT_TARGET = 10.13;
PRODUCT_BUNDLE_IDENTIFIER = com.ranchero.Articles; PRODUCT_BUNDLE_IDENTIFIER = com.ranchero.Articles;
@ -353,6 +354,7 @@
844BEE711F0AB3C9004AB7CD /* Release */ = { 844BEE711F0AB3C9004AB7CD /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
MACOSX_DEPLOYMENT_TARGET = 10.13; MACOSX_DEPLOYMENT_TARGET = 10.13;
PRODUCT_BUNDLE_IDENTIFIER = com.ranchero.Articles; PRODUCT_BUNDLE_IDENTIFIER = com.ranchero.Articles;

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11134" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11134"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="SafariExtensionViewController" customModuleProvider="target">
<connections>
<outlet property="view" destination="c22-O7-iKe" id="vwT-Xx-Aiz"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customView id="c22-O7-iKe">
<rect key="frame" x="0.0" y="0.0" width="330" height="119"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4Iy-aV-wGF">
<rect key="frame" x="103" y="82" width="124" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Subscribe to Feed" id="2Ec-kd-q2K">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
</customView>
</objects>
</document>

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Subscribe to Feed</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.Safari.extension</string>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).SafariExtensionHandler</string>
<key>SFSafariContentScript</key>
<array>
<dict>
<key>Script</key>
<string>evergreen-subscribe-to-feed.js</string>
</dict>
</array>
<key>SFSafariToolbarItem</key>
<dict>
<key>Action</key>
<string>Command</string>
<key>Identifier</key>
<string>Button</string>
<key>Image</key>
<string>ToolbarItemIcon.pdf</string>
<key>Label</key>
<string>Subscribe to Feed</string>
</dict>
<key>SFSafariWebsiteAccess</key>
<dict>
<key>Allowed Domains</key>
<array>
<string>*.*</string>
</array>
<key>Level</key>
<string>All</string>
</dict>
</dict>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2018 Ranchero Software. All rights reserved.</string>
<key>NSHumanReadableDescription</key>
<string>This extension adds a Safari toolbar button for easily subscribing to the syndication feed for the current page.</string>
</dict>
</plist>

View File

@ -0,0 +1,128 @@
//
// SafariExtensionHandler.swift
// Subscribe to Feed
//
// Created by Daniel Jalkut on 6/11/18.
// Copyright © 2018 Ranchero Software. All rights reserved.
//
import SafariServices
class SafariExtensionHandler: SFSafariExtensionHandler {
// Safari App Extensions don't support any reasonable means of detecting whether a
// specific Safari page was loaded with the benefit of the extension's injected
// JavaScript. For this reason a condition can easily be reached where the toolbar
// icon is active for a page, but the expected supporting code is not loaded into
// the page. To detect this and disable our icon, we use a kind of "ping" trick
// to verify whether our code is installed.
// I tried to use a NSMapTable from String to the closure directly, but Swift
// complains that the object has to be a class type.
typealias ValidationHandler = (Bool, String) -> Void
class ValidationWrapper {
let validationHandler: ValidationHandler
init(validationHandler: @escaping ValidationHandler) {
self.validationHandler = validationHandler
}
}
// Maps from UUID to a validation wrapper
static var gPingPongMap = Dictionary<String, ValidationWrapper>()
static var validationQueue = DispatchQueue(label: "Toolbar Validation")
// Bottleneck for calling through to a validation handler we have saved, and removing it from the list.
static func callValidationHandler(forHandlerID handlerID: String, withShouldValidate shouldValidate: Bool) {
if let validationWrapper = gPingPongMap[handlerID] {
validationWrapper.validationHandler(shouldValidate, "")
gPingPongMap.removeValue(forKey: handlerID)
}
}
override func messageReceived(withName messageName: String, from page: SFSafariPage, userInfo: [String : Any]?) {
if (messageName == "subscribeToFeed") {
if let feedURLString = userInfo?["url"] as? String {
if let feedURL = URL(string: feedURLString) {
// We could do something more Evergreen-specific like invoke an app-specific scheme
// to subscribe in the app. For starters we just let NSWorkspace open the URL in the
// default "feed:" URL scheme handler.
NSWorkspace.shared.open(feedURL)
}
}
}
else if (messageName == "pong") {
if let validationIDString = userInfo?["validationID"] as? String {
// Should we validate the button?
let shouldValidate = userInfo?["shouldValidate"] as? Bool ?? false
SafariExtensionHandler.callValidationHandler(forHandlerID: validationIDString, withShouldValidate:shouldValidate)
}
}
}
override func toolbarItemClicked(in window: SFSafariWindow) {
window.getActiveTab { (activeTab) in
activeTab?.getActivePage(completionHandler: { (activePage) in
activePage?.dispatchMessageToScript(withName: "toolbarButtonClicked", userInfo: nil)
})
}
}
override func validateToolbarItem(in window: SFSafariWindow, validationHandler: @escaping ((Bool, String) -> Void)) {
let uniqueValidationID = NSUUID().uuidString
SafariExtensionHandler.validationQueue.sync {
// Save it right away to eliminate any doubt of whether the handler gets deallocated while
// we are waiting for a callback from the getActiveTab or getActivatePage methods below.
let validationWrapper = ValidationWrapper(validationHandler: validationHandler)
SafariExtensionHandler.gPingPongMap[uniqueValidationID] = validationWrapper
// To avoid problems with validation handlers dispatched after we've, for example,
// switched to a new tab, we aggressively clear out the map of any pending validations,
// and focus only on the newest validation request we've been asked for.
for thisValidationID in SafariExtensionHandler.gPingPongMap.keys {
if thisValidationID != uniqueValidationID {
// Default to valid ... we'll know soon enough whether the latest state
// is actually still valid or not...
SafariExtensionHandler.callValidationHandler(forHandlerID: thisValidationID, withShouldValidate: true);
}
}
// See comments above where gPingPongMap is declared. Upon being asked to validate the
// toolbar icon for a specific page, we save the validationHandler and postpone calling
// it until we have either received a response from our installed JavaScript, or until
// a timeout period has elapsed
window.getActiveTab { (activeTab) in
guard let activeTab = activeTab else {
SafariExtensionHandler.callValidationHandler(forHandlerID: uniqueValidationID, withShouldValidate:false);
return
}
activeTab.getActivePage { (activePage) in
guard let activePage = activePage else {
SafariExtensionHandler.callValidationHandler(forHandlerID: uniqueValidationID, withShouldValidate:false);
return
}
activePage.getPropertiesWithCompletionHandler { (pageProperties) in
if let isActive = pageProperties?.isActive {
if isActive {
// Capture the uniqueValidationID to ensure it doesn't change out from under us on a future call
activePage.dispatchMessageToScript(withName: "ping", userInfo: ["validationID": uniqueValidationID])
let pongTimeoutInNanoseconds = Int(Double(NSEC_PER_SEC) * 0.5)
let timeoutDeadline = DispatchTime.now() + DispatchTimeInterval.nanoseconds(pongTimeoutInNanoseconds)
DispatchQueue.main.asyncAfter(deadline: timeoutDeadline, execute: { [timedOutValidationID = uniqueValidationID] in
SafariExtensionHandler.callValidationHandler(forHandlerID: timedOutValidationID, withShouldValidate:false)
})
}
}
}
}
}
}
}
}

View File

@ -0,0 +1,20 @@
//
// SafariExtensionViewController.swift
// Subscribe to Feed
//
// Created by Daniel Jalkut on 6/11/18.
// Copyright © 2018 Ranchero Software. All rights reserved.
//
import SafariServices
class SafariExtensionViewController: SFSafariExtensionViewController {
// This would be the place to handle a popover that could, for example, list the possibly multiple feeds offered by a site.
static let shared: SafariExtensionViewController = {
let shared = SafariExtensionViewController()
shared.preferredContentSize = NSSize(width:320, height:240)
return shared
}()
}

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
</dict>
</plist>

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,118 @@
var thisPageLinkObjects = null;
// I convert the native "link" node into an object that I can pass out to the global page
function objectFromLink(theLink) {
var linkObject = new Object();
linkObject.href = theLink.href;
linkObject.type = theLink.type;
linkObject.title = theLink.title;
return linkObject;
}
// Some sites will list feeds with inappropriate or at least less-than-ideal information
// in the MIME type attribute. We cover some edge cases here that allow to be passed through,
// where they will successfully open as "feed://" URLs in the browser.
function isValidFeedLink(theLink) {
var isValid = false;
switch (theLink.type)
{
case "application/atom+xml":
case "application/x.atom+xml":
case "application/rss+xml":
// These types do not require other criteria.
isValid = (theLink.href != null);
case "text/xml":
case "application/rdf+xml":
// These types require a title that has "RSS" in it.
if (theLink.title && theLink.title.search(/RSS/i) != -1)
{
isValid = (theLink.href != null);
}
}
return isValid;
}
function scanForSyndicationFeeds() {
// In case we don't find any, we establish that we have at least tried by setting the
// variables to empty instead of null.
thisPageLinkObjects = []
thisPageLinks = document.getElementsByTagName("link");
for (thisLinkIndex = 0; thisLinkIndex < thisPageLinks.length; thisLinkIndex++)
{
var thisLink = thisPageLinks[thisLinkIndex];
var thisLinkRel = thisLink.getAttribute("rel");
if (thisLinkRel == "alternate")
{
if (isValidFeedLink(thisLink))
{
thisPageLinkObjects.push(objectFromLink(thisLink));
}
}
}
}
function subscribeToFeed(theFeed) {
// Convert the URL to a feed:// scheme because Safari
// will refuse to load e.g. a feed that is listed merely
// as "text/xml". We do some preflighting of the link rel
// in the PageLoadEnd.js so we can be more confident it's a
// good feed: URL.
var feedURL = theFeed.href;
if (feedURL.match(/^http[s]?:\/\//))
{
feedURL = feedURL.replace(/^http[s]?:\/\//, "feed://");
}
else if (feedURL.match(/^feed:/) == false)
{
feedURL = "feed:" + feedURL;
}
safari.extension.dispatchMessage("subscribeToFeed", { "url": feedURL });
}
function messageHandler(event) {
if (event.name === "toolbarButtonClicked")
{
// Workaround Radar #31182842, in which residual copies of our
// app extension may remain loaded in context of pages in Safari,
// causing multiple responses to broadcast message about toolbar
// button being clicked. In the case of the "extra" injections,
// the document location is null, so we can avoid doing on anything.
if ((document.location != null) && (thisPageLinkObjects.length > 0))
{
feedToOpen = thisPageLinkObjects[0];
subscribeToFeed(feedToOpen);
}
}
else if (event.name === "ping")
{
// Just a hack to get the toolbar icon validation to work as expected.
// If we don't pong back, the extension knows we are not loaded in a page.
// There is a bug in Safari where the messageHandler is apparently held on to by Safari
// even after an extension is disabled. So an effort to "ping" an extension's scripts will
// succeed even if its been disabled and the page reloaded. Checking for the existance of
// document.location seems to ensure we have enough of a handle still on the document that
// we can do something useful with it.
var shouldValidate = (document.location != null) && (thisPageLinkObjects.length > 0);
// Pass back the same validationID we were handed so they can look up the correlated validationHandler
safari.extension.dispatchMessage("pong", { "validationID": event.message.validationID, "shouldValidate": shouldValidate });
}
}
document.addEventListener("DOMContentLoaded", function(event) {
// Prevent injecting the JavaScript in IFRAMES, and from acting before Safari is ready...
if ((window.top === window) && (typeof safari != 'undefined') && (document.location != null))
{
safari.self.addEventListener("message", messageHandler, false)
scanForSyndicationFeeds();
}
});

View File

@ -2,6 +2,12 @@
Evergreen uses [Git submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules) to include shared frameworks. At this writing (June 2018) they are DB5, RSCore, RSDatabase, RSWeb, RSTree, and RSParser. Evergreen uses [Git submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules) to include shared frameworks. At this writing (June 2018) they are DB5, RSCore, RSDatabase, RSWeb, RSTree, and RSParser.
After your first checkout:
git submodule init
git submodule update
To add a submodule: To add a submodule:
git submodule add https://github.com/username/path git submodule add https://github.com/username/path