diff --git a/Frameworks/Account/AccountMetadataFile.swift b/Frameworks/Account/AccountMetadataFile.swift index cb1aaed5d..03b5ccf7e 100644 --- a/Frameworks/Account/AccountMetadataFile.swift +++ b/Frameworks/Account/AccountMetadataFile.swift @@ -48,8 +48,8 @@ private extension AccountMetadataFile { if let fileData = try? Data(contentsOf: readURL) { let decoder = PropertyListDecoder() account.metadata = (try? decoder.decode(AccountMetadata.self, from: fileData)) ?? AccountMetadata() - account.metadata.delegate = account } + account.metadata.delegate = account }) if let error = errorPointer?.pointee { diff --git a/Frameworks/Account/FeedMetadataFile.swift b/Frameworks/Account/FeedMetadataFile.swift index a602819b6..42fb8a460 100644 --- a/Frameworks/Account/FeedMetadataFile.swift +++ b/Frameworks/Account/FeedMetadataFile.swift @@ -48,10 +48,10 @@ private extension FeedMetadataFile { if let fileData = try? Data(contentsOf: readURL) { let decoder = PropertyListDecoder() account.feedMetadata = (try? decoder.decode(Account.FeedMetadataDictionary.self, from: fileData)) ?? Account.FeedMetadataDictionary() - account.feedMetadata.values.forEach { $0.delegate = account } - if !account.startingUp { - account.resetFeedMetadataAndUnreadCounts() - } + } + account.feedMetadata.values.forEach { $0.delegate = account } + if !account.startingUp { + account.resetFeedMetadataAndUnreadCounts() } }) diff --git a/Mac/MainWindow/ArticleExtractorButton.swift b/Mac/MainWindow/ArticleExtractorButton.swift index 4fd04bf45..69e250ed5 100644 --- a/Mac/MainWindow/ArticleExtractorButton.swift +++ b/Mac/MainWindow/ArticleExtractorButton.swift @@ -57,7 +57,7 @@ class ArticleExtractorButton: NSButton { case isError: addImageSublayer(to: hostedLayer, image: AppAssets.articleExtractorError, opacity: opacity) case isInProgress: - addProgressSublayer(to: hostedLayer) + addAnimatedSublayer(to: hostedLayer) default: addImageSublayer(to: hostedLayer, image: AppAssets.articleExtractor, opacity: opacity) } @@ -77,7 +77,7 @@ class ArticleExtractorButton: NSButton { hostedLayer.addSublayer(imageLayer) } - private func addProgressSublayer(to hostedLayer: CALayer) { + private func addAnimatedSublayer(to hostedLayer: CALayer) { let imageProgress1 = AppAssets.articleExtractorProgress1 let imageProgress2 = AppAssets.articleExtractorProgress2 let imageProgress3 = AppAssets.articleExtractorProgress3 diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 80f6d7d5a..34b79a0b5 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -10,6 +10,7 @@ 49F40DF82335B71000552BF4 /* newsfoot.js in Resources */ = {isa = PBXBuildFile; fileRef = 49F40DEF2335B71000552BF4 /* newsfoot.js */; }; 49F40DF92335B71000552BF4 /* newsfoot.js in Resources */ = {isa = PBXBuildFile; fileRef = 49F40DEF2335B71000552BF4 /* newsfoot.js */; }; 510BD15D232D765D002692E4 /* SettingsReaderAPIAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 557EE1A522B6F4E1004206FA /* SettingsReaderAPIAccountView.swift */; }; + 51102165233A7D6C0007A5F7 /* ArticleExtractorButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51102164233A7D6C0007A5F7 /* ArticleExtractorButton.swift */; }; 51126DA4225FDE2F00722696 /* RSImage-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51126DA3225FDE2F00722696 /* RSImage-Extensions.swift */; }; 5115CAF42266301400B21BCE /* AddContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51121B5A22661FEF00BC0EC1 /* AddContainerViewController.swift */; }; 511D43CF231FA62200FB1562 /* DetailKeyboardShortcuts.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5127B237222B4849006D641D /* DetailKeyboardShortcuts.plist */; }; @@ -81,7 +82,7 @@ 5170743A232AABFC00A461A3 /* FlattenedAccountFolderPickerData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C452812265093600C03939 /* FlattenedAccountFolderPickerData.swift */; }; 517630042336215100E15FFF /* main.js in Resources */ = {isa = PBXBuildFile; fileRef = 517630032336215100E15FFF /* main.js */; }; 517630052336215100E15FFF /* main.js in Resources */ = {isa = PBXBuildFile; fileRef = 517630032336215100E15FFF /* main.js */; }; - 517630232336657E00E15FFF /* DetailViewControllerWebViewProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 517630222336657E00E15FFF /* DetailViewControllerWebViewProvider.swift */; }; + 517630232336657E00E15FFF /* ArticleViewControllerWebViewProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 517630222336657E00E15FFF /* ArticleViewControllerWebViewProvider.swift */; }; 5183CCD0226E1E880010922C /* NonIntrinsicLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCCF226E1E880010922C /* NonIntrinsicLabel.swift */; }; 5183CCDA226E31A50010922C /* NonIntrinsicImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCD9226E31A50010922C /* NonIntrinsicImageView.swift */; }; 5183CCDD226F1F5C0010922C /* NavigationProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCDC226F1F5C0010922C /* NavigationProgressView.swift */; }; @@ -144,7 +145,7 @@ 51C452792265091600C03939 /* MasterTimelineTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C452722265091600C03939 /* MasterTimelineTableViewCell.swift */; }; 51C4527B2265091600C03939 /* MasterUnreadIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C452742265091600C03939 /* MasterUnreadIndicatorView.swift */; }; 51C4527C2265091600C03939 /* MasterTimelineDefaultCellLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C452752265091600C03939 /* MasterTimelineDefaultCellLayout.swift */; }; - 51C4527F2265092C00C03939 /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C4527E2265092C00C03939 /* DetailViewController.swift */; }; + 51C4527F2265092C00C03939 /* ArticleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C4527E2265092C00C03939 /* ArticleViewController.swift */; }; 51C452852265093600C03939 /* FlattenedAccountFolderPickerData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C452812265093600C03939 /* FlattenedAccountFolderPickerData.swift */; }; 51C452862265093600C03939 /* Add.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 51C452822265093600C03939 /* Add.storyboard */; }; 51C452882265093600C03939 /* AddFeedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C452842265093600C03939 /* AddFeedViewController.swift */; }; @@ -780,6 +781,7 @@ 510D707D22B02A4B004E8F65 /* SettingsLocalAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsLocalAccountView.swift; sourceTree = ""; }; 510D707F22B02A5F004E8F65 /* SettingsFeedbinAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsFeedbinAccountView.swift; sourceTree = ""; }; 510D708122B041CC004E8F65 /* SettingsAccountLabelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsAccountLabelView.swift; sourceTree = ""; }; + 51102164233A7D6C0007A5F7 /* ArticleExtractorButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleExtractorButton.swift; sourceTree = ""; }; 51121AA12265430A00BC0EC1 /* NetNewsWire_iOSapp_target.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = NetNewsWire_iOSapp_target.xcconfig; sourceTree = ""; }; 51121B5A22661FEF00BC0EC1 /* AddContainerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddContainerViewController.swift; sourceTree = ""; }; 51126DA3225FDE2F00722696 /* RSImage-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RSImage-Extensions.swift"; sourceTree = ""; }; @@ -819,7 +821,7 @@ 515D4FCE2325B3D000EE1167 /* NetNewsWire_iOSshareextension_target.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = NetNewsWire_iOSshareextension_target.xcconfig; sourceTree = ""; }; 51707438232AA97100A461A3 /* ShareFolderPickerController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareFolderPickerController.swift; sourceTree = ""; }; 517630032336215100E15FFF /* main.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = main.js; sourceTree = ""; }; - 517630222336657E00E15FFF /* DetailViewControllerWebViewProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailViewControllerWebViewProvider.swift; sourceTree = ""; }; + 517630222336657E00E15FFF /* ArticleViewControllerWebViewProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleViewControllerWebViewProvider.swift; sourceTree = ""; }; 5183CCCF226E1E880010922C /* NonIntrinsicLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonIntrinsicLabel.swift; sourceTree = ""; }; 5183CCD9226E31A50010922C /* NonIntrinsicImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonIntrinsicImageView.swift; sourceTree = ""; }; 5183CCDC226F1F5C0010922C /* NavigationProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationProgressView.swift; sourceTree = ""; }; @@ -853,7 +855,7 @@ 51C452722265091600C03939 /* MasterTimelineTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MasterTimelineTableViewCell.swift; sourceTree = ""; }; 51C452742265091600C03939 /* MasterUnreadIndicatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MasterUnreadIndicatorView.swift; sourceTree = ""; }; 51C452752265091600C03939 /* MasterTimelineDefaultCellLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MasterTimelineDefaultCellLayout.swift; sourceTree = ""; }; - 51C4527E2265092C00C03939 /* DetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; }; + 51C4527E2265092C00C03939 /* ArticleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArticleViewController.swift; sourceTree = ""; }; 51C452812265093600C03939 /* FlattenedAccountFolderPickerData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlattenedAccountFolderPickerData.swift; sourceTree = ""; }; 51C452822265093600C03939 /* Add.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Add.storyboard; sourceTree = ""; }; 51C452842265093600C03939 /* AddFeedViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddFeedViewController.swift; sourceTree = ""; }; @@ -1375,13 +1377,14 @@ path = Cell; sourceTree = ""; }; - 51C4527D2265092C00C03939 /* Detail */ = { + 51C4527D2265092C00C03939 /* Article */ = { isa = PBXGroup; children = ( - 51C4527E2265092C00C03939 /* DetailViewController.swift */, - 517630222336657E00E15FFF /* DetailViewControllerWebViewProvider.swift */, + 51C4527E2265092C00C03939 /* ArticleViewController.swift */, + 517630222336657E00E15FFF /* ArticleViewControllerWebViewProvider.swift */, + 51102164233A7D6C0007A5F7 /* ArticleExtractorButton.swift */, ); - path = Detail; + path = Article; sourceTree = ""; }; 51C452802265093600C03939 /* Add */ = { @@ -1963,7 +1966,7 @@ 51BB7C262335A8E5008E8144 /* ArticleActivityItemSource.swift */, 51C4525D226508F600C03939 /* MasterFeed */, 51C4526D2265091600C03939 /* MasterTimeline */, - 51C4527D2265092C00C03939 /* Detail */, + 51C4527D2265092C00C03939 /* Article */, 51C452802265093600C03939 /* Add */, 5183CCEB227117C70010922C /* Settings */, 5183CCDB226F1EEB0010922C /* Progress */, @@ -2160,7 +2163,9 @@ isa = PBXNativeTarget; buildConfigurationList = 840D61A32029031E009BC708 /* Build configuration list for PBXNativeTarget "NetNewsWire-iOS" */; buildPhases = ( + 517D2D80233A46ED00FF3E35 /* Update ArticleExtractorConfig.swift */, 840D61782029031C009BC708 /* Sources */, + 517D2D81233A47AD00FF3E35 /* Reset ArticleExtractorConfig.swift */, 840D61792029031C009BC708 /* Frameworks */, 840D617A2029031C009BC708 /* Resources */, 51C451DF2264C7F200C03939 /* Embed Frameworks */, @@ -2190,8 +2195,9 @@ isa = PBXNativeTarget; buildConfigurationList = 849C647A1ED37A5D003D8FC0 /* Build configuration list for PBXNativeTarget "NetNewsWire" */; buildPhases = ( - 51D6803823330CFF0097A009 /* Update Feedbin Mercury API Keys */, + 51D6803823330CFF0097A009 /* Update ArticleExtractorConfig.swift */, 849C645C1ED37A5D003D8FC0 /* Sources */, + 517D2D82233A53D600FF3E35 /* Reset ArticleExtractorConfig.swift */, 849C645D1ED37A5D003D8FC0 /* Frameworks */, 849C645E1ED37A5D003D8FC0 /* Resources */, 84C987A52000AC9E0066B150 /* Run Script: Automated build numbers */, @@ -2603,7 +2609,7 @@ shellPath = /bin/sh; shellScript = "xcrun -sdk macosx swiftc -target x86_64-macosx10.11 buildscripts/VerifyNoBuildSettings.swift -o $CONFIGURATION_TEMP_DIR/VerifyNoBS\n$CONFIGURATION_TEMP_DIR/VerifyNoBS ${PROJECT_NAME}.xcodeproj/project.pbxproj\n"; }; - 51D6803823330CFF0097A009 /* Update Feedbin Mercury API Keys */ = { + 517D2D80233A46ED00FF3E35 /* Update ArticleExtractorConfig.swift */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -2612,14 +2618,68 @@ ); inputPaths = ( ); - name = "Update Feedbin Mercury API Keys"; + name = "Update ArticleExtractorConfig.swift"; outputFileListPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "FAILED=false\n\nif [ \"${CONFIGURATION}\" = \"Debug\" ]; then\necho \"Not a release build. ArticleExtractorConfig.swift not changed.\"\nexit 0\nfi\n\nif [ -z \"${MERCURY_CLIENT_ID}\" ]; then\necho \"${SRCROOT}/Shared/Article Extractor/ArticleExtractorConfig.swift:21:1: warning: Missing Feedbin Mercury Client ID\"\nFAILED=true\nfi\n\nif [ -z \"${MERCURY_CLIENT_SECRET}\" ]; then\necho \"${SRCROOT}/Shared/Article Extractor/ArticleExtractorConfig.swift:22:1: warning: Missing Feedbin Mercury Client Secret\"\nFAILED=true\nfi\n\nsed -i .tmp \"s|{MERCURYID}|${MERCURY_CLIENT_ID}|g; s|{MERCURYSECRET}|${MERCURY_CLIENT_SECRET}|g\" \"${SRCROOT}/Shared/Article Extractor/ArticleExtractorConfig.swift\"\n\nrm -f \"${SRCROOT}/Shared/Article Extractor/ArticleExtractorConfig.swift.tmp\"\n\nif [ \"$FAILED\" = true ]; then\nexit 1\nfi\n\necho \"All env values found!\"\n"; + shellScript = "FAILED=false\n\nif [ -z \"${MERCURY_CLIENT_ID}\" ]; then\nFAILED=true\nfi\n\nif [ -z \"${MERCURY_CLIENT_SECRET}\" ]; then\nFAILED=true\nfi\n\nif [ \"$FAILED\" = true ]; then\necho \"Missing Feedbin Mercury credetials. ArticleExtractorConfig.swift not changed.\"\nexit 0\nfi\n\nsed -i .tmp \"s|{MERCURYID}|${MERCURY_CLIENT_ID}|g; s|{MERCURYSECRET}|${MERCURY_CLIENT_SECRET}|g\" \"${SRCROOT}/Shared/Article Extractor/ArticleExtractorConfig.swift\"\n\nrm -f \"${SRCROOT}/Shared/Article Extractor/ArticleExtractorConfig.swift.tmp\"\n\necho \"All env values found!\"\n"; + }; + 517D2D81233A47AD00FF3E35 /* Reset ArticleExtractorConfig.swift */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Reset ArticleExtractorConfig.swift"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "git checkout \"${SRCROOT}/Shared/Article Extractor/ArticleExtractorConfig.swift\"\n"; + }; + 517D2D82233A53D600FF3E35 /* Reset ArticleExtractorConfig.swift */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Reset ArticleExtractorConfig.swift"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "git checkout \"${SRCROOT}/Shared/Article Extractor/ArticleExtractorConfig.swift\"\n"; + }; + 51D6803823330CFF0097A009 /* Update ArticleExtractorConfig.swift */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Update ArticleExtractorConfig.swift"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "FAILED=false\n\nif [ -z \"${MERCURY_CLIENT_ID}\" ]; then\nFAILED=true\nfi\n\nif [ -z \"${MERCURY_CLIENT_SECRET}\" ]; then\nFAILED=true\nfi\n\nif [ \"$FAILED\" = true ]; then\necho \"Missing Feedbin Mercury credetials. ArticleExtractorConfig.swift not changed.\"\nexit 0\nfi\n\nsed -i .tmp \"s|{MERCURYID}|${MERCURY_CLIENT_ID}|g; s|{MERCURYSECRET}|${MERCURY_CLIENT_SECRET}|g\" \"${SRCROOT}/Shared/Article Extractor/ArticleExtractorConfig.swift\"\n\nrm -f \"${SRCROOT}/Shared/Article Extractor/ArticleExtractorConfig.swift.tmp\"\n\necho \"All env values found!\"\n\n"; }; 8423E3E3220158E700C3795B /* Run Script: codesign release builds */ = { isa = PBXShellScriptBuildPhase; @@ -2714,7 +2774,7 @@ 51C452A722650A3D00C03939 /* RSImage-Extensions.swift in Sources */, 51C45269226508F600C03939 /* MasterFeedTableViewCell.swift in Sources */, 51F85BFD2275DCA800C787DC /* SingleLineUILabelSizer.swift in Sources */, - 517630232336657E00E15FFF /* DetailViewControllerWebViewProvider.swift in Sources */, + 517630232336657E00E15FFF /* ArticleViewControllerWebViewProvider.swift in Sources */, 51C4528F226509BD00C03939 /* UnreadFeed.swift in Sources */, 51AF460E232488C6001742EF /* Account-Extensions.swift in Sources */, 5183CCDD226F1F5C0010922C /* NavigationProgressView.swift in Sources */, @@ -2763,7 +2823,7 @@ 51FA73A82332BE880090D516 /* ExtractedArticle.swift in Sources */, 51C4527C2265091600C03939 /* MasterTimelineDefaultCellLayout.swift in Sources */, 51C4529A22650A0400C03939 /* ArticleStyle.swift in Sources */, - 51C4527F2265092C00C03939 /* DetailViewController.swift in Sources */, + 51C4527F2265092C00C03939 /* ArticleViewController.swift in Sources */, 51C4526A226508F600C03939 /* MasterFeedTableViewCellLayout.swift in Sources */, 51C452AE2265104D00C03939 /* TimelineStringFormatter.swift in Sources */, 512E08E62268800D00BDCFDD /* FolderTreeControllerDelegate.swift in Sources */, @@ -2772,6 +2832,7 @@ 51F85BF722749FA100C787DC /* UIFont-Extensions.swift in Sources */, 51C452AF2265108300C03939 /* ArticleArray.swift in Sources */, 51C4528E2265099C00C03939 /* SmartFeedsController.swift in Sources */, + 51102165233A7D6C0007A5F7 /* ArticleExtractorButton.swift in Sources */, 84CAFCA522BC8C08007694F0 /* FetchRequestQueue.swift in Sources */, 51C4529C22650A1000C03939 /* SingleFaviconDownloader.swift in Sources */, 51E595A6228CC36500FCC42B /* ArticleStatusSyncTimer.swift in Sources */, diff --git a/Shared/Activity/ActivityManager.swift b/Shared/Activity/ActivityManager.swift index dafc7e854..efb30230c 100644 --- a/Shared/Activity/ActivityManager.swift +++ b/Shared/Activity/ActivityManager.swift @@ -119,8 +119,8 @@ class ActivityManager { } func invalidateReading() { - nextUnreadActivity?.invalidate() - nextUnreadActivity = nil + readingActivity?.invalidate() + readingActivity = nil } static func cleanUp(_ account: Account) { diff --git a/Shared/Article Extractor/ArticleExtractor.swift b/Shared/Article Extractor/ArticleExtractor.swift index ea1d64c67..281fe601d 100644 --- a/Shared/Article Extractor/ArticleExtractor.swift +++ b/Shared/Article Extractor/ArticleExtractor.swift @@ -21,12 +21,6 @@ protocol ArticleExtractorDelegate { func articleExtractionDidComplete(extractedArticle: ExtractedArticle) } -enum ArticleExtractorError: Error { - case UnableToParseHTML - case MissingURL - case UnableToLoadURL -} - class ArticleExtractor { private var dataTask: URLSessionDataTask? = nil @@ -41,9 +35,9 @@ class ArticleExtractor { public init?(_ articleLink: String) { self.articleLink = articleLink - let clientURL = ArticleExtractorConfig.Mercury.clientURL - let username = ArticleExtractorConfig.Mercury.clientId - let signiture = articleLink.hmacUsingSHA1(key: ArticleExtractorConfig.Mercury.clientSecret) + let clientURL = ArticleExtractorConfig.clientURL + let username = ArticleExtractorConfig.clientId + let signiture = articleLink.hmacUsingSHA1(key: ArticleExtractorConfig.clientSecret) if let base64URL = articleLink.data(using: .utf8)?.base64EncodedString() { let fullURL = "\(clientURL)/\(username)/\(signiture)?base64_url=\(base64URL)" @@ -75,7 +69,7 @@ class ArticleExtractor { guard let data = data else { self.state = .failedToParse DispatchQueue.main.async { - self.delegate?.articleExtractionDidFail(with: ArticleExtractorError.UnableToLoadURL) + self.delegate?.articleExtractionDidFail(with: URLError(.cannotDecodeContentData)) } return } diff --git a/Shared/Article Extractor/ArticleExtractorConfig.swift b/Shared/Article Extractor/ArticleExtractorConfig.swift index 0fa5fb576..7f4518fd4 100644 --- a/Shared/Article Extractor/ArticleExtractorConfig.swift +++ b/Shared/Article Extractor/ArticleExtractorConfig.swift @@ -9,27 +9,7 @@ import Foundation enum ArticleExtractorConfig { - - enum Mercury { - // For testing add the environment variables in the scheme you are using - static let clientId = ArticleExtractorConfig.environmentVariable(named: "MERCURY_CLIENT_ID") ?? Release.mercuryId - static let clientSecret = ArticleExtractorConfig.environmentVariable(named: "MERCURY_CLIENT_SECRET") ?? Release.mercurySecret - static let clientURL = Release.mercuryURL - } - - private enum Release { - static let mercuryId = "{MERCURYID}" - static let mercurySecret = "{MERCURYSECRET}" - static let mercuryURL = "https://extract.feedbin.com/parser" - } - - private static func environmentVariable(named: String) -> String? { - let processInfo = ProcessInfo.processInfo - guard let value = processInfo.environment[named] else { - print("‼️ Missing Environment Variable: '\(named)'") - return nil - } - return value - } - + static let clientId = "{MERCURYID}" + static let clientSecret = "{MERCURYSECRET}" + static let clientURL = "https://extract.feedbin.com/parser" } diff --git a/iOS/AppAssets.swift b/iOS/AppAssets.swift index 4cf148530..d669980d0 100644 --- a/iOS/AppAssets.swift +++ b/iOS/AppAssets.swift @@ -10,6 +10,28 @@ import RSCore struct AppAssets { + static var articleExtractorError: UIImage = { + return UIImage(named: "articleExtractorOff")! + }() + + static var articleExtractorOff: UIImage = { + return UIImage(named: "articleExtractorOff")! + }() + + static var articleExtractorOffTinted: UIImage = { + let image = UIImage(named: "articleExtractorOff")! + return image.maskWithColor(color: AppAssets.primaryAccentColor.cgColor)! + }() + + static var articleExtractorOn: UIImage = { + return UIImage(named: "articleExtractorOn")! + }() + + static var articleExtractorOnTinted: UIImage = { + let image = UIImage(named: "articleExtractorOn")! + return image.maskWithColor(color: AppAssets.primaryAccentColor.cgColor)! + }() + static var avatarBackgroundColor: UIColor = { return UIColor(named: "avatarBackgroundColor")! }() diff --git a/iOS/AppDelegate.swift b/iOS/AppDelegate.swift index 2bce61ac6..9a4757548 100644 --- a/iOS/AppDelegate.swift +++ b/iOS/AppDelegate.swift @@ -54,7 +54,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele appDelegate = self // Force lazy initialization of the web view provider so that it can warm up the queue of prepared web views - let _ = DetailViewControllerWebViewProvider.shared + let _ = ArticleViewControllerWebViewProvider.shared AccountManager.shared = AccountManager() AppDefaults.shared = UserDefaults.init(suiteName: "group.\(Bundle.main.bundleIdentifier!)")! diff --git a/iOS/Article/ArticleExtractorButton.swift b/iOS/Article/ArticleExtractorButton.swift new file mode 100644 index 000000000..8c4641964 --- /dev/null +++ b/iOS/Article/ArticleExtractorButton.swift @@ -0,0 +1,78 @@ +// +// ArticleExtractorButton.swift +// NetNewsWire-iOS +// +// Created by Maurice Parker on 9/24/19. +// Copyright © 2019 Ranchero Software. All rights reserved. +// + +import UIKit + +enum ArticleExtractorButtonState { + case error + case animated + case on + case off +} + +class ArticleExtractorButton: UIButton { + + var buttonState: ArticleExtractorButtonState = .off { + didSet { + if buttonState != oldValue { + switch buttonState { + case .error: + stripSublayer() + setImage(AppAssets.articleExtractorError, for: .normal) + case .animated: + setImage(nil, for: .normal) + setNeedsLayout() + case .on: + stripSublayer() + setImage(AppAssets.articleExtractorOn, for: .normal) + case .off: + stripSublayer() + setImage(AppAssets.articleExtractorOff, for: .normal) + } + } + } + } + + override func layoutSubviews() { + super.layoutSubviews() + guard case .animated = buttonState else { + return + } + stripSublayer() + addAnimatedSublayer(to: layer) + } + + private func stripSublayer() { + if layer.sublayers?.count ?? 0 > 1 { + layer.sublayers?.last?.removeFromSuperlayer() + } + } + + private func addAnimatedSublayer(to hostedLayer: CALayer) { + let image1 = AppAssets.articleExtractorOffTinted.cgImage! + let image2 = AppAssets.articleExtractorOnTinted.cgImage! + let images = [image1, image2, image1] + + let imageLayer = CALayer() + let imageSize = AppAssets.articleExtractorOff.size + imageLayer.bounds = CGRect(x: 0, y: 0, width: imageSize.width, height: imageSize.height) + imageLayer.position = CGPoint(x: bounds.midX, y: bounds.midY) + + hostedLayer.addSublayer(imageLayer) + + let animation = CAKeyframeAnimation(keyPath: "contents") + animation.calculationMode = CAAnimationCalculationMode.linear + animation.keyTimes = [0, 0.5, 1] + animation.duration = 2 + animation.values = images as [Any] + animation.repeatCount = HUGE + + imageLayer.add(animation, forKey: "contents") + } + +} diff --git a/iOS/Detail/DetailViewController.swift b/iOS/Article/ArticleViewController.swift similarity index 88% rename from iOS/Detail/DetailViewController.swift rename to iOS/Article/ArticleViewController.swift index bf2e35ad7..5684e0572 100644 --- a/iOS/Detail/DetailViewController.swift +++ b/iOS/Article/ArticleViewController.swift @@ -1,5 +1,5 @@ // -// DetailViewController.swift +// ArticleViewController.swift // NetNewsWire // // Created by Maurice Parker on 4/8/19. @@ -12,7 +12,7 @@ import Account import Articles import SafariServices -enum DetailViewState: Equatable { +enum ArticleViewState: Equatable { case noSelection case multipleSelection case loading @@ -20,8 +20,9 @@ enum DetailViewState: Equatable { case extracted(Article, ExtractedArticle) } -class DetailViewController: UIViewController { +class ArticleViewController: UIViewController { + @IBOutlet private weak var articleExtractorButton: ArticleExtractorButton! @IBOutlet private weak var nextUnreadBarButtonItem: UIBarButtonItem! @IBOutlet private weak var prevArticleBarButtonItem: UIBarButtonItem! @IBOutlet private weak var nextArticleBarButtonItem: UIBarButtonItem! @@ -34,7 +35,7 @@ class DetailViewController: UIViewController { weak var coordinator: SceneCoordinator! - var state: DetailViewState = .noSelection { + var state: ArticleViewState = .noSelection { didSet { if state != oldValue { updateUI() @@ -54,6 +55,15 @@ class DetailViewController: UIViewController { } } + var articleExtractorButtonState: ArticleExtractorButtonState { + get { + return articleExtractorButton.buttonState + } + set { + articleExtractorButton.buttonState = newValue + } + } + private let keyboardManager = KeyboardManager(type: .detail) override var keyCommands: [UIKeyCommand]? { return keyboardManager.keyCommands @@ -61,7 +71,7 @@ class DetailViewController: UIViewController { deinit { webView.removeFromSuperview() - DetailViewControllerWebViewProvider.shared.enqueueWebView(webView) + ArticleViewControllerWebViewProvider.shared.enqueueWebView(webView) webView = nil } @@ -73,7 +83,10 @@ class DetailViewController: UIViewController { NotificationCenter.default.addObserver(self, selector: #selector(progressDidChange(_:)), name: .AccountRefreshProgressDidChange, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(contentSizeCategoryDidChange(_:)), name: UIContentSizeCategory.didChangeNotification, object: nil) - DetailViewControllerWebViewProvider.shared.dequeueWebView() { webView in + // For some reason interface builder won't let me set this there. + articleExtractorButton.addTarget(self, action: #selector(toggleArticleExtractor(_:)), for: .touchUpInside) + + ArticleViewControllerWebViewProvider.shared.dequeueWebView() { webView in self.webView = webView self.webViewContainer.addChildAndPin(webView) @@ -95,6 +108,7 @@ class DetailViewController: UIViewController { func updateUI() { guard let article = currentArticle else { + articleExtractorButton.isEnabled = false nextUnreadBarButtonItem.isEnabled = false prevArticleBarButtonItem.isEnabled = false nextArticleBarButtonItem.isEnabled = false @@ -109,6 +123,7 @@ class DetailViewController: UIViewController { prevArticleBarButtonItem.isEnabled = coordinator.isPrevArticleAvailable nextArticleBarButtonItem.isEnabled = coordinator.isNextArticleAvailable + articleExtractorButton.isEnabled = true readBarButtonItem.isEnabled = true starBarButtonItem.isEnabled = true browserBarButtonItem.isEnabled = true @@ -178,6 +193,10 @@ class DetailViewController: UIViewController { // MARK: Actions + @IBAction func toggleArticleExtractor(_ sender: Any) { + coordinator.toggleArticleExtractor() + } + @IBAction func nextUnread(_ sender: Any) { coordinator.selectNextUnread() } @@ -248,7 +267,7 @@ class DetailViewController: UIViewController { // MARK: WKNavigationDelegate -extension DetailViewController: WKNavigationDelegate { +extension ArticleViewController: WKNavigationDelegate { func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { if navigationAction.navigationType == .linkActivated { @@ -284,7 +303,7 @@ extension DetailViewController: WKNavigationDelegate { // MARK: Private -private extension DetailViewController { +private extension ArticleViewController { func updateProgressIndicatorIfNeeded() { if !(UIDevice.current.userInterfaceIdiom == .pad) { diff --git a/iOS/Detail/DetailViewControllerWebViewProvider.swift b/iOS/Article/ArticleViewControllerWebViewProvider.swift similarity index 92% rename from iOS/Detail/DetailViewControllerWebViewProvider.swift rename to iOS/Article/ArticleViewControllerWebViewProvider.swift index 58c1d7fdf..f221110a1 100644 --- a/iOS/Detail/DetailViewControllerWebViewProvider.swift +++ b/iOS/Article/ArticleViewControllerWebViewProvider.swift @@ -1,5 +1,5 @@ // -// DetailViewControllerWebViewProvider.swift +// ArticleViewControllerWebViewProvider.swift // NetNewsWire-iOS // // Created by Maurice Parker on 9/21/19. @@ -11,9 +11,9 @@ import WebKit /// WKWebView has an awful behavior of a flash to white on first load when in dark mode. /// Keep a queue of WebViews where we've already done a trivial load so that by the time we need them in the UI, they're past the flash-to-shite part of their lifecycle. -class DetailViewControllerWebViewProvider: NSObject, WKNavigationDelegate { +class ArticleViewControllerWebViewProvider: NSObject, WKNavigationDelegate { - static let shared = DetailViewControllerWebViewProvider() + static let shared = ArticleViewControllerWebViewProvider() private let minimumQueueDepth = 3 private let maximumQueueDepth = 6 diff --git a/iOS/Base.lproj/Main.storyboard b/iOS/Base.lproj/Main.storyboard index ef1fd9be4..17f5e4a52 100644 --- a/iOS/Base.lproj/Main.storyboard +++ b/iOS/Base.lproj/Main.storyboard @@ -7,16 +7,16 @@ - + - + - + @@ -98,10 +98,20 @@ - + + + + + + + @@ -152,6 +162,7 @@ + @@ -203,7 +214,10 @@ - + + + + @@ -225,6 +239,7 @@ + diff --git a/iOS/Resources/Assets.xcassets/articleExtractorError.imageset/ArticleExtractorOff.pdf b/iOS/Resources/Assets.xcassets/articleExtractorError.imageset/ArticleExtractorOff.pdf new file mode 100644 index 000000000..2df7fdd06 Binary files /dev/null and b/iOS/Resources/Assets.xcassets/articleExtractorError.imageset/ArticleExtractorOff.pdf differ diff --git a/iOS/Resources/Assets.xcassets/articleExtractorError.imageset/Contents.json b/iOS/Resources/Assets.xcassets/articleExtractorError.imageset/Contents.json new file mode 100644 index 000000000..da8081b60 --- /dev/null +++ b/iOS/Resources/Assets.xcassets/articleExtractorError.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ArticleExtractorOff.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" + } +} \ No newline at end of file diff --git a/iOS/Resources/Assets.xcassets/articleExtractorOff.imageset/ArticleExtractorOff.pdf b/iOS/Resources/Assets.xcassets/articleExtractorOff.imageset/ArticleExtractorOff.pdf new file mode 100644 index 000000000..2df7fdd06 Binary files /dev/null and b/iOS/Resources/Assets.xcassets/articleExtractorOff.imageset/ArticleExtractorOff.pdf differ diff --git a/iOS/Resources/Assets.xcassets/articleExtractorOff.imageset/Contents.json b/iOS/Resources/Assets.xcassets/articleExtractorOff.imageset/Contents.json new file mode 100644 index 000000000..da8081b60 --- /dev/null +++ b/iOS/Resources/Assets.xcassets/articleExtractorOff.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ArticleExtractorOff.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" + } +} \ No newline at end of file diff --git a/iOS/Resources/Assets.xcassets/articleExtractorOn.imageset/ArticleExtractorOn.pdf b/iOS/Resources/Assets.xcassets/articleExtractorOn.imageset/ArticleExtractorOn.pdf new file mode 100644 index 000000000..07c0a9a30 Binary files /dev/null and b/iOS/Resources/Assets.xcassets/articleExtractorOn.imageset/ArticleExtractorOn.pdf differ diff --git a/iOS/Resources/Assets.xcassets/articleExtractorOn.imageset/Contents.json b/iOS/Resources/Assets.xcassets/articleExtractorOn.imageset/Contents.json new file mode 100644 index 000000000..2617bbdfe --- /dev/null +++ b/iOS/Resources/Assets.xcassets/articleExtractorOn.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ArticleExtractorOn.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" + } +} \ No newline at end of file diff --git a/iOS/SceneCoordinator.swift b/iOS/SceneCoordinator.swift index 65e2d8abd..cdfacaa43 100644 --- a/iOS/SceneCoordinator.swift +++ b/iOS/SceneCoordinator.swift @@ -27,6 +27,9 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider { private var activityManager = ActivityManager() + private var isShowingExtractedArticle = false + private var articleExtractor: ArticleExtractor? = nil + private var rootSplitViewController: RootSplitViewController! private var masterNavigationController: UINavigationController! private var masterFeedViewController: MasterFeedViewController! @@ -36,17 +39,17 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider { return rootSplitViewController.children.last as? UISplitViewController } - private var detailViewController: DetailViewController? { - if let detail = masterNavigationController.viewControllers.last as? DetailViewController { + private var articleViewController: ArticleViewController? { + if let detail = masterNavigationController.viewControllers.last as? ArticleViewController { return detail } if let subSplit = subSplitViewController { if let navController = subSplit.viewControllers.last as? UINavigationController { - return navController.topViewController as? DetailViewController + return navController.topViewController as? ArticleViewController } } else { if let navController = rootSplitViewController.viewControllers.last as? UINavigationController { - return navController.topViewController as? DetailViewController + return navController.topViewController as? ArticleViewController } } return nil @@ -289,9 +292,9 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider { masterFeedViewController.coordinator = self masterNavigationController.pushViewController(masterFeedViewController, animated: false) - let detailViewController = UIStoryboard.main.instantiateController(ofType: DetailViewController.self) - detailViewController.coordinator = self - let detailNavigationController = addNavControllerIfNecessary(detailViewController, showButton: false) + let articleViewController = UIStoryboard.main.instantiateController(ofType: ArticleViewController.self) + articleViewController.coordinator = self + let detailNavigationController = addNavControllerIfNecessary(articleViewController, showButton: false) rootSplitViewController.showDetailViewController(detailNavigationController, sender: self) configureThreePanelMode(for: size) @@ -553,32 +556,37 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider { func selectArticle(_ article: Article?, automated: Bool = true) { guard article != currentArticle else { return } + articleExtractor?.cancel() + articleExtractor = nil + isShowingExtractedArticle = false + articleViewController?.articleExtractorButtonState = .off + currentArticle = article activityManager.reading(currentArticle) if article == nil { if rootSplitViewController.isCollapsed { - if masterNavigationController.children.last is DetailViewController { + if masterNavigationController.children.last is ArticleViewController { masterNavigationController.popViewController(animated: !automated) } } else { - detailViewController?.state = .noSelection + articleViewController?.state = .noSelection } masterTimelineViewController?.updateArticleSelection(animate: !automated) return } - if detailViewController == nil { - let detailViewController = UIStoryboard.main.instantiateController(ofType: DetailViewController.self) - detailViewController.coordinator = self - installDetailController(detailViewController, automated: automated) + if articleViewController == nil { + let articleViewController = UIStoryboard.main.instantiateController(ofType: ArticleViewController.self) + articleViewController.coordinator = self + installArticleController(articleViewController, automated: automated) } if automated { masterTimelineViewController?.updateArticleSelection(animate: false) } - detailViewController?.state = .article(article!) + articleViewController?.state = .article(article!) if let article = currentArticle { markArticles(Set([article]), statusKey: .read, flag: true) @@ -686,8 +694,8 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider { } func scrollOrGoToNextUnread() { - if detailViewController?.canScrollDown() ?? false { - detailViewController?.scrollPageDown() + if articleViewController?.canScrollDown() ?? false { + articleViewController?.scrollPageDown() } else { selectNextUnread() } @@ -795,6 +803,40 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider { masterFeedViewController.present(addViewController, animated: true) } + func toggleArticleExtractor() { + + guard let article = currentArticle else { + return + } + + guard articleExtractor?.state != .processing else { + articleExtractor?.cancel() + articleExtractor = nil + isShowingExtractedArticle = false + articleViewController?.articleExtractorButtonState = .off + articleViewController?.state = .article(article) + return + } + + guard !isShowingExtractedArticle else { + isShowingExtractedArticle = false + articleViewController?.articleExtractorButtonState = .off + articleViewController?.state = .article(article) + return + } + + if let articleExtractor = articleExtractor, let extractedArticle = articleExtractor.article { + if currentArticle?.preferredLink == articleExtractor.articleLink { + isShowingExtractedArticle = true + articleViewController?.articleExtractorButtonState = .on + articleViewController?.state = .extracted(article, extractedArticle) + } + } else { + startArticleExtractorForCurrentLink() + } + + } + func homePageURLForFeed(_ indexPath: IndexPath) -> URL? { guard let node = nodeFor(indexPath), let feed = node.representedObject as? Feed, @@ -844,7 +886,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider { } func navigateToDetail() { - detailViewController?.focus() + articleViewController?.focus() } } @@ -880,6 +922,24 @@ extension SceneCoordinator: UINavigationControllerDelegate { } +// MARK: ArticleExtractorDelegate + +extension SceneCoordinator: ArticleExtractorDelegate { + + func articleExtractionDidFail(with: Error) { + articleViewController?.articleExtractorButtonState = .error + } + + func articleExtractionDidComplete(extractedArticle: ExtractedArticle) { + if let article = currentArticle, articleExtractor?.state != .cancelled { + isShowingExtractedArticle = true + articleViewController?.state = .extracted(article, extractedArticle) + articleViewController?.articleExtractorButtonState = .on + } + } + +} + // MARK: Private private extension SceneCoordinator { @@ -1181,6 +1241,15 @@ private extension SceneCoordinator { // MARK: Fetching Articles + func startArticleExtractorForCurrentLink() { + if let link = currentArticle?.preferredLink, let extractor = ArticleExtractor(link) { + extractor.delegate = self + extractor.process() + articleExtractor = extractor + articleViewController?.articleExtractorButtonState = .animated + } + } + func emptyTheTimeline() { if !articles.isEmpty { replaceArticles(with: Set
(), animate: true) @@ -1340,16 +1409,16 @@ private extension SceneCoordinator { } } - func installDetailController(_ detailController: UIViewController, automated: Bool) { + func installArticleController(_ articleController: UIViewController, automated: Bool) { if let subSplit = subSplitViewController { - let controller = addNavControllerIfNecessary(detailController, showButton: false) + let controller = addNavControllerIfNecessary(articleController, showButton: false) subSplit.showDetailViewController(controller, sender: self) } else if rootSplitViewController.isCollapsed { - let controller = addNavControllerIfNecessary(detailController, showButton: false) + let controller = addNavControllerIfNecessary(articleController, showButton: false) masterNavigationController.pushViewController(controller, animated: !automated) } else { - let controller = addNavControllerIfNecessary(detailController, showButton: true) + let controller = addNavControllerIfNecessary(articleController, showButton: true) rootSplitViewController.showDetailViewController(controller, sender: self) } @@ -1406,12 +1475,12 @@ private extension SceneCoordinator { } let controller: UIViewController = { - if let result = detailViewController { + if let result = articleViewController { return result } else { - let detailController = UIStoryboard.main.instantiateController(ofType: DetailViewController.self) - detailController.coordinator = self - return detailController + let articleViewController = UIStoryboard.main.instantiateController(ofType: ArticleViewController.self) + articleViewController.coordinator = self + return articleViewController } }() diff --git a/xcconfig/NetNewsWire_iOSapp_target.xcconfig b/xcconfig/NetNewsWire_iOSapp_target.xcconfig index a10ee2172..95779eaa8 100644 --- a/xcconfig/NetNewsWire_iOSapp_target.xcconfig +++ b/xcconfig/NetNewsWire_iOSapp_target.xcconfig @@ -30,6 +30,7 @@ PROVISIONING_PROFILE_SPECIFIER = // /Users/Shared/git/SharedXcodeSettings/DeveloperSettings.xcconfig // +#include? "../../SharedXcodeSettings/ProjectSettings.xcconfig" #include? "../../SharedXcodeSettings/DeveloperSettings.xcconfig" ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES diff --git a/xcconfig/NetNewsWire_project.xcconfig b/xcconfig/NetNewsWire_project.xcconfig index fbb95fcf1..d69ff02a4 100644 --- a/xcconfig/NetNewsWire_project.xcconfig +++ b/xcconfig/NetNewsWire_project.xcconfig @@ -1,3 +1,5 @@ +#include? "../../SharedXcodeSettings/ProjectSettings.xcconfig" + ALWAYS_SEARCH_USER_PATHS = NO CLANG_ANALYZER_NONNULL = YES CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; diff --git a/xcconfig/NetNewsWire_project_release.xcconfig b/xcconfig/NetNewsWire_project_release.xcconfig index 4756e91a1..f4d9e6289 100644 --- a/xcconfig/NetNewsWire_project_release.xcconfig +++ b/xcconfig/NetNewsWire_project_release.xcconfig @@ -1,4 +1,3 @@ -#include? "../../SharedXcodeSettings/ReleaseSettings.xcconfig" #include "./NetNewsWire_project.xcconfig" COPY_PHASE_STRIP = NO