diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 65cff4bd6..7ec5b8ce8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,13 @@ name: CI -on: [push] +on: + push: + branches: + - master + - mac-candidate + - mac-release + - ios-candidate + - ios-release jobs: build: diff --git a/.gitmodules b/.gitmodules index 5b7b8b710..9ddb37391 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,7 @@ [submodule "submodules/RSDatabase"] path = submodules/RSDatabase url = https://github.com/brentsimmons/RSDatabase +[submodule "submodules/Sparkle"] + path = submodules/Sparkle + url = https://github.com/brentsimmons/Sparkle + branch = ui-separation-and-xpc diff --git a/AppStore/ios/TestFlight.txt b/AppStore/ios/TestFlight.txt new file mode 100644 index 000000000..2f47b2338 --- /dev/null +++ b/AppStore/ios/TestFlight.txt @@ -0,0 +1,31 @@ +NetNewsWire 5.0 for iOS - TestFlight Test Information + +Beta App Description: + +NetNewsWire is an RSS reader. It shows you articles from your favorite blogs and news sites, and it keeps track of what you’ve read. + +Features: + +* Direct feed-downloading +* Syncing via Feedbin +* Share sheet +* Dark Mode +* Starred articles +* All Unread and Today smart feeds +* Folders +* Importing and exporting OPML feed lists +* Multiple accounts + +Feedback Email: + +brent@ranchero.com + +Marketing URL: + +https://ranchero.com/netnewswire/ + +Privacy Policy URL: + +https://ranchero.com/netnewswire/privacypolicy + +License: MIT \ No newline at end of file diff --git a/Appcasts/netnewswire-beta.xml b/Appcasts/netnewswire-beta.xml index e270c3370..acd2dce0a 100755 --- a/Appcasts/netnewswire-beta.xml +++ b/Appcasts/netnewswire-beta.xml @@ -6,6 +6,36 @@ Most recent NetNewsWire changes with links to updates. en + + NetNewsWire 5.0.3 + Same as 5.0.3b2 — just bumped the version number to 5.0.3.

+ ]]>
+ Tue, 22 Oct 2019 13:00:00 -0700 + + 10.14.4 +
+ + + NetNewsWire 5.0.3b2 + Significantly enhanced performance during syncs and refreshes.

+ +

When running for the first time, and the user previously used NetNewsWire 3, it will automatically import NetNewsWire 3 subscriptions instead of the defaults for new users.

+ +

You can also import NetNewsWire 3 subscriptions via the new File > Import NNW3 Subscriptions… command.

+ +

Fixed the space bar when running on Catalina. It wouldn’t advance to the next unread — now it will. (This was due to a change in JavaScript in Catalina.)

+ +

Fixed a crashing bug having to do with async database fetches for the timeline.

+ +

Periodically empties the articles cache that was added in 5.0.3b1, so its memory use doesn’t just keep expanding.

+ ]]>
+ Sat, 19 Oct 2019 10:20:00 -0700 + + 10.14.4 +
+ NetNewsWire 5.0.3b1 Most recent NetNewsWire releases (not test builds). Well, we’re including test builds up until 5.0 ships, but after that it won’t be test builds. en + + NetNewsWire 5.0.3 + Significantly enhanced performance during syncs and refreshes. Fetching articles from the database is also faster.

+ +

When running for the first time, and the user previously used NetNewsWire 3, it will automatically import NetNewsWire 3 subscriptions instead of the defaults for new users.

+ +

You can also import NetNewsWire 3 subscriptions via the new File > Import NNW3 Subscriptions… command.

+ +

Keyboard shortcuts: the 's' key toggles starred status. The 'r' and 'u' keys now both toggle read status (instead of setting read and unread status, respectively).

+ +

Articles view: articles where the feed icon is quite large would be slow to render — now they render as fast as other articles.

+ +

Articles view: a bug where keyboard shortcuts wouldn’t work after giving the articles view focus has been fixed.

+ +

Articles view: YouTube videos could end up small. Fixed.

+ +

Articles view: fixed a bug scaling images to fit in the view.

+ +

Fixed the space bar when running on Catalina. It wouldn’t advance to the next unread — now it will. (This was due to a change in JavaScript in Catalina.)

+ +

Fixed a crashing bug having to do with async database fetches for the timeline.

+ +

Feedbin syncing: fixed a bug where renaming a tag on the Feedbin site would result in feeds in NNW ending up at the top level.

+ +

Help menu: fixed the expired Slack link.

+ + ]]>
+ Tue, 22 Oct 2019 13:00:00 -0700 + + 10.14.4 +
+ NetNewsWire 5.0.2 Folder? { + return folders?.first(where: { $0.nameForDisplay == displayName }) + } + func newFeed(with opmlFeedSpecifier: RSOPMLFeedSpecifier) -> Feed { let feedURL = opmlFeedSpecifier.feedURL let metadata = feedMetadata(feedURL: feedURL, feedID: feedURL) diff --git a/Frameworks/Account/Account.xcodeproj/project.pbxproj b/Frameworks/Account/Account.xcodeproj/project.pbxproj index 2e1647969..67dd8f4f4 100644 --- a/Frameworks/Account/Account.xcodeproj/project.pbxproj +++ b/Frameworks/Account/Account.xcodeproj/project.pbxproj @@ -47,7 +47,6 @@ 51D5875C227F630B00900287 /* tags_initial.json in Resources */ = {isa = PBXBuildFile; fileRef = 51D58759227F630B00900287 /* tags_initial.json */; }; 51D5875E227F643C00900287 /* AccountFeedbinFolderSyncTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51D5875D227F643C00900287 /* AccountFeedbinFolderSyncTest.swift */; }; 51E148EC234B8FFC0004F7A5 /* SyncDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51E148EB234B8FFC0004F7A5 /* SyncDatabase.framework */; }; - 51E148ED234B8FFC0004F7A5 /* SyncDatabase.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 51E148EB234B8FFC0004F7A5 /* SyncDatabase.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 51E3EB41229AF61B00645299 /* AccountError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E3EB40229AF61B00645299 /* AccountError.swift */; }; 51E490362288C37100C791F0 /* FeedbinDate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E490352288C37100C791F0 /* FeedbinDate.swift */; }; 51E59599228C77BC00FCC42B /* FeedbinUnreadEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E59598228C77BC00FCC42B /* FeedbinUnreadEntry.swift */; }; @@ -178,20 +177,6 @@ }; /* End PBXContainerItemProxy section */ -/* Begin PBXCopyFilesBuildPhase section */ - 51E148EE234B8FFC0004F7A5 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 51E148ED234B8FFC0004F7A5 /* SyncDatabase.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - /* Begin PBXFileReference section */ 3BF610C423571CD4000EF978 /* FeedWranglerAPICaller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedWranglerAPICaller.swift; sourceTree = ""; }; 3BF610C523571CD4000EF978 /* FeedWranglerConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedWranglerConfig.swift; sourceTree = ""; }; @@ -686,7 +671,6 @@ 848934F21F62484F00CEBD24 /* Frameworks */, 848934F31F62484F00CEBD24 /* Headers */, 848934F41F62484F00CEBD24 /* Resources */, - 51E148EE234B8FFC0004F7A5 /* Embed Frameworks */, 51C8F34C234FB14B0048ED95 /* Run Script: Verify No Build Settings */, ); buildRules = ( @@ -729,11 +713,11 @@ 848934F51F62484F00CEBD24 = { CreatedOnToolsVersion = 9.0; LastSwiftMigration = 0900; - ProvisioningStyle = Automatic; + ProvisioningStyle = Manual; }; 848934FE1F62484F00CEBD24 = { CreatedOnToolsVersion = 9.0; - ProvisioningStyle = Automatic; + ProvisioningStyle = Manual; }; }; }; diff --git a/Frameworks/Account/AccountError.swift b/Frameworks/Account/AccountError.swift index 480871f2b..2c7fdb720 100644 --- a/Frameworks/Account/AccountError.swift +++ b/Frameworks/Account/AccountError.swift @@ -28,7 +28,7 @@ public enum AccountError: LocalizedError { switch error { case TransportError.httpError(let status): if status == 401 { - let localizedText = NSLocalizedString("Your \"%@\" credentials are invalid or expired.", comment: "Invalid or expired") + let localizedText = NSLocalizedString("Your “%@” credentials are invalid or expired.", comment: "Invalid or expired") return NSString.localizedStringWithFormat(localizedText as NSString, account.nameForDisplay) as String } else { return unknownError(error, account) @@ -62,7 +62,7 @@ public enum AccountError: LocalizedError { } private func unknownError(_ error: Error, _ account: Account) -> String { - let localizedText = NSLocalizedString("An error occurred while processing the \"%@\" account: %@", comment: "Unknown error") + let localizedText = NSLocalizedString("An error occurred while processing the “%@” account: %@", comment: "Unknown error") return NSString.localizedStringWithFormat(localizedText as NSString, account.nameForDisplay, error.localizedDescription) as String } } diff --git a/Frameworks/Account/AccountManager.swift b/Frameworks/Account/AccountManager.swift index 29b7e9095..7c7ab7f1b 100644 --- a/Frameworks/Account/AccountManager.swift +++ b/Frameworks/Account/AccountManager.swift @@ -58,6 +58,10 @@ public final class AccountManager: UnreadCountProvider { return sortByName(activeAccounts) } + public func findActiveAccount(forDisplayName displayName: String) -> Account? { + return AccountManager.shared.activeAccounts.first(where: { $0.nameForDisplay == displayName }) + } + public var refreshInProgress: Bool { for account in activeAccounts { if account.refreshInProgress { diff --git a/Frameworks/Account/Feedly/FeedlyAccountDelegateError.swift b/Frameworks/Account/Feedly/FeedlyAccountDelegateError.swift index ed23a71cc..a77fcfe02 100644 --- a/Frameworks/Account/Feedly/FeedlyAccountDelegateError.swift +++ b/Frameworks/Account/Feedly/FeedlyAccountDelegateError.swift @@ -22,37 +22,37 @@ enum FeedlyAccountDelegateError: LocalizedError { var errorDescription: String? { switch self { case .notLoggedIn: - return NSLocalizedString("Please add the Feedly account again.", comment: "Feedly - Credentials not found.") + return NSLocalizedString("Please add the Feedly account again.", comment: "Feedly – Credentials not found.") case .unableToAddFolder(let name): - let template = NSLocalizedString("Could not create a folder named \"%@\".", comment: "Feedly - Could not create a folder/collection.") + let template = NSLocalizedString("Could not create a folder named “%@”.", comment: "Feedly – Could not create a folder/collection.") return String(format: template, name) case .unableToRenameFolder(let from, let to): - let template = NSLocalizedString("Could not rename \"%@\" to \"%@\".", comment: "Feedly - Could not rename a folder/collection.") + let template = NSLocalizedString("Could not rename “%@” to “%@”.", comment: "Feedly – Could not rename a folder/collection.") return String(format: template, from, to) case .unableToRemoveFolder(let name): - let template = NSLocalizedString("Could not remove the folder named \"%@\".", comment: "Feedly - Could not remove a folder/collection.") + let template = NSLocalizedString("Could not remove the folder named “%@”.", comment: "Feedly – Could not remove a folder/collection.") return String(format: template, name) case .unableToMoveFeedBetweenFolders(let feed, _, let to): - let template = NSLocalizedString("Could not move \"%@\" to \"%@\".", comment: "Feedly - Could not move a feed between folders/collections.") + let template = NSLocalizedString("Could not move “%@” to “%@”.", comment: "Feedly – Could not move a feed between folders/collections.") return String(format: template, feed.nameForDisplay, to.nameForDisplay) case .addFeedChooseFolder: - return NSLocalizedString("Please choose a folder to contain the feed.", comment: "Feedly - Feed can only be added to folders.") + return NSLocalizedString("Please choose a folder to contain the feed.", comment: "Feedly – Feed can only be added to folders.") case .addFeedInvalidFolder(let invalidFolder): - let template = NSLocalizedString("Feeds cannot be added to the \"%@\" folder.", comment: "Feedly - Feed can only be added to folders.") + let template = NSLocalizedString("Feeds cannot be added to the “%@” folder.", comment: "Feedly – Feed can only be added to folders.") return String(format: template, invalidFolder.nameForDisplay) case .unableToRenameFeed(let from, let to): - let template = NSLocalizedString("Could not rename \"%@\" to \"%@\".", comment: "Feedly - Could not rename a feed.") + let template = NSLocalizedString("Could not rename “%@” to “%@”.", comment: "Feedly – Could not rename a feed.") return String(format: template, from, to) case .unableToRemoveFeed(let feed): - let template = NSLocalizedString("Could not remove \"%@\".", comment: "Feedly - Could not remove a feed.") + let template = NSLocalizedString("Could not remove “%@”.", comment: "Feedly – Could not remove a feed.") return String(format: template, feed.nameForDisplay) } } @@ -72,14 +72,14 @@ enum FeedlyAccountDelegateError: LocalizedError { return nil case .unableToMoveFeedBetweenFolders(let feed, let from, let to): - let template = NSLocalizedString("\"%@\" may be in both \"%@\" and \"%@\".", comment: "Feedly - Could not move a feed between folders/collections.") + let template = NSLocalizedString("“%@” may be in both “%@” and “%@”.", comment: "Feedly – Could not move a feed between folders/collections.") return String(format: template, feed.nameForDisplay, from.nameForDisplay, to.nameForDisplay) case .addFeedChooseFolder: return nil case .addFeedInvalidFolder: - return NSLocalizedString("Please choose a different folder to contain the feed.", comment: "Feedly - Feed can only be added to folders recovery suggestion.") + return NSLocalizedString("Please choose a different folder to contain the feed.", comment: "Feedly – Feed can only be added to folders recovery suggestion.") case .unableToRemoveFeed: return nil diff --git a/Frameworks/Vendor/Sparkle.framework/Headers b/Frameworks/Vendor/Sparkle.framework/Headers deleted file mode 120000 index a177d2a6b..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Headers +++ /dev/null @@ -1 +0,0 @@ -Versions/Current/Headers \ No newline at end of file diff --git a/Frameworks/Vendor/Sparkle.framework/Modules b/Frameworks/Vendor/Sparkle.framework/Modules deleted file mode 120000 index 5736f3186..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Modules +++ /dev/null @@ -1 +0,0 @@ -Versions/Current/Modules \ No newline at end of file diff --git a/Frameworks/Vendor/Sparkle.framework/PrivateHeaders b/Frameworks/Vendor/Sparkle.framework/PrivateHeaders deleted file mode 120000 index d8e564526..000000000 --- a/Frameworks/Vendor/Sparkle.framework/PrivateHeaders +++ /dev/null @@ -1 +0,0 @@ -Versions/Current/PrivateHeaders \ No newline at end of file diff --git a/Frameworks/Vendor/Sparkle.framework/Resources b/Frameworks/Vendor/Sparkle.framework/Resources deleted file mode 120000 index 953ee36f3..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Resources +++ /dev/null @@ -1 +0,0 @@ -Versions/Current/Resources \ No newline at end of file diff --git a/Frameworks/Vendor/Sparkle.framework/Sparkle b/Frameworks/Vendor/Sparkle.framework/Sparkle deleted file mode 120000 index b2c52731e..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Sparkle +++ /dev/null @@ -1 +0,0 @@ -Versions/Current/Sparkle \ No newline at end of file diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SPUDownloadData.h b/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SPUDownloadData.h deleted file mode 100644 index 41cd57434..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SPUDownloadData.h +++ /dev/null @@ -1,43 +0,0 @@ -// -// SPUDownloadData.h -// Sparkle -// -// Created by Mayur Pawashe on 8/10/16. -// Copyright © 2016 Sparkle Project. All rights reserved. -// - -#if __has_feature(modules) -@import Foundation; -#else -#import -#endif - -#import "SUExport.h" - -NS_ASSUME_NONNULL_BEGIN - -/*! - * A class for containing downloaded data along with some information about it. - */ -SU_EXPORT @interface SPUDownloadData : NSObject - -- (instancetype)initWithData:(NSData *)data textEncodingName:(NSString * _Nullable)textEncodingName MIMEType:(NSString * _Nullable)MIMEType; - -/*! - * The raw data that was downloaded. - */ -@property (nonatomic, readonly) NSData *data; - -/*! - * The IANA charset encoding name if available. Eg: "utf-8" - */ -@property (nonatomic, readonly, nullable, copy) NSString *textEncodingName; - -/*! - * The MIME type if available. Eg: "text/plain" - */ -@property (nonatomic, readonly, nullable, copy) NSString *MIMEType; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SPUDownloader.h b/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SPUDownloader.h deleted file mode 100644 index 5eee9bd5e..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SPUDownloader.h +++ /dev/null @@ -1,25 +0,0 @@ -// -// SPUDownloader.h -// Downloader -// -// Created by Mayur Pawashe on 4/1/16. -// Copyright © 2016 Sparkle Project. All rights reserved. -// - -#if __has_feature(modules) -@import Foundation; -#else -#import -#endif -#import "SPUDownloaderProtocol.h" - -@protocol SPUDownloaderDelegate; - -// This object implements the protocol which we have defined. It provides the actual behavior for the service. It is 'exported' by the service to make it available to the process hosting the service over an NSXPCConnection. -@interface SPUDownloader : NSObject - -// Due to XPC remote object reasons, this delegate is strongly referenced -// Invoke cleanup when done with this instance -- (instancetype)initWithDelegate:(id )delegate; - -@end diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SPUDownloaderDelegate.h b/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SPUDownloaderDelegate.h deleted file mode 100644 index 76e7e750a..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SPUDownloaderDelegate.h +++ /dev/null @@ -1,38 +0,0 @@ -// -// SPUDownloaderDelegate.h -// Sparkle -// -// Created by Mayur Pawashe on 4/1/16. -// Copyright © 2016 Sparkle Project. All rights reserved. -// - -#if __has_feature(modules) -@import Foundation; -#else -#import -#endif - -NS_ASSUME_NONNULL_BEGIN - -@class SPUDownloadData; - -@protocol SPUDownloaderDelegate - -// This is only invoked for persistent downloads -- (void)downloaderDidSetDestinationName:(NSString *)destinationName temporaryDirectory:(NSString *)temporaryDirectory; - -// Under rare cases, this may be called more than once, in which case the current progress should be reset back to 0 -// This is only invoked for persistent downloads -- (void)downloaderDidReceiveExpectedContentLength:(int64_t)expectedContentLength; - -// This is only invoked for persistent downloads -- (void)downloaderDidReceiveDataOfLength:(uint64_t)length; - -// downloadData is nil if this is a persisent download, otherwise it's non-nil if it's a temporary download -- (void)downloaderDidFinishWithTemporaryDownloadData:(SPUDownloadData * _Nullable)downloadData; - -- (void)downloaderDidFailWithError:(NSError *)error; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SPUDownloaderDeprecated.h b/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SPUDownloaderDeprecated.h deleted file mode 100644 index 36302df48..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SPUDownloaderDeprecated.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// SPUDownloaderDeprecated.h -// Sparkle -// -// Created by Deadpikle on 12/20/17. -// Copyright © 2017 Sparkle Project. All rights reserved. -// - -#import "SPUDownloader.h" - -@interface SPUDownloaderDeprecated : SPUDownloader - -@end diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SPUDownloaderProtocol.h b/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SPUDownloaderProtocol.h deleted file mode 100644 index ebe477fe7..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SPUDownloaderProtocol.h +++ /dev/null @@ -1,34 +0,0 @@ -// -// SPUDownloaderProtocol.h -// PersistentDownloader -// -// Created by Mayur Pawashe on 4/1/16. -// Copyright © 2016 Sparkle Project. All rights reserved. -// - -#if __has_feature(modules) -@import Foundation; -#else -#import -#endif - -NS_ASSUME_NONNULL_BEGIN - -@class SPUURLRequest; - -// The protocol that this service will vend as its API. This header file will also need to be visible to the process hosting the service. -@protocol SPUDownloaderProtocol - -- (void)startPersistentDownloadWithRequest:(SPUURLRequest *)request bundleIdentifier:(NSString *)bundleIdentifier desiredFilename:(NSString *)desiredFilename; - -- (void)startTemporaryDownloadWithRequest:(SPUURLRequest *)request; - -- (void)downloadDidFinish; - -- (void)cleanup; - -- (void)cancel; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SPUDownloaderSession.h b/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SPUDownloaderSession.h deleted file mode 100644 index 4bde75aac..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SPUDownloaderSession.h +++ /dev/null @@ -1,20 +0,0 @@ -// -// SPUDownloaderSession.h -// Sparkle -// -// Created by Deadpikle on 12/20/17. -// Copyright © 2017 Sparkle Project. All rights reserved. -// - -#if __has_feature(modules) -@import Foundation; -#else -#import -#endif -#import "SPUDownloader.h" -#import "SPUDownloaderProtocol.h" - -NS_CLASS_AVAILABLE(NSURLSESSION_AVAILABLE, 7_0) -@interface SPUDownloaderSession : SPUDownloader - -@end diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SPUURLRequest.h b/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SPUURLRequest.h deleted file mode 100644 index 694961470..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SPUURLRequest.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// SPUURLRequest.h -// Sparkle -// -// Created by Mayur Pawashe on 5/19/16. -// Copyright © 2016 Sparkle Project. All rights reserved. -// - -#if __has_feature(modules) -@import Foundation; -#else -#import -#endif - -NS_ASSUME_NONNULL_BEGIN - -// A class that wraps NSURLRequest and implements NSSecureCoding -// This class exists because NSURLRequest did not support NSSecureCoding in macOS 10.8 -// I have not verified if NSURLRequest in 10.9 implements NSSecureCoding or not -@interface SPUURLRequest : NSObject - -// Creates a new URL request -// Only these properties are currently tracked: -// * URL -// * Cache policy -// * Timeout interval -// * HTTP header fields -// * networkServiceType -+ (instancetype)URLRequestWithRequest:(NSURLRequest *)request; - -@property (nonatomic, readonly) NSURLRequest *request; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUAppcast.h b/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUAppcast.h deleted file mode 100644 index 34276b7da..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUAppcast.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// SUAppcast.h -// Sparkle -// -// Created by Andy Matuschak on 3/12/06. -// Copyright 2006 Andy Matuschak. All rights reserved. -// - -#ifndef SUAPPCAST_H -#define SUAPPCAST_H - -#if __has_feature(modules) -@import Foundation; -#else -#import -#endif -#import "SUExport.h" - -NS_ASSUME_NONNULL_BEGIN - -@class SUAppcastItem; -SU_EXPORT @interface SUAppcast : NSObject - -@property (copy, nullable) NSString *userAgentString; -@property (copy, nullable) NSDictionary *httpHeaders; - -- (void)fetchAppcastFromURL:(NSURL *)url inBackground:(BOOL)bg completionBlock:(void (^)(NSError *_Nullable))err; -- (SUAppcast *)copyWithoutDeltaUpdates; - -@property (readonly, copy, nullable) NSArray *items; -@end - -NS_ASSUME_NONNULL_END - -#endif diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUAppcastItem.h b/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUAppcastItem.h deleted file mode 100644 index c0380dd83..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUAppcastItem.h +++ /dev/null @@ -1,52 +0,0 @@ -// -// SUAppcastItem.h -// Sparkle -// -// Created by Andy Matuschak on 3/12/06. -// Copyright 2006 Andy Matuschak. All rights reserved. -// - -#ifndef SUAPPCASTITEM_H -#define SUAPPCASTITEM_H - -#if __has_feature(modules) -@import Foundation; -#else -#import -#endif -#import "SUExport.h" -@class SUSignatures; - -SU_EXPORT @interface SUAppcastItem : NSObject -@property (copy, readonly) NSString *title; -@property (copy, readonly) NSString *dateString; -@property (copy, readonly) NSString *itemDescription; -@property (strong, readonly) NSURL *releaseNotesURL; -@property (strong, readonly) SUSignatures *signatures; -@property (copy, readonly) NSString *minimumSystemVersion; -@property (copy, readonly) NSString *maximumSystemVersion; -@property (strong, readonly) NSURL *fileURL; -@property (nonatomic, readonly) uint64_t contentLength; -@property (copy, readonly) NSString *versionString; -@property (copy, readonly) NSString *osString; -@property (copy, readonly) NSString *displayVersionString; -@property (copy, readonly) NSDictionary *deltaUpdates; -@property (strong, readonly) NSURL *infoURL; - -// Initializes with data from a dictionary provided by the RSS class. -- (instancetype)initWithDictionary:(NSDictionary *)dict; -- (instancetype)initWithDictionary:(NSDictionary *)dict failureReason:(NSString **)error; - -@property (getter=isDeltaUpdate, readonly) BOOL deltaUpdate; -@property (getter=isCriticalUpdate, readonly) BOOL criticalUpdate; -@property (getter=isMacOsUpdate, readonly) BOOL macOsUpdate; -@property (getter=isInformationOnlyUpdate, readonly) BOOL informationOnlyUpdate; - -// Returns the dictionary provided in initWithDictionary; this might be useful later for extensions. -@property (readonly, copy) NSDictionary *propertiesDictionary; - -- (NSURL *)infoURL; - -@end - -#endif diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUCodeSigningVerifier.h b/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUCodeSigningVerifier.h deleted file mode 100644 index f034cd20f..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUCodeSigningVerifier.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// SUCodeSigningVerifier.h -// Sparkle -// -// Created by Andy Matuschak on 7/5/12. -// -// - -#ifndef SUCODESIGNINGVERIFIER_H -#define SUCODESIGNINGVERIFIER_H - -#import -#import "SUExport.h" - -SU_EXPORT @interface SUCodeSigningVerifier : NSObject -+ (BOOL)codeSignatureAtBundleURL:(NSURL *)oldBundlePath matchesSignatureAtBundleURL:(NSURL *)newBundlePath error:(NSError **)error; -+ (BOOL)codeSignatureIsValidAtBundleURL:(NSURL *)bundlePath error:(NSError **)error; -+ (BOOL)bundleAtURLIsCodeSigned:(NSURL *)bundlePath; -+ (NSDictionary *)codeSignatureInfoAtBundleURL:(NSURL *)bundlePath; -@end - -#endif diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUErrors.h b/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUErrors.h deleted file mode 100644 index 7d2e73ae9..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUErrors.h +++ /dev/null @@ -1,56 +0,0 @@ -// -// SUErrors.h -// Sparkle -// -// Created by C.W. Betts on 10/13/14. -// Copyright (c) 2014 Sparkle Project. All rights reserved. -// - -#ifndef SUERRORS_H -#define SUERRORS_H - -#if __has_feature(modules) -@import Foundation; -#else -#import -#endif -#import "SUExport.h" - -/** - * Error domain used by Sparkle - */ -SU_EXPORT extern NSString *const SUSparkleErrorDomain; - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wc++98-compat" -typedef NS_ENUM(OSStatus, SUError) { - // Appcast phase errors. - SUAppcastParseError = 1000, - SUNoUpdateError = 1001, - SUAppcastError = 1002, - SURunningFromDiskImageError = 1003, - - // Download phase errors. - SUTemporaryDirectoryError = 2000, - SUDownloadError = 2001, - - // Extraction phase errors. - SUUnarchivingError = 3000, - SUSignatureError = 3001, - - // Installation phase errors. - SUFileCopyFailure = 4000, - SUAuthenticationFailure = 4001, - SUMissingUpdateError = 4002, - SUMissingInstallerToolError = 4003, - SURelaunchError = 4004, - SUInstallationError = 4005, - SUDowngradeError = 4006, - SUInstallationCancelledError = 4007, - - // System phase errors - SUSystemPowerOffError = 5000 -}; -#pragma clang diagnostic pop - -#endif diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUExport.h b/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUExport.h deleted file mode 100644 index 3e3f8a164..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUExport.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// SUExport.h -// Sparkle -// -// Created by Jake Petroules on 2014-08-23. -// Copyright (c) 2014 Sparkle Project. All rights reserved. -// - -#ifndef SUEXPORT_H -#define SUEXPORT_H - -#ifdef BUILDING_SPARKLE -#define SU_EXPORT __attribute__((visibility("default"))) -#else -#define SU_EXPORT -#endif - -#endif diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUStandardVersionComparator.h b/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUStandardVersionComparator.h deleted file mode 100644 index ed11921a5..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUStandardVersionComparator.h +++ /dev/null @@ -1,52 +0,0 @@ -// -// SUStandardVersionComparator.h -// Sparkle -// -// Created by Andy Matuschak on 12/21/07. -// Copyright 2007 Andy Matuschak. All rights reserved. -// - -#ifndef SUSTANDARDVERSIONCOMPARATOR_H -#define SUSTANDARDVERSIONCOMPARATOR_H - -#if __has_feature(modules) -@import Foundation; -#else -#import -#endif -#import "SUExport.h" -#import "SUVersionComparisonProtocol.h" - -NS_ASSUME_NONNULL_BEGIN - -/*! - Sparkle's default version comparator. - - This comparator is adapted from MacPAD, by Kevin Ballard. - It's "dumb" in that it does essentially string comparison, - in components split by character type. -*/ -SU_EXPORT @interface SUStandardVersionComparator : NSObject - -/*! - Initializes a new instance of the standard version comparator. - */ -- (instancetype)init; - -/*! - Returns a singleton instance of the comparator. - - It is usually preferred to alloc/init new a comparator instead. -*/ -+ (SUStandardVersionComparator *)defaultComparator; - -/*! - Compares version strings through textual analysis. - - See the implementation for more details. -*/ -- (NSComparisonResult)compareVersion:(NSString *)versionA toVersion:(NSString *)versionB; -@end - -NS_ASSUME_NONNULL_END -#endif diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUUpdater.h b/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUUpdater.h deleted file mode 100644 index bc1d49163..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUUpdater.h +++ /dev/null @@ -1,231 +0,0 @@ -// -// SUUpdater.h -// Sparkle -// -// Created by Andy Matuschak on 1/4/06. -// Copyright 2006 Andy Matuschak. All rights reserved. -// - -#ifndef SUUPDATER_H -#define SUUPDATER_H - -#if __has_feature(modules) -@import Cocoa; -#else -#import -#endif -#import "SUExport.h" -#import "SUVersionComparisonProtocol.h" -#import "SUVersionDisplayProtocol.h" - -@class SUAppcastItem, SUAppcast; - -@protocol SUUpdaterDelegate; - -/*! - The main API in Sparkle for controlling the update mechanism. - - This class is used to configure the update paramters as well as manually - and automatically schedule and control checks for updates. - */ -SU_EXPORT @interface SUUpdater : NSObject - -@property (unsafe_unretained) IBOutlet id delegate; - -/*! - The shared updater for the main bundle. - - This is equivalent to passing [NSBundle mainBundle] to SUUpdater::updaterForBundle: - */ -+ (SUUpdater *)sharedUpdater; - -/*! - The shared updater for a specified bundle. - - If an updater has already been initialized for the provided bundle, that shared instance will be returned. - */ -+ (SUUpdater *)updaterForBundle:(NSBundle *)bundle; - -/*! - Designated initializer for SUUpdater. - - If an updater has already been initialized for the provided bundle, that shared instance will be returned. - */ -- (instancetype)initForBundle:(NSBundle *)bundle; - -/*! - Explicitly checks for updates and displays a progress dialog while doing so. - - This method is meant for a main menu item. - Connect any menu item to this action in Interface Builder, - and Sparkle will check for updates and report back its findings verbosely - when it is invoked. - - This will find updates that the user has opted into skipping. - */ -- (IBAction)checkForUpdates:(id)sender; - -/*! - The menu item validation used for the -checkForUpdates: action - */ -- (BOOL)validateMenuItem:(NSMenuItem *)menuItem; - -/*! - Checks for updates, but does not display any UI unless an update is found. - - This is meant for programmatically initating a check for updates. That is, - it will display no UI unless it actually finds an update, in which case it - proceeds as usual. - - If automatic downloading of updates it turned on and allowed, however, - this will invoke that behavior, and if an update is found, it will be downloaded - in the background silently and will be prepped for installation. - - This will not find updates that the user has opted into skipping. - */ -- (void)checkForUpdatesInBackground; - -/*! - A property indicating whether or not to check for updates automatically. - - Setting this property will persist in the host bundle's user defaults. - The update schedule cycle will be reset in a short delay after the property's new value is set. - This is to allow reverting this property without kicking off a schedule change immediately - */ -@property BOOL automaticallyChecksForUpdates; - -/*! - A property indicating whether or not updates can be automatically downloaded in the background. - - Note that automatic downloading of updates can be disallowed by the developer - or by the user's system if silent updates cannot be done (eg: if they require authentication). - In this case, -automaticallyDownloadsUpdates will return NO regardless of how this property is set. - - Setting this property will persist in the host bundle's user defaults. - */ -@property BOOL automaticallyDownloadsUpdates; - -/*! - A property indicating the current automatic update check interval. - - Setting this property will persist in the host bundle's user defaults. - The update schedule cycle will be reset in a short delay after the property's new value is set. - This is to allow reverting this property without kicking off a schedule change immediately - */ -@property NSTimeInterval updateCheckInterval; - -/*! - Begins a "probing" check for updates which will not actually offer to - update to that version. - - However, the delegate methods - SUUpdaterDelegate::updater:didFindValidUpdate: and - SUUpdaterDelegate::updaterDidNotFindUpdate: will be called, - so you can use that information in your UI. - - Updates that have been skipped by the user will not be found. - */ -- (void)checkForUpdateInformation; - -/*! - The URL of the appcast used to download update information. - - Setting this property will persist in the host bundle's user defaults. - If you don't want persistence, you may want to consider instead implementing - SUUpdaterDelegate::feedURLStringForUpdater: or SUUpdaterDelegate::feedParametersForUpdater:sendingSystemProfile: - - This property must be called on the main thread. - */ -@property (copy) NSURL *feedURL; - -/*! - The host bundle that is being updated. - */ -@property (readonly, strong) NSBundle *hostBundle; - -/*! - The bundle this class (SUUpdater) is loaded into. - */ -@property (strong, readonly) NSBundle *sparkleBundle; - -/*! - The user agent used when checking for updates. - - The default implementation can be overrided. - */ -@property (nonatomic, copy) NSString *userAgentString; - -/*! - The HTTP headers used when checking for updates. - - The keys of this dictionary are HTTP header fields (NSString) and values are corresponding values (NSString) - */ -@property (copy) NSDictionary *httpHeaders; - -/*! - A property indicating whether or not the user's system profile information is sent when checking for updates. - - Setting this property will persist in the host bundle's user defaults. - */ -@property BOOL sendsSystemProfile; - -/*! - A property indicating the decryption password used for extracting updates shipped as Apple Disk Images (dmg) - */ -@property (nonatomic, copy) NSString *decryptionPassword; - -/*! - This function ignores normal update schedule, ignores user preferences, - and interrupts users with an unwanted immediate app update. - - WARNING: this function should not be used in regular apps. This function - is a user-unfriendly hack only for very special cases, like unstable - rapidly-changing beta builds that would not run correctly if they were - even one day out of date. - - Instead of this function you should set `SUAutomaticallyUpdate` to `YES`, - which will gracefully install updates when the app quits. - - For UI-less/daemon apps that aren't usually quit, instead of this function, - you can use the delegate method - SUUpdaterDelegate::updater:willInstallUpdateOnQuit:immediateInstallationInvocation: - to immediately start installation when an update was found. - - A progress dialog is shown but the user will never be prompted to read the - release notes. - - This function will cause update to be downloaded twice if automatic updates are - enabled. - - You may want to respond to the userDidCancelDownload delegate method in case - the user clicks the "Cancel" button while the update is downloading. - */ -- (void)installUpdatesIfAvailable; - -/*! - Returns the date of last update check. - - \returns \c nil if no check has been performed. - */ -@property (readonly, copy) NSDate *lastUpdateCheckDate; - -/*! - Appropriately schedules or cancels the update checking timer according to - the preferences for time interval and automatic checks. - - This call does not change the date of the next check, - but only the internal NSTimer. - */ -- (void)resetUpdateCycle; - -/*! - A property indicating whether or not an update is in progress. - - Note this property is not indicative of whether or not user initiated updates can be performed. - Use SUUpdater::validateMenuItem: for that instead. - */ -@property (readonly) BOOL updateInProgress; - -@end - -#endif diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUUpdaterDelegate.h b/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUUpdaterDelegate.h deleted file mode 100644 index 86d1eb9e9..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUUpdaterDelegate.h +++ /dev/null @@ -1,301 +0,0 @@ -// -// SUUpdaterDelegate.h -// Sparkle -// -// Created by Mayur Pawashe on 12/25/16. -// Copyright © 2016 Sparkle Project. All rights reserved. -// - -#if __has_feature(modules) -@import Foundation; -#else -#import -#endif - -#import "SUExport.h" - -@protocol SUVersionComparison, SUVersionDisplay; -@class SUUpdater, SUAppcast, SUAppcastItem; - -NS_ASSUME_NONNULL_BEGIN - -// ----------------------------------------------------------------------------- -// SUUpdater Notifications for events that might be interesting to more than just the delegate -// The updater will be the notification object -// ----------------------------------------------------------------------------- -SU_EXPORT extern NSString *const SUUpdaterDidFinishLoadingAppCastNotification; -SU_EXPORT extern NSString *const SUUpdaterDidFindValidUpdateNotification; -SU_EXPORT extern NSString *const SUUpdaterDidNotFindUpdateNotification; -SU_EXPORT extern NSString *const SUUpdaterWillRestartNotification; -#define SUUpdaterWillRelaunchApplicationNotification SUUpdaterWillRestartNotification; -#define SUUpdaterWillInstallUpdateNotification SUUpdaterWillRestartNotification; - -// Key for the SUAppcastItem object in the SUUpdaterDidFindValidUpdateNotification userInfo -SU_EXPORT extern NSString *const SUUpdaterAppcastItemNotificationKey; -// Key for the SUAppcast object in the SUUpdaterDidFinishLoadingAppCastNotification userInfo -SU_EXPORT extern NSString *const SUUpdaterAppcastNotificationKey; - -// ----------------------------------------------------------------------------- -// SUUpdater Delegate: -// ----------------------------------------------------------------------------- - -/*! - Provides methods to control the behavior of an SUUpdater object. - */ -@protocol SUUpdaterDelegate -@optional - -/*! - Returns whether to allow Sparkle to pop up. - - For example, this may be used to prevent Sparkle from interrupting a setup assistant. - - \param updater The SUUpdater instance. - */ -- (BOOL)updaterMayCheckForUpdates:(SUUpdater *)updater; - -/*! - Returns additional parameters to append to the appcast URL's query string. - - This is potentially based on whether or not Sparkle will also be sending along the system profile. - - \param updater The SUUpdater instance. - \param sendingProfile Whether the system profile will also be sent. - - \return An array of dictionaries with keys: "key", "value", "displayKey", "displayValue", the latter two being specifically for display to the user. - */ -- (NSArray *> *)feedParametersForUpdater:(SUUpdater *)updater sendingSystemProfile:(BOOL)sendingProfile; - -/*! - Returns a custom appcast URL. - - Override this to dynamically specify the entire URL. - - An alternative may be to use SUUpdaterDelegate::feedParametersForUpdater:sendingSystemProfile: - and let the server handle what kind of feed to provide. - - \param updater The SUUpdater instance. - */ -- (nullable NSString *)feedURLStringForUpdater:(SUUpdater *)updater; - -/*! - Returns whether Sparkle should prompt the user about automatic update checks. - - Use this to override the default behavior. - - \param updater The SUUpdater instance. - */ -- (BOOL)updaterShouldPromptForPermissionToCheckForUpdates:(SUUpdater *)updater; - -/*! - Called after Sparkle has downloaded the appcast from the remote server. - - Implement this if you want to do some special handling with the appcast once it finishes loading. - - \param updater The SUUpdater instance. - \param appcast The appcast that was downloaded from the remote server. - */ -- (void)updater:(SUUpdater *)updater didFinishLoadingAppcast:(SUAppcast *)appcast; - -/*! - Returns the item in the appcast corresponding to the update that should be installed. - - If you're using special logic or extensions in your appcast, - implement this to use your own logic for finding a valid update, if any, - in the given appcast. - - \param appcast The appcast that was downloaded from the remote server. - \param updater The SUUpdater instance. - */ -- (nullable SUAppcastItem *)bestValidUpdateInAppcast:(SUAppcast *)appcast forUpdater:(SUUpdater *)updater; - -/*! - Called when a valid update is found by the update driver. - - \param updater The SUUpdater instance. - \param item The appcast item corresponding to the update that is proposed to be installed. - */ -- (void)updater:(SUUpdater *)updater didFindValidUpdate:(SUAppcastItem *)item; - -/*! - Called when a valid update is not found. - - \param updater The SUUpdater instance. - */ -- (void)updaterDidNotFindUpdate:(SUUpdater *)updater; - -/*! - Called immediately before downloading the specified update. - - \param updater The SUUpdater instance. - \param item The appcast item corresponding to the update that is proposed to be downloaded. - \param request The mutable URL request that will be used to download the update. - */ -- (void)updater:(SUUpdater *)updater willDownloadUpdate:(SUAppcastItem *)item withRequest:(NSMutableURLRequest *)request; - -/*! - Called immediately after succesfull download of the specified update. - - \param updater The SUUpdater instance. - \param item The appcast item corresponding to the update that has been downloaded. - */ -- (void)updater:(SUUpdater *)updater didDownloadUpdate:(SUAppcastItem *)item; - -/*! - Called after the specified update failed to download. - - \param updater The SUUpdater instance. - \param item The appcast item corresponding to the update that failed to download. - \param error The error generated by the failed download. - */ -- (void)updater:(SUUpdater *)updater failedToDownloadUpdate:(SUAppcastItem *)item error:(NSError *)error; - -/*! - Called when the user clicks the cancel button while and update is being downloaded. - - \param updater The SUUpdater instance. - */ -- (void)userDidCancelDownload:(SUUpdater *)updater; - -/*! - Called immediately before extracting the specified downloaded update. - - \param updater The SUUpdater instance. - \param item The appcast item corresponding to the update that is proposed to be extracted. - */ -- (void)updater:(SUUpdater *)updater willExtractUpdate:(SUAppcastItem *)item; - -/*! - Called immediately after extracting the specified downloaded update. - - \param updater The SUUpdater instance. - \param item The appcast item corresponding to the update that has been extracted. - */ -- (void)updater:(SUUpdater *)updater didExtractUpdate:(SUAppcastItem *)item; - -/*! - Called immediately before installing the specified update. - - \param updater The SUUpdater instance. - \param item The appcast item corresponding to the update that is proposed to be installed. - */ -- (void)updater:(SUUpdater *)updater willInstallUpdate:(SUAppcastItem *)item; - -/*! - Returns whether the relaunch should be delayed in order to perform other tasks. - - This is not called if the user didn't relaunch on the previous update, - in that case it will immediately restart. - - \param updater The SUUpdater instance. - \param item The appcast item corresponding to the update that is proposed to be installed. - \param invocation The invocation that must be completed with `[invocation invoke]` before continuing with the relaunch. - - \return \c YES to delay the relaunch until \p invocation is invoked. - */ -- (BOOL)updater:(SUUpdater *)updater shouldPostponeRelaunchForUpdate:(SUAppcastItem *)item untilInvoking:(NSInvocation *)invocation; - -/*! - Returns whether the application should be relaunched at all. - - Some apps \b cannot be relaunched under certain circumstances. - This method can be used to explicitly prevent a relaunch. - - \param updater The SUUpdater instance. - */ -- (BOOL)updaterShouldRelaunchApplication:(SUUpdater *)updater; - -/*! - Called immediately before relaunching. - - \param updater The SUUpdater instance. - */ -- (void)updaterWillRelaunchApplication:(SUUpdater *)updater; - -/*! - Called immediately after relaunching. SUUpdater delegate must be set before applicationDidFinishLaunching: to catch this event. - - \param updater The SUUpdater instance. - */ -- (void)updaterDidRelaunchApplication:(SUUpdater *)updater; - -/*! - Returns an object that compares version numbers to determine their arithmetic relation to each other. - - This method allows you to provide a custom version comparator. - If you don't implement this method or return \c nil, - the standard version comparator will be used. - - \sa SUStandardVersionComparator - - \param updater The SUUpdater instance. - */ -- (nullable id)versionComparatorForUpdater:(SUUpdater *)updater; - -/*! - Returns an object that formats version numbers for display to the user. - - If you don't implement this method or return \c nil, - the standard version formatter will be used. - - \sa SUUpdateAlert - - \param updater The SUUpdater instance. - */ -- (nullable id)versionDisplayerForUpdater:(SUUpdater *)updater; - -/*! - Returns the path which is used to relaunch the client after the update is installed. - - The default is the path of the host bundle. - - \param updater The SUUpdater instance. - */ -- (nullable NSString *)pathToRelaunchForUpdater:(SUUpdater *)updater; - -/*! - Called before an updater shows a modal alert window, - to give the host the opportunity to hide attached windows that may get in the way. - - \param updater The SUUpdater instance. - */ -- (void)updaterWillShowModalAlert:(SUUpdater *)updater; - -/*! - Called after an updater shows a modal alert window, - to give the host the opportunity to hide attached windows that may get in the way. - - \param updater The SUUpdater instance. - */ -- (void)updaterDidShowModalAlert:(SUUpdater *)updater; - -/*! - Called when an update is scheduled to be silently installed on quit. - This is after an update has been automatically downloaded in the background. - (i.e. SUUpdater::automaticallyDownloadsUpdates is YES) - - \param updater The SUUpdater instance. - \param item The appcast item corresponding to the update that is proposed to be installed. - \param invocation Can be used to trigger an immediate silent install and relaunch. - */ -- (void)updater:(SUUpdater *)updater willInstallUpdateOnQuit:(SUAppcastItem *)item immediateInstallationInvocation:(NSInvocation *)invocation; - -/*! - Calls after an update that was scheduled to be silently installed on quit has been canceled. - - \param updater The SUUpdater instance. - \param item The appcast item corresponding to the update that was proposed to be installed. - */ -- (void)updater:(SUUpdater *)updater didCancelInstallUpdateOnQuit:(SUAppcastItem *)item; - -/*! - Called after an update is aborted due to an error. - - \param updater The SUUpdater instance. - \param error The error that caused the abort - */ -- (void)updater:(SUUpdater *)updater didAbortWithError:(NSError *)error; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUVersionComparisonProtocol.h b/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUVersionComparisonProtocol.h deleted file mode 100644 index c654fc4d0..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUVersionComparisonProtocol.h +++ /dev/null @@ -1,37 +0,0 @@ -// -// SUVersionComparisonProtocol.h -// Sparkle -// -// Created by Andy Matuschak on 12/21/07. -// Copyright 2007 Andy Matuschak. All rights reserved. -// - -#ifndef SUVERSIONCOMPARISONPROTOCOL_H -#define SUVERSIONCOMPARISONPROTOCOL_H - -#if __has_feature(modules) -@import Foundation; -#else -#import -#endif -#import "SUExport.h" - -NS_ASSUME_NONNULL_BEGIN - -/*! - Provides version comparison facilities for Sparkle. -*/ -@protocol SUVersionComparison - -/*! - An abstract method to compare two version strings. - - Should return NSOrderedAscending if b > a, NSOrderedDescending if b < a, - and NSOrderedSame if they are equivalent. -*/ -- (NSComparisonResult)compareVersion:(NSString *)versionA toVersion:(NSString *)versionB; // *** MAY BE CALLED ON NON-MAIN THREAD! - -@end - -NS_ASSUME_NONNULL_END -#endif diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUVersionDisplayProtocol.h b/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUVersionDisplayProtocol.h deleted file mode 100644 index 980efb3fe..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/SUVersionDisplayProtocol.h +++ /dev/null @@ -1,29 +0,0 @@ -// -// SUVersionDisplayProtocol.h -// EyeTV -// -// Created by Uli Kusterer on 08.12.09. -// Copyright 2009 Elgato Systems GmbH. All rights reserved. -// - -#if __has_feature(modules) -@import Foundation; -#else -#import -#endif -#import "SUExport.h" - -/*! - Applies special display formatting to version numbers. -*/ -@protocol SUVersionDisplay - -/*! - Formats two version strings. - - Both versions are provided so that important distinguishing information - can be displayed while also leaving out unnecessary/confusing parts. -*/ -- (void)formatVersion:(NSString *_Nonnull*_Nonnull)inOutVersionA andVersion:(NSString *_Nonnull*_Nonnull)inOutVersionB; - -@end diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/Sparkle.h b/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/Sparkle.h deleted file mode 100644 index 5ae2e6a6d..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/Headers/Sparkle.h +++ /dev/null @@ -1,33 +0,0 @@ -// -// Sparkle.h -// Sparkle -// -// Created by Andy Matuschak on 3/16/06. (Modified by CDHW on 23/12/07) -// Copyright 2006 Andy Matuschak. All rights reserved. -// - -#ifndef SPARKLE_H -#define SPARKLE_H - -// This list should include the shared headers. It doesn't matter if some of them aren't shared (unless -// there are name-space collisions) so we can list all of them to start with: - -#import "SUAppcast.h" -#import "SUAppcastItem.h" -#import "SUStandardVersionComparator.h" -#import "SUUpdater.h" -#import "SUUpdaterDelegate.h" -#import "SUVersionComparisonProtocol.h" -#import "SUVersionDisplayProtocol.h" -#import "SUErrors.h" - -#import "SPUDownloader.h" -#import "SPUDownloaderDelegate.h" -#import "SPUDownloaderDeprecated.h" -#import "SPUDownloadData.h" -#import "SPUDownloaderProtocol.h" -#import "SPUDownloaderSession.h" -#import "SPUURLRequest.h" -#import "SUCodeSigningVerifier.h" - -#endif diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Modules/module.modulemap b/Frameworks/Vendor/Sparkle.framework/Versions/A/Modules/module.modulemap deleted file mode 100644 index af3fe6d05..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/Modules/module.modulemap +++ /dev/null @@ -1,6 +0,0 @@ -framework module Sparkle { - umbrella header "Sparkle.h" - - export * - module * { export * } -} diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/PrivateHeaders/SUUnarchiver.h b/Frameworks/Vendor/Sparkle.framework/Versions/A/PrivateHeaders/SUUnarchiver.h deleted file mode 100644 index a52bf5a2d..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/PrivateHeaders/SUUnarchiver.h +++ /dev/null @@ -1,21 +0,0 @@ -// -// SUUnarchiver.h -// Sparkle -// -// Created by Andy Matuschak on 3/16/06. -// Copyright 2006 Andy Matuschak. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@protocol SUUnarchiverProtocol; - -@interface SUUnarchiver : NSObject - -+ (nullable id )unarchiverForPath:(NSString *)path updatingHostBundlePath:(nullable NSString *)hostPath decryptionPassword:(nullable NSString *)decryptionPassword; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Info.plist b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Info.plist deleted file mode 100644 index 7805efaa4..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Info.plist +++ /dev/null @@ -1,54 +0,0 @@ - - - - - BuildMachineOSBuild - 18D42 - CFBundleDevelopmentRegion - English - CFBundleExecutable - Autoupdate - CFBundleIconFile - AppIcon.icns - CFBundleIdentifier - org.sparkle-project.Sparkle.Autoupdate - CFBundleInfoDictionaryVersion - 6.0 - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.21.3 18-g1ff157710 - CFBundleSignature - ???? - CFBundleSupportedPlatforms - - MacOSX - - CFBundleVersion - 1.21.3 - DTCompiler - com.apple.compilers.llvm.clang.1_0 - DTPlatformBuild - 10B61 - DTPlatformVersion - GM - DTSDKBuild - 18B71 - DTSDKName - macosx10.14 - DTXcode - 1010 - DTXcodeBuild - 10B61 - LSBackgroundOnly - 1 - LSMinimumSystemVersion - 10.7 - LSUIElement - 1 - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/MacOS/Autoupdate b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/MacOS/Autoupdate deleted file mode 100755 index ee2732523..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/MacOS/Autoupdate and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/MacOS/fileop b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/MacOS/fileop deleted file mode 100755 index 561ff48c7..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/MacOS/fileop and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/PkgInfo b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/PkgInfo deleted file mode 100644 index bd04210fb..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/PkgInfo +++ /dev/null @@ -1 +0,0 @@ -APPL???? \ No newline at end of file diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/AppIcon.icns b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/AppIcon.icns deleted file mode 100644 index 7f2a571c8..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/AppIcon.icns and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/SUStatus.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/SUStatus.nib deleted file mode 100644 index da18126a3..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/SUStatus.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ar.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ar.lproj/Sparkle.strings deleted file mode 100644 index 4cd92c0dd..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ar.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ca.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ca.lproj/Sparkle.strings deleted file mode 100644 index cc238f685..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ca.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/cs.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/cs.lproj/Sparkle.strings deleted file mode 100644 index c93688a31..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/cs.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/da.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/da.lproj/Sparkle.strings deleted file mode 100644 index 10e3c5a5d..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/da.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/de.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/de.lproj/Sparkle.strings deleted file mode 100644 index 698dc6737..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/de.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/el.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/el.lproj/Sparkle.strings deleted file mode 100644 index deed9efb2..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/el.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/en.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/en.lproj/Sparkle.strings deleted file mode 100644 index 8c38dc674..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/en.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/es.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/es.lproj/Sparkle.strings deleted file mode 100644 index 4f2015f0b..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/es.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/fi.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/fi.lproj/Sparkle.strings deleted file mode 100644 index dab921c62..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/fi.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/fr.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/fr.lproj/Sparkle.strings deleted file mode 100644 index c7a557147..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/fr.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/he.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/he.lproj/Sparkle.strings deleted file mode 100644 index fec4d0d8b..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/he.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/hr.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/hr.lproj/Sparkle.strings deleted file mode 100644 index 2a727d3a3..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/hr.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/hu.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/hu.lproj/Sparkle.strings deleted file mode 100644 index 9cd6bff18..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/hu.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/is.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/is.lproj/Sparkle.strings deleted file mode 100644 index 74ae72802..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/is.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/it.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/it.lproj/Sparkle.strings deleted file mode 100644 index 68b6d366b..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/it.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ja.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ja.lproj/Sparkle.strings deleted file mode 100644 index f5e9c6d11..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ja.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ko.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ko.lproj/Sparkle.strings deleted file mode 100644 index 92c18eeb2..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ko.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/nb.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/nb.lproj/Sparkle.strings deleted file mode 100644 index ec2561b8a..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/nb.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/nl.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/nl.lproj/Sparkle.strings deleted file mode 100644 index 58be0e82b..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/nl.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/pl.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/pl.lproj/Sparkle.strings deleted file mode 100644 index 2b9c46152..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/pl.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/pt_BR.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/pt_BR.lproj/Sparkle.strings deleted file mode 100644 index e55c6fd1b..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/pt_BR.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/pt_PT.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/pt_PT.lproj/Sparkle.strings deleted file mode 100644 index 00df86ff1..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/pt_PT.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ro.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ro.lproj/Sparkle.strings deleted file mode 100644 index 318baa960..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ro.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ru.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ru.lproj/Sparkle.strings deleted file mode 100644 index c33086d89..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ru.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/sk.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/sk.lproj/Sparkle.strings deleted file mode 100644 index a7d2ebce6..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/sk.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/sl.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/sl.lproj/Sparkle.strings deleted file mode 100644 index 1be2a8079..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/sl.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/sv.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/sv.lproj/Sparkle.strings deleted file mode 100644 index 738c9008b..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/sv.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/th.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/th.lproj/Sparkle.strings deleted file mode 100644 index eca257024..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/th.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/tr.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/tr.lproj/Sparkle.strings deleted file mode 100644 index 4def140e5..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/tr.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/uk.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/uk.lproj/Sparkle.strings deleted file mode 100644 index f7eb257b7..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/uk.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/zh_CN.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/zh_CN.lproj/Sparkle.strings deleted file mode 100644 index 214331cd1..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/zh_CN.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/zh_TW.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/zh_TW.lproj/Sparkle.strings deleted file mode 100644 index 533e20862..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/zh_TW.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/DarkAqua.css b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/DarkAqua.css deleted file mode 100644 index a41e0f285..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/DarkAqua.css +++ /dev/null @@ -1,9 +0,0 @@ -html { - color: #FFFFFFD8; -} -:link { - color: #419CFF; -} -:link:active { - color: #FF1919; -} diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Info.plist b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Info.plist deleted file mode 100644 index 3fdc42fff..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/Info.plist +++ /dev/null @@ -1,44 +0,0 @@ - - - - - BuildMachineOSBuild - 18D42 - CFBundleDevelopmentRegion - en - CFBundleExecutable - Sparkle - CFBundleIdentifier - org.sparkle-project.Sparkle - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - Sparkle - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.21.3 - CFBundleSignature - ???? - CFBundleSupportedPlatforms - - MacOSX - - CFBundleVersion - 1.21.3 - DTCompiler - com.apple.compilers.llvm.clang.1_0 - DTPlatformBuild - 10B61 - DTPlatformVersion - GM - DTSDKBuild - 18B71 - DTSDKName - macosx10.14 - DTXcode - 1010 - DTXcodeBuild - 10B61 - - diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/SUModelTranslation.plist b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/SUModelTranslation.plist deleted file mode 100644 index 1f75b248c..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/SUModelTranslation.plist +++ /dev/null @@ -1,314 +0,0 @@ - - - - - ADP2,1 - Developer Transition Kit - iMac1,1 - iMac G3 (Rev A-D) - iMac4,1 - iMac (Core Duo) - iMac4,2 - iMac for Education (17 inch, Core Duo) - iMac5,1 - iMac (Core 2 Duo, 17 or 20 inch, SuperDrive) - iMac5,2 - iMac (Core 2 Duo, 17 inch, Combo Drive) - iMac6,1 - iMac (Core 2 Duo, 24 inch, SuperDrive) - iMac7,1 - iMac Intel Core 2 Duo (aluminum enclosure) - iMac8,1 - iMac (Core 2 Duo, 20 or 24 inch, Early 2008 ) - iMac9,1 - iMac (Core 2 Duo, 20 or 24 inch, Early or Mid 2009 ) - iMac10,1 - iMac (Core 2 Duo, 21.5 or 27 inch, Late 2009 ) - iMac11,1 - iMac (Core i5 or i7, 27 inch Late 2009) - iMac11,2 - 21.5" iMac (mid 2010) - iMac11,3 - iMac (Core i5 or i7, 27 inch Mid 2010) - iMac12,1 - iMac (Core i3 or i5 or i7, 21.5 inch Mid 2010 or Late 2011) - iMac12,2 - iMac (Core i5 or i7, 27 inch Mid 2011) - iMac13,1 - iMac (Core i3 or i5 or i7, 21.5 inch Late 2012 or Early 2013) - iMac13,2 - iMac (Core i5 or i7, 27 inch Late 2012) - iMac14,1 - iMac (Core i5, 21.5 inch Late 2013) - iMac14,2 - iMac (Core i5 or i7, 27 inch Late 2013) - iMac14,3 - iMac (Core i5 or i7, 21.5 inch Late 2013) - iMac14,4 - iMac (Core i5, 21.5 inch Mid 2014) - iMac15,1 - iMac (Retina 5K Core i5 or i7, 27 inch Late 2014 or Mid 2015) - iMac16,1 - iMac (Core i5, 21,5 inch Late 2015) - iMac16,2 - iMac (Retina 4K Core i5 or i7, 21.5 inch Late 2015) - iMac17,1 - iMac (Retina 5K Core i5 or i7, 27 inch Late 2015) - MacBook1,1 - MacBook (Core Duo) - MacBook2,1 - MacBook (Core 2 Duo) - MacBook4,1 - MacBook (Core 2 Duo Feb 2008) - MacBook5,1 - MacBook (Core 2 Duo, Late 2008, Unibody) - MacBook5,2 - MacBook (Core 2 Duo, Early 2009, White) - MacBook6,1 - MacBook (Core 2 Duo, Late 2009, Unibody) - MacBook7,1 - MacBook (Core 2 Duo, Mid 2010, White) - MacBook8,1 - MacBook (Core M, 12 inch, Early 2015) - MacBookAir1,1 - MacBook Air (Core 2 Duo, 13 inch, Early 2008) - MacBookAir2,1 - MacBook Air (Core 2 Duo, 13 inch, Mid 2009) - MacBookAir3,1 - MacBook Air (Core 2 Duo, 11 inch, Late 2010) - MacBookAir3,2 - MacBook Air (Core 2 Duo, 13 inch, Late 2010) - MacBookAir4,1 - MacBook Air (Core i5 or i7, 11 inch, Mid 2011) - MacBookAir4,2 - MacBook Air (Core i5 or i7, 13 inch, Mid 2011) - MacBookAir5,1 - MacBook Air (Core i5 or i7, 11 inch, Mid 2012) - MacBookAir5,2 - MacBook Air (Core i5 or i7, 13 inch, Mid 2012) - MacBookAir6,1 - MacBook Air (Core i5 or i7, 11 inch, Mid 2013 or Early 2014) - MacBookAir6,2 - MacBook Air (Core i5 or i7, 13 inch, Mid 2013 or Early 2014) - MacBookAir7,1 - MacBook Air (Core i5 or i7, 11 inch, Early 2015) - MacBookAir7,2 - MacBook Air (Core i5 or i7, 13 inch, Early 2015) - MacBookPro1,1 - MacBook Pro Core Duo (15-inch) - MacBookPro1,2 - MacBook Pro Core Duo (17-inch) - MacBookPro2,1 - MacBook Pro Core 2 Duo (17-inch) - MacBookPro2,2 - MacBook Pro Core 2 Duo (15-inch) - MacBookPro3,1 - MacBook Pro Core 2 Duo (15-inch LED, Core 2 Duo) - MacBookPro3,2 - MacBook Pro Core 2 Duo (17-inch HD, Core 2 Duo) - MacBookPro4,1 - MacBook Pro (Core 2 Duo Feb 2008) - MacBookPro5,1 - MacBook Pro Intel Core 2 Duo (aluminum unibody) - MacBookPro5,2 - MacBook Pro Intel Core 2 Duo (aluminum unibody) - MacBookPro5,3 - MacBook Pro Intel Core 2 Duo (aluminum unibody) - MacBookPro5,4 - MacBook Pro Intel Core 2 Duo (aluminum unibody) - MacBookPro5,5 - MacBook Pro Intel Core 2 Duo (aluminum unibody) - MacBookPro6,1 - MacBook Pro Intel Core i5, Intel Core i7 (mid 2010) - MacBookPro6,2 - MacBook Pro Intel Core i5, Intel Core i7 (mid 2010) - MacBookPro7,1 - MacBook Pro Intel Core 2 Duo (mid 2010) - MacBookPro8,1 - MacBook Pro Intel Core i5, Intel Core i7, 13" (early 2011) - MacBookPro8,2 - MacBook Pro Intel Core i7, 15" (early 2011) - MacBookPro8,3 - MacBook Pro Intel Core i7, 17" (early 2011) - MacBookPro9,1 - MacBook Pro (15-inch, Mid 2012) - MacBookPro9,2 - MacBook Pro (13-inch, Mid 2012) - MacBookPro10,1 - MacBook Pro (Retina, Mid 2012) - MacBookPro10,2 - MacBook Pro (Retina, 13-inch, Late 2012) - MacBookPro11,1 - MacBook Pro (Retina, 13-inch, Late 2013) - MacBookPro11,2 - MacBook Pro (Retina, 15-inch, Late 2013) - MacBookPro11,3 - MacBook Pro (Retina, 15-inch, Late 2013) - MacbookPro11,4 - MacBook Pro (Retina, 15-inch, Mid 2015) - MacbookPro11,5 - MacBook Pro (Retina, 15-inch, Mid 2015) - MacbookPro12,1  - MacBook Pro (Retina, 13-inch, Early 2015) - Macmini1,1 - Mac Mini (Core Solo/Duo) - Macmini2,1 - Mac mini Intel Core - Macmini3,1 - Mac mini Intel Core - Macmini4,1 - Mac mini Intel Core (Mid 2010) - Macmini5,1 - Mac mini (Core i5, Mid 2011) - Macmini5,2 - Mac mini (Core i5 or Core i7, Mid 2011) - Macmini5,3 - Mac mini (Core i7, Server, Mid 2011) - Macmini6,1 - Mac mini (Core i5, Late 2012) - Macmini6,2 - Mac mini (Core i7, Normal or Server, Late 2012) - Macmini7,1 - Mac mini (Core i5 or Core i7, Late 2014) - MacPro1,1,Quad - Mac Pro - MacPro1,1 - Mac Pro (four-core) - MacPro2,1 - Mac Pro (eight-core) - MacPro3,1 - Mac Pro (January 2008 4- or 8- core "Harpertown") - MacPro4,1 - Mac Pro (March 2009) - MacPro5,1 - Mac Pro (2010 or 2012) - MacPro6,1 - Mac Pro (Late 2013) - PowerBook1,1 - PowerBook G3 - PowerBook2,1 - iBook G3 - PowerBook2,2 - iBook G3 (FireWire) - PowerBook2,3 - iBook G3 - PowerBook2,4 - iBook G3 - PowerBook3,1 - PowerBook G3 (FireWire) - PowerBook3,2 - PowerBook G4 - PowerBook3,3 - PowerBook G4 (Gigabit Ethernet) - PowerBook3,4 - PowerBook G4 (DVI) - PowerBook3,5 - PowerBook G4 (1GHz / 867MHz) - PowerBook4,1 - iBook G3 (Dual USB, Late 2001) - PowerBook4,2 - iBook G3 (16MB VRAM) - PowerBook4,3 - iBook G3 Opaque 16MB VRAM, 32MB VRAM, Early 2003) - PowerBook5,1 - PowerBook G4 (17 inch) - PowerBook5,2 - PowerBook G4 (15 inch FW 800) - PowerBook5,3 - PowerBook G4 (17-inch 1.33GHz) - PowerBook5,4 - PowerBook G4 (15 inch 1.5/1.33GHz) - PowerBook5,5 - PowerBook G4 (17-inch 1.5GHz) - PowerBook5,6 - PowerBook G4 (15 inch 1.67GHz/1.5GHz) - PowerBook5,7 - PowerBook G4 (17-inch 1.67GHz) - PowerBook5,8 - PowerBook G4 (Double layer SD, 15 inch) - PowerBook5,9 - PowerBook G4 (Double layer SD, 17 inch) - PowerBook6,1 - PowerBook G4 (12 inch) - PowerBook6,2 - PowerBook G4 (12 inch, DVI) - PowerBook6,3 - iBook G4 - PowerBook6,4 - PowerBook G4 (12 inch 1.33GHz) - PowerBook6,5 - iBook G4 (Early-Late 2004) - PowerBook6,7 - iBook G4 (Mid 2005) - PowerBook6,8 - PowerBook G4 (12 inch 1.5GHz) - PowerMac1,1 - Power Macintosh G3 (Blue & White) - PowerMac1,2 - Power Macintosh G4 (PCI Graphics) - PowerMac2,1 - iMac G3 (Slot-loading CD-ROM) - PowerMac2,2 - iMac G3 (Summer 2000) - PowerMac3,1 - Power Macintosh G4 (AGP Graphics) - PowerMac3,2 - Power Macintosh G4 (AGP Graphics) - PowerMac3,3 - Power Macintosh G4 (Gigabit Ethernet) - PowerMac3,4 - Power Macintosh G4 (Digital Audio) - PowerMac3,5 - Power Macintosh G4 (Quick Silver) - PowerMac3,6 - Power Macintosh G4 (Mirrored Drive Door) - PowerMac4,1 - iMac G3 (Early/Summer 2001) - PowerMac4,2 - iMac G4 (Flat Panel) - PowerMac4,4 - eMac - PowerMac4,5 - iMac G4 (17-inch Flat Panel) - PowerMac5,1 - Power Macintosh G4 Cube - PowerMac5,2 - Power Mac G4 Cube - PowerMac6,1 - iMac G4 (USB 2.0) - PowerMac6,3 - iMac G4 (20-inch Flat Panel) - PowerMac6,4 - eMac (USB 2.0, 2005) - PowerMac7,2 - Power Macintosh G5 - PowerMac7,3 - Power Macintosh G5 - PowerMac8,1 - iMac G5 - PowerMac8,2 - iMac G5 (Ambient Light Sensor) - PowerMac9,1 - Power Macintosh G5 (Late 2005) - PowerMac10,1 - Mac Mini G4 - PowerMac10,2 - Mac Mini (Late 2005) - PowerMac11,2 - Power Macintosh G5 (Late 2005) - PowerMac12,1 - iMac G5 (iSight) - RackMac1,1 - Xserve G4 - RackMac1,2 - Xserve G4 (slot-loading, cluster node) - RackMac3,1 - Xserve G5 - Xserve1,1 - Xserve (Intel Xeon) - Xserve2,1 - Xserve (January 2008 quad-core) - Xserve3,1 - Xserve (early 2009) - - diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/SUStatus.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/SUStatus.nib deleted file mode 100644 index da18126a3..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/SUStatus.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ar.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ar.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index 29127f1a4..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ar.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ar.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ar.lproj/SUUpdateAlert.nib deleted file mode 100644 index c619e69f3..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ar.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ar.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ar.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index 57735179e..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ar.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ar.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ar.lproj/Sparkle.strings deleted file mode 100644 index 4cd92c0dd..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ar.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ca.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ca.lproj/Sparkle.strings deleted file mode 100644 index cc238f685..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ca.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/cs.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/cs.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index b3d57f661..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/cs.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/cs.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/cs.lproj/SUUpdateAlert.nib deleted file mode 100644 index 30a49ec7c..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/cs.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/cs.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/cs.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index f4c853251..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/cs.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/cs.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/cs.lproj/Sparkle.strings deleted file mode 100644 index c93688a31..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/cs.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/da.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/da.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index ef46ccaaf..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/da.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/da.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/da.lproj/SUUpdateAlert.nib deleted file mode 100644 index 778a46846..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/da.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/da.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/da.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index e43590456..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/da.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/da.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/da.lproj/Sparkle.strings deleted file mode 100644 index 10e3c5a5d..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/da.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/de.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/de.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index 7540fa1a5..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/de.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdateAlert.nib deleted file mode 100644 index fed8b2565..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index 6ecec4549..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/de.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/de.lproj/Sparkle.strings deleted file mode 100644 index 698dc6737..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/de.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/el.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/el.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index 6e803a702..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/el.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/el.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/el.lproj/SUUpdateAlert.nib deleted file mode 100644 index 8ca181cd0..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/el.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/el.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/el.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index 353156a68..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/el.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/el.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/el.lproj/Sparkle.strings deleted file mode 100644 index deed9efb2..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/el.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index 15f157f4e..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib deleted file mode 100644 index 29d60da43..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index 72f172e6c..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/en.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/en.lproj/Sparkle.strings deleted file mode 100644 index 8c38dc674..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/en.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index 9b3f7238a..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib deleted file mode 100644 index 265bacc9f..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index 87f4e632f..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/es.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/es.lproj/Sparkle.strings deleted file mode 100644 index 4f2015f0b..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/es.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fi.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fi.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index a882db0da..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fi.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fi.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fi.lproj/SUUpdateAlert.nib deleted file mode 100644 index c7a3311a0..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fi.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fi.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fi.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index 60cd95449..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fi.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fi.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fi.lproj/Sparkle.strings deleted file mode 100644 index dab921c62..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fi.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fr.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fr.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index 5112924b2..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fr.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdateAlert.nib deleted file mode 100644 index e24e3fd6c..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index 88598ebfb..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fr.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fr.lproj/Sparkle.strings deleted file mode 100644 index c7a557147..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fr.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fr_CA.lproj b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fr_CA.lproj deleted file mode 120000 index f9834a395..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/fr_CA.lproj +++ /dev/null @@ -1 +0,0 @@ -fr.lproj \ No newline at end of file diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/he.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/he.lproj/Sparkle.strings deleted file mode 100644 index fec4d0d8b..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/he.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/hr.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/hr.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index 75761ac7b..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/hr.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/hr.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/hr.lproj/SUUpdateAlert.nib deleted file mode 100644 index 867b7c0b2..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/hr.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/hr.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/hr.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index f1090d7e1..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/hr.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/hr.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/hr.lproj/Sparkle.strings deleted file mode 100644 index 2a727d3a3..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/hr.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/hu.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/hu.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index 4d7e8a942..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/hu.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/hu.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/hu.lproj/SUUpdateAlert.nib deleted file mode 100644 index 40571fdd0..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/hu.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/hu.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/hu.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index ff2e24f3b..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/hu.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/hu.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/hu.lproj/Sparkle.strings deleted file mode 100644 index 9cd6bff18..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/hu.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/is.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/is.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index e27ca6db3..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/is.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/is.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/is.lproj/SUUpdateAlert.nib deleted file mode 100644 index 3e2d8efc0..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/is.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/is.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/is.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index 0dceed4fd..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/is.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/is.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/is.lproj/Sparkle.strings deleted file mode 100644 index 74ae72802..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/is.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index c0522dcca..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib deleted file mode 100644 index 5013418a7..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index cc828213f..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/it.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/it.lproj/Sparkle.strings deleted file mode 100644 index 68b6d366b..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/it.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ja.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ja.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index 27f5abfa6..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ja.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ja.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ja.lproj/SUUpdateAlert.nib deleted file mode 100644 index 86798fe29..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ja.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ja.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ja.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index 57fcc83a7..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ja.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ja.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ja.lproj/Sparkle.strings deleted file mode 100644 index f5e9c6d11..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ja.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ko.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ko.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index 977dc0a70..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ko.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ko.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ko.lproj/SUUpdateAlert.nib deleted file mode 100644 index d52bd5d9a..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ko.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ko.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ko.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index 7880aef60..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ko.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ko.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ko.lproj/Sparkle.strings deleted file mode 100644 index 92c18eeb2..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ko.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/nb.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/nb.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index fd5b85124..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/nb.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/nb.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/nb.lproj/SUUpdateAlert.nib deleted file mode 100644 index 6b05c1f73..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/nb.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/nb.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/nb.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index b1474d1f0..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/nb.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/nb.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/nb.lproj/Sparkle.strings deleted file mode 100644 index ec2561b8a..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/nb.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/nl.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/nl.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index 19e19ff7c..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/nl.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdateAlert.nib deleted file mode 100644 index 13a6ea648..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index 690b23a02..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/nl.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/nl.lproj/Sparkle.strings deleted file mode 100644 index 58be0e82b..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/nl.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pl.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pl.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index 3de644f16..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pl.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pl.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pl.lproj/SUUpdateAlert.nib deleted file mode 100644 index b05aea7ad..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pl.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pl.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pl.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index fc42fa21a..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pl.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pl.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pl.lproj/Sparkle.strings deleted file mode 100644 index 2b9c46152..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pl.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt.lproj b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt.lproj deleted file mode 120000 index 3c1c9f6dc..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt.lproj +++ /dev/null @@ -1 +0,0 @@ -pt_BR.lproj \ No newline at end of file diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt_BR.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt_BR.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index c43d99661..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt_BR.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt_BR.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt_BR.lproj/SUUpdateAlert.nib deleted file mode 100644 index bf5e54da8..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt_BR.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt_BR.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt_BR.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index 0773eee71..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt_BR.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt_BR.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt_BR.lproj/Sparkle.strings deleted file mode 100644 index e55c6fd1b..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt_BR.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt_PT.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt_PT.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index f787d8c8d..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt_PT.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt_PT.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt_PT.lproj/SUUpdateAlert.nib deleted file mode 100644 index a0ea252e5..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt_PT.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt_PT.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt_PT.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index 8df1dbba4..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt_PT.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt_PT.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt_PT.lproj/Sparkle.strings deleted file mode 100644 index 00df86ff1..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/pt_PT.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ro.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ro.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index b4068e824..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ro.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ro.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ro.lproj/SUUpdateAlert.nib deleted file mode 100644 index 998781b59..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ro.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ro.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ro.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index 011aaf5a1..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ro.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ro.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ro.lproj/Sparkle.strings deleted file mode 100644 index 318baa960..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ro.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ru.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ru.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index 09fb08882..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ru.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdateAlert.nib deleted file mode 100644 index 423b2ce30..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index 19e13ec5c..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ru.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ru.lproj/Sparkle.strings deleted file mode 100644 index c33086d89..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/ru.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sk.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sk.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index cf9cb702f..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sk.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sk.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sk.lproj/SUUpdateAlert.nib deleted file mode 100644 index 0413025e0..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sk.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sk.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sk.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index ea04cc1d8..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sk.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sk.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sk.lproj/Sparkle.strings deleted file mode 100644 index a7d2ebce6..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sk.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sl.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sl.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index ac4ded9c4..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sl.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sl.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sl.lproj/SUUpdateAlert.nib deleted file mode 100644 index fc1c75723..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sl.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sl.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sl.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index 913fb3b42..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sl.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sl.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sl.lproj/Sparkle.strings deleted file mode 100644 index 1be2a8079..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sl.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sv.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sv.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index 5c5774cd0..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sv.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdateAlert.nib deleted file mode 100644 index bff9b7fd5..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index 00410e33c..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sv.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sv.lproj/Sparkle.strings deleted file mode 100644 index 738c9008b..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/sv.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/th.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/th.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index 9126de587..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/th.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/th.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/th.lproj/SUUpdateAlert.nib deleted file mode 100644 index 867b481a1..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/th.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/th.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/th.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index 25e48c879..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/th.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/th.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/th.lproj/Sparkle.strings deleted file mode 100644 index eca257024..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/th.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/tr.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/tr.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index 6526d27c1..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/tr.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/tr.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/tr.lproj/SUUpdateAlert.nib deleted file mode 100644 index 4e7b7485c..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/tr.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/tr.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/tr.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index 21bed5f8b..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/tr.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/tr.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/tr.lproj/Sparkle.strings deleted file mode 100644 index 4def140e5..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/tr.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/uk.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/uk.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index 5d2dda5d6..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/uk.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/uk.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/uk.lproj/SUUpdateAlert.nib deleted file mode 100644 index 94c9dc790..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/uk.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/uk.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/uk.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index ac62cbf7d..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/uk.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/uk.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/uk.lproj/Sparkle.strings deleted file mode 100644 index f7eb257b7..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/uk.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/zh_CN.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/zh_CN.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index 789fbdbc7..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/zh_CN.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/zh_CN.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/zh_CN.lproj/SUUpdateAlert.nib deleted file mode 100644 index 9ea3f4d19..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/zh_CN.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/zh_CN.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/zh_CN.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index aec87f298..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/zh_CN.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/zh_CN.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/zh_CN.lproj/Sparkle.strings deleted file mode 100644 index 214331cd1..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/zh_CN.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/zh_TW.lproj/SUAutomaticUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/zh_TW.lproj/SUAutomaticUpdateAlert.nib deleted file mode 100644 index c5f6ea824..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/zh_TW.lproj/SUAutomaticUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/zh_TW.lproj/SUUpdateAlert.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/zh_TW.lproj/SUUpdateAlert.nib deleted file mode 100644 index 1b4b140c9..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/zh_TW.lproj/SUUpdateAlert.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/zh_TW.lproj/SUUpdatePermissionPrompt.nib b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/zh_TW.lproj/SUUpdatePermissionPrompt.nib deleted file mode 100644 index 1a642e884..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/zh_TW.lproj/SUUpdatePermissionPrompt.nib and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/zh_TW.lproj/Sparkle.strings b/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/zh_TW.lproj/Sparkle.strings deleted file mode 100644 index 533e20862..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Resources/zh_TW.lproj/Sparkle.strings and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/A/Sparkle b/Frameworks/Vendor/Sparkle.framework/Versions/A/Sparkle deleted file mode 100755 index d26bf77f6..000000000 Binary files a/Frameworks/Vendor/Sparkle.framework/Versions/A/Sparkle and /dev/null differ diff --git a/Frameworks/Vendor/Sparkle.framework/Versions/Current b/Frameworks/Vendor/Sparkle.framework/Versions/Current deleted file mode 120000 index 8c7e5a667..000000000 --- a/Frameworks/Vendor/Sparkle.framework/Versions/Current +++ /dev/null @@ -1 +0,0 @@ -A \ No newline at end of file diff --git a/Mac/AppDelegate.swift b/Mac/AppDelegate.swift index e36d30a8b..52eedd75e 100644 --- a/Mac/AppDelegate.swift +++ b/Mac/AppDelegate.swift @@ -5,6 +5,7 @@ // Created by Brent Simmons on 7/11/15. // Copyright © 2015 Ranchero Software, LLC. All rights reserved. // + import AppKit import UserNotifications import Articles @@ -12,14 +13,21 @@ import RSTree import RSWeb import Account import RSCore -#if TEST + +// If we're not going to import Sparkle, provide dummy protocols to make it easy +// for AppDelegate to comply +#if MAC_APP_STORE || TEST +protocol SPUStandardUserDriverDelegate {} +protocol SPUUpdaterDelegate {} +#else import Sparkle #endif var appDelegate: AppDelegate! @NSApplicationMain -class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, UNUserNotificationCenterDelegate, UnreadCountProvider { +class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, UNUserNotificationCenterDelegate, UnreadCountProvider, SPUStandardUserDriverDelegate, SPUUpdaterDelegate +{ var userNotificationManager: UserNotificationManager! var faviconDownloader: FaviconDownloader! @@ -62,7 +70,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, private var addFeedController: AddFeedController? private var addFolderWindowController: AddFolderWindowController? private var importOPMLController: ImportOPMLWindowController? - private var importNNW3Controller: ImportNNW3WindowController? private var exportOPMLController: ExportOPMLWindowController? private var keyboardShortcutsWindowController: WebViewWindowController? private var inspectorWindowController: InspectorWindowController? @@ -70,6 +77,9 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, private let log = Log() private let appNewsURLString = "https://nnw.ranchero.com/feed.json" private let appMovementMonitor = RSAppMovementMonitor() + #if !MAC_APP_STORE && !TEST + private var softwareUpdater: SPUUpdater! + #endif override init() { NSWindow.allowsAutomaticWindowTabbing = false @@ -114,18 +124,27 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, } // MARK: - NSApplicationDelegate + func applicationWillFinishLaunching(_ notification: Notification) { installAppleEventHandlers() - #if TEST - // Don't prompt for updates while running automated tests - SUUpdater.shared()?.automaticallyChecksForUpdates = false - #endif } func applicationDidFinishLaunching(_ note: Notification) { - #if MAC_APP_STORE + #if MAC_APP_STORE || TEST checkForUpdatesMenuItem.isHidden = true + #else + // Initialize Sparkle... + let hostBundle = Bundle.main + let updateDriver = SPUStandardUserDriver(hostBundle: hostBundle, delegate: self) + self.softwareUpdater = SPUUpdater(hostBundle: hostBundle, applicationBundle: hostBundle, userDriver: updateDriver, delegate: self) + + do { + try self.softwareUpdater.start() + } + catch { + NSLog("Failed to start software updater with error: \(error)") + } #endif appName = (Bundle.main.infoDictionary!["CFBundleExecutable"]! as! String) @@ -136,9 +155,14 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, logDebugMessage("Is first run.") } let localAccount = AccountManager.shared.defaultAccount - NNW3FeedsImporter.importIfNeeded(isFirstRun, account: localAccount) - DefaultFeedsImporter.importIfNeeded(isFirstRun, account: localAccount) - + + if isFirstRun && !AccountManager.shared.anyAccountHasAtLeastOneFeed() { + // Import feeds. Either old NNW 3 feeds or the default feeds. + if !NNW3ImportController.importSubscriptionsIfFileExists(account: localAccount) { + DefaultFeedsImporter.importDefaultFeeds(account: localAccount) + } + } + let tempDirectory = NSTemporaryDirectory() let bundleIdentifier = (Bundle.main.infoDictionary!["CFBundleIdentifier"]! as! String) let cacheFolder = (tempDirectory as NSString).appendingPathComponent(bundleIdentifier) @@ -249,7 +273,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, func applicationDidResignActive(_ notification: Notification) { - TimelineStringFormatter.emptyCaches() + ArticleStringFormatter.emptyCaches() saveState() } @@ -452,9 +476,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, if mainWindowController!.isDisplayingSheet { return } - - importNNW3Controller = ImportNNW3WindowController() - importNNW3Controller?.runSheetOnWindow(mainWindowController!.window!) + NNW3ImportController.askUserToImportNNW3Subscriptions(window: mainWindowController!.window!) } @IBAction func exportOPML(_ sender: Any?) { @@ -567,7 +589,13 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, @IBAction func groupByFeedToggled(_ sender: NSMenuItem) { AppDefaults.timelineGroupByFeed.toggle() } - + + @IBAction func checkForUpdates(_ sender: Any?) { + #if !MAC_APP_STORE && !TEST + self.softwareUpdater.checkForUpdates() + #endif + } + } // MARK: - Debug Menu @@ -645,4 +673,4 @@ extension AppDelegate : ScriptingAppDelegate { internal var scriptingSelectedArticles: [Article] { return self.scriptingMainWindowController?.scriptingSelectedArticles ?? [] } -} \ No newline at end of file +} diff --git a/Mac/Base.lproj/Main.storyboard b/Mac/Base.lproj/Main.storyboard index 3e56dfe39..ba4a9a4de 100644 --- a/Mac/Base.lproj/Main.storyboard +++ b/Mac/Base.lproj/Main.storyboard @@ -30,7 +30,7 @@ - + @@ -92,7 +92,7 @@ - + @@ -623,7 +623,6 @@ - diff --git a/Mac/Base.lproj/Preferences.storyboard b/Mac/Base.lproj/Preferences.storyboard index 46d049133..6b2ac07d5 100644 --- a/Mac/Base.lproj/Preferences.storyboard +++ b/Mac/Base.lproj/Preferences.storyboard @@ -234,17 +234,7 @@ - - - - - - - - - - - + @@ -293,7 +283,7 @@ - + @@ -382,8 +372,8 @@ - + diff --git a/Mac/MainWindow/Detail/DetailWebViewController.swift b/Mac/MainWindow/Detail/DetailWebViewController.swift index cdcd744fd..9f2c08b12 100644 --- a/Mac/MainWindow/Detail/DetailWebViewController.swift +++ b/Mac/MainWindow/Detail/DetailWebViewController.swift @@ -205,7 +205,10 @@ private extension DetailWebViewController { } func fetchScrollInfo(_ callback: @escaping (ScrollInfo?) -> Void) { - let javascriptString = "var x = {contentHeight: document.body.scrollHeight, offsetY: document.body.scrollTop}; x" + var javascriptString = "var x = {contentHeight: document.body.scrollHeight, offsetY: document.body.scrollTop}; x" + if #available(macOS 10.15, *) { + javascriptString = "var x = {contentHeight: document.body.scrollHeight, offsetY: window.pageYOffset}; x" + } webView.evaluateJavaScript(javascriptString) { (info, error) in guard let info = info as? [String: Any] else { diff --git a/Mac/MainWindow/NNW3/ImportNNW3Sheet.xib b/Mac/MainWindow/NNW3/ImportNNW3Sheet.xib deleted file mode 100644 index 522ead006..000000000 --- a/Mac/MainWindow/NNW3/ImportNNW3Sheet.xib +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Mac/MainWindow/NNW3/ImportNNW3WindowController.swift b/Mac/MainWindow/NNW3/ImportNNW3WindowController.swift deleted file mode 100644 index 3488ecb03..000000000 --- a/Mac/MainWindow/NNW3/ImportNNW3WindowController.swift +++ /dev/null @@ -1,110 +0,0 @@ -// -// ImportNNW3WindowController.swift -// NetNewsWire -// -// Created by Maurice Parker on 10/14/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import AppKit -import Account - -class ImportNNW3WindowController: NSWindowController { - - @IBOutlet weak var accountPopUpButton: NSPopUpButton! - private weak var hostWindow: NSWindow? - - convenience init() { - self.init(windowNibName: NSNib.Name("ImportNNW3Sheet")) - } - - override func windowDidLoad() { - accountPopUpButton.removeAllItems() - - let menu = NSMenu() - accountPopUpButton.menu = menu - - for oneAccount in AccountManager.shared.sortedActiveAccounts { - - let oneMenuItem = NSMenuItem() - oneMenuItem.title = oneAccount.nameForDisplay - oneMenuItem.representedObject = oneAccount - menu.addItem(oneMenuItem) - - if oneAccount.accountID == AppDefaults.importOPMLAccountID { - accountPopUpButton.select(oneMenuItem) - } - - } - } - - // MARK: API - - func runSheetOnWindow(_ hostWindow: NSWindow) { - - self.hostWindow = hostWindow - - if AccountManager.shared.activeAccounts.count == 1 { - let account = AccountManager.shared.activeAccounts.first! - importNNW3(account: account) - } else { - hostWindow.beginSheet(window!) - } - - } - - // MARK: Actions - - @IBAction func cancel(_ sender: Any) { - hostWindow!.endSheet(window!, returnCode: NSApplication.ModalResponse.cancel) - } - - @IBAction func importNNW3(_ sender: Any) { - - guard let menuItem = accountPopUpButton.selectedItem else { - return - } - - let account = menuItem.representedObject as! Account - AppDefaults.importOPMLAccountID = account.accountID - hostWindow!.endSheet(window!, returnCode: NSApplication.ModalResponse.OK) - importNNW3(account: account) - - } - - func importNNW3(account: Account) { - - let panel = NSOpenPanel() - panel.canDownloadUbiquitousContents = true - panel.canResolveUbiquitousConflicts = true - panel.canChooseFiles = true - panel.allowsMultipleSelection = false - panel.canChooseDirectories = false - panel.resolvesAliases = true - panel.directoryURL = URL(fileURLWithPath: NNW3PlistConverter.defaultFilePath) - panel.allowedFileTypes = ["plist"] - panel.allowsOtherFileTypes = false - - panel.beginSheetModal(for: hostWindow!) { modalResult in - if modalResult == NSApplication.ModalResponse.OK, let url = panel.url { - - guard let opmlURL = NNW3PlistConverter.convertToOPML(url: url) else { - return - } - - account.importOPML(opmlURL) { result in - try? FileManager.default.removeItem(at: opmlURL) - switch result { - case .success: - break - case .failure(let error): - NSApplication.shared.presentError(error) - } - } - - } - } - - } - -} diff --git a/Mac/MainWindow/NNW3/NNW3Document.swift b/Mac/MainWindow/NNW3/NNW3Document.swift index d5738631f..536f5500d 100644 --- a/Mac/MainWindow/NNW3/NNW3Document.swift +++ b/Mac/MainWindow/NNW3/NNW3Document.swift @@ -7,47 +7,138 @@ // import Foundation +import RSCore -class NNW3Document: NNW3Entry { - - init(plist: [[String: Any]]) { - super.init(title: "NNW3") - - for child in plist { - if child["isContainer"] as? Bool ?? false { - entries.append(NNW3Entry(plist: child, parent: self)) - } else { - entries.append(NNW3Feed(plist: child, parent: self)) - } - } - +struct NNW3Document { + + private let children: [OPMLRepresentable]? + + private init(plist: [[String: AnyObject]]) { + self.children = NNW3Folder.itemsWithPlist(plist: plist) } - - override func makeXML(indentLevel: Int) -> String { - + + init?(subscriptionsPlistURL url: URL) { + guard let data = try? Data(contentsOf: url) else { + return nil + } + guard let plist = try? PropertyListSerialization.propertyList(from: data, options: [], format: nil) as? [[String: AnyObject]] else { + return nil + } + self.init(plist: plist) + } +} + +// MARK: OPMLRepresentable + +extension NNW3Document: OPMLRepresentable { + + func OPMLString(indentLevel: Int, strictConformance: Bool) -> String { var s = """ - \(title ?? "") + NetNewsWire 3 Subscriptions - + """ - - for entry in entries { - s += entry.makeXML(indentLevel: indentLevel + 1) + + if let children = children { + for child in children { + s += child.OPMLString(indentLevel: indentLevel + 1, strictConformance: true) + } } s += """ - - - """ - + + + """ + return s - } - } + +// MARK: - NNW3Folder + +private struct NNW3Folder { + + private let title: String? + private let children: [OPMLRepresentable]? + + init(plist: [String: Any]) { + self.title = plist["name"] as? String + guard let childrenArray = plist["childrenArray"] as? [[String: Any]] else { + self.children = nil + return + } + self.children = NNW3Folder.itemsWithPlist(plist: childrenArray) + } + + static func itemsWithPlist(plist: [[String: Any]]) -> [OPMLRepresentable]? { + // Also used by NNW3Document. + var items = [OPMLRepresentable]() + for child in plist { + if child["isContainer"] as? Bool ?? false { + items.append(NNW3Folder(plist: child)) + } else { + items.append(NNW3Feed(plist: child)) + } + } + return items.isEmpty ? nil : items + } +} + +// MARK: OPMLRepresentable + +extension NNW3Folder: OPMLRepresentable { + + func OPMLString(indentLevel: Int, strictConformance: Bool) -> String { + let t = title?.rs_stringByEscapingSpecialXMLCharacters() ?? "" + guard let children = children else { + // Empty folder. + return "\n".rs_string(byPrependingNumberOfTabs: indentLevel) + } + + var s = "\n".rs_string(byPrependingNumberOfTabs: indentLevel) + for child in children { + s += child.OPMLString(indentLevel: indentLevel + 1, strictConformance: true) + } + + s += "\n".rs_string(byPrependingNumberOfTabs: indentLevel) + return s + } +} + +// MARK: - NNW3Feed + +private struct NNW3Feed { + + private let title: String? + private let homePageURL: String? + private let feedURL: String? + + init(plist: [String: Any]) { + self.title = plist["name"] as? String + self.homePageURL = plist["home"] as? String + self.feedURL = plist["rss"] as? String + } +} + +// MARK: OPMLRepresentable + +extension NNW3Feed: OPMLRepresentable { + + func OPMLString(indentLevel: Int, strictConformance: Bool) -> String { + let t = title?.rs_stringByEscapingSpecialXMLCharacters() ?? "" + let p = homePageURL?.rs_stringByEscapingSpecialXMLCharacters() ?? "" + let f = feedURL?.rs_stringByEscapingSpecialXMLCharacters() ?? "" + + var s = "\n" + s = s.rs_string(byPrependingNumberOfTabs: indentLevel) + + return s + } +} + diff --git a/Mac/MainWindow/NNW3/NNW3Entry.swift b/Mac/MainWindow/NNW3/NNW3Entry.swift deleted file mode 100644 index 4cc19b911..000000000 --- a/Mac/MainWindow/NNW3/NNW3Entry.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// NNW3Entry.swift -// NetNewsWire -// -// Created by Maurice Parker on 10/14/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import Foundation -import RSCore - -class NNW3Entry { - - var title: String? - var entries = [NNW3Entry]() - - weak var parent: NNW3Entry? - - var isFolder: Bool { - return type(of: self) == NNW3Entry.self - } - - init(title: String?, parent: NNW3Entry? = nil) { - self.title = title - self.parent = parent - } - - convenience init(plist: [String: Any], parent: NNW3Entry? = nil) { - let title = plist["name"] as? String - self.init(title: title, parent: parent) - - guard let childrenArray = plist["childrenArray"] as? [[String: AnyObject]] else { - return - } - - for child in childrenArray { - if child["isContainer"] as? Bool ?? false { - entries.append(NNW3Entry(plist: child, parent: self)) - } else { - entries.append(NNW3Feed(plist: child, parent: self)) - } - } - - } - - func makeXML(indentLevel: Int) -> String { - - let t = title?.rs_stringByEscapingSpecialXMLCharacters() ?? "" - var s = "\n".rs_string(byPrependingNumberOfTabs: indentLevel) - - for entry in entries { - s += entry.makeXML(indentLevel: indentLevel + 1) - } - - s += "\n".rs_string(byPrependingNumberOfTabs: indentLevel) - - return s - - } - -} diff --git a/Mac/MainWindow/NNW3/NNW3Feed.swift b/Mac/MainWindow/NNW3/NNW3Feed.swift deleted file mode 100644 index f6d54a480..000000000 --- a/Mac/MainWindow/NNW3/NNW3Feed.swift +++ /dev/null @@ -1,48 +0,0 @@ -// -// NNW3Feed.swift -// NetNewsWire -// -// Created by Maurice Parker on 10/14/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import Foundation -import RSCore - -class NNW3Feed: NNW3Entry { - - var pageURL: String? - var feedURL: String? - - init(feedURL: String) { - super.init(title: nil) - self.feedURL = feedURL - } - - init(title: String?, pageURL: String?, feedURL: String?, parent: NNW3Entry? = nil) { - super.init(title: title, parent: parent) - self.pageURL = pageURL - self.feedURL = feedURL - } - - convenience init(plist: [String: Any], parent: NNW3Entry? = nil) { - let title = plist["name"] as? String - let pageURL = plist["home"] as? String - let feedURL = plist["rss"] as? String - self.init(title: title, pageURL: pageURL, feedURL: feedURL, parent: parent) - } - - override func makeXML(indentLevel: Int) -> String { - - let t = title?.rs_stringByEscapingSpecialXMLCharacters() ?? "" - let p = pageURL?.rs_stringByEscapingSpecialXMLCharacters() ?? "" - let f = feedURL?.rs_stringByEscapingSpecialXMLCharacters() ?? "" - - var s = "\n" - s = s.rs_string(byPrependingNumberOfTabs: indentLevel) - - return s - - } - -} diff --git a/Mac/MainWindow/NNW3/NNW3FeedsImporter.swift b/Mac/MainWindow/NNW3/NNW3FeedsImporter.swift deleted file mode 100644 index baaa14eba..000000000 --- a/Mac/MainWindow/NNW3/NNW3FeedsImporter.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// NNW3FeedsImporter.swift -// NetNewsWire -// -// Created by Maurice Parker on 10/14/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import Foundation -import Account -import RSCore - -struct NNW3FeedsImporter { - - static func importIfNeeded(_ isFirstRun: Bool, account: Account) { - guard shouldImportDefaultFeeds(isFirstRun) else { - return - } - - if !FileManager.default.fileExists(atPath: NNW3PlistConverter.defaultFilePath) { - return - } - - appDelegate.logDebugMessage("Importing NNW3 feeds.") - - let url = URL(fileURLWithPath: NNW3PlistConverter.defaultFilePath) - guard let opmlURL = NNW3PlistConverter.convertToOPML(url: url) else { - return - } - - account.importOPML(opmlURL) { result in - try? FileManager.default.removeItem(at: opmlURL) - switch result { - case .success: - appDelegate.logDebugMessage("Importing NNW3 feeds succeeded.") - case .failure(let error): - appDelegate.logDebugMessage("Importing NNW3 feeds failed. \(error.localizedDescription)") - } - } - - } - - private static func shouldImportDefaultFeeds(_ isFirstRun: Bool) -> Bool { - if !isFirstRun || AccountManager.shared.anyAccountHasAtLeastOneFeed() { - return false - } - return true - } - -} diff --git a/Mac/MainWindow/NNW3/NNW3ImportController.swift b/Mac/MainWindow/NNW3/NNW3ImportController.swift new file mode 100644 index 000000000..f3103e1e1 --- /dev/null +++ b/Mac/MainWindow/NNW3/NNW3ImportController.swift @@ -0,0 +1,108 @@ +// +// NNW3ImportController.swift +// NetNewsWire +// +// Created by Brent Simmons on 10/14/19. +// Copyright © 2019 Ranchero Software. All rights reserved. +// + +import AppKit +import Account + +struct NNW3ImportController { + + /// Import NNW3 subscriptions if they exist. + /// Return true if Subscriptions.plist was found and subscriptions were imported. + static func importSubscriptionsIfFileExists(account: Account) -> Bool { + guard let subscriptionsPlistURL = defaultFileURL else { + return false + } + if !FileManager.default.fileExists(atPath: subscriptionsPlistURL.path) { + return false + } + NNW3ImportController.importSubscriptionsPlist(subscriptionsPlistURL, into: account) + return true + } + + /// Run an NSOpenPanel and import subscriptions (if the user chooses to). + static func askUserToImportNNW3Subscriptions(window: NSWindow) { + chooseFile(window) + } +} + +private extension NNW3ImportController { + + /// URL to ~/Library/Application Support/NetNewsWire/Subscriptions.plist + static var defaultFileURL: URL? { + guard let applicationSupportURL = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first else { + return nil + } + let folderURL = applicationSupportURL.appendingPathComponent("NetNewsWire", isDirectory: true) + return folderURL.appendingPathComponent("Subscriptions.plist", isDirectory: false) + } + + /// Import Subscriptions.plist file. Convert to OPML and then import into specified Account. + static func importSubscriptionsPlist(_ subscriptionsPlistURL: URL, into account: Account) { + guard let opmlURL = convertToOPMLFile(subscriptionsPlistURL: subscriptionsPlistURL) else { + return + } + account.importOPML(opmlURL) { result in + try? FileManager.default.removeItem(at: opmlURL) + switch result { + case .success: + break + case .failure(let error): + NSApplication.shared.presentError(error) + } + } + } + + /// Run the NSOpenPanel. On success, import subscriptions to the selected account. + static func chooseFile(_ window: NSWindow) { + let accessoryViewController = NNW3OpenPanelAccessoryViewController() + + let panel = NSOpenPanel() + panel.canDownloadUbiquitousContents = true + panel.canResolveUbiquitousConflicts = true + panel.canChooseFiles = true + panel.allowsMultipleSelection = false + panel.canChooseDirectories = false + panel.resolvesAliases = true + panel.directoryURL = NNW3ImportController.defaultFileURL + panel.allowedFileTypes = ["plist"] + panel.allowsOtherFileTypes = false + panel.accessoryView = accessoryViewController.view + panel.isAccessoryViewDisclosed = true + panel.title = NSLocalizedString("Choose a Subscriptions.plist file:", comment: "NNW3 Import") + + panel.beginSheetModal(for: window) { modalResult in + guard modalResult == .OK, let subscriptionsPlistURL = panel.url else { + return + } + guard let account = accessoryViewController.selectedAccount else { + return + } + AppDefaults.importOPMLAccountID = account.accountID + + NNW3ImportController.importSubscriptionsPlist(subscriptionsPlistURL, into: account) + } + } + + /// Convert Subscriptions.plist on disk to a temporary OPML file. + static func convertToOPMLFile(subscriptionsPlistURL url: URL) -> URL? { + guard let document = NNW3Document(subscriptionsPlistURL: url) else { + return nil + } + let opml = document.OPMLString(indentLevel: 0, strictConformance: true) + + let opmlURL = FileManager.default.temporaryDirectory.appendingPathComponent("NNW3.opml") + do { + try opml.write(to: opmlURL, atomically: true, encoding: .utf8) + } catch let error as NSError { + NSApplication.shared.presentError(error) + return nil + } + + return opmlURL + } +} diff --git a/Mac/MainWindow/NNW3/NNW3OpenPanelAccessoryView.xib b/Mac/MainWindow/NNW3/NNW3OpenPanelAccessoryView.xib new file mode 100644 index 000000000..bfed3618b --- /dev/null +++ b/Mac/MainWindow/NNW3/NNW3OpenPanelAccessoryView.xib @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Choose a NetNewsWire 3 “Subscriptions.plist” file. + +Then choose the account to receive your imported subscriptions. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Mac/MainWindow/NNW3/NNW3OpenPanelAccessoryViewController.swift b/Mac/MainWindow/NNW3/NNW3OpenPanelAccessoryViewController.swift new file mode 100644 index 000000000..a7a05fc8f --- /dev/null +++ b/Mac/MainWindow/NNW3/NNW3OpenPanelAccessoryViewController.swift @@ -0,0 +1,47 @@ +// +// NNW3OpenPanelAccessoryViewController.swift +// NetNewsWire +// +// Created by Brent Simmons on 10/14/19. +// Copyright © 2019 Ranchero Software. All rights reserved. +// + +import AppKit +import Account + +final class NNW3OpenPanelAccessoryViewController: NSViewController { + + @IBOutlet weak var accountPopUpButton: NSPopUpButton! + + var selectedAccount: Account? { + accountPopUpButton.selectedItem?.representedObject as? Account + } + + init() { + super.init(nibName: "NNW3OpenPanelAccessoryView", bundle: nil) + } + + // MARK: - NSViewController + + required init?(coder: NSCoder) { + preconditionFailure("NNW3OpenPanelAccessoryViewController.init(coder) not implemented by design.") + } + + override func viewDidLoad() { + accountPopUpButton.removeAllItems() + + let menu = NSMenu() + accountPopUpButton.menu = menu + + for account in AccountManager.shared.sortedActiveAccounts { + let menuItem = NSMenuItem() + menuItem.title = account.nameForDisplay + menuItem.representedObject = account + menu.addItem(menuItem) + + if account.accountID == AppDefaults.importOPMLAccountID { + accountPopUpButton.select(menuItem) + } + } + } +} diff --git a/Mac/MainWindow/NNW3/NNW3PlistConverter.swift b/Mac/MainWindow/NNW3/NNW3PlistConverter.swift deleted file mode 100644 index 310a2d93d..000000000 --- a/Mac/MainWindow/NNW3/NNW3PlistConverter.swift +++ /dev/null @@ -1,39 +0,0 @@ -// -// NNW3Importer.swift -// NetNewsWire -// -// Created by Maurice Parker on 10/14/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import Foundation - -class NNW3PlistConverter { - - static var defaultFilePath: String { - return ("~/Library/Application Support/NetNewsWire/Subscriptions.plist" as NSString).expandingTildeInPath - } - - static func convertToOPML(url: URL) -> URL? { - guard let data = try? Data(contentsOf: url) else { - return nil - } - - guard let nnw3plist = try? PropertyListSerialization.propertyList(from: data, options: [], format: nil) as? [[String: AnyObject]] else { - return nil - } - - let opmlURL = FileManager.default.temporaryDirectory.appendingPathComponent("NNW3.opml") - let doc = NNW3Document(plist: nnw3plist) - let opml = doc.makeXML(indentLevel: 0) - do { - try opml.write(to: opmlURL, atomically: true, encoding: .utf8) - } catch let error as NSError { - NSApplication.shared.presentError(error) - return nil - } - - return opmlURL - } - -} diff --git a/Mac/MainWindow/Timeline/Cell/TimelineCellData.swift b/Mac/MainWindow/Timeline/Cell/TimelineCellData.swift index 5db407f63..87afcd9e3 100644 --- a/Mac/MainWindow/Timeline/Cell/TimelineCellData.swift +++ b/Mac/MainWindow/Timeline/Cell/TimelineCellData.swift @@ -24,13 +24,13 @@ struct TimelineCellData { init(article: Article, showFeedName: Bool, feedName: String?, avatar: NSImage?, showAvatar: Bool, featuredImage: NSImage?) { - self.title = TimelineStringFormatter.truncatedTitle(article) - self.text = TimelineStringFormatter.truncatedSummary(article) + self.title = ArticleStringFormatter.truncatedTitle(article) + self.text = ArticleStringFormatter.truncatedSummary(article) - self.dateString = TimelineStringFormatter.dateString(article.logicalDatePublished) + self.dateString = ArticleStringFormatter.dateString(article.logicalDatePublished) if let feedName = feedName { - self.feedName = TimelineStringFormatter.truncatedFeedName(feedName) + self.feedName = ArticleStringFormatter.truncatedFeedName(feedName) } else { self.feedName = "" diff --git a/Mac/Preferences/Accounts/AccountsPreferencesViewController.swift b/Mac/Preferences/Accounts/AccountsPreferencesViewController.swift index cfc540d09..5c5022610 100644 --- a/Mac/Preferences/Accounts/AccountsPreferencesViewController.swift +++ b/Mac/Preferences/Accounts/AccountsPreferencesViewController.swift @@ -52,8 +52,8 @@ final class AccountsPreferencesViewController: NSViewController { let alert = NSAlert() alert.alertStyle = .warning let deletePrompt = NSLocalizedString("Delete", comment: "Delete") - alert.messageText = "\(deletePrompt) \"\(acctName)\"?" - alert.informativeText = NSLocalizedString("Are you sure you want to delete the account \"\(acctName)\"? This can not be undone.", comment: "Delete text") + alert.messageText = "\(deletePrompt) “\(acctName)”?" + alert.informativeText = NSLocalizedString("Are you sure you want to delete the account “\(acctName)”? This can not be undone.", comment: "Delete text") alert.addButton(withTitle: NSLocalizedString("Delete", comment: "Delete Account")) alert.addButton(withTitle: NSLocalizedString("Cancel", comment: "Cancel Delete Account")) diff --git a/Mac/Preferences/PreferencesWindowController.swift b/Mac/Preferences/PreferencesWindowController.swift index d8ae463bc..79570b50a 100644 --- a/Mac/Preferences/PreferencesWindowController.swift +++ b/Mac/Preferences/PreferencesWindowController.swift @@ -35,7 +35,14 @@ class PreferencesWindowController : NSWindowController, NSToolbarDelegate { var specs = [PreferencesToolbarItemSpec]() specs += [PreferencesToolbarItemSpec(identifierRawValue: ToolbarItemIdentifier.General, name: NSLocalizedString("General", comment: "Preferences"), imageName: NSImage.preferencesGeneralName)] specs += [PreferencesToolbarItemSpec(identifierRawValue: ToolbarItemIdentifier.Accounts, name: NSLocalizedString("Accounts", comment: "Preferences"), imageName: NSImage.userAccountsName)] - specs += [PreferencesToolbarItemSpec(identifierRawValue: ToolbarItemIdentifier.Advanced, name: NSLocalizedString("Advanced", comment: "Preferences"), imageName: NSImage.advancedName)] + + // Omit the Advanced Preferences for now because the Software Update related functionality is + // forbidden/non-applicable, and we can rely upon Apple to some extent for crash reports. We + // can add back the Crash Reporter preferences when we're ready to dynamically shuffle the rest + // of the content in this tab. + #if !MAC_APP_STORE + specs += [PreferencesToolbarItemSpec(identifierRawValue: ToolbarItemIdentifier.Advanced, name: NSLocalizedString("Advanced", comment: "Preferences"), imageName: NSImage.advancedName)] + #endif return specs }() diff --git a/Mac/Resources/Assets.xcassets/accountLocal.imageset/Contents.json b/Mac/Resources/Assets.xcassets/accountLocal.imageset/Contents.json index 4b7dc7acc..1d99e9ded 100644 --- a/Mac/Resources/Assets.xcassets/accountLocal.imageset/Contents.json +++ b/Mac/Resources/Assets.xcassets/accountLocal.imageset/Contents.json @@ -2,7 +2,7 @@ "images" : [ { "idiom" : "universal", - "filename" : "accountLocal.pdf" + "filename" : "localAccountMac.pdf" } ], "info" : { diff --git a/iOS/Resources/Assets.xcassets/accountLocal.imageset/accountLocal.pdf b/Mac/Resources/Assets.xcassets/accountLocal.imageset/localAccountMac.pdf similarity index 75% rename from iOS/Resources/Assets.xcassets/accountLocal.imageset/accountLocal.pdf rename to Mac/Resources/Assets.xcassets/accountLocal.imageset/localAccountMac.pdf index c32cc3b89..5c3292ce0 100644 Binary files a/iOS/Resources/Assets.xcassets/accountLocal.imageset/accountLocal.pdf and b/Mac/Resources/Assets.xcassets/accountLocal.imageset/localAccountMac.pdf differ diff --git a/Mac/Resources/NetNewsWire.entitlements b/Mac/Resources/NetNewsWire.entitlements index 65f91a796..ef6f5c233 100644 --- a/Mac/Resources/NetNewsWire.entitlements +++ b/Mac/Resources/NetNewsWire.entitlements @@ -2,9 +2,15 @@ + com.apple.security.app-sandbox + com.apple.developer.icloud-container-identifiers com.apple.security.automation.apple-events + com.apple.security.files.user-selected.read-write + + com.apple.security.network.client + diff --git a/Mac/Resources/container-migration.plist b/Mac/Resources/container-migration.plist new file mode 100644 index 000000000..c512c75bd --- /dev/null +++ b/Mac/Resources/container-migration.plist @@ -0,0 +1,10 @@ + + + + + Move + + ${ApplicationSupport}/NetNewsWire + + + diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 1b01c1494..45dc8a390 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -11,7 +11,6 @@ 3B29BC6A233EA81F002A346D /* AccountsFeedWrangler.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3B29BC68233EA81F002A346D /* AccountsFeedWrangler.xib */; }; 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 */; }; @@ -30,34 +29,35 @@ 512E09012268907400BDCFDD /* MasterFeedTableViewSectionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 512E08F722688F7C00BDCFDD /* MasterFeedTableViewSectionHeader.swift */; }; 512E09352268B25900BDCFDD /* UISplitViewController-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 512E092B2268B25500BDCFDD /* UISplitViewController-Extensions.swift */; }; 512E094D2268B8AB00BDCFDD /* DeleteCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B99C9C1FAE83C600ECDEDB /* DeleteCommand.swift */; }; - 51322855232EED360033D4ED /* VibrantSelectAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51322854232EED360033D4ED /* VibrantSelectAction.swift */; }; - 51322859232FDDB80033D4ED /* VibrantButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51322858232FDDB80033D4ED /* VibrantButtonStyle.swift */; }; - 5132285B232FF2C40033D4ED /* SettingsRefreshSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5132285A232FF2C40033D4ED /* SettingsRefreshSelectionView.swift */; }; + 5131463E235A7BBE00387FDC /* NetNewsWire iOS Intents Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 51314637235A7BBE00387FDC /* NetNewsWire iOS Intents Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 51314668235A7E4600387FDC /* IntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51314666235A7E4600387FDC /* IntentHandler.swift */; }; + 513146B2235A81A400387FDC /* AddFeedIntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 513146B1235A81A400387FDC /* AddFeedIntentHandler.swift */; }; + 513146B3235A81A400387FDC /* AddFeedIntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 513146B1235A81A400387FDC /* AddFeedIntentHandler.swift */; }; + 513146B4235A8FD000387FDC /* RSCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37F8520DD8CF200CA8CF5 /* RSCore.framework */; }; + 513146B6235A8FD000387FDC /* RSDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37FC420DD8E0C00CA8CF5 /* RSDatabase.framework */; }; + 513146B8235A8FD000387FDC /* RSParser.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37F8C20DD8CF800CA8CF5 /* RSParser.framework */; }; + 513146BA235A8FD000387FDC /* RSTree.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37F9520DD8CFE00CA8CF5 /* RSTree.framework */; }; + 513146BC235A8FD000387FDC /* RSWeb.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37FA320DD8D0500CA8CF5 /* RSWeb.framework */; }; + 513146BF235A8FDB00387FDC /* Account.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8407166A2262A60D00344432 /* Account.framework */; }; + 513146C1235A8FDB00387FDC /* Articles.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 840716732262A60F00344432 /* Articles.framework */; }; + 513146C3235A8FDB00387FDC /* ArticlesDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8407167F2262A61100344432 /* ArticlesDatabase.framework */; }; + 513146C5235A8FDB00387FDC /* SyncDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51554C01228B6EB50055115A /* SyncDatabase.framework */; }; + 51314704235C41FC00387FDC /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 51314707235C41FC00387FDC /* Intents.intentdefinition */; }; + 51314705235C41FC00387FDC /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 51314707235C41FC00387FDC /* Intents.intentdefinition */; }; 513228FB233037630033D4ED /* Reachability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 513228F2233037620033D4ED /* Reachability.swift */; }; 513228FC233037630033D4ED /* Reachability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 513228F2233037620033D4ED /* Reachability.swift */; }; - 513229312330523F0033D4ED /* SettingsAttributedStringView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 513229302330523F0033D4ED /* SettingsAttributedStringView.swift */; }; - 5132293B23305D4C0033D4ED /* SettingsAboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5132293A23305D4C0033D4ED /* SettingsAboutView.swift */; }; 513C5CE9232571C2003D4054 /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 513C5CE8232571C2003D4054 /* ShareViewController.swift */; }; 513C5CEC232571C2003D4054 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 513C5CEA232571C2003D4054 /* MainInterface.storyboard */; }; 513C5CF0232571C2003D4054 /* NetNewsWire iOS Share Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 513C5CE6232571C2003D4054 /* NetNewsWire iOS Share Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 513C5CFD2325749A003D4054 /* Account.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8407166A2262A60D00344432 /* Account.framework */; }; - 513C5CFE2325749A003D4054 /* Account.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8407166A2262A60D00344432 /* Account.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 513C5D00232574AF003D4054 /* Articles.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 840716732262A60F00344432 /* Articles.framework */; }; - 513C5D01232574AF003D4054 /* Articles.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 840716732262A60F00344432 /* Articles.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 513C5D02232574B4003D4054 /* ArticlesDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8407167F2262A61100344432 /* ArticlesDatabase.framework */; }; - 513C5D03232574B4003D4054 /* ArticlesDatabase.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8407167F2262A61100344432 /* ArticlesDatabase.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 513C5D04232574B9003D4054 /* RSCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37F8520DD8CF200CA8CF5 /* RSCore.framework */; }; - 513C5D05232574B9003D4054 /* RSCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37F8520DD8CF200CA8CF5 /* RSCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 513C5D06232574C0003D4054 /* RSDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37FC420DD8E0C00CA8CF5 /* RSDatabase.framework */; }; - 513C5D07232574C0003D4054 /* RSDatabase.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37FC420DD8E0C00CA8CF5 /* RSDatabase.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 513C5D08232574C6003D4054 /* RSParser.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37F8C20DD8CF800CA8CF5 /* RSParser.framework */; }; - 513C5D09232574C6003D4054 /* RSParser.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37F8C20DD8CF800CA8CF5 /* RSParser.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 513C5D0A232574D2003D4054 /* RSWeb.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37FA320DD8D0500CA8CF5 /* RSWeb.framework */; }; - 513C5D0B232574D2003D4054 /* RSWeb.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37FA320DD8D0500CA8CF5 /* RSWeb.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 513C5D0C232574DA003D4054 /* RSTree.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37F9520DD8CFE00CA8CF5 /* RSTree.framework */; }; - 513C5D0D232574DA003D4054 /* RSTree.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37F9520DD8CFE00CA8CF5 /* RSTree.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 513C5D0E232574E4003D4054 /* SyncDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51554C01228B6EB50055115A /* SyncDatabase.framework */; }; - 513C5D0F232574E4003D4054 /* SyncDatabase.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 51554C01228B6EB50055115A /* SyncDatabase.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 5142192A23522B5500E07E2C /* ImageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5142192923522B5500E07E2C /* ImageViewController.swift */; }; 514219372352510100E07E2C /* ImageScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514219362352510100E07E2C /* ImageScrollView.swift */; }; 5142194B2353C1CF00E07E2C /* main_mac.js in Resources */ = {isa = PBXBuildFile; fileRef = 5142194A2353C1CF00E07E2C /* main_mac.js */; }; @@ -75,8 +75,6 @@ 5148F4552336DB7000F8CD8B /* MasterTimelineTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5148F4542336DB7000F8CD8B /* MasterTimelineTitleView.swift */; }; 514B7C8323205EFB00BAC947 /* RootSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514B7C8223205EFB00BAC947 /* RootSplitViewController.swift */; }; 514B7D1F23219F3C00BAC947 /* AddControllerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514B7D1E23219F3C00BAC947 /* AddControllerType.swift */; }; - 5152E0F923248F6200E5C7AD /* SettingsLocalAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 510D707D22B02A4B004E8F65 /* SettingsLocalAccountView.swift */; }; - 5152E1022324900D00E5C7AD /* SettingsAddAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 510D707322B028E1004E8F65 /* SettingsAddAccountView.swift */; }; 5154368B229404D1005E1CDF /* FaviconGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F76227716200050506E /* FaviconGenerator.swift */; }; 51554C24228B71910055115A /* SyncDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51554C01228B6EB50055115A /* SyncDatabase.framework */; }; 51554C25228B71910055115A /* SyncDatabase.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 51554C01228B6EB50055115A /* SyncDatabase.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -85,6 +83,9 @@ 515D4FC123257A3200EE1167 /* FolderTreeControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97A11ED9F180007D329B /* FolderTreeControllerDelegate.swift */; }; 515D4FCA23257CB500EE1167 /* Node-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97971ED9EFAA007D329B /* Node-Extensions.swift */; }; 515D4FCC2325815A00EE1167 /* SafariExt.js in Resources */ = {isa = PBXBuildFile; fileRef = 515D4FCB2325815A00EE1167 /* SafariExt.js */; }; + 516A093723609A3600EAE89B /* SettingsAccountTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 516A091D23609A3600EAE89B /* SettingsAccountTableViewCell.xib */; }; + 516A09392360A2AE00EAE89B /* SettingsAccountTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 516A09382360A2AE00EAE89B /* SettingsAccountTableViewCell.swift */; }; + 516A093B2360A4A000EAE89B /* SettingsTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 516A093A2360A4A000EAE89B /* SettingsTableViewCell.xib */; }; 51707439232AA97100A461A3 /* ShareFolderPickerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51707438232AA97100A461A3 /* ShareFolderPickerController.swift */; }; 5170743A232AABFC00A461A3 /* FlattenedAccountFolderPickerData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C452812265093600C03939 /* FlattenedAccountFolderPickerData.swift */; }; 517630042336215100E15FFF /* main.js in Resources */ = {isa = PBXBuildFile; fileRef = 517630032336215100E15FFF /* main.js */; }; @@ -98,28 +99,25 @@ 5183CCE6226F4E110010922C /* RefreshInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCE4226F4DFA0010922C /* RefreshInterval.swift */; }; 5183CCE8226F68D90010922C /* AccountRefreshTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCE7226F68D90010922C /* AccountRefreshTimer.swift */; }; 5183CCE9226F68D90010922C /* AccountRefreshTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCE7226F68D90010922C /* AccountRefreshTimer.swift */; }; - 518651AC23555EB20078E021 /* ImportNNW3WindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518651A523555EB20078E021 /* ImportNNW3WindowController.swift */; }; - 518651AD23555EB20078E021 /* NNW3PlistConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518651A623555EB20078E021 /* NNW3PlistConverter.swift */; }; - 518651AE23555EB20078E021 /* ImportNNW3Sheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 518651A723555EB20078E021 /* ImportNNW3Sheet.xib */; }; - 518651AF23555EB20078E021 /* NNW3Entry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518651A823555EB20078E021 /* NNW3Entry.swift */; }; - 518651B023555EB20078E021 /* NNW3FeedsImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518651A923555EB20078E021 /* NNW3FeedsImporter.swift */; }; - 518651B123555EB20078E021 /* NNW3Feed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518651AA23555EB20078E021 /* NNW3Feed.swift */; }; 518651B223555EB20078E021 /* NNW3Document.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518651AB23555EB20078E021 /* NNW3Document.swift */; }; 518651DA235621840078E021 /* ImageTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518651D9235621840078E021 /* ImageTransition.swift */; }; + 5186A635235EF3A800C97195 /* VibrantLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5186A634235EF3A800C97195 /* VibrantLabel.swift */; }; 518B2EE82351B45600400001 /* NetNewsWire_iOSTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840D61952029031D009BC708 /* NetNewsWire_iOSTests.swift */; }; 51934CCB230F599B006127BE /* ThemedNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51934CC1230F5963006127BE /* ThemedNavigationController.swift */; }; 51934CCE2310792F006127BE /* ActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51934CCD2310792F006127BE /* ActivityManager.swift */; }; 51938DF2231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51938DF1231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift */; }; 51938DF3231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51938DF1231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift */; }; 519B8D332143397200FA689C /* SharingServiceDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519B8D322143397200FA689C /* SharingServiceDelegate.swift */; }; - 519D73FB2323FF35008BB345 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F35D0822AFD4760003CE1B /* SettingsView.swift */; }; 519D740623243CC0008BB345 /* RefreshInterval-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519D740523243CC0008BB345 /* RefreshInterval-Extensions.swift */; }; - 519D740723243FE7008BB345 /* SettingsSubscriptionsExportDocumentPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5194B5F122B69FCC00144881 /* SettingsSubscriptionsExportDocumentPickerView.swift */; }; - 519D740823243FEA008BB345 /* SettingsSubscriptionsImportDocumentPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5194B5ED22B6965300144881 /* SettingsSubscriptionsImportDocumentPickerView.swift */; }; 519E743D22C663F900A78E47 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519E743422C663F900A78E47 /* SceneDelegate.swift */; }; - 51AF45E123246731001742EF /* SettingsAccountLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 510D708122B041CC004E8F65 /* SettingsAccountLabelView.swift */; }; - 51AF460323247321001742EF /* SettingsDetailAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F772EC22B2789B0087D9D1 /* SettingsDetailAccountView.swift */; }; - 51AF460C23247F11001742EF /* SettingsFeedbinAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 510D707F22B02A5F004E8F65 /* SettingsFeedbinAccountView.swift */; }; + 51A16997235E10D700EB091F /* RefreshIntervalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A1698D235E10D600EB091F /* RefreshIntervalViewController.swift */; }; + 51A16999235E10D700EB091F /* AddLocalAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A1698F235E10D600EB091F /* AddLocalAccountViewController.swift */; }; + 51A1699A235E10D700EB091F /* Settings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 51A16990235E10D600EB091F /* Settings.storyboard */; }; + 51A1699B235E10D700EB091F /* DetailAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A16991235E10D600EB091F /* DetailAccountViewController.swift */; }; + 51A1699C235E10D700EB091F /* AddAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A16992235E10D600EB091F /* AddAccountViewController.swift */; }; + 51A1699D235E10D700EB091F /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A16993235E10D600EB091F /* SettingsViewController.swift */; }; + 51A1699F235E10D700EB091F /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A16995235E10D600EB091F /* AboutViewController.swift */; }; + 51A169A0235E10D700EB091F /* FeedbinAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A16996235E10D700EB091F /* FeedbinAccountViewController.swift */; }; 51AF460E232488C6001742EF /* Account-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51AF460D232488C6001742EF /* Account-Extensions.swift */; }; 51B62E68233186730085F949 /* MasterTimelineAvatarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51B62E67233186730085F949 /* MasterTimelineAvatarView.swift */; }; 51BB7C272335A8E5008E8144 /* ArticleActivityItemSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51BB7C262335A8E5008E8144 /* ArticleActivityItemSource.swift */; }; @@ -191,7 +189,7 @@ 51C452A922650DC600C03939 /* ArticleRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A977D1ED9EC42007D329B /* ArticleRenderer.swift */; }; 51C452AB22650DC600C03939 /* template.html in Resources */ = {isa = PBXBuildFile; fileRef = 848362FE2262A30E00DA1D35 /* template.html */; }; 51C452AC22650FD200C03939 /* AppNotifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842E45CD1ED8C308000A8B52 /* AppNotifications.swift */; }; - 51C452AE2265104D00C03939 /* TimelineStringFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97731ED9EC04007D329B /* TimelineStringFormatter.swift */; }; + 51C452AE2265104D00C03939 /* ArticleStringFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97731ED9EC04007D329B /* ArticleStringFormatter.swift */; }; 51C452AF2265108300C03939 /* ArticleArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F204DF1FAACBB30076E152 /* ArticleArray.swift */; }; 51C452B42265141B00C03939 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51C452B32265141B00C03939 /* WebKit.framework */; }; 51C452B82265178500C03939 /* styleSheet.css in Resources */ = {isa = PBXBuildFile; fileRef = 51C452B72265178500C03939 /* styleSheet.css */; }; @@ -199,9 +197,6 @@ 51D5948722668EFA00DFC836 /* MarkStatusCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84702AA31FA27AC0006B8943 /* MarkStatusCommand.swift */; }; 51D6A5BC23199C85001C27D8 /* MasterTimelineDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51D6A5BB23199C85001C27D8 /* MasterTimelineDataSource.swift */; }; 51D87EE12311D34700E63F03 /* ActivityType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51D87EE02311D34700E63F03 /* ActivityType.swift */; }; - 51E149B3234D82E40004F7A5 /* PasswordField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E149B2234D82E40004F7A5 /* PasswordField.swift */; }; - 51E149C0234D839E0004F7A5 /* ShowHidePasswordView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 51E149BF234D839E0004F7A5 /* ShowHidePasswordView.xib */; }; - 51E149C2234D852F0004F7A5 /* ShowHidePasswordView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E149C1234D852F0004F7A5 /* ShowHidePasswordView.swift */; }; 51E3EB33229AB02C00645299 /* ErrorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E3EB32229AB02C00645299 /* ErrorHandler.swift */; }; 51E3EB3D229AB08300645299 /* ErrorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E3EB3C229AB08300645299 /* ErrorHandler.swift */; }; 51E595A5228CC36500FCC42B /* ArticleStatusSyncTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E595A4228CC36500FCC42B /* ArticleStatusSyncTimer.swift */; }; @@ -239,14 +234,219 @@ 51FE10042345529D0056195D /* UserNotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51FE10022345529D0056195D /* UserNotificationManager.swift */; }; 51FE10092346739D0056195D /* ActivityType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51D87EE02311D34700E63F03 /* ActivityType.swift */; }; 51FE100A234673A00056195D /* ActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51934CCD2310792F006127BE /* ActivityManager.swift */; }; + 51FFF0C4235EE8E5002762AA /* VibrantButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51FFF0C3235EE8E5002762AA /* VibrantButton.swift */; }; 55E15BCB229D65A900D6602A /* AccountsReaderAPI.xib in Resources */ = {isa = PBXBuildFile; fileRef = 55E15BC1229D65A900D6602A /* AccountsReaderAPI.xib */; }; 55E15BCC229D65A900D6602A /* AccountsReaderAPIWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55E15BCA229D65A900D6602A /* AccountsReaderAPIWindowController.swift */; }; - 5F323809231DF9F000706F6B /* NNWTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F323808231DF9F000706F6B /* NNWTableViewCell.swift */; }; + 5F323809231DF9F000706F6B /* VibrantTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F323808231DF9F000706F6B /* VibrantTableViewCell.swift */; }; 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 /* netnewswire-subscribe-to-feed.js in Resources */ = {isa = PBXBuildFile; fileRef = 6581C73F20CED60100F4AD34 /* netnewswire-subscribe-to-feed.js */; }; 6581C74220CED60100F4AD34 /* ToolbarItemIcon.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 6581C74120CED60100F4AD34 /* ToolbarItemIcon.pdf */; }; + 65ED3FB7235DEF6C0081F399 /* ArticleArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F204DF1FAACBB30076E152 /* ArticleArray.swift */; }; + 65ED3FB8235DEF6C0081F399 /* CrashReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848B937121C8C5540038DC0D /* CrashReporter.swift */; }; + 65ED3FB9235DEF6C0081F399 /* TimelineAvatarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847CD6C9232F4CBF00FAC46D /* TimelineAvatarView.swift */; }; + 65ED3FBA235DEF6C0081F399 /* ArticleExtractorConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51FA73A92332C2FD0090D516 /* ArticleExtractorConfig.swift */; }; + 65ED3FBB235DEF6C0081F399 /* InspectorWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84BBB12C20142A4700F054F5 /* InspectorWindowController.swift */; }; + 65ED3FBC235DEF6C0081F399 /* ColorHash.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F78227716380050506E /* ColorHash.swift */; }; + 65ED3FBD235DEF6C0081F399 /* AppDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E46C7C1F75EF7B005ECFB3 /* AppDefaults.swift */; }; + 65ED3FBE235DEF6C0081F399 /* Account+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5907D962004B7EB005947E5 /* Account+Scriptability.swift */; }; + 65ED3FBF235DEF6C0081F399 /* NothingInspectorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841ABA4D20145E7300980E11 /* NothingInspectorViewController.swift */; }; + 65ED3FC0235DEF6C0081F399 /* AppNotifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842E45CD1ED8C308000A8B52 /* AppNotifications.swift */; }; + 65ED3FC1235DEF6C0081F399 /* TimelineKeyboardDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844B5B5A1FEA00FB00C7C76A /* TimelineKeyboardDelegate.swift */; }; + 65ED3FC2235DEF6C0081F399 /* Browser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842E45DC1ED8C54B000A8B52 /* Browser.swift */; }; + 65ED3FC3235DEF6C0081F399 /* DetailWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84216D0222128B9D0049B9B9 /* DetailWebViewController.swift */; }; + 65ED3FC4235DEF6C0081F399 /* OPMLExporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8444C8F11FED81840051386C /* OPMLExporter.swift */; }; + 65ED3FC5235DEF6C0081F399 /* MainWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A975D1ED9EB72007D329B /* MainWindowController.swift */; }; + 65ED3FC6235DEF6C0081F399 /* UnreadFeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2D5391FC2308B00998D64 /* UnreadFeed.swift */; }; + 65ED3FC7235DEF6C0081F399 /* Reachability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 513228F2233037620033D4ED /* Reachability.swift */; }; + 65ED3FC8235DEF6C0081F399 /* SidebarCellLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845A29211FC9251E007B49E3 /* SidebarCellLayout.swift */; }; + 65ED3FC9235DEF6C0081F399 /* SmartFeedPasteboardWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84AD1EB92031649C00BC20B7 /* SmartFeedPasteboardWriter.swift */; }; + 65ED3FCA235DEF6C0081F399 /* SmartFeedsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CC88171FE59CBF00644329 /* SmartFeedsController.swift */; }; + 65ED3FCB235DEF6C0081F399 /* SidebarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97621ED9EB96007D329B /* SidebarViewController.swift */; }; + 65ED3FCC235DEF6C0081F399 /* AccountsFeedlyWebWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EA33BB72318F8C10097B644 /* AccountsFeedlyWebWindowController.swift */; }; + 65ED3FCD235DEF6C0081F399 /* SidebarOutlineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97601ED9EB96007D329B /* SidebarOutlineView.swift */; }; + 65ED3FCE235DEF6C0081F399 /* DetailKeyboardDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5127B236222B4849006D641D /* DetailKeyboardDelegate.swift */; }; + 65ED3FCF235DEF6C0081F399 /* TimelineContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8405DD9822153B6B008CE1BF /* TimelineContainerView.swift */; }; + 65ED3FD0235DEF6C0081F399 /* Author+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A2678B20130ECF00A8D3C0 /* Author+Scriptability.swift */; }; + 65ED3FD1235DEF6C0081F399 /* PseudoFeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2D5351FC22FCB00998D64 /* PseudoFeed.swift */; }; + 65ED3FD2235DEF6C0081F399 /* AccountsAddViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F8F2279C9500050506E /* AccountsAddViewController.swift */; }; + 65ED3FD3235DEF6C0081F399 /* NSScriptCommand+NetNewsWire.swift in Sources */ = {isa = PBXBuildFile; fileRef = D57BE6DF204CD35F00D11AAC /* NSScriptCommand+NetNewsWire.swift */; }; + 65ED3FD4235DEF6C0081F399 /* Article+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D553737C20186C1F006D8857 /* Article+Scriptability.swift */; }; + 65ED3FD5235DEF6C0081F399 /* SmartFeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845EE7C01FC2488C00854A1F /* SmartFeed.swift */; }; + 65ED3FD6235DEF6C0081F399 /* MarkStatusCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84702AA31FA27AC0006B8943 /* MarkStatusCommand.swift */; }; + 65ED3FD7235DEF6C0081F399 /* NSApplication+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5907D7E2004AC00005947E5 /* NSApplication+Scriptability.swift */; }; + 65ED3FD8235DEF6C0081F399 /* NSView-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8405DD9B22153BD7008CE1BF /* NSView-Extensions.swift */; }; + 65ED3FD9235DEF6C0081F399 /* SidebarCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A979E1ED9F130007D329B /* SidebarCell.swift */; }; + 65ED3FDA235DEF6C0081F399 /* ArticleStatusSyncTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E595A4228CC36500FCC42B /* ArticleStatusSyncTimer.swift */; }; + 65ED3FDB235DEF6C0081F399 /* FeedTreeControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97611ED9EB96007D329B /* FeedTreeControllerDelegate.swift */; }; + 65ED3FDC235DEF6C0081F399 /* UnreadCountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97631ED9EB96007D329B /* UnreadCountView.swift */; }; + 65ED3FDD235DEF6C0081F399 /* ActivityType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51D87EE02311D34700E63F03 /* ActivityType.swift */; }; + 65ED3FDE235DEF6C0081F399 /* CrashReportWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840BEE4021D70E64009BBAFA /* CrashReportWindowController.swift */; }; + 65ED3FDF235DEF6C0081F399 /* FeedIconDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842611891FCB67AA0086A189 /* FeedIconDownloader.swift */; }; + 65ED3FE0235DEF6C0081F399 /* AccountsControlsBackgroundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C9FC7122629E1200D921D6 /* AccountsControlsBackgroundView.swift */; }; + 65ED3FE1235DEF6C0081F399 /* MarkCommandValidationStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84162A142038C12C00035290 /* MarkCommandValidationStatus.swift */; }; + 65ED3FE2235DEF6C0081F399 /* ArticlePasteboardWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E95D231FB1087500552D99 /* ArticlePasteboardWriter.swift */; }; + 65ED3FE3235DEF6C0081F399 /* ArticleUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97581ED9EB0D007D329B /* ArticleUtilities.swift */; }; + 65ED3FE4235DEF6C0081F399 /* NNW3OpenPanelAccessoryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849ADEE7235981A0000E1B81 /* NNW3OpenPanelAccessoryViewController.swift */; }; + 65ED3FE5235DEF6C0081F399 /* DefaultFeedsImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97591ED9EB0D007D329B /* DefaultFeedsImporter.swift */; }; + 65ED3FE6235DEF6C0081F399 /* RenameWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A37CB4201ECD610087C5AF /* RenameWindowController.swift */; }; + 65ED3FE7235DEF6C0081F399 /* SendToMicroBlogCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A14FF220048CA70046AD9A /* SendToMicroBlogCommand.swift */; }; + 65ED3FE8235DEF6C0081F399 /* ArticleStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97871ED9ECEF007D329B /* ArticleStyle.swift */; }; + 65ED3FE9235DEF6C0081F399 /* FaviconURLFinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84FF69B01FC3793300DC198E /* FaviconURLFinder.swift */; }; + 65ED3FEA235DEF6C0081F399 /* SidebarViewController+ContextualMenus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B7178B201E66580091657D /* SidebarViewController+ContextualMenus.swift */; }; + 65ED3FEB235DEF6C0081F399 /* ExportOPMLWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA42227A380F00D19003 /* ExportOPMLWindowController.swift */; }; + 65ED3FEC235DEF6C0081F399 /* RSHTMLMetadata+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842611A11FCB769D0086A189 /* RSHTMLMetadata+Extension.swift */; }; + 65ED3FED235DEF6C0081F399 /* SendToMarsEditCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A1500420048DDF0046AD9A /* SendToMarsEditCommand.swift */; }; + 65ED3FEE235DEF6C0081F399 /* UserNotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51FE10022345529D0056195D /* UserNotificationManager.swift */; }; + 65ED3FEF235DEF6C0081F399 /* ScriptingObjectContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5907DB12004BB37005947E5 /* ScriptingObjectContainer.swift */; }; + 65ED3FF0235DEF6C0081F399 /* ArticleStylesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97881ED9ECEF007D329B /* ArticleStylesManager.swift */; }; + 65ED3FF1235DEF6C0081F399 /* DetailContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8405DD892213E0E3008CE1BF /* DetailContainerView.swift */; }; + 65ED3FF2235DEF6C0081F399 /* SharingServiceDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519B8D322143397200FA689C /* SharingServiceDelegate.swift */; }; + 65ED3FF3235DEF6C0081F399 /* ArticleSorter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF3ABF1423259DDB0074C542 /* ArticleSorter.swift */; }; + 65ED3FF4235DEF6C0081F399 /* TimelineViewController+ContextualMenus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E8E0DA202EC49300562D8F /* TimelineViewController+ContextualMenus.swift */; }; + 65ED3FF5235DEF6C0081F399 /* ArticleStringFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97731ED9EC04007D329B /* ArticleStringFormatter.swift */; }; + 65ED3FF6235DEF6C0081F399 /* MultilineTextFieldSizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E185C2203BB12600F69BFA /* MultilineTextFieldSizer.swift */; }; + 65ED3FF7235DEF6C0081F399 /* SearchFeedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8477ACBD22238E9500DF7F37 /* SearchFeedDelegate.swift */; }; + 65ED3FF8235DEF6C0081F399 /* ErrorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E3EB32229AB02C00645299 /* ErrorHandler.swift */; }; + 65ED3FF9235DEF6C0081F399 /* ActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51934CCD2310792F006127BE /* ActivityManager.swift */; }; + 65ED3FFA235DEF6C0081F399 /* FeedInspectorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8472058020142E8900AD578B /* FeedInspectorViewController.swift */; }; + 65ED3FFB235DEF6C0081F399 /* AccountsReaderAPIWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55E15BCA229D65A900D6602A /* AccountsReaderAPIWindowController.swift */; }; + 65ED3FFC235DEF6C0081F399 /* AccountsAddLocalWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA372279FC6200D19003 /* AccountsAddLocalWindowController.swift */; }; + 65ED3FFD235DEF6C0081F399 /* PasteboardFolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84AD1EA92031617300BC20B7 /* PasteboardFolder.swift */; }; + 65ED3FFE235DEF6C0081F399 /* AccountsFeedbinWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA4F227B8E4500D19003 /* AccountsFeedbinWindowController.swift */; }; + 65ED3FFF235DEF6C0081F399 /* SidebarOutlineDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84AD1EBB2032AF5C00BC20B7 /* SidebarOutlineDataSource.swift */; }; + 65ED4000235DEF6C0081F399 /* SidebarCellAppearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845A29231FC9255E007B49E3 /* SidebarCellAppearance.swift */; }; + 65ED4001235DEF6C0081F399 /* StarredFeedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845EE7B01FC2366500854A1F /* StarredFeedDelegate.swift */; }; + 65ED4002235DEF6C0081F399 /* FaviconDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848F6AE41FC29CFA002D422E /* FaviconDownloader.swift */; }; + 65ED4003235DEF6C0081F399 /* AdvancedPreferencesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C9FC6B22629E1200D921D6 /* AdvancedPreferencesViewController.swift */; }; + 65ED4004235DEF6C0081F399 /* SharingServicePickerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849EE72020391F560082A1EA /* SharingServicePickerDelegate.swift */; }; + 65ED4005235DEF6C0081F399 /* Node-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97971ED9EFAA007D329B /* Node-Extensions.swift */; }; + 65ED4006235DEF6C0081F399 /* AppAssets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849EE70E203919360082A1EA /* AppAssets.swift */; }; + 65ED4007235DEF6C0081F399 /* AddFeedController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97511ED9EAC0007D329B /* AddFeedController.swift */; }; + 65ED4008235DEF6C0081F399 /* AccountRefreshTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCE7226F68D90010922C /* AccountRefreshTimer.swift */; }; + 65ED4009235DEF6C0081F399 /* SidebarStatusBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97821ED9EC63007D329B /* SidebarStatusBarView.swift */; }; + 65ED400A235DEF6C0081F399 /* SearchTimelineFeedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51938DF1231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift */; }; + 65ED400B235DEF6C0081F399 /* TodayFeedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2D5361FC22FCB00998D64 /* TodayFeedDelegate.swift */; }; + 65ED400C235DEF6C0081F399 /* FolderInspectorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841ABA5D20145E9200980E11 /* FolderInspectorViewController.swift */; }; + 65ED400D235DEF6C0081F399 /* SmartFeedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DEE56422C32CA4005FC42C /* SmartFeedDelegate.swift */; }; + 65ED400E235DEF6C0081F399 /* ImageDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845213221FCA5B10003B6E93 /* ImageDownloader.swift */; }; + 65ED400F235DEF6C0081F399 /* ArticleExtractorButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51FA73B62332D5F70090D516 /* ArticleExtractorButton.swift */; }; + 65ED4010235DEF6C0081F399 /* AccountsAddTableCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F912279CA620050506E /* AccountsAddTableCellView.swift */; }; + 65ED4011235DEF6C0081F399 /* AddFolderWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97421ED9EAA9007D329B /* AddFolderWindowController.swift */; }; + 65ED4012235DEF6C0081F399 /* TimelineContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8405DDA422168C62008CE1BF /* TimelineContainerViewController.swift */; }; + 65ED4013235DEF6C0081F399 /* MainWIndowKeyboardHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844B5B661FEA18E300C7C76A /* MainWIndowKeyboardHandler.swift */; }; + 65ED4014235DEF6C0081F399 /* PasteboardFeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848D578D21543519005FFAD5 /* PasteboardFeed.swift */; }; + 65ED4015235DEF6C0081F399 /* AccountsDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA2E2279FAB600D19003 /* AccountsDetailViewController.swift */; }; + 65ED4016235DEF6C0081F399 /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A977E1ED9EC42007D329B /* DetailViewController.swift */; }; + 65ED4017235DEF6C0081F399 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C9FC6622629B3900D921D6 /* AppDelegate.swift */; }; + 65ED4018235DEF6C0081F399 /* AccountsTableViewBackgroundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C9FC7022629E1200D921D6 /* AccountsTableViewBackgroundView.swift */; }; + 65ED4019235DEF6C0081F399 /* FetchRequestOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CAFCAE22BC8C35007694F0 /* FetchRequestOperation.swift */; }; + 65ED401A235DEF6C0081F399 /* HTMLMetadataDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8426119D1FCB6ED40086A189 /* HTMLMetadataDownloader.swift */; }; + 65ED401B235DEF6C0081F399 /* TimelineViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A976B1ED9EBC8007D329B /* TimelineViewController.swift */; }; + 65ED401C235DEF6C0081F399 /* FaviconGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F76227716200050506E /* FaviconGenerator.swift */; }; + 65ED401D235DEF6C0081F399 /* RefreshInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCE4226F4DFA0010922C /* RefreshInterval.swift */; }; + 65ED401E235DEF6C0081F399 /* TimelineCellData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97711ED9EC04007D329B /* TimelineCellData.swift */; }; + 65ED401F235DEF6C0081F399 /* BuiltinSmartFeedInspectorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841ABA5F20145EC100980E11 /* BuiltinSmartFeedInspectorViewController.swift */; }; + 65ED4020235DEF6C0081F399 /* AppDelegate+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5E4CC53202C1361009B4FFC /* AppDelegate+Scriptability.swift */; }; + 65ED4021235DEF6C0081F399 /* NNW3Document.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518651AB23555EB20078E021 /* NNW3Document.swift */; }; + 65ED4022235DEF6C0081F399 /* ScriptingObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F4EDB4200744A700B9E363 /* ScriptingObject.swift */; }; + 65ED4023235DEF6C0081F399 /* Folder+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F4EDB820074D7C00B9E363 /* Folder+Scriptability.swift */; }; + 65ED4024235DEF6C0081F399 /* TimelineCellLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97721ED9EC04007D329B /* TimelineCellLayout.swift */; }; + 65ED4025235DEF6C0081F399 /* DetailWebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E8E0EA202F693600562D8F /* DetailWebView.swift */; }; + 65ED4026235DEF6C0081F399 /* TimelineTableRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97691ED9EBC8007D329B /* TimelineTableRowView.swift */; }; + 65ED4027235DEF6C0081F399 /* UnreadIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97751ED9EC04007D329B /* UnreadIndicatorView.swift */; }; + 65ED4028235DEF6C0081F399 /* ExtractedArticle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51FA73A62332BE880090D516 /* ExtractedArticle.swift */; }; + 65ED4029235DEF6C0081F399 /* DeleteCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B99C9C1FAE83C600ECDEDB /* DeleteCommand.swift */; }; + 65ED402A235DEF6C0081F399 /* AddFeedWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97521ED9EAC0007D329B /* AddFeedWindowController.swift */; }; + 65ED402B235DEF6C0081F399 /* ImportOPMLWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA3E227A37EC00D19003 /* ImportOPMLWindowController.swift */; }; + 65ED402C235DEF6C0081F399 /* TimelineTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A976A1ED9EBC8007D329B /* TimelineTableView.swift */; }; + 65ED402D235DEF6C0081F399 /* DetailStatusBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D52E941FE588BB00D14F5B /* DetailStatusBarView.swift */; }; + 65ED402E235DEF6C0081F399 /* MainWindowController+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5E4CC63202C1AC1009B4FFC /* MainWindowController+Scriptability.swift */; }; + 65ED402F235DEF6C0081F399 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C9FC6E22629E1200D921D6 /* PreferencesWindowController.swift */; }; + 65ED4030235DEF6C0081F399 /* SmallIconProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84411E701FE5FBFA004B527F /* SmallIconProvider.swift */; }; + 65ED4031235DEF6C0081F399 /* ArticleExtractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51FA73A32332BE110090D516 /* ArticleExtractor.swift */; }; + 65ED4032235DEF6C0081F399 /* FetchRequestQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CAFCA322BC8C08007694F0 /* FetchRequestQueue.swift */; }; + 65ED4033235DEF6C0081F399 /* SidebarKeyboardDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844B5B581FE9FE4F00C7C76A /* SidebarKeyboardDelegate.swift */; }; + 65ED4034235DEF6C0081F399 /* AccountsPreferencesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C9FC7222629E1200D921D6 /* AccountsPreferencesViewController.swift */; }; + 65ED4035235DEF6C0081F399 /* FolderTreeMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EC114B2149FE3300B296E3 /* FolderTreeMenu.swift */; }; + 65ED4036235DEF6C0081F399 /* NNW3ImportController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849ADEE02359817D000E1B81 /* NNW3ImportController.swift */; }; + 65ED4037235DEF6C0081F399 /* FolderTreeControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97A11ED9F180007D329B /* FolderTreeControllerDelegate.swift */; }; + 65ED4038235DEF6C0081F399 /* RSImage-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51126DA3225FDE2F00722696 /* RSImage-Extensions.swift */; }; + 65ED4039235DEF6C0081F399 /* SingleFaviconDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845A29081FC74B8E007B49E3 /* SingleFaviconDownloader.swift */; }; + 65ED403A235DEF6C0081F399 /* Feed+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F4EDB620074D6500B9E363 /* Feed+Scriptability.swift */; }; + 65ED403B235DEF6C0081F399 /* AuthorAvatarDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E850851FCB60CE0072EA88 /* AuthorAvatarDownloader.swift */; }; + 65ED403C235DEF6C0081F399 /* SingleLineTextFieldSizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E185B2203B74E500F69BFA /* SingleLineTextFieldSizer.swift */; }; + 65ED403D235DEF6C0081F399 /* TimelineTableCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97741ED9EC04007D329B /* TimelineTableCellView.swift */; }; + 65ED403E235DEF6C0081F399 /* TimelineCellAppearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97701ED9EC04007D329B /* TimelineCellAppearance.swift */; }; + 65ED403F235DEF6C0081F399 /* ArticleRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A977D1ED9EC42007D329B /* ArticleRenderer.swift */; }; + 65ED4040235DEF6C0081F399 /* GeneralPrefencesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C9FC6D22629E1200D921D6 /* GeneralPrefencesViewController.swift */; }; + 65ED4043235DEF6C0081F399 /* RSWeb.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37F9F20DD8D0500CA8CF5 /* RSWeb.framework */; }; + 65ED4044235DEF6C0081F399 /* RSDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37FC020DD8E0C00CA8CF5 /* RSDatabase.framework */; }; + 65ED4045235DEF6C0081F399 /* RSTree.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37F9520DD8CFE00CA8CF5 /* RSTree.framework */; }; + 65ED4046235DEF6C0081F399 /* ArticlesDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8407167F2262A61100344432 /* ArticlesDatabase.framework */; }; + 65ED4047235DEF6C0081F399 /* RSParser.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37F8C20DD8CF800CA8CF5 /* RSParser.framework */; }; + 65ED4048235DEF6C0081F399 /* Account.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8407166A2262A60D00344432 /* Account.framework */; }; + 65ED4049235DEF6C0081F399 /* Articles.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 840716732262A60F00344432 /* Articles.framework */; }; + 65ED404A235DEF6C0081F399 /* RSCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37F8120DD8CF200CA8CF5 /* RSCore.framework */; }; + 65ED404B235DEF6C0081F399 /* SyncDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51554C01228B6EB50055115A /* SyncDatabase.framework */; }; + 65ED404E235DEF6C0081F399 /* NNW3OpenPanelAccessoryView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 849ADEE523598189000E1B81 /* NNW3OpenPanelAccessoryView.xib */; }; + 65ED404F235DEF6C0081F399 /* GlobalKeyboardShortcuts.plist in Resources */ = {isa = PBXBuildFile; fileRef = 844B5B641FEA11F200C7C76A /* GlobalKeyboardShortcuts.plist */; }; + 65ED4050235DEF6C0081F399 /* DetailKeyboardShortcuts.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5127B237222B4849006D641D /* DetailKeyboardShortcuts.plist */; }; + 65ED4051235DEF6C0081F399 /* TimelineKeyboardShortcuts.plist in Resources */ = {isa = PBXBuildFile; fileRef = 845479871FEB77C000AD8B59 /* TimelineKeyboardShortcuts.plist */; }; + 65ED4052235DEF6C0081F399 /* template.html in Resources */ = {isa = PBXBuildFile; fileRef = 848362FE2262A30E00DA1D35 /* template.html */; }; + 65ED4053235DEF6C0081F399 /* AccountsFeedlyWeb.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9EA33BB82318F8C10097B644 /* AccountsFeedlyWeb.xib */; }; + 65ED4054235DEF6C0081F399 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 848363062262A3DD00DA1D35 /* Main.storyboard */; }; + 65ED4055235DEF6C0081F399 /* AccountsAdd.xib in Resources */ = {isa = PBXBuildFile; fileRef = 51EF0F8D2279C9260050506E /* AccountsAdd.xib */; }; + 65ED4056235DEF6C0081F399 /* NetNewsWire.sdef in Resources */ = {isa = PBXBuildFile; fileRef = 84C9FC8A22629E8F00D921D6 /* NetNewsWire.sdef */; }; + 65ED4057235DEF6C0081F399 /* AccountsDetail.xib in Resources */ = {isa = PBXBuildFile; fileRef = 84C9FC7422629E1200D921D6 /* AccountsDetail.xib */; }; + 65ED4058235DEF6C0081F399 /* main.js in Resources */ = {isa = PBXBuildFile; fileRef = 517630032336215100E15FFF /* main.js */; }; + 65ED4059235DEF6C0081F399 /* AccountsAddLocal.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5144EA352279FC3D00D19003 /* AccountsAddLocal.xib */; }; + 65ED405A235DEF6C0081F399 /* main_mac.js in Resources */ = {isa = PBXBuildFile; fileRef = 5142194A2353C1CF00E07E2C /* main_mac.js */; }; + 65ED405B235DEF6C0081F399 /* KeyboardShortcuts.html in Resources */ = {isa = PBXBuildFile; fileRef = 84C9FC8722629E8F00D921D6 /* KeyboardShortcuts.html */; }; + 65ED405C235DEF6C0081F399 /* ImportOPMLSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5144EA3A227A379E00D19003 /* ImportOPMLSheet.xib */; }; + 65ED405D235DEF6C0081F399 /* SidebarKeyboardShortcuts.plist in Resources */ = {isa = PBXBuildFile; fileRef = 844B5B681FEA20DF00C7C76A /* SidebarKeyboardShortcuts.plist */; }; + 65ED405E235DEF6C0081F399 /* DefaultFeeds.opml in Resources */ = {isa = PBXBuildFile; fileRef = 84A3EE52223B667F00557320 /* DefaultFeeds.opml */; }; + 65ED405F235DEF6C0081F399 /* Preferences.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 84C9FC8022629E4800D921D6 /* Preferences.storyboard */; }; + 65ED4060235DEF6C0081F399 /* ExportOPMLSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5144EA3C227A37AF00D19003 /* ExportOPMLSheet.xib */; }; + 65ED4061235DEF6C0081F399 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 849C64671ED37A5D003D8FC0 /* Assets.xcassets */; }; + 65ED4062235DEF6C0081F399 /* styleSheet.css in Resources */ = {isa = PBXBuildFile; fileRef = 848362FC2262A30800DA1D35 /* styleSheet.css */; }; + 65ED4063235DEF6C0081F399 /* RenameSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 848363092262A3F000DA1D35 /* RenameSheet.xib */; }; + 65ED4064235DEF6C0081F399 /* AddFolderSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 848363032262A3CC00DA1D35 /* AddFolderSheet.xib */; }; + 65ED4065235DEF6C0081F399 /* AccountsFeedbin.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5144EA50227B8E4500D19003 /* AccountsFeedbin.xib */; }; + 65ED4066235DEF6C0081F399 /* TimelineTableView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8405DDA122168920008CE1BF /* TimelineTableView.xib */; }; + 65ED4067235DEF6C0081F399 /* page.html in Resources */ = {isa = PBXBuildFile; fileRef = B528F81D23333C7E00E735DD /* page.html */; }; + 65ED4068235DEF6C0081F399 /* MainWindow.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8483630C2262A3FE00DA1D35 /* MainWindow.storyboard */; }; + 65ED4069235DEF6C0081F399 /* AccountsReaderAPI.xib in Resources */ = {isa = PBXBuildFile; fileRef = 55E15BC1229D65A900D6602A /* AccountsReaderAPI.xib */; }; + 65ED406A235DEF6C0081F399 /* newsfoot.js in Resources */ = {isa = PBXBuildFile; fileRef = 49F40DEF2335B71000552BF4 /* newsfoot.js */; }; + 65ED406B235DEF6C0081F399 /* CrashReporterWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 84BAE64821CEDAF20046DB56 /* CrashReporterWindow.xib */; }; + 65ED406C235DEF6C0081F399 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 84C9FC8922629E8F00D921D6 /* Credits.rtf */; }; + 65ED406D235DEF6C0081F399 /* Inspector.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 84BBB12B20142A4700F054F5 /* Inspector.storyboard */; }; + 65ED406E235DEF6C0081F399 /* AddFeedSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 848363002262A3BC00DA1D35 /* AddFeedSheet.xib */; }; + 65ED4071235DEF6C0081F399 /* RSWeb.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37F9F20DD8D0500CA8CF5 /* RSWeb.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 65ED4072235DEF6C0081F399 /* RSDatabase.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37FC020DD8E0C00CA8CF5 /* RSDatabase.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 65ED4073235DEF6C0081F399 /* RSTree.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37F9520DD8CFE00CA8CF5 /* RSTree.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 65ED4074235DEF6C0081F399 /* ArticlesDatabase.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8407167F2262A61100344432 /* ArticlesDatabase.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 65ED4076235DEF6C0081F399 /* Account.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8407166A2262A60D00344432 /* Account.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 65ED4077235DEF6C0081F399 /* Articles.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 840716732262A60F00344432 /* Articles.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 65ED4078235DEF6C0081F399 /* RSParser.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37F8C20DD8CF800CA8CF5 /* RSParser.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 65ED4079235DEF6C0081F399 /* SyncDatabase.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 51554C01228B6EB50055115A /* SyncDatabase.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 65ED407A235DEF6C0081F399 /* RSCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 84C37F8120DD8CF200CA8CF5 /* RSCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 65ED407C235DEF6C0081F399 /* Subscribe to Feed.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 6581C73320CED60000F4AD34 /* Subscribe to Feed.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 65ED4092235DEF770081F399 /* SafariExtensionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6581C73920CED60100F4AD34 /* SafariExtensionViewController.swift */; }; + 65ED4093235DEF770081F399 /* SafariExtensionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6581C73720CED60100F4AD34 /* SafariExtensionHandler.swift */; }; + 65ED4096235DEF770081F399 /* ToolbarItemIcon.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 6581C74120CED60100F4AD34 /* ToolbarItemIcon.pdf */; }; + 65ED4097235DEF770081F399 /* SafariExtensionViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6581C73B20CED60100F4AD34 /* SafariExtensionViewController.xib */; }; + 65ED4098235DEF770081F399 /* netnewswire-subscribe-to-feed.js in Resources */ = {isa = PBXBuildFile; fileRef = 6581C73F20CED60100F4AD34 /* netnewswire-subscribe-to-feed.js */; }; + 65ED40A0235DEFF00081F399 /* container-migration.plist in Resources */ = {isa = PBXBuildFile; fileRef = 65ED409F235DEFF00081F399 /* container-migration.plist */; }; + 65ED40A1235DEFF00081F399 /* container-migration.plist in Resources */ = {isa = PBXBuildFile; fileRef = 65ED409F235DEFF00081F399 /* container-migration.plist */; }; + 65ED42D9235E740D0081F399 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65ED42B0235E71B40081F399 /* Sparkle.framework */; }; + 65ED42DA235E74230081F399 /* org.sparkle-project.Downloader.xpc in Embed XPC Services */ = {isa = PBXBuildFile; fileRef = 65ED42BC235E71B40081F399 /* org.sparkle-project.Downloader.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 65ED42DB235E74230081F399 /* org.sparkle-project.InstallerConnection.xpc in Embed XPC Services */ = {isa = PBXBuildFile; fileRef = 65ED42B8235E71B40081F399 /* org.sparkle-project.InstallerConnection.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 65ED42DC235E74230081F399 /* org.sparkle-project.InstallerLauncher.xpc in Embed XPC Services */ = {isa = PBXBuildFile; fileRef = 65ED42B6235E71B40081F399 /* org.sparkle-project.InstallerLauncher.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 65ED42DD235E74230081F399 /* org.sparkle-project.InstallerStatus.xpc in Embed XPC Services */ = {isa = PBXBuildFile; fileRef = 65ED42BA235E71B40081F399 /* org.sparkle-project.InstallerStatus.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 65ED42DE235E74230081F399 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65ED42B0235E71B40081F399 /* Sparkle.framework */; }; + 65ED42DF235E74230081F399 /* Sparkle.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 65ED42B0235E71B40081F399 /* Sparkle.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 8405DD8A2213E0E3008CE1BF /* DetailContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8405DD892213E0E3008CE1BF /* DetailContainerView.swift */; }; 8405DD9922153B6B008CE1BF /* TimelineContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8405DD9822153B6B008CE1BF /* TimelineContainerView.swift */; }; 8405DD9C22153BD7008CE1BF /* NSView-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8405DD9B22153BD7008CE1BF /* NSView-Extensions.swift */; }; @@ -310,7 +510,7 @@ 849A97761ED9EC04007D329B /* TimelineCellAppearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97701ED9EC04007D329B /* TimelineCellAppearance.swift */; }; 849A97771ED9EC04007D329B /* TimelineCellData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97711ED9EC04007D329B /* TimelineCellData.swift */; }; 849A97781ED9EC04007D329B /* TimelineCellLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97721ED9EC04007D329B /* TimelineCellLayout.swift */; }; - 849A97791ED9EC04007D329B /* TimelineStringFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97731ED9EC04007D329B /* TimelineStringFormatter.swift */; }; + 849A97791ED9EC04007D329B /* ArticleStringFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97731ED9EC04007D329B /* ArticleStringFormatter.swift */; }; 849A977A1ED9EC04007D329B /* TimelineTableCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97741ED9EC04007D329B /* TimelineTableCellView.swift */; }; 849A977B1ED9EC04007D329B /* UnreadIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97751ED9EC04007D329B /* UnreadIndicatorView.swift */; }; 849A977F1ED9EC42007D329B /* ArticleRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A977D1ED9EC42007D329B /* ArticleRenderer.swift */; }; @@ -321,6 +521,9 @@ 849A97981ED9EFAA007D329B /* Node-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97971ED9EFAA007D329B /* Node-Extensions.swift */; }; 849A979F1ED9F130007D329B /* SidebarCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A979E1ED9F130007D329B /* SidebarCell.swift */; }; 849A97A31ED9F180007D329B /* FolderTreeControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97A11ED9F180007D329B /* FolderTreeControllerDelegate.swift */; }; + 849ADEE42359817E000E1B81 /* NNW3ImportController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849ADEE02359817D000E1B81 /* NNW3ImportController.swift */; }; + 849ADEE623598189000E1B81 /* NNW3OpenPanelAccessoryView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 849ADEE523598189000E1B81 /* NNW3OpenPanelAccessoryView.xib */; }; + 849ADEE8235981A0000E1B81 /* NNW3OpenPanelAccessoryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849ADEE7235981A0000E1B81 /* NNW3OpenPanelAccessoryViewController.swift */; }; 849C64681ED37A5D003D8FC0 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 849C64671ED37A5D003D8FC0 /* Assets.xcassets */; }; 849EE70F203919360082A1EA /* AppAssets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849EE70E203919360082A1EA /* AppAssets.swift */; }; 849EE72120391F560082A1EA /* SharingServicePickerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849EE72020391F560082A1EA /* SharingServicePickerDelegate.swift */; }; @@ -399,8 +602,6 @@ 84F9EAF4213660A100CF2DE4 /* testGenericScript.applescript in Sources */ = {isa = PBXBuildFile; fileRef = 84F9EAE1213660A100CF2DE4 /* testGenericScript.applescript */; }; 84F9EAF5213660A100CF2DE4 /* establishMainWindowStartingState.applescript in Sources */ = {isa = PBXBuildFile; fileRef = 84F9EAE2213660A100CF2DE4 /* establishMainWindowStartingState.applescript */; }; 84F9EAF7213660A100CF2DE4 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 84F9EAE4213660A100CF2DE4 /* Info.plist */; }; - 84FB9A2F1EDCD6C4003D53B9 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84FB9A2D1EDCD6B8003D53B9 /* Sparkle.framework */; }; - 84FB9A301EDCD6C4003D53B9 /* Sparkle.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 84FB9A2D1EDCD6B8003D53B9 /* Sparkle.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 84FF69B11FC3793300DC198E /* FaviconURLFinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84FF69B01FC3793300DC198E /* FaviconURLFinder.swift */; }; 9EA33BB92318F8C10097B644 /* AccountsFeedlyWebWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EA33BB72318F8C10097B644 /* AccountsFeedlyWebWindowController.swift */; }; 9EA33BBA2318F8C10097B644 /* AccountsFeedlyWeb.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9EA33BB82318F8C10097B644 /* AccountsFeedlyWeb.xib */; }; @@ -417,7 +618,6 @@ D5F4EDB720074D6500B9E363 /* Feed+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F4EDB620074D6500B9E363 /* Feed+Scriptability.swift */; }; D5F4EDB920074D7C00B9E363 /* Folder+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F4EDB820074D7C00B9E363 /* Folder+Scriptability.swift */; }; DD82AB0A231003F6002269DF /* SharingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD82AB09231003F6002269DF /* SharingTests.swift */; }; - DF999FF722B5AEFA0064B687 /* SafariView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF999FF622B5AEFA0064B687 /* SafariView.swift */; }; FF3ABF13232599810074C542 /* ArticleSorterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF3ABF09232599450074C542 /* ArticleSorterTests.swift */; }; FF3ABF1523259DDB0074C542 /* ArticleSorter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF3ABF1423259DDB0074C542 /* ArticleSorter.swift */; }; FF3ABF162325AF5D0074C542 /* ArticleSorter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF3ABF1423259DDB0074C542 /* ArticleSorter.swift */; }; @@ -425,6 +625,13 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 5131463C235A7BBE00387FDC /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 849C64581ED37A5D003D8FC0 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 51314636235A7BBE00387FDC; + remoteInfo = "NetNewsWire iOS Intents Extension"; + }; 51554C00228B6EB50055115A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 51554BFC228B6EB50055115A /* SyncDatabase.xcodeproj */; @@ -467,6 +674,230 @@ remoteGlobalIDString = 848934F51F62484F00CEBD24; remoteInfo = Account; }; + 65ED3FA4235DEF6C0081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 84C37F7A20DD8CF200CA8CF5 /* RSCore.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 84CFF4F31AC3C69700CEA6C8; + remoteInfo = RSCore; + }; + 65ED3FA6235DEF6C0081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 84C37F9820DD8D0400CA8CF5 /* RSWeb.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 849C08B51E0CAC85006B03FA; + remoteInfo = RSWeb; + }; + 65ED3FA8235DEF6C0081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 84C37F8F20DD8CFD00CA8CF5 /* RSTree.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 842A0BE01CFCB9BC00BF746C; + remoteInfo = RSTree; + }; + 65ED3FAA235DEF6C0081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 84C37F8620DD8CF800CA8CF5 /* RSParser.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 84FF5F831EFA285800C15A01; + remoteInfo = RSParser; + }; + 65ED3FAC235DEF6C0081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 84C37FB920DD8E0C00CA8CF5 /* RSDatabase.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 84F22C541B52E0D9000060CE; + remoteInfo = RSDatabase; + }; + 65ED3FAE235DEF6C0081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 841D4D5E2106B3E100DD04E6 /* ArticlesDatabase.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 844BEE361F0AB3AA004AB7CD; + remoteInfo = ArticlesDatabase; + }; + 65ED3FB0235DEF6C0081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 841D4D542106B3D500DD04E6 /* Articles.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 844BEE5A1F0AB3C8004AB7CD; + remoteInfo = Articles; + }; + 65ED3FB2235DEF6C0081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 846E77301F6EF5D600A165E2 /* Account.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 848934F51F62484F00CEBD24; + remoteInfo = Account; + }; + 65ED3FB4235DEF6C0081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 51554BFC228B6EB50055115A /* SyncDatabase.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 51554BEA228B6E8F0055115A; + remoteInfo = SyncDatabase; + }; + 65ED41C4235E61550081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 849C64581ED37A5D003D8FC0 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 6581C73220CED60000F4AD34; + remoteInfo = "Subscribe to Feed"; + }; + 65ED41C6235E615E0081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 849C64581ED37A5D003D8FC0 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 65ED4090235DEF770081F399; + remoteInfo = "Subscribe to Feed MAS"; + }; + 65ED42AF235E71B40081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 65ED4299235E71B40081F399 /* Sparkle.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 8DC2EF5B0486A6940098B216; + remoteInfo = Sparkle; + }; + 65ED42B1235E71B40081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 65ED4299235E71B40081F399 /* Sparkle.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 72A5D59C1D6927730009E5AC; + remoteInfo = SparkleCore; + }; + 65ED42B3235E71B40081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 65ED4299235E71B40081F399 /* Sparkle.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 72B398D21D3D879300EE297F; + remoteInfo = Autoupdate; + }; + 65ED42B5235E71B40081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 65ED4299235E71B40081F399 /* Sparkle.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 726E07AD1CAF08D6001A286B; + remoteInfo = SparkleInstallerLauncher; + }; + 65ED42B7235E71B40081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 65ED4299235E71B40081F399 /* Sparkle.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 724BB36C1D31D0B7005D534A; + remoteInfo = SparkleInstallerConnection; + }; + 65ED42B9235E71B40081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 65ED4299235E71B40081F399 /* Sparkle.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 724BB3931D333832005D534A; + remoteInfo = SparkleInstallerStatus; + }; + 65ED42BB235E71B40081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 65ED4299235E71B40081F399 /* Sparkle.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 726E07EF1CAF37BD001A286B; + remoteInfo = SparkleDownloader; + }; + 65ED42BD235E71B40081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 65ED4299235E71B40081F399 /* Sparkle.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 61B5F90209C4CEE200B25A18; + remoteInfo = "Sparkle Test App"; + }; + 65ED42BF235E71B40081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 65ED4299235E71B40081F399 /* Sparkle.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 726E4A161C86C88F00C57C6A; + remoteInfo = TestAppHelper; + }; + 65ED42C1235E71B40081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 65ED4299235E71B40081F399 /* Sparkle.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 612279D90DB5470200AB99EA; + remoteInfo = "Sparkle Unit Tests"; + }; + 65ED42C3235E71B40081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 65ED4299235E71B40081F399 /* Sparkle.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 5D06E8D00FD68C7C005AE3F6; + remoteInfo = BinaryDelta; + }; + 65ED42C5235E71B40081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 65ED4299235E71B40081F399 /* Sparkle.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 72D9549E1CBB415B006F28BD; + remoteInfo = "sparkle-cli"; + }; + 65ED42C7235E71B40081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 65ED4299235E71B40081F399 /* Sparkle.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 721C24451CB753E6005440CB; + remoteInfo = "Installer Progress"; + }; + 65ED42C9235E71B40081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 65ED4299235E71B40081F399 /* Sparkle.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 726B2B5D1C645FC900388755; + remoteInfo = "UI Tests"; + }; + 65ED42CB235E71B40081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 65ED4299235E71B40081F399 /* Sparkle.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 7205C43E1E13049400E370AE; + remoteInfo = generate_appcast; + }; + 65ED42CD235E71B40081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 65ED4299235E71B40081F399 /* Sparkle.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = EA1E280F22B64522004AA304; + remoteInfo = bsdiff; + }; + 65ED42CF235E71F60081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 65ED4299235E71B40081F399 /* Sparkle.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 8DC2EF4F0486A6940098B216; + remoteInfo = Sparkle; + }; + 65ED42D1235E72000081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 65ED4299235E71B40081F399 /* Sparkle.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 726E07EE1CAF37BD001A286B; + remoteInfo = SparkleDownloader; + }; + 65ED42D3235E72000081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 65ED4299235E71B40081F399 /* Sparkle.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 724BB36B1D31D0B7005D534A; + remoteInfo = SparkleInstallerConnection; + }; + 65ED42D5235E72000081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 65ED4299235E71B40081F399 /* Sparkle.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 726E07AC1CAF08D6001A286B; + remoteInfo = SparkleInstallerLauncher; + }; + 65ED42D7235E72000081F399 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 65ED4299235E71B40081F399 /* Sparkle.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 724BB3921D333832005D534A; + remoteInfo = SparkleInstallerStatus; + }; 840716692262A60D00344432 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 846E77301F6EF5D600A165E2 /* Account.xcodeproj */; @@ -652,29 +1083,11 @@ dstSubfolderSpec = 13; files = ( 513C5CF0232571C2003D4054 /* NetNewsWire iOS Share Extension.appex in Embed App Extensions */, + 5131463E235A7BBE00387FDC /* NetNewsWire iOS Intents Extension.appex in Embed App Extensions */, ); name = "Embed App Extensions"; runOnlyForDeploymentPostprocessing = 0; }; - 513C5CFF2325749A003D4054 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 513C5D0B232574D2003D4054 /* RSWeb.framework in Embed Frameworks */, - 513C5D0D232574DA003D4054 /* RSTree.framework in Embed Frameworks */, - 513C5CFE2325749A003D4054 /* Account.framework in Embed Frameworks */, - 513C5D01232574AF003D4054 /* Articles.framework in Embed Frameworks */, - 513C5D09232574C6003D4054 /* RSParser.framework in Embed Frameworks */, - 513C5D07232574C0003D4054 /* RSDatabase.framework in Embed Frameworks */, - 513C5D0F232574E4003D4054 /* SyncDatabase.framework in Embed Frameworks */, - 513C5D05232574B9003D4054 /* RSCore.framework in Embed Frameworks */, - 513C5D03232574B4003D4054 /* ArticlesDatabase.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; 51C451DF2264C7F200C03939 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -705,6 +1118,50 @@ name = "Embed App Extensions"; runOnlyForDeploymentPostprocessing = 0; }; + 65ED4070235DEF6C0081F399 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 65ED4071235DEF6C0081F399 /* RSWeb.framework in Embed Frameworks */, + 65ED4072235DEF6C0081F399 /* RSDatabase.framework in Embed Frameworks */, + 65ED4073235DEF6C0081F399 /* RSTree.framework in Embed Frameworks */, + 65ED4074235DEF6C0081F399 /* ArticlesDatabase.framework in Embed Frameworks */, + 65ED4076235DEF6C0081F399 /* Account.framework in Embed Frameworks */, + 65ED4077235DEF6C0081F399 /* Articles.framework in Embed Frameworks */, + 65ED4078235DEF6C0081F399 /* RSParser.framework in Embed Frameworks */, + 65ED4079235DEF6C0081F399 /* SyncDatabase.framework in Embed Frameworks */, + 65ED407A235DEF6C0081F399 /* RSCore.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; + 65ED407B235DEF6C0081F399 /* Embed App Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + 65ED407C235DEF6C0081F399 /* Subscribe to Feed.appex in Embed App Extensions */, + ); + name = "Embed App Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; + 65ED42E0235E74240081F399 /* Embed XPC Services */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "$(CONTENTS_FOLDER_PATH)/XPCServices"; + dstSubfolderSpec = 16; + files = ( + 65ED42DD235E74230081F399 /* org.sparkle-project.InstallerStatus.xpc in Embed XPC Services */, + 65ED42DB235E74230081F399 /* org.sparkle-project.InstallerConnection.xpc in Embed XPC Services */, + 65ED42DC235E74230081F399 /* org.sparkle-project.InstallerLauncher.xpc in Embed XPC Services */, + 65ED42DA235E74230081F399 /* org.sparkle-project.Downloader.xpc in Embed XPC Services */, + ); + name = "Embed XPC Services"; + runOnlyForDeploymentPostprocessing = 0; + }; 84B06F681ED37B9000F0B54B /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -715,10 +1172,10 @@ 84C37FC620DD8E1D00CA8CF5 /* RSDatabase.framework in Embed Frameworks */, 84C37FAE20DD8D9900CA8CF5 /* RSTree.framework in Embed Frameworks */, 51C451AA226377C200C03939 /* ArticlesDatabase.framework in Embed Frameworks */, - 84FB9A301EDCD6C4003D53B9 /* Sparkle.framework in Embed Frameworks */, 51C451BE226377D000C03939 /* Account.framework in Embed Frameworks */, 51C451BA226377C900C03939 /* Articles.framework in Embed Frameworks */, 84C37FB620DD8DBB00CA8CF5 /* RSParser.framework in Embed Frameworks */, + 65ED42DF235E74230081F399 /* Sparkle.framework in Embed Frameworks */, 51554C25228B71910055115A /* SyncDatabase.framework in Embed Frameworks */, 84C37FA620DD8D8400CA8CF5 /* RSCore.framework in Embed Frameworks */, ); @@ -740,10 +1197,6 @@ 3B29BC5F233EA81F002A346D /* AccountsFeedWranglerWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountsFeedWranglerWindowController.swift; sourceTree = ""; }; 3B29BC68233EA81F002A346D /* AccountsFeedWrangler.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AccountsFeedWrangler.xib; sourceTree = ""; }; 49F40DEF2335B71000552BF4 /* newsfoot.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = newsfoot.js; sourceTree = ""; }; - 510D707322B028E1004E8F65 /* SettingsAddAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsAddAccountView.swift; sourceTree = ""; }; - 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 = ""; }; @@ -756,12 +1209,15 @@ 5127B237222B4849006D641D /* DetailKeyboardShortcuts.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = DetailKeyboardShortcuts.plist; sourceTree = ""; }; 512E08F722688F7C00BDCFDD /* MasterFeedTableViewSectionHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MasterFeedTableViewSectionHeader.swift; sourceTree = ""; }; 512E092B2268B25500BDCFDD /* UISplitViewController-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UISplitViewController-Extensions.swift"; sourceTree = ""; }; - 51322854232EED360033D4ED /* VibrantSelectAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VibrantSelectAction.swift; sourceTree = ""; }; - 51322858232FDDB80033D4ED /* VibrantButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VibrantButtonStyle.swift; sourceTree = ""; }; - 5132285A232FF2C40033D4ED /* SettingsRefreshSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsRefreshSelectionView.swift; sourceTree = ""; }; + 51314617235A797400387FDC /* NetNewsWire_iOSintentextension_target.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = NetNewsWire_iOSintentextension_target.xcconfig; sourceTree = ""; }; + 51314637235A7BBE00387FDC /* NetNewsWire iOS Intents Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "NetNewsWire iOS Intents Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; + 51314665235A7E4600387FDC /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 51314666235A7E4600387FDC /* IntentHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntentHandler.swift; sourceTree = ""; }; + 51314684235A7EB900387FDC /* NetNewsWire_iOS_IntentsExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NetNewsWire_iOS_IntentsExtension.entitlements; sourceTree = ""; }; + 513146B1235A81A400387FDC /* AddFeedIntentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddFeedIntentHandler.swift; sourceTree = ""; }; + 51314706235C41FC00387FDC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; name = Base; path = Base.lproj/Intents.intentdefinition; sourceTree = ""; }; + 51314714235C420900387FDC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Intents.strings; sourceTree = ""; }; 513228F2233037620033D4ED /* Reachability.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Reachability.swift; sourceTree = ""; }; - 513229302330523F0033D4ED /* SettingsAttributedStringView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsAttributedStringView.swift; sourceTree = ""; }; - 5132293A23305D4C0033D4ED /* SettingsAboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsAboutView.swift; sourceTree = ""; }; 513C5CE6232571C2003D4054 /* NetNewsWire iOS Share Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "NetNewsWire iOS Share Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; 513C5CE8232571C2003D4054 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = ""; }; 513C5CEB232571C2003D4054 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = ""; }; @@ -787,6 +1243,9 @@ 515D4FCB2325815A00EE1167 /* SafariExt.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = SafariExt.js; sourceTree = ""; }; 515D4FCD2325909200EE1167 /* NetNewsWire_iOS_ShareExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NetNewsWire_iOS_ShareExtension.entitlements; sourceTree = ""; }; 515D4FCE2325B3D000EE1167 /* NetNewsWire_iOSshareextension_target.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = NetNewsWire_iOSshareextension_target.xcconfig; sourceTree = ""; }; + 516A091D23609A3600EAE89B /* SettingsAccountTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SettingsAccountTableViewCell.xib; sourceTree = ""; }; + 516A09382360A2AE00EAE89B /* SettingsAccountTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsAccountTableViewCell.swift; sourceTree = ""; }; + 516A093A2360A4A000EAE89B /* SettingsTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SettingsTableViewCell.xib; 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 /* ArticleViewControllerWebViewProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleViewControllerWebViewProvider.swift; sourceTree = ""; }; @@ -796,24 +1255,25 @@ 5183CCDE226F1FCC0010922C /* UINavigationController+Progress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UINavigationController+Progress.swift"; sourceTree = ""; }; 5183CCE4226F4DFA0010922C /* RefreshInterval.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshInterval.swift; sourceTree = ""; }; 5183CCE7226F68D90010922C /* AccountRefreshTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountRefreshTimer.swift; sourceTree = ""; }; - 518651A523555EB20078E021 /* ImportNNW3WindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImportNNW3WindowController.swift; sourceTree = ""; }; - 518651A623555EB20078E021 /* NNW3PlistConverter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NNW3PlistConverter.swift; sourceTree = ""; }; - 518651A723555EB20078E021 /* ImportNNW3Sheet.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ImportNNW3Sheet.xib; sourceTree = ""; }; - 518651A823555EB20078E021 /* NNW3Entry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NNW3Entry.swift; sourceTree = ""; }; - 518651A923555EB20078E021 /* NNW3FeedsImporter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NNW3FeedsImporter.swift; sourceTree = ""; }; - 518651AA23555EB20078E021 /* NNW3Feed.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NNW3Feed.swift; sourceTree = ""; }; 518651AB23555EB20078E021 /* NNW3Document.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NNW3Document.swift; sourceTree = ""; }; 518651D9235621840078E021 /* ImageTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageTransition.swift; sourceTree = ""; }; + 5186A634235EF3A800C97195 /* VibrantLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VibrantLabel.swift; sourceTree = ""; }; 518B2ED22351B3DD00400001 /* NetNewsWire-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "NetNewsWire-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 518B2EE92351B4C200400001 /* NetNewsWire_iOSTests_target.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = NetNewsWire_iOSTests_target.xcconfig; sourceTree = ""; }; 51934CC1230F5963006127BE /* ThemedNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemedNavigationController.swift; sourceTree = ""; }; 51934CCD2310792F006127BE /* ActivityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityManager.swift; sourceTree = ""; }; 51938DF1231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchTimelineFeedDelegate.swift; sourceTree = ""; }; - 5194B5ED22B6965300144881 /* SettingsSubscriptionsImportDocumentPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsSubscriptionsImportDocumentPickerView.swift; sourceTree = ""; }; - 5194B5F122B69FCC00144881 /* SettingsSubscriptionsExportDocumentPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsSubscriptionsExportDocumentPickerView.swift; sourceTree = ""; }; 519B8D322143397200FA689C /* SharingServiceDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharingServiceDelegate.swift; sourceTree = ""; }; 519D740523243CC0008BB345 /* RefreshInterval-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RefreshInterval-Extensions.swift"; sourceTree = ""; }; 519E743422C663F900A78E47 /* SceneDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 51A1698D235E10D600EB091F /* RefreshIntervalViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RefreshIntervalViewController.swift; sourceTree = ""; }; + 51A1698F235E10D600EB091F /* AddLocalAccountViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddLocalAccountViewController.swift; sourceTree = ""; }; + 51A16990235E10D600EB091F /* Settings.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Settings.storyboard; sourceTree = ""; }; + 51A16991235E10D600EB091F /* DetailAccountViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailAccountViewController.swift; sourceTree = ""; }; + 51A16992235E10D600EB091F /* AddAccountViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddAccountViewController.swift; sourceTree = ""; }; + 51A16993235E10D600EB091F /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; }; + 51A16995235E10D600EB091F /* AboutViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = ""; }; + 51A16996235E10D700EB091F /* FeedbinAccountViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedbinAccountViewController.swift; sourceTree = ""; }; 51AF460D232488C6001742EF /* Account-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Account-Extensions.swift"; sourceTree = ""; }; 51B62E67233186730085F949 /* MasterTimelineAvatarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MasterTimelineAvatarView.swift; sourceTree = ""; }; 51BB7C262335A8E5008E8144 /* ArticleActivityItemSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleActivityItemSource.swift; sourceTree = ""; }; @@ -842,9 +1302,6 @@ 51CC9B3D231720B2000E842F /* MasterFeedDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MasterFeedDataSource.swift; sourceTree = ""; }; 51D6A5BB23199C85001C27D8 /* MasterTimelineDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MasterTimelineDataSource.swift; sourceTree = ""; }; 51D87EE02311D34700E63F03 /* ActivityType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityType.swift; sourceTree = ""; }; - 51E149B2234D82E40004F7A5 /* PasswordField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordField.swift; sourceTree = ""; }; - 51E149BF234D839E0004F7A5 /* ShowHidePasswordView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ShowHidePasswordView.xib; sourceTree = ""; }; - 51E149C1234D852F0004F7A5 /* ShowHidePasswordView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShowHidePasswordView.swift; sourceTree = ""; }; 51E3EB32229AB02C00645299 /* ErrorHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorHandler.swift; sourceTree = ""; }; 51E3EB3C229AB08300645299 /* ErrorHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorHandler.swift; sourceTree = ""; }; 51E595A4228CC36500FCC42B /* ArticleStatusSyncTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleStatusSyncTimer.swift; sourceTree = ""; }; @@ -858,8 +1315,6 @@ 51EF0F8D2279C9260050506E /* AccountsAdd.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AccountsAdd.xib; sourceTree = ""; }; 51EF0F8F2279C9500050506E /* AccountsAddViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsAddViewController.swift; sourceTree = ""; }; 51EF0F912279CA620050506E /* AccountsAddTableCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsAddTableCellView.swift; sourceTree = ""; }; - 51F35D0822AFD4760003CE1B /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; - 51F772EC22B2789B0087D9D1 /* SettingsDetailAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsDetailAccountView.swift; sourceTree = ""; }; 51F85BEA22724CB600C787DC /* About.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = About.rtf; sourceTree = ""; }; 51F85BEC227251DF00C787DC /* Acknowledgments.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = Acknowledgments.rtf; sourceTree = ""; }; 51F85BEE2272520B00C787DC /* Thanks.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = Thanks.rtf; sourceTree = ""; }; @@ -877,10 +1332,10 @@ 51FD40BD2341555600880194 /* UIImage-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage-Extensions.swift"; sourceTree = ""; }; 51FD413A2342BD0500880194 /* MasterTimelineUnreadCountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MasterTimelineUnreadCountView.swift; sourceTree = ""; }; 51FE10022345529D0056195D /* UserNotificationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserNotificationManager.swift; sourceTree = ""; }; - 557EE1A522B6F4E1004206FA /* SettingsReaderAPIAccountView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsReaderAPIAccountView.swift; sourceTree = ""; }; + 51FFF0C3235EE8E5002762AA /* VibrantButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VibrantButton.swift; sourceTree = ""; }; 55E15BC1229D65A900D6602A /* AccountsReaderAPI.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AccountsReaderAPI.xib; sourceTree = ""; }; 55E15BCA229D65A900D6602A /* AccountsReaderAPIWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountsReaderAPIWindowController.swift; sourceTree = ""; }; - 5F323808231DF9F000706F6B /* NNWTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NNWTableViewCell.swift; sourceTree = ""; }; + 5F323808231DF9F000706F6B /* VibrantTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VibrantTableViewCell.swift; sourceTree = ""; }; 6543108B2322D90900658221 /* common */ = {isa = PBXFileReference; lastKnownFileType = folder; path = common; sourceTree = ""; }; 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; }; @@ -891,6 +1346,12 @@ 6581C73F20CED60100F4AD34 /* netnewswire-subscribe-to-feed.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = "netnewswire-subscribe-to-feed.js"; sourceTree = ""; }; 6581C74120CED60100F4AD34 /* ToolbarItemIcon.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = ToolbarItemIcon.pdf; sourceTree = ""; }; 6581C74320CED60100F4AD34 /* Subscribe_to_Feed.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Subscribe_to_Feed.entitlements; sourceTree = ""; }; + 65ED4083235DEF6C0081F399 /* NetNewsWire.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = NetNewsWire.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 65ED409D235DEF770081F399 /* Subscribe to Feed.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Subscribe to Feed.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; + 65ED409F235DEFF00081F399 /* container-migration.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "container-migration.plist"; sourceTree = ""; }; + 65ED40F2235DF5E00081F399 /* NetNewsWire_macapp_target_macappstore.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = NetNewsWire_macapp_target_macappstore.xcconfig; sourceTree = ""; }; + 65ED4186235E045B0081F399 /* NetNewsWire_safariextension_target_macappstore.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = NetNewsWire_safariextension_target_macappstore.xcconfig; sourceTree = ""; }; + 65ED4299235E71B40081F399 /* Sparkle.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Sparkle.xcodeproj; path = submodules/Sparkle/Sparkle.xcodeproj; sourceTree = SOURCE_ROOT; }; 8405DD892213E0E3008CE1BF /* DetailContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailContainerView.swift; sourceTree = ""; }; 8405DD9822153B6B008CE1BF /* TimelineContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineContainerView.swift; sourceTree = ""; }; 8405DD9B22153BD7008CE1BF /* NSView-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSView-Extensions.swift"; sourceTree = ""; }; @@ -962,7 +1423,7 @@ 849A97701ED9EC04007D329B /* TimelineCellAppearance.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimelineCellAppearance.swift; sourceTree = ""; }; 849A97711ED9EC04007D329B /* TimelineCellData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimelineCellData.swift; sourceTree = ""; }; 849A97721ED9EC04007D329B /* TimelineCellLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimelineCellLayout.swift; sourceTree = ""; }; - 849A97731ED9EC04007D329B /* TimelineStringFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimelineStringFormatter.swift; sourceTree = ""; }; + 849A97731ED9EC04007D329B /* ArticleStringFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArticleStringFormatter.swift; sourceTree = ""; }; 849A97741ED9EC04007D329B /* TimelineTableCellView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimelineTableCellView.swift; sourceTree = ""; }; 849A97751ED9EC04007D329B /* UnreadIndicatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnreadIndicatorView.swift; sourceTree = ""; }; 849A977D1ED9EC42007D329B /* ArticleRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArticleRenderer.swift; sourceTree = ""; }; @@ -973,6 +1434,9 @@ 849A97971ED9EFAA007D329B /* Node-Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Node-Extensions.swift"; sourceTree = ""; }; 849A979E1ED9F130007D329B /* SidebarCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SidebarCell.swift; sourceTree = ""; }; 849A97A11ED9F180007D329B /* FolderTreeControllerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FolderTreeControllerDelegate.swift; sourceTree = ""; }; + 849ADEE02359817D000E1B81 /* NNW3ImportController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NNW3ImportController.swift; sourceTree = ""; }; + 849ADEE523598189000E1B81 /* NNW3OpenPanelAccessoryView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NNW3OpenPanelAccessoryView.xib; sourceTree = ""; }; + 849ADEE7235981A0000E1B81 /* NNW3OpenPanelAccessoryViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NNW3OpenPanelAccessoryViewController.swift; sourceTree = ""; }; 849C64601ED37A5D003D8FC0 /* NetNewsWire.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = NetNewsWire.app; sourceTree = BUILT_PRODUCTS_DIR; }; 849C64671ED37A5D003D8FC0 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 849C64711ED37A5D003D8FC0 /* NetNewsWireTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NetNewsWireTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1050,7 +1514,6 @@ 84F9EAE1213660A100CF2DE4 /* testGenericScript.applescript */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.applescript; path = testGenericScript.applescript; sourceTree = ""; }; 84F9EAE2213660A100CF2DE4 /* establishMainWindowStartingState.applescript */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.applescript; path = establishMainWindowStartingState.applescript; sourceTree = ""; }; 84F9EAE4213660A100CF2DE4 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 84FB9A2D1EDCD6B8003D53B9 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sparkle.framework; path = Frameworks/Vendor/Sparkle.framework; sourceTree = SOURCE_ROOT; }; 84FF69B01FC3793300DC198E /* FaviconURLFinder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FaviconURLFinder.swift; sourceTree = ""; }; 9EA33BB72318F8C10097B644 /* AccountsFeedlyWebWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsFeedlyWebWindowController.swift; sourceTree = ""; }; 9EA33BB82318F8C10097B644 /* AccountsFeedlyWeb.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AccountsFeedlyWeb.xib; sourceTree = ""; }; @@ -1075,13 +1538,28 @@ D5F4EDB620074D6500B9E363 /* Feed+Scriptability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Feed+Scriptability.swift"; sourceTree = ""; }; D5F4EDB820074D7C00B9E363 /* Folder+Scriptability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Folder+Scriptability.swift"; sourceTree = ""; }; DD82AB09231003F6002269DF /* SharingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SharingTests.swift; sourceTree = ""; }; - DF999FF622B5AEFA0064B687 /* SafariView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariView.swift; sourceTree = ""; }; FF3ABF09232599450074C542 /* ArticleSorterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleSorterTests.swift; sourceTree = ""; }; FF3ABF1423259DDB0074C542 /* ArticleSorter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleSorter.swift; sourceTree = ""; }; FFD43E372340F320009E5CA3 /* UndoAvailableAlertController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UndoAvailableAlertController.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 51314634235A7BBE00387FDC /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 513146B6235A8FD000387FDC /* RSDatabase.framework in Frameworks */, + 513146BC235A8FD000387FDC /* RSWeb.framework in Frameworks */, + 513146C3235A8FDB00387FDC /* ArticlesDatabase.framework in Frameworks */, + 513146BF235A8FDB00387FDC /* Account.framework in Frameworks */, + 513146C1235A8FDB00387FDC /* Articles.framework in Frameworks */, + 513146BA235A8FD000387FDC /* RSTree.framework in Frameworks */, + 513146C5235A8FDB00387FDC /* SyncDatabase.framework in Frameworks */, + 513146B4235A8FD000387FDC /* RSCore.framework in Frameworks */, + 513146B8235A8FD000387FDC /* RSParser.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 513C5CE3232571C2003D4054 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -1112,6 +1590,29 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 65ED4042235DEF6C0081F399 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 65ED4043235DEF6C0081F399 /* RSWeb.framework in Frameworks */, + 65ED4044235DEF6C0081F399 /* RSDatabase.framework in Frameworks */, + 65ED4045235DEF6C0081F399 /* RSTree.framework in Frameworks */, + 65ED4046235DEF6C0081F399 /* ArticlesDatabase.framework in Frameworks */, + 65ED4047235DEF6C0081F399 /* RSParser.framework in Frameworks */, + 65ED4048235DEF6C0081F399 /* Account.framework in Frameworks */, + 65ED4049235DEF6C0081F399 /* Articles.framework in Frameworks */, + 65ED404A235DEF6C0081F399 /* RSCore.framework in Frameworks */, + 65ED404B235DEF6C0081F399 /* SyncDatabase.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 65ED4094235DEF770081F399 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 840D61792029031C009BC708 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -1133,6 +1634,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 65ED42DE235E74230081F399 /* Sparkle.framework in Frameworks */, + 65ED42D9235E740D0081F399 /* Sparkle.framework in Frameworks */, 84C37FA920DD8D9000CA8CF5 /* RSWeb.framework in Frameworks */, 84C37FC520DD8E1D00CA8CF5 /* RSDatabase.framework in Frameworks */, 84C37FAD20DD8D9900CA8CF5 /* RSTree.framework in Frameworks */, @@ -1142,7 +1645,6 @@ 51C451B9226377C900C03939 /* Articles.framework in Frameworks */, 84C37FA520DD8D8400CA8CF5 /* RSCore.framework in Frameworks */, 51554C24228B71910055115A /* SyncDatabase.framework in Frameworks */, - 84FB9A2F1EDCD6C4003D53B9 /* Sparkle.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1193,6 +1695,25 @@ path = Tree; sourceTree = ""; }; + 513145F9235A55A700387FDC /* Intents */ = { + isa = PBXGroup; + children = ( + 51314707235C41FC00387FDC /* Intents.intentdefinition */, + 513146B1235A81A400387FDC /* AddFeedIntentHandler.swift */, + ); + path = Intents; + sourceTree = ""; + }; + 51314643235A7C2300387FDC /* IntentsExtension */ = { + isa = PBXGroup; + children = ( + 51314666235A7E4600387FDC /* IntentHandler.swift */, + 51314665235A7E4600387FDC /* Info.plist */, + 51314684235A7EB900387FDC /* NetNewsWire_iOS_IntentsExtension.entitlements */, + ); + path = IntentsExtension; + sourceTree = ""; + }; 513228F1233037620033D4ED /* Network */ = { isa = PBXGroup; children = ( @@ -1233,19 +1754,6 @@ name = Products; sourceTree = ""; }; - 515E4F06232506240057B0E7 /* Account */ = { - isa = PBXGroup; - children = ( - 510D708122B041CC004E8F65 /* SettingsAccountLabelView.swift */, - 510D707322B028E1004E8F65 /* SettingsAddAccountView.swift */, - 51F772EC22B2789B0087D9D1 /* SettingsDetailAccountView.swift */, - 510D707F22B02A5F004E8F65 /* SettingsFeedbinAccountView.swift */, - 510D707D22B02A4B004E8F65 /* SettingsLocalAccountView.swift */, - 557EE1A522B6F4E1004206FA /* SettingsReaderAPIAccountView.swift */, - ); - path = Account; - sourceTree = ""; - }; 5183CCDB226F1EEB0010922C /* Progress */ = { isa = PBXGroup; children = ( @@ -1268,13 +1776,17 @@ 5183CCEB227117C70010922C /* Settings */ = { isa = PBXGroup; children = ( - 51F35D0822AFD4760003CE1B /* SettingsView.swift */, - 5132293A23305D4C0033D4ED /* SettingsAboutView.swift */, - 513229302330523F0033D4ED /* SettingsAttributedStringView.swift */, - 5132285A232FF2C40033D4ED /* SettingsRefreshSelectionView.swift */, - 5194B5F122B69FCC00144881 /* SettingsSubscriptionsExportDocumentPickerView.swift */, - 5194B5ED22B6965300144881 /* SettingsSubscriptionsImportDocumentPickerView.swift */, - 515E4F06232506240057B0E7 /* Account */, + 51A16990235E10D600EB091F /* Settings.storyboard */, + 51A16995235E10D600EB091F /* AboutViewController.swift */, + 51A16992235E10D600EB091F /* AddAccountViewController.swift */, + 51A1698F235E10D600EB091F /* AddLocalAccountViewController.swift */, + 51A16991235E10D600EB091F /* DetailAccountViewController.swift */, + 51A16996235E10D700EB091F /* FeedbinAccountViewController.swift */, + 51A1698D235E10D600EB091F /* RefreshIntervalViewController.swift */, + 516A09382360A2AE00EAE89B /* SettingsAccountTableViewCell.swift */, + 516A091D23609A3600EAE89B /* SettingsAccountTableViewCell.xib */, + 516A093A2360A4A000EAE89B /* SettingsTableViewCell.xib */, + 51A16993235E10D600EB091F /* SettingsViewController.swift */, ); path = Settings; sourceTree = ""; @@ -1282,13 +1794,10 @@ 518651A423555EB20078E021 /* NNW3 */ = { isa = PBXGroup; children = ( - 518651A523555EB20078E021 /* ImportNNW3WindowController.swift */, - 518651A623555EB20078E021 /* NNW3PlistConverter.swift */, - 518651A723555EB20078E021 /* ImportNNW3Sheet.xib */, - 518651A823555EB20078E021 /* NNW3Entry.swift */, - 518651A923555EB20078E021 /* NNW3FeedsImporter.swift */, - 518651AA23555EB20078E021 /* NNW3Feed.swift */, + 849ADEE02359817D000E1B81 /* NNW3ImportController.swift */, 518651AB23555EB20078E021 /* NNW3Document.swift */, + 849ADEE523598189000E1B81 /* NNW3OpenPanelAccessoryView.xib */, + 849ADEE7235981A0000E1B81 /* NNW3OpenPanelAccessoryViewController.swift */, ); path = NNW3; sourceTree = ""; @@ -1302,19 +1811,6 @@ path = Activity; sourceTree = ""; }; - 5194B5E222B693EC00144881 /* SwiftUI Extensions */ = { - isa = PBXGroup; - children = ( - DF999FF622B5AEFA0064B687 /* SafariView.swift */, - 51322858232FDDB80033D4ED /* VibrantButtonStyle.swift */, - 51322854232EED360033D4ED /* VibrantSelectAction.swift */, - 51E149B2234D82E40004F7A5 /* PasswordField.swift */, - 51E149C1234D852F0004F7A5 /* ShowHidePasswordView.swift */, - 51E149BF234D839E0004F7A5 /* ShowHidePasswordView.xib */, - ); - path = "SwiftUI Extensions"; - sourceTree = ""; - }; 519D740423243C68008BB345 /* Model Extensions */ = { isa = PBXGroup; children = ( @@ -1329,7 +1825,6 @@ children = ( 51F85BFA2275D85000C787DC /* Array-Extensions.swift */, 51F85BF42273625800C787DC /* Bundle-Extensions.swift */, - 5F323808231DF9F000706F6B /* NNWTableViewCell.swift */, 51EAED95231363EF00A9EEE3 /* NonIntrinsicButton.swift */, 5183CCD9226E31A50010922C /* NonIntrinsicImageView.swift */, 5183CCCF226E1E880010922C /* NonIntrinsicLabel.swift */, @@ -1340,6 +1835,9 @@ 51FD40BD2341555600880194 /* UIImage-Extensions.swift */, 512E092B2268B25500BDCFDD /* UISplitViewController-Extensions.swift */, 51C4524E226506F400C03939 /* UIStoryboard-Extensions.swift */, + 51FFF0C3235EE8E5002762AA /* VibrantButton.swift */, + 5186A634235EF3A800C97195 /* VibrantLabel.swift */, + 5F323808231DF9F000706F6B /* VibrantTableViewCell.swift */, ); path = "UIKit Extensions"; sourceTree = ""; @@ -1438,7 +1936,6 @@ FF3ABF1423259DDB0074C542 /* ArticleSorter.swift */, 84CAFCAE22BC8C35007694F0 /* FetchRequestOperation.swift */, 84CAFCA322BC8C08007694F0 /* FetchRequestQueue.swift */, - 849A97731ED9EC04007D329B /* TimelineStringFormatter.swift */, ); path = Timeline; sourceTree = ""; @@ -1483,6 +1980,29 @@ path = SafariExtension; sourceTree = ""; }; + 65ED429A235E71B40081F399 /* Products */ = { + isa = PBXGroup; + children = ( + 65ED42B0235E71B40081F399 /* Sparkle.framework */, + 65ED42B2235E71B40081F399 /* SparkleCore.framework */, + 65ED42B4235E71B40081F399 /* Autoupdate */, + 65ED42B6235E71B40081F399 /* org.sparkle-project.InstallerLauncher.xpc */, + 65ED42B8235E71B40081F399 /* org.sparkle-project.InstallerConnection.xpc */, + 65ED42BA235E71B40081F399 /* org.sparkle-project.InstallerStatus.xpc */, + 65ED42BC235E71B40081F399 /* org.sparkle-project.Downloader.xpc */, + 65ED42BE235E71B40081F399 /* Sparkle Test App.app */, + 65ED42C0235E71B40081F399 /* TestAppHelper.xpc */, + 65ED42C2235E71B40081F399 /* Sparkle Unit Tests.xctest */, + 65ED42C4235E71B40081F399 /* BinaryDelta */, + 65ED42C6235E71B40081F399 /* sparkle.app */, + 65ED42C8235E71B40081F399 /* Updater.app */, + 65ED42CA235E71B40081F399 /* UI Tests.xctest */, + 65ED42CC235E71B40081F399 /* generate_appcast */, + 65ED42CE235E71B40081F399 /* libbsdiff.a */, + ); + name = Products; + sourceTree = ""; + }; 840716652262A60D00344432 /* Products */ = { isa = PBXGroup; children = ( @@ -1659,6 +2179,7 @@ 849A97561ED9EB0D007D329B /* Data */ = { isa = PBXGroup; children = ( + 849A97731ED9EC04007D329B /* ArticleStringFormatter.swift */, 849A97581ED9EB0D007D329B /* ArticleUtilities.swift */, 84411E701FE5FBFA004B527F /* SmallIconProvider.swift */, ); @@ -1782,6 +2303,9 @@ 6581C73320CED60000F4AD34 /* Subscribe to Feed.appex */, 513C5CE6232571C2003D4054 /* NetNewsWire iOS Share Extension.appex */, 518B2ED22351B3DD00400001 /* NetNewsWire-iOSTests.xctest */, + 51314637235A7BBE00387FDC /* NetNewsWire iOS Intents Extension.appex */, + 65ED4083235DEF6C0081F399 /* NetNewsWire.app */, + 65ED409D235DEF770081F399 /* Subscribe to Feed.appex */, ); name = Products; sourceTree = ""; @@ -1971,6 +2495,7 @@ 84C9FC8A22629E8F00D921D6 /* NetNewsWire.sdef */, 84C9FC9022629ECB00D921D6 /* NetNewsWire.entitlements */, 84C9FC9122629F2200D921D6 /* Info.plist */, + 65ED409F235DEFF00081F399 /* container-migration.plist */, 84C9FC8622629E8F00D921D6 /* KeyboardShortcuts */, ); path = Resources; @@ -2004,12 +2529,13 @@ 51C4527D2265092C00C03939 /* Article */, 51C452802265093600C03939 /* Add */, 5123DB95233EC69300282CC9 /* Inspector */, - 5183CCEB227117C70010922C /* Settings */, + 513145F9235A55A700387FDC /* Intents */, 5183CCDB226F1EEB0010922C /* Progress */, + 5183CCEB227117C70010922C /* Settings */, 519D740423243C68008BB345 /* Model Extensions */, - 5194B5E222B693EC00144881 /* SwiftUI Extensions */, 51C45245226506C800C03939 /* UIKit Extensions */, 513C5CE7232571C2003D4054 /* ShareExtension */, + 51314643235A7C2300387FDC /* IntentsExtension */, 84C9FC9A2262A1A900D921D6 /* Resources */, ); path = iOS; @@ -2116,11 +2642,10 @@ isa = PBXGroup; children = ( 847752FE2008879500D93690 /* CoreServices.framework */, - 84FB9A2D1EDCD6B8003D53B9 /* Sparkle.framework */, 6581C73420CED60100F4AD34 /* Cocoa.framework */, + 65ED4299235E71B40081F399 /* Sparkle.xcodeproj */, ); name = Frameworks; - path = ../NetNewsWire/Extensions; sourceTree = ""; }; D5907CDA2002F084005947E5 /* xcconfig */ = { @@ -2131,9 +2656,12 @@ D5907CDC2002F0BE005947E5 /* NetNewsWire_project_release.xcconfig */, D5907CDE2002F0BE005947E5 /* NetNewsWire_project.xcconfig */, D5907CE02002F0FA005947E5 /* NetNewsWire_macapp_target.xcconfig */, + 65ED40F2235DF5E00081F399 /* NetNewsWire_macapp_target_macappstore.xcconfig */, D5907CDF2002F0F9005947E5 /* NetNewsWireTests_target.xcconfig */, D519E74722EE553300923F27 /* NetNewsWire_safariextension_target.xcconfig */, + 65ED4186235E045B0081F399 /* NetNewsWire_safariextension_target_macappstore.xcconfig */, 51121AA12265430A00BC0EC1 /* NetNewsWire_iOSapp_target.xcconfig */, + 51314617235A797400387FDC /* NetNewsWire_iOSintentextension_target.xcconfig */, 515D4FCE2325B3D000EE1167 /* NetNewsWire_iOSshareextension_target.xcconfig */, 518B2EE92351B4C200400001 /* NetNewsWire_iOSTests_target.xcconfig */, 6543108B2322D90900658221 /* common */, @@ -2162,6 +2690,23 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 51314636235A7BBE00387FDC /* NetNewsWire iOS Intents Extension */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5131463F235A7BBE00387FDC /* Build configuration list for PBXNativeTarget "NetNewsWire iOS Intents Extension" */; + buildPhases = ( + 51314633235A7BBE00387FDC /* Sources */, + 51314634235A7BBE00387FDC /* Frameworks */, + 51314635235A7BBE00387FDC /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "NetNewsWire iOS Intents Extension"; + productName = "NetNewsWire iOS Intents Extension"; + productReference = 51314637235A7BBE00387FDC /* NetNewsWire iOS Intents Extension.appex */; + productType = "com.apple.product-type.app-extension"; + }; 513C5CE5232571C2003D4054 /* NetNewsWire iOS Share Extension */ = { isa = PBXNativeTarget; buildConfigurationList = 513C5CFC232571C2003D4054 /* Build configuration list for PBXNativeTarget "NetNewsWire iOS Share Extension" */; @@ -2169,7 +2714,6 @@ 513C5CE2232571C2003D4054 /* Sources */, 513C5CE3232571C2003D4054 /* Frameworks */, 513C5CE4232571C2003D4054 /* Resources */, - 513C5CFF2325749A003D4054 /* Embed Frameworks */, ); buildRules = ( ); @@ -2215,6 +2759,56 @@ productReference = 6581C73320CED60000F4AD34 /* Subscribe to Feed.appex */; productType = "com.apple.product-type.app-extension"; }; + 65ED3FA2235DEF6C0081F399 /* NetNewsWire MAS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 65ED407F235DEF6C0081F399 /* Build configuration list for PBXNativeTarget "NetNewsWire MAS" */; + buildPhases = ( + 65ED3FB5235DEF6C0081F399 /* Run Script: Update ArticleExtractorConfig.swift */, + 65ED3FB6235DEF6C0081F399 /* Sources */, + 65ED4041235DEF6C0081F399 /* Run Script: Reset ArticleExtractorConfig.swift */, + 65ED4042235DEF6C0081F399 /* Frameworks */, + 65ED404D235DEF6C0081F399 /* Resources */, + 65ED406F235DEF6C0081F399 /* Run Script: Automated build numbers */, + 65ED4070235DEF6C0081F399 /* Embed Frameworks */, + 65ED407B235DEF6C0081F399 /* Embed App Extensions */, + 65ED407D235DEF6C0081F399 /* Run Script: Verify No Build Settings */, + ); + buildRules = ( + ); + dependencies = ( + 65ED41C7235E615E0081F399 /* PBXTargetDependency */, + 65ED3FA3235DEF6C0081F399 /* PBXTargetDependency */, + 65ED3FA5235DEF6C0081F399 /* PBXTargetDependency */, + 65ED3FA7235DEF6C0081F399 /* PBXTargetDependency */, + 65ED3FA9235DEF6C0081F399 /* PBXTargetDependency */, + 65ED3FAB235DEF6C0081F399 /* PBXTargetDependency */, + 65ED3FAD235DEF6C0081F399 /* PBXTargetDependency */, + 65ED3FAF235DEF6C0081F399 /* PBXTargetDependency */, + 65ED3FB1235DEF6C0081F399 /* PBXTargetDependency */, + 65ED3FB3235DEF6C0081F399 /* PBXTargetDependency */, + ); + name = "NetNewsWire MAS"; + productName = NetNewsWire; + productReference = 65ED4083235DEF6C0081F399 /* NetNewsWire.app */; + productType = "com.apple.product-type.application"; + }; + 65ED4090235DEF770081F399 /* Subscribe to Feed MAS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 65ED4099235DEF770081F399 /* Build configuration list for PBXNativeTarget "Subscribe to Feed MAS" */; + buildPhases = ( + 65ED4091235DEF770081F399 /* Sources */, + 65ED4094235DEF770081F399 /* Frameworks */, + 65ED4095235DEF770081F399 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Subscribe to Feed MAS"; + productName = "Subscribe to Feed"; + productReference = 65ED409D235DEF770081F399 /* Subscribe to Feed.appex */; + productType = "com.apple.product-type.app-extension"; + }; 840D617B2029031C009BC708 /* NetNewsWire-iOS */ = { isa = PBXNativeTarget; buildConfigurationList = 840D61A32029031E009BC708 /* Build configuration list for PBXNativeTarget "NetNewsWire-iOS" */; @@ -2231,6 +2825,7 @@ buildRules = ( ); dependencies = ( + 5131463D235A7BBE00387FDC /* PBXTargetDependency */, ); name = "NetNewsWire-iOS"; productName = "NetNewsWire-iOS"; @@ -2249,12 +2844,14 @@ 84C987A52000AC9E0066B150 /* Run Script: Automated build numbers */, 84B06F681ED37B9000F0B54B /* Embed Frameworks */, 6581C75720CED60100F4AD34 /* Embed App Extensions */, + 65ED42E0235E74240081F399 /* Embed XPC Services */, D519E77022EE5B4100923F27 /* Run Script: Verify No Build Settings */, - 8423E3E3220158E700C3795B /* Run Script: codesign release builds */, + 8423E3E3220158E700C3795B /* Run Script: Code Sign Sparkle */, ); buildRules = ( ); dependencies = ( + 65ED41C5235E61550081F399 /* PBXTargetDependency */, 84C37FA820DD8D8400CA8CF5 /* PBXTargetDependency */, 84C37FAC20DD8D9000CA8CF5 /* PBXTargetDependency */, 84C37FB020DD8D9900CA8CF5 /* PBXTargetDependency */, @@ -2264,6 +2861,11 @@ 51C451BC226377C900C03939 /* PBXTargetDependency */, 51C451C0226377D000C03939 /* PBXTargetDependency */, 51554C27228B71910055115A /* PBXTargetDependency */, + 65ED42D0235E71F60081F399 /* PBXTargetDependency */, + 65ED42D2235E72000081F399 /* PBXTargetDependency */, + 65ED42D4235E72000081F399 /* PBXTargetDependency */, + 65ED42D6235E72000081F399 /* PBXTargetDependency */, + 65ED42D8235E72000081F399 /* PBXTargetDependency */, ); name = NetNewsWire; productName = NetNewsWire; @@ -2299,6 +2901,12 @@ LastUpgradeCheck = 0930; ORGANIZATIONNAME = "Ranchero Software"; TargetAttributes = { + 51314636235A7BBE00387FDC = { + CreatedOnToolsVersion = 11.2; + DevelopmentTeam = SHJK2V3AJG; + LastSwiftMigration = 1120; + ProvisioningStyle = Automatic; + }; 513C5CE5232571C2003D4054 = { CreatedOnToolsVersion = 11.0; DevelopmentTeam = 8EQFQ9RY84; @@ -2314,6 +2922,14 @@ DevelopmentTeam = 8EQFQ9RY84; ProvisioningStyle = Automatic; }; + 65ED3FA2235DEF6C0081F399 = { + DevelopmentTeam = SHJK2V3AJG; + ProvisioningStyle = Automatic; + }; + 65ED4090235DEF770081F399 = { + DevelopmentTeam = SHJK2V3AJG; + ProvisioningStyle = Automatic; + }; 840D617B2029031C009BC708 = { CreatedOnToolsVersion = 9.3; DevelopmentTeam = 8EQFQ9RY84; @@ -2387,6 +3003,10 @@ ProductGroup = 84C37F9920DD8D0400CA8CF5 /* Products */; ProjectRef = 84C37F9820DD8D0400CA8CF5 /* RSWeb.xcodeproj */; }, + { + ProductGroup = 65ED429A235E71B40081F399 /* Products */; + ProjectRef = 65ED4299235E71B40081F399 /* Sparkle.xcodeproj */; + }, { ProductGroup = 51554BFD228B6EB50055115A /* Products */; ProjectRef = 51554BFC228B6EB50055115A /* SyncDatabase.xcodeproj */; @@ -2395,10 +3015,13 @@ projectRoot = ""; targets = ( 849C645F1ED37A5D003D8FC0 /* NetNewsWire */, + 65ED3FA2235DEF6C0081F399 /* NetNewsWire MAS */, 849C64701ED37A5D003D8FC0 /* NetNewsWireTests */, 840D617B2029031C009BC708 /* NetNewsWire-iOS */, 6581C73220CED60000F4AD34 /* Subscribe to Feed */, + 65ED4090235DEF770081F399 /* Subscribe to Feed MAS */, 513C5CE5232571C2003D4054 /* NetNewsWire iOS Share Extension */, + 51314636235A7BBE00387FDC /* NetNewsWire iOS Intents Extension */, 518B2ED12351B3DD00400001 /* NetNewsWire-iOSTests */, ); }; @@ -2412,6 +3035,118 @@ remoteRef = 51554C00228B6EB50055115A /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + 65ED42B0235E71B40081F399 /* Sparkle.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = Sparkle.framework; + remoteRef = 65ED42AF235E71B40081F399 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 65ED42B2235E71B40081F399 /* SparkleCore.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = SparkleCore.framework; + remoteRef = 65ED42B1235E71B40081F399 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 65ED42B4235E71B40081F399 /* Autoupdate */ = { + isa = PBXReferenceProxy; + fileType = "compiled.mach-o.executable"; + path = Autoupdate; + remoteRef = 65ED42B3235E71B40081F399 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 65ED42B6235E71B40081F399 /* org.sparkle-project.InstallerLauncher.xpc */ = { + isa = PBXReferenceProxy; + fileType = "wrapper.xpc-service"; + path = "org.sparkle-project.InstallerLauncher.xpc"; + remoteRef = 65ED42B5235E71B40081F399 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 65ED42B8235E71B40081F399 /* org.sparkle-project.InstallerConnection.xpc */ = { + isa = PBXReferenceProxy; + fileType = "wrapper.xpc-service"; + path = "org.sparkle-project.InstallerConnection.xpc"; + remoteRef = 65ED42B7235E71B40081F399 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 65ED42BA235E71B40081F399 /* org.sparkle-project.InstallerStatus.xpc */ = { + isa = PBXReferenceProxy; + fileType = "wrapper.xpc-service"; + path = "org.sparkle-project.InstallerStatus.xpc"; + remoteRef = 65ED42B9235E71B40081F399 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 65ED42BC235E71B40081F399 /* org.sparkle-project.Downloader.xpc */ = { + isa = PBXReferenceProxy; + fileType = "wrapper.xpc-service"; + path = "org.sparkle-project.Downloader.xpc"; + remoteRef = 65ED42BB235E71B40081F399 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 65ED42BE235E71B40081F399 /* Sparkle Test App.app */ = { + isa = PBXReferenceProxy; + fileType = wrapper.application; + path = "Sparkle Test App.app"; + remoteRef = 65ED42BD235E71B40081F399 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 65ED42C0235E71B40081F399 /* TestAppHelper.xpc */ = { + isa = PBXReferenceProxy; + fileType = "wrapper.xpc-service"; + path = TestAppHelper.xpc; + remoteRef = 65ED42BF235E71B40081F399 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 65ED42C2235E71B40081F399 /* Sparkle Unit Tests.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = "Sparkle Unit Tests.xctest"; + remoteRef = 65ED42C1235E71B40081F399 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 65ED42C4235E71B40081F399 /* BinaryDelta */ = { + isa = PBXReferenceProxy; + fileType = "compiled.mach-o.executable"; + path = BinaryDelta; + remoteRef = 65ED42C3235E71B40081F399 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 65ED42C6235E71B40081F399 /* sparkle.app */ = { + isa = PBXReferenceProxy; + fileType = wrapper.application; + path = sparkle.app; + remoteRef = 65ED42C5235E71B40081F399 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 65ED42C8235E71B40081F399 /* Updater.app */ = { + isa = PBXReferenceProxy; + fileType = wrapper.application; + path = Updater.app; + remoteRef = 65ED42C7235E71B40081F399 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 65ED42CA235E71B40081F399 /* UI Tests.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = "UI Tests.xctest"; + remoteRef = 65ED42C9235E71B40081F399 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 65ED42CC235E71B40081F399 /* generate_appcast */ = { + isa = PBXReferenceProxy; + fileType = "compiled.mach-o.executable"; + path = generate_appcast; + remoteRef = 65ED42CB235E71B40081F399 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 65ED42CE235E71B40081F399 /* libbsdiff.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libbsdiff.a; + remoteRef = 65ED42CD235E71B40081F399 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; 8407166A2262A60D00344432 /* Account.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; @@ -2548,6 +3283,13 @@ /* End PBXReferenceProxy section */ /* Begin PBXResourcesBuildPhase section */ + 51314635235A7BBE00387FDC /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 513C5CE4232571C2003D4054 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -2574,6 +3316,57 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 65ED404D235DEF6C0081F399 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 65ED404E235DEF6C0081F399 /* NNW3OpenPanelAccessoryView.xib in Resources */, + 65ED404F235DEF6C0081F399 /* GlobalKeyboardShortcuts.plist in Resources */, + 65ED4050235DEF6C0081F399 /* DetailKeyboardShortcuts.plist in Resources */, + 65ED4051235DEF6C0081F399 /* TimelineKeyboardShortcuts.plist in Resources */, + 65ED4052235DEF6C0081F399 /* template.html in Resources */, + 65ED4053235DEF6C0081F399 /* AccountsFeedlyWeb.xib in Resources */, + 65ED4054235DEF6C0081F399 /* Main.storyboard in Resources */, + 65ED4055235DEF6C0081F399 /* AccountsAdd.xib in Resources */, + 65ED4056235DEF6C0081F399 /* NetNewsWire.sdef in Resources */, + 65ED4057235DEF6C0081F399 /* AccountsDetail.xib in Resources */, + 65ED4058235DEF6C0081F399 /* main.js in Resources */, + 65ED40A1235DEFF00081F399 /* container-migration.plist in Resources */, + 65ED4059235DEF6C0081F399 /* AccountsAddLocal.xib in Resources */, + 65ED405A235DEF6C0081F399 /* main_mac.js in Resources */, + 65ED405B235DEF6C0081F399 /* KeyboardShortcuts.html in Resources */, + 65ED405C235DEF6C0081F399 /* ImportOPMLSheet.xib in Resources */, + 65ED405D235DEF6C0081F399 /* SidebarKeyboardShortcuts.plist in Resources */, + 65ED405E235DEF6C0081F399 /* DefaultFeeds.opml in Resources */, + 65ED405F235DEF6C0081F399 /* Preferences.storyboard in Resources */, + 65ED4060235DEF6C0081F399 /* ExportOPMLSheet.xib in Resources */, + 65ED4061235DEF6C0081F399 /* Assets.xcassets in Resources */, + 65ED4062235DEF6C0081F399 /* styleSheet.css in Resources */, + 65ED4063235DEF6C0081F399 /* RenameSheet.xib in Resources */, + 65ED4064235DEF6C0081F399 /* AddFolderSheet.xib in Resources */, + 65ED4065235DEF6C0081F399 /* AccountsFeedbin.xib in Resources */, + 65ED4066235DEF6C0081F399 /* TimelineTableView.xib in Resources */, + 65ED4067235DEF6C0081F399 /* page.html in Resources */, + 65ED4068235DEF6C0081F399 /* MainWindow.storyboard in Resources */, + 65ED4069235DEF6C0081F399 /* AccountsReaderAPI.xib in Resources */, + 65ED406A235DEF6C0081F399 /* newsfoot.js in Resources */, + 65ED406B235DEF6C0081F399 /* CrashReporterWindow.xib in Resources */, + 65ED406C235DEF6C0081F399 /* Credits.rtf in Resources */, + 65ED406D235DEF6C0081F399 /* Inspector.storyboard in Resources */, + 65ED406E235DEF6C0081F399 /* AddFeedSheet.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 65ED4095235DEF770081F399 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 65ED4096235DEF770081F399 /* ToolbarItemIcon.pdf in Resources */, + 65ED4097235DEF770081F399 /* SafariExtensionViewController.xib in Resources */, + 65ED4098235DEF770081F399 /* netnewswire-subscribe-to-feed.js in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 840D617A2029031C009BC708 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -2586,16 +3379,18 @@ 511D43D2231FA62C00FB1562 /* GlobalKeyboardShortcuts.plist in Resources */, 84C9FCA12262A1B300D921D6 /* Main.storyboard in Resources */, 51BB7C312335ACDE008E8144 /* page.html in Resources */, + 516A093723609A3600EAE89B /* SettingsAccountTableViewCell.xib in Resources */, 51F85BF32272531500C787DC /* Dedication.rtf in Resources */, 84C9FCA42262A1B800D921D6 /* LaunchScreenPhone.storyboard in Resources */, 51F85BEB22724CB600C787DC /* About.rtf in Resources */, 51F85BED227251DF00C787DC /* Acknowledgments.rtf in Resources */, + 516A093B2360A4A000EAE89B /* SettingsTableViewCell.xib in Resources */, 511D43D1231FA62800FB1562 /* SidebarKeyboardShortcuts.plist in Resources */, 51C452AB22650DC600C03939 /* template.html in Resources */, - 51E149C0234D839E0004F7A5 /* ShowHidePasswordView.xib in Resources */, 51F85BF12272524100C787DC /* Credits.rtf in Resources */, 84A3EE61223B667F00557320 /* DefaultFeeds.opml in Resources */, 511D43CF231FA62200FB1562 /* DetailKeyboardShortcuts.plist in Resources */, + 51A1699A235E10D700EB091F /* Settings.storyboard in Resources */, 49F40DF92335B71000552BF4 /* newsfoot.js in Resources */, 51F85BEF2272520B00C787DC /* Thanks.rtf in Resources */, 84C9FC9D2262A1A900D921D6 /* Assets.xcassets in Resources */, @@ -2608,9 +3403,9 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 849ADEE623598189000E1B81 /* NNW3OpenPanelAccessoryView.xib in Resources */, 844B5B651FEA11F200C7C76A /* GlobalKeyboardShortcuts.plist in Resources */, 5127B23A222B4849006D641D /* DetailKeyboardShortcuts.plist in Resources */, - 518651AE23555EB20078E021 /* ImportNNW3Sheet.xib in Resources */, 845479881FEB77C000AD8B59 /* TimelineKeyboardShortcuts.plist in Resources */, 848362FF2262A30E00DA1D35 /* template.html in Resources */, 9EA33BBA2318F8C10097B644 /* AccountsFeedlyWeb.xib in Resources */, @@ -2619,6 +3414,7 @@ 84C9FC8F22629E8F00D921D6 /* NetNewsWire.sdef in Resources */, 84C9FC7D22629E1200D921D6 /* AccountsDetail.xib in Resources */, 517630042336215100E15FFF /* main.js in Resources */, + 65ED40A0235DEFF00081F399 /* container-migration.plist in Resources */, 5144EA362279FC3D00D19003 /* AccountsAddLocal.xib in Resources */, 5142194B2353C1CF00E07E2C /* main_mac.js in Resources */, 84C9FC8C22629E8F00D921D6 /* KeyboardShortcuts.html in Resources */, @@ -2746,7 +3542,7 @@ 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 */ = { + 65ED3FB5235DEF6C0081F399 /* Run Script: Update ArticleExtractorConfig.swift */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -2755,14 +3551,82 @@ ); inputPaths = ( ); - name = "Run Script: codesign release builds"; + name = "Run Script: Update ArticleExtractorConfig.swift"; outputFileListPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# See https://github.com/Watson1978/kotori/commit/ffe320f2e058828f0af294b65ed88dfd7baaabff\n\nif [ \"${CONFIGURATION}\" = \"Release\" ]; then\n codesign --verbose --force --deep -o runtime --sign \"Developer ID Application: Brent Simmons\" \"${CODESIGNING_FOLDER_PATH}/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/AutoUpdate.app\"\nfi\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\n"; + }; + 65ED4041235DEF6C0081F399 /* Run Script: Reset ArticleExtractorConfig.swift */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Run Script: Reset ArticleExtractorConfig.swift"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "git checkout \"${SRCROOT}/Shared/Article Extractor/ArticleExtractorConfig.swift\"\n"; + }; + 65ED406F235DEF6C0081F399 /* Run Script: Automated build numbers */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script: Automated build numbers"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "# See https://blog.curtisherbert.com/automated-build-numbers/\n\n# WARNING: If automated build numbers are restored then take \n# care to ensure any app extensions are versioned the same as the app.\n# ask Daniel (jalkut@red-sweater.com) if in doubt about this. \n#git=`sh /etc/profile; which git`\n#branch_name=`$git symbolic-ref HEAD | sed -e 's,.*/\\\\(.*\\\\),\\\\1,'`\n#git_count=`$git rev-list $branch_name |wc -l | sed 's/^ *//;s/ *$//'`\n#simple_branch_name=`$git rev-parse --abbrev-ref HEAD`\n\n#build_number=\"$git_count\"\n#if [ $CONFIGURATION != \"Release\" ]; then\n#build_number+=\"-$simple_branch_name\"\n#fi\n\n#plist=\"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}\"\n#dsym_plist=\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"\n\n#/usr/libexec/PlistBuddy -c \"Set :CFBundleVersion $build_number\" \"$plist\"\n#if [ -f \"$DSYM_INFO_PLIST\" ] ; then\n#/usr/libexec/PlistBuddy -c \"Set :CFBundleVersion $build_number\" \"$dsym_plist\"\n#fi\n"; + }; + 65ED407D235DEF6C0081F399 /* Run Script: Verify No Build Settings */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Run Script: Verify No Build Settings"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + 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"; + }; + 8423E3E3220158E700C3795B /* Run Script: Code Sign Sparkle */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Run Script: Code Sign Sparkle"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "# Remove unused Sparkle components\n\n# Sign XPC Helpers\ncodesign --verbose --entitlements \"${PROJECT_DIR}/submodules/Sparkle/Downloader/org.sparkle-project.Downloader.entitlements\" --force -o runtime --sign \"${EXPANDED_CODE_SIGN_IDENTITY}\" \"${CODESIGNING_FOLDER_PATH}/Contents/XPCServices/org.sparkle-project.Downloader.xpc\"\ncodesign --verbose --force -o runtime --sign \"${EXPANDED_CODE_SIGN_IDENTITY}\" \"${CODESIGNING_FOLDER_PATH}/Contents/XPCServices/org.sparkle-project.InstallerLauncher.xpc\"\ncodesign --verbose --force -o runtime --sign \"${EXPANDED_CODE_SIGN_IDENTITY}\" \"${CODESIGNING_FOLDER_PATH}/Contents/XPCServices/org.sparkle-project.InstallerConnection.xpc\"\ncodesign --verbose --force -o runtime --sign \"${EXPANDED_CODE_SIGN_IDENTITY}\" \"${CODESIGNING_FOLDER_PATH}/Contents/XPCServices/org.sparkle-project.InstallerStatus.xpc\"\n"; }; 84C987A52000AC9E0066B150 /* Run Script: Automated build numbers */ = { isa = PBXShellScriptBuildPhase; @@ -2799,6 +3663,16 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 51314633235A7BBE00387FDC /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 513146B3235A81A400387FDC /* AddFeedIntentHandler.swift in Sources */, + 51314705235C41FC00387FDC /* Intents.intentdefinition in Sources */, + 51314668235A7E4600387FDC /* IntentHandler.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 513C5CE2232571C2003D4054 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -2828,19 +3702,172 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 65ED3FB6235DEF6C0081F399 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 65ED3FB7235DEF6C0081F399 /* ArticleArray.swift in Sources */, + 65ED3FB8235DEF6C0081F399 /* CrashReporter.swift in Sources */, + 65ED3FB9235DEF6C0081F399 /* TimelineAvatarView.swift in Sources */, + 65ED3FBA235DEF6C0081F399 /* ArticleExtractorConfig.swift in Sources */, + 65ED3FBB235DEF6C0081F399 /* InspectorWindowController.swift in Sources */, + 65ED3FBC235DEF6C0081F399 /* ColorHash.swift in Sources */, + 65ED3FBD235DEF6C0081F399 /* AppDefaults.swift in Sources */, + 65ED3FBE235DEF6C0081F399 /* Account+Scriptability.swift in Sources */, + 65ED3FBF235DEF6C0081F399 /* NothingInspectorViewController.swift in Sources */, + 65ED3FC0235DEF6C0081F399 /* AppNotifications.swift in Sources */, + 65ED3FC1235DEF6C0081F399 /* TimelineKeyboardDelegate.swift in Sources */, + 65ED3FC2235DEF6C0081F399 /* Browser.swift in Sources */, + 65ED3FC3235DEF6C0081F399 /* DetailWebViewController.swift in Sources */, + 65ED3FC4235DEF6C0081F399 /* OPMLExporter.swift in Sources */, + 65ED3FC5235DEF6C0081F399 /* MainWindowController.swift in Sources */, + 65ED3FC6235DEF6C0081F399 /* UnreadFeed.swift in Sources */, + 65ED3FC7235DEF6C0081F399 /* Reachability.swift in Sources */, + 65ED3FC8235DEF6C0081F399 /* SidebarCellLayout.swift in Sources */, + 65ED3FC9235DEF6C0081F399 /* SmartFeedPasteboardWriter.swift in Sources */, + 65ED3FCA235DEF6C0081F399 /* SmartFeedsController.swift in Sources */, + 65ED3FCB235DEF6C0081F399 /* SidebarViewController.swift in Sources */, + 65ED3FCC235DEF6C0081F399 /* AccountsFeedlyWebWindowController.swift in Sources */, + 65ED3FCD235DEF6C0081F399 /* SidebarOutlineView.swift in Sources */, + 65ED3FCE235DEF6C0081F399 /* DetailKeyboardDelegate.swift in Sources */, + 65ED3FCF235DEF6C0081F399 /* TimelineContainerView.swift in Sources */, + 65ED3FD0235DEF6C0081F399 /* Author+Scriptability.swift in Sources */, + 65ED3FD1235DEF6C0081F399 /* PseudoFeed.swift in Sources */, + 65ED3FD2235DEF6C0081F399 /* AccountsAddViewController.swift in Sources */, + 65ED3FD3235DEF6C0081F399 /* NSScriptCommand+NetNewsWire.swift in Sources */, + 65ED3FD4235DEF6C0081F399 /* Article+Scriptability.swift in Sources */, + 65ED3FD5235DEF6C0081F399 /* SmartFeed.swift in Sources */, + 65ED3FD6235DEF6C0081F399 /* MarkStatusCommand.swift in Sources */, + 65ED3FD7235DEF6C0081F399 /* NSApplication+Scriptability.swift in Sources */, + 65ED3FD8235DEF6C0081F399 /* NSView-Extensions.swift in Sources */, + 65ED3FD9235DEF6C0081F399 /* SidebarCell.swift in Sources */, + 65ED3FDA235DEF6C0081F399 /* ArticleStatusSyncTimer.swift in Sources */, + 65ED3FDB235DEF6C0081F399 /* FeedTreeControllerDelegate.swift in Sources */, + 65ED3FDC235DEF6C0081F399 /* UnreadCountView.swift in Sources */, + 65ED3FDD235DEF6C0081F399 /* ActivityType.swift in Sources */, + 65ED3FDE235DEF6C0081F399 /* CrashReportWindowController.swift in Sources */, + 65ED3FDF235DEF6C0081F399 /* FeedIconDownloader.swift in Sources */, + 65ED3FE0235DEF6C0081F399 /* AccountsControlsBackgroundView.swift in Sources */, + 65ED3FE1235DEF6C0081F399 /* MarkCommandValidationStatus.swift in Sources */, + 65ED3FE2235DEF6C0081F399 /* ArticlePasteboardWriter.swift in Sources */, + 65ED3FE3235DEF6C0081F399 /* ArticleUtilities.swift in Sources */, + 65ED3FE4235DEF6C0081F399 /* NNW3OpenPanelAccessoryViewController.swift in Sources */, + 65ED3FE5235DEF6C0081F399 /* DefaultFeedsImporter.swift in Sources */, + 65ED3FE6235DEF6C0081F399 /* RenameWindowController.swift in Sources */, + 65ED3FE7235DEF6C0081F399 /* SendToMicroBlogCommand.swift in Sources */, + 65ED3FE8235DEF6C0081F399 /* ArticleStyle.swift in Sources */, + 65ED3FE9235DEF6C0081F399 /* FaviconURLFinder.swift in Sources */, + 65ED3FEA235DEF6C0081F399 /* SidebarViewController+ContextualMenus.swift in Sources */, + 65ED3FEB235DEF6C0081F399 /* ExportOPMLWindowController.swift in Sources */, + 65ED3FEC235DEF6C0081F399 /* RSHTMLMetadata+Extension.swift in Sources */, + 65ED3FED235DEF6C0081F399 /* SendToMarsEditCommand.swift in Sources */, + 65ED3FEE235DEF6C0081F399 /* UserNotificationManager.swift in Sources */, + 65ED3FEF235DEF6C0081F399 /* ScriptingObjectContainer.swift in Sources */, + 65ED3FF0235DEF6C0081F399 /* ArticleStylesManager.swift in Sources */, + 65ED3FF1235DEF6C0081F399 /* DetailContainerView.swift in Sources */, + 65ED3FF2235DEF6C0081F399 /* SharingServiceDelegate.swift in Sources */, + 65ED3FF3235DEF6C0081F399 /* ArticleSorter.swift in Sources */, + 65ED3FF4235DEF6C0081F399 /* TimelineViewController+ContextualMenus.swift in Sources */, + 65ED3FF5235DEF6C0081F399 /* ArticleStringFormatter.swift in Sources */, + 65ED3FF6235DEF6C0081F399 /* MultilineTextFieldSizer.swift in Sources */, + 65ED3FF7235DEF6C0081F399 /* SearchFeedDelegate.swift in Sources */, + 65ED3FF8235DEF6C0081F399 /* ErrorHandler.swift in Sources */, + 65ED3FF9235DEF6C0081F399 /* ActivityManager.swift in Sources */, + 65ED3FFA235DEF6C0081F399 /* FeedInspectorViewController.swift in Sources */, + 65ED3FFB235DEF6C0081F399 /* AccountsReaderAPIWindowController.swift in Sources */, + 65ED3FFC235DEF6C0081F399 /* AccountsAddLocalWindowController.swift in Sources */, + 65ED3FFD235DEF6C0081F399 /* PasteboardFolder.swift in Sources */, + 65ED3FFE235DEF6C0081F399 /* AccountsFeedbinWindowController.swift in Sources */, + 65ED3FFF235DEF6C0081F399 /* SidebarOutlineDataSource.swift in Sources */, + 65ED4000235DEF6C0081F399 /* SidebarCellAppearance.swift in Sources */, + 65ED4001235DEF6C0081F399 /* StarredFeedDelegate.swift in Sources */, + 65ED4002235DEF6C0081F399 /* FaviconDownloader.swift in Sources */, + 65ED4003235DEF6C0081F399 /* AdvancedPreferencesViewController.swift in Sources */, + 65ED4004235DEF6C0081F399 /* SharingServicePickerDelegate.swift in Sources */, + 65ED4005235DEF6C0081F399 /* Node-Extensions.swift in Sources */, + 65ED4006235DEF6C0081F399 /* AppAssets.swift in Sources */, + 65ED4007235DEF6C0081F399 /* AddFeedController.swift in Sources */, + 65ED4008235DEF6C0081F399 /* AccountRefreshTimer.swift in Sources */, + 65ED4009235DEF6C0081F399 /* SidebarStatusBarView.swift in Sources */, + 65ED400A235DEF6C0081F399 /* SearchTimelineFeedDelegate.swift in Sources */, + 65ED400B235DEF6C0081F399 /* TodayFeedDelegate.swift in Sources */, + 65ED400C235DEF6C0081F399 /* FolderInspectorViewController.swift in Sources */, + 65ED400D235DEF6C0081F399 /* SmartFeedDelegate.swift in Sources */, + 65ED400E235DEF6C0081F399 /* ImageDownloader.swift in Sources */, + 65ED400F235DEF6C0081F399 /* ArticleExtractorButton.swift in Sources */, + 65ED4010235DEF6C0081F399 /* AccountsAddTableCellView.swift in Sources */, + 65ED4011235DEF6C0081F399 /* AddFolderWindowController.swift in Sources */, + 65ED4012235DEF6C0081F399 /* TimelineContainerViewController.swift in Sources */, + 65ED4013235DEF6C0081F399 /* MainWIndowKeyboardHandler.swift in Sources */, + 65ED4014235DEF6C0081F399 /* PasteboardFeed.swift in Sources */, + 65ED4015235DEF6C0081F399 /* AccountsDetailViewController.swift in Sources */, + 65ED4016235DEF6C0081F399 /* DetailViewController.swift in Sources */, + 65ED4017235DEF6C0081F399 /* AppDelegate.swift in Sources */, + 65ED4018235DEF6C0081F399 /* AccountsTableViewBackgroundView.swift in Sources */, + 65ED4019235DEF6C0081F399 /* FetchRequestOperation.swift in Sources */, + 65ED401A235DEF6C0081F399 /* HTMLMetadataDownloader.swift in Sources */, + 65ED401B235DEF6C0081F399 /* TimelineViewController.swift in Sources */, + 65ED401C235DEF6C0081F399 /* FaviconGenerator.swift in Sources */, + 65ED401D235DEF6C0081F399 /* RefreshInterval.swift in Sources */, + 65ED401E235DEF6C0081F399 /* TimelineCellData.swift in Sources */, + 65ED401F235DEF6C0081F399 /* BuiltinSmartFeedInspectorViewController.swift in Sources */, + 65ED4020235DEF6C0081F399 /* AppDelegate+Scriptability.swift in Sources */, + 65ED4021235DEF6C0081F399 /* NNW3Document.swift in Sources */, + 65ED4022235DEF6C0081F399 /* ScriptingObject.swift in Sources */, + 65ED4023235DEF6C0081F399 /* Folder+Scriptability.swift in Sources */, + 65ED4024235DEF6C0081F399 /* TimelineCellLayout.swift in Sources */, + 65ED4025235DEF6C0081F399 /* DetailWebView.swift in Sources */, + 65ED4026235DEF6C0081F399 /* TimelineTableRowView.swift in Sources */, + 65ED4027235DEF6C0081F399 /* UnreadIndicatorView.swift in Sources */, + 65ED4028235DEF6C0081F399 /* ExtractedArticle.swift in Sources */, + 65ED4029235DEF6C0081F399 /* DeleteCommand.swift in Sources */, + 65ED402A235DEF6C0081F399 /* AddFeedWindowController.swift in Sources */, + 65ED402B235DEF6C0081F399 /* ImportOPMLWindowController.swift in Sources */, + 65ED402C235DEF6C0081F399 /* TimelineTableView.swift in Sources */, + 65ED402D235DEF6C0081F399 /* DetailStatusBarView.swift in Sources */, + 65ED402E235DEF6C0081F399 /* MainWindowController+Scriptability.swift in Sources */, + 65ED402F235DEF6C0081F399 /* PreferencesWindowController.swift in Sources */, + 65ED4030235DEF6C0081F399 /* SmallIconProvider.swift in Sources */, + 65ED4031235DEF6C0081F399 /* ArticleExtractor.swift in Sources */, + 65ED4032235DEF6C0081F399 /* FetchRequestQueue.swift in Sources */, + 65ED4033235DEF6C0081F399 /* SidebarKeyboardDelegate.swift in Sources */, + 65ED4034235DEF6C0081F399 /* AccountsPreferencesViewController.swift in Sources */, + 65ED4035235DEF6C0081F399 /* FolderTreeMenu.swift in Sources */, + 65ED4036235DEF6C0081F399 /* NNW3ImportController.swift in Sources */, + 65ED4037235DEF6C0081F399 /* FolderTreeControllerDelegate.swift in Sources */, + 65ED4038235DEF6C0081F399 /* RSImage-Extensions.swift in Sources */, + 65ED4039235DEF6C0081F399 /* SingleFaviconDownloader.swift in Sources */, + 65ED403A235DEF6C0081F399 /* Feed+Scriptability.swift in Sources */, + 65ED403B235DEF6C0081F399 /* AuthorAvatarDownloader.swift in Sources */, + 65ED403C235DEF6C0081F399 /* SingleLineTextFieldSizer.swift in Sources */, + 65ED403D235DEF6C0081F399 /* TimelineTableCellView.swift in Sources */, + 65ED403E235DEF6C0081F399 /* TimelineCellAppearance.swift in Sources */, + 65ED403F235DEF6C0081F399 /* ArticleRenderer.swift in Sources */, + 65ED4040235DEF6C0081F399 /* GeneralPrefencesViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 65ED4091235DEF770081F399 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 65ED4092235DEF770081F399 /* SafariExtensionViewController.swift in Sources */, + 65ED4093235DEF770081F399 /* SafariExtensionHandler.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 840D61782029031C009BC708 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 840D617F2029031C009BC708 /* AppDelegate.swift in Sources */, - 51E149B3234D82E40004F7A5 /* PasswordField.swift in Sources */, 512E08E72268801200BDCFDD /* FeedTreeControllerDelegate.swift in Sources */, 51C452A422650A2D00C03939 /* ArticleUtilities.swift in Sources */, 51EF0F79227716380050506E /* ColorHash.swift in Sources */, 5183CCDA226E31A50010922C /* NonIntrinsicImageView.swift in Sources */, 51EAED96231363EF00A9EEE3 /* NonIntrinsicButton.swift in Sources */, 51C4527B2265091600C03939 /* MasterUnreadIndicatorView.swift in Sources */, - 5152E1022324900D00E5C7AD /* SettingsAddAccountView.swift in Sources */, + 5186A635235EF3A800C97195 /* VibrantLabel.swift in Sources */, 51F85BF92274AA7B00C787DC /* UIBarButtonItem-Extensions.swift in Sources */, 51B62E68233186730085F949 /* MasterTimelineAvatarView.swift in Sources */, 51C45296226509D300C03939 /* OPMLExporter.swift in Sources */, @@ -2852,40 +3879,36 @@ 51C4528F226509BD00C03939 /* UnreadFeed.swift in Sources */, 51AF460E232488C6001742EF /* Account-Extensions.swift in Sources */, 51FD413B2342BD0500880194 /* MasterTimelineUnreadCountView.swift in Sources */, + 513146B2235A81A400387FDC /* AddFeedIntentHandler.swift in Sources */, 5183CCDD226F1F5C0010922C /* NavigationProgressView.swift in Sources */, - 51AF45E123246731001742EF /* SettingsAccountLabelView.swift in Sources */, 51D87EE12311D34700E63F03 /* ActivityType.swift in Sources */, 51C452772265091600C03939 /* MultilineUILabelSizer.swift in Sources */, 51C452A522650A2D00C03939 /* SmallIconProvider.swift in Sources */, + 516A09392360A2AE00EAE89B /* SettingsAccountTableViewCell.swift in Sources */, 51D5948722668EFA00DFC836 /* MarkStatusCommand.swift in Sources */, - 51322859232FDDB80033D4ED /* VibrantButtonStyle.swift in Sources */, + 51A1699C235E10D700EB091F /* AddAccountViewController.swift in Sources */, + 51A16999235E10D700EB091F /* AddLocalAccountViewController.swift in Sources */, 514B7C8323205EFB00BAC947 /* RootSplitViewController.swift in Sources */, - 5152E0F923248F6200E5C7AD /* SettingsLocalAccountView.swift in Sources */, 51FA73A52332BE110090D516 /* ArticleExtractor.swift in Sources */, + 51314704235C41FC00387FDC /* Intents.intentdefinition in Sources */, FF3ABF162325AF5D0074C542 /* ArticleSorter.swift in Sources */, - 510BD15D232D765D002692E4 /* SettingsReaderAPIAccountView.swift in Sources */, 51C4525C226508DF00C03939 /* String-Extensions.swift in Sources */, 51C452792265091600C03939 /* MasterTimelineTableViewCell.swift in Sources */, 51FA73AB2332C2FD0090D516 /* ArticleExtractorConfig.swift in Sources */, - 5132285B232FF2C40033D4ED /* SettingsRefreshSelectionView.swift in Sources */, 51C452852265093600C03939 /* FlattenedAccountFolderPickerData.swift in Sources */, 51C4526B226508F600C03939 /* MasterFeedViewController.swift in Sources */, 5126EE97226CB48A00C22AFC /* SceneCoordinator.swift in Sources */, 51FD40C72341555A00880194 /* UIImage-Extensions.swift in Sources */, - 5132293B23305D4C0033D4ED /* SettingsAboutView.swift in Sources */, 84CAFCB022BC8C35007694F0 /* FetchRequestOperation.swift in Sources */, 51EF0F77227716200050506E /* FaviconGenerator.swift in Sources */, 51938DF3231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift in Sources */, 51C4525A226508D600C03939 /* UIStoryboard-Extensions.swift in Sources */, - 519D740823243FEA008BB345 /* SettingsSubscriptionsImportDocumentPickerView.swift in Sources */, 51BB7C272335A8E5008E8144 /* ArticleActivityItemSource.swift in Sources */, - 51AF460C23247F11001742EF /* SettingsFeedbinAccountView.swift in Sources */, 51F85BF52273625800C787DC /* Bundle-Extensions.swift in Sources */, - 519D740723243FE7008BB345 /* SettingsSubscriptionsExportDocumentPickerView.swift in Sources */, 51C452A622650A3500C03939 /* Node-Extensions.swift in Sources */, 5183CCDF226F1FCC0010922C /* UINavigationController+Progress.swift in Sources */, 51C45294226509C800C03939 /* SearchFeedDelegate.swift in Sources */, - 5F323809231DF9F000706F6B /* NNWTableViewCell.swift in Sources */, + 5F323809231DF9F000706F6B /* VibrantTableViewCell.swift in Sources */, 512E09352268B25900BDCFDD /* UISplitViewController-Extensions.swift in Sources */, 51FE10042345529D0056195D /* UserNotificationManager.swift in Sources */, 51C452A022650A1900C03939 /* FeedIconDownloader.swift in Sources */, @@ -2903,8 +3926,7 @@ 51C4529A22650A0400C03939 /* ArticleStyle.swift in Sources */, 51C4527F2265092C00C03939 /* ArticleViewController.swift in Sources */, 51C4526A226508F600C03939 /* MasterFeedTableViewCellLayout.swift in Sources */, - 51E149C2234D852F0004F7A5 /* ShowHidePasswordView.swift in Sources */, - 51C452AE2265104D00C03939 /* TimelineStringFormatter.swift in Sources */, + 51C452AE2265104D00C03939 /* ArticleStringFormatter.swift in Sources */, 512E08E62268800D00BDCFDD /* FolderTreeControllerDelegate.swift in Sources */, 51C4529922650A0000C03939 /* ArticleStylesManager.swift in Sources */, 5123DB9F233EC6FD00282CC9 /* FeedInspectorView.swift in Sources */, @@ -2916,27 +3938,28 @@ 84CAFCA522BC8C08007694F0 /* FetchRequestQueue.swift in Sources */, 51C4529C22650A1000C03939 /* SingleFaviconDownloader.swift in Sources */, 51E595A6228CC36500FCC42B /* ArticleStatusSyncTimer.swift in Sources */, + 51A1699F235E10D700EB091F /* AboutViewController.swift in Sources */, 51C45290226509C100C03939 /* PseudoFeed.swift in Sources */, 51C452A922650DC600C03939 /* ArticleRenderer.swift in Sources */, - 51AF460323247321001742EF /* SettingsDetailAccountView.swift in Sources */, 5115CAF42266301400B21BCE /* AddContainerViewController.swift in Sources */, 51C45297226509E300C03939 /* DefaultFeedsImporter.swift in Sources */, 512E094D2268B8AB00BDCFDD /* DeleteCommand.swift in Sources */, 51F85BFB2275D85000C787DC /* Array-Extensions.swift in Sources */, 51C452AC22650FD200C03939 /* AppNotifications.swift in Sources */, 51EF0F7E2277A57D0050506E /* MasterTimelineAccessibilityCellLayout.swift in Sources */, + 51A1699B235E10D700EB091F /* DetailAccountViewController.swift in Sources */, 51C452762265091600C03939 /* MasterTimelineViewController.swift in Sources */, 5183CCE9226F68D90010922C /* AccountRefreshTimer.swift in Sources */, 51C452882265093600C03939 /* AddFeedViewController.swift in Sources */, + 51A169A0235E10D700EB091F /* FeedbinAccountViewController.swift in Sources */, 51934CCE2310792F006127BE /* ActivityManager.swift in Sources */, 518651DA235621840078E021 /* ImageTransition.swift in Sources */, 514219372352510100E07E2C /* ImageScrollView.swift in Sources */, - DF999FF722B5AEFA0064B687 /* SafariView.swift in Sources */, + 51A16997235E10D700EB091F /* RefreshIntervalViewController.swift in Sources */, 51C4529B22650A1000C03939 /* FaviconDownloader.swift in Sources */, 84DEE56622C32CA4005FC42C /* SmartFeedDelegate.swift in Sources */, 512E09012268907400BDCFDD /* MasterFeedTableViewSectionHeader.swift in Sources */, 519D740623243CC0008BB345 /* RefreshInterval-Extensions.swift in Sources */, - 51322855232EED360033D4ED /* VibrantSelectAction.swift in Sources */, 51C45268226508F600C03939 /* MasterFeedUnreadCountView.swift in Sources */, 5183CCD0226E1E880010922C /* NonIntrinsicLabel.swift in Sources */, 51C4529F22650A1900C03939 /* AuthorAvatarDownloader.swift in Sources */, @@ -2947,12 +3970,12 @@ 51C4528D2265095F00C03939 /* AddFolderViewController.swift in Sources */, 51C452782265091600C03939 /* MasterTimelineCellData.swift in Sources */, 5148F4552336DB7000F8CD8B /* MasterTimelineTitleView.swift in Sources */, + 51FFF0C4235EE8E5002762AA /* VibrantButton.swift in Sources */, 513228FC233037630033D4ED /* Reachability.swift in Sources */, 51C45259226508D300C03939 /* AppDefaults.swift in Sources */, - 519D73FB2323FF35008BB345 /* SettingsView.swift in Sources */, 511D4419231FC02D00FB1562 /* KeyboardManager.swift in Sources */, + 51A1699D235E10D700EB091F /* SettingsViewController.swift in Sources */, 51C45293226509C800C03939 /* StarredFeedDelegate.swift in Sources */, - 513229312330523F0033D4ED /* SettingsAttributedStringView.swift in Sources */, 51D6A5BC23199C85001C27D8 /* MasterTimelineDataSource.swift in Sources */, 51934CCB230F599B006127BE /* ThemedNavigationController.swift in Sources */, ); @@ -2983,12 +4006,10 @@ 845A29221FC9251E007B49E3 /* SidebarCellLayout.swift in Sources */, 84AD1EBA2031649C00BC20B7 /* SmartFeedPasteboardWriter.swift in Sources */, 84CC88181FE59CBF00644329 /* SmartFeedsController.swift in Sources */, - 518651AF23555EB20078E021 /* NNW3Entry.swift in Sources */, 849A97661ED9EB96007D329B /* SidebarViewController.swift in Sources */, 9EA33BB92318F8C10097B644 /* AccountsFeedlyWebWindowController.swift in Sources */, 849A97641ED9EB96007D329B /* SidebarOutlineView.swift in Sources */, 5127B238222B4849006D641D /* DetailKeyboardDelegate.swift in Sources */, - 518651AC23555EB20078E021 /* ImportNNW3WindowController.swift in Sources */, 8405DD9922153B6B008CE1BF /* TimelineContainerView.swift in Sources */, D5A2678C20130ECF00A8D3C0 /* Author+Scriptability.swift in Sources */, 84F2D5371FC22FCC00998D64 /* PseudoFeed.swift in Sources */, @@ -3010,13 +4031,13 @@ 84162A152038C12C00035290 /* MarkCommandValidationStatus.swift in Sources */, 84E95D241FB1087500552D99 /* ArticlePasteboardWriter.swift in Sources */, 849A975B1ED9EB0D007D329B /* ArticleUtilities.swift in Sources */, + 849ADEE8235981A0000E1B81 /* NNW3OpenPanelAccessoryViewController.swift in Sources */, 849A975C1ED9EB0D007D329B /* DefaultFeedsImporter.swift in Sources */, 84A37CB5201ECD610087C5AF /* RenameWindowController.swift in Sources */, 84A14FF320048CA70046AD9A /* SendToMicroBlogCommand.swift in Sources */, 849A97891ED9ECEF007D329B /* ArticleStyle.swift in Sources */, 84FF69B11FC3793300DC198E /* FaviconURLFinder.swift in Sources */, 84B7178C201E66580091657D /* SidebarViewController+ContextualMenus.swift in Sources */, - 518651AD23555EB20078E021 /* NNW3PlistConverter.swift in Sources */, 5144EA43227A380F00D19003 /* ExportOPMLWindowController.swift in Sources */, 842611A21FCB769D0086A189 /* RSHTMLMetadata+Extension.swift in Sources */, 84A1500520048DDF0046AD9A /* SendToMarsEditCommand.swift in Sources */, @@ -3027,7 +4048,7 @@ 519B8D332143397200FA689C /* SharingServiceDelegate.swift in Sources */, FF3ABF1523259DDB0074C542 /* ArticleSorter.swift in Sources */, 84E8E0DB202EC49300562D8F /* TimelineViewController+ContextualMenus.swift in Sources */, - 849A97791ED9EC04007D329B /* TimelineStringFormatter.swift in Sources */, + 849A97791ED9EC04007D329B /* ArticleStringFormatter.swift in Sources */, 84E185C3203BB12600F69BFA /* MultilineTextFieldSizer.swift in Sources */, 8477ACBE22238E9500DF7F37 /* SearchFeedDelegate.swift in Sources */, 51E3EB33229AB02C00645299 /* ErrorHandler.swift in Sources */, @@ -3058,7 +4079,6 @@ 849A97431ED9EAA9007D329B /* AddFolderWindowController.swift in Sources */, 8405DDA522168C62008CE1BF /* TimelineContainerViewController.swift in Sources */, 844B5B671FEA18E300C7C76A /* MainWIndowKeyboardHandler.swift in Sources */, - 518651B123555EB20078E021 /* NNW3Feed.swift in Sources */, 848D578E21543519005FFAD5 /* PasteboardFeed.swift in Sources */, 5144EA2F2279FAB600D19003 /* AccountsDetailViewController.swift in Sources */, 849A97801ED9EC42007D329B /* DetailViewController.swift in Sources */, @@ -3093,8 +4113,8 @@ 844B5B591FE9FE4F00C7C76A /* SidebarKeyboardDelegate.swift in Sources */, 84C9FC7C22629E1200D921D6 /* AccountsPreferencesViewController.swift in Sources */, 51EC114C2149FE3300B296E3 /* FolderTreeMenu.swift in Sources */, + 849ADEE42359817E000E1B81 /* NNW3ImportController.swift in Sources */, 849A97A31ED9F180007D329B /* FolderTreeControllerDelegate.swift in Sources */, - 518651B023555EB20078E021 /* NNW3FeedsImporter.swift in Sources */, 51126DA4225FDE2F00722696 /* RSImage-Extensions.swift in Sources */, 845A29091FC74B8E007B49E3 /* SingleFaviconDownloader.swift in Sources */, D5F4EDB720074D6500B9E363 /* Feed+Scriptability.swift in Sources */, @@ -3137,6 +4157,11 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 5131463D235A7BBE00387FDC /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 51314636235A7BBE00387FDC /* NetNewsWire iOS Intents Extension */; + targetProxy = 5131463C235A7BBE00387FDC /* PBXContainerItemProxy */; + }; 51554C27228B71910055115A /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = SyncDatabase; @@ -3162,6 +4187,86 @@ name = Account; targetProxy = 51C451BF226377D000C03939 /* PBXContainerItemProxy */; }; + 65ED3FA3235DEF6C0081F399 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = RSCore; + targetProxy = 65ED3FA4235DEF6C0081F399 /* PBXContainerItemProxy */; + }; + 65ED3FA5235DEF6C0081F399 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = RSWeb; + targetProxy = 65ED3FA6235DEF6C0081F399 /* PBXContainerItemProxy */; + }; + 65ED3FA7235DEF6C0081F399 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = RSTree; + targetProxy = 65ED3FA8235DEF6C0081F399 /* PBXContainerItemProxy */; + }; + 65ED3FA9235DEF6C0081F399 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = RSParser; + targetProxy = 65ED3FAA235DEF6C0081F399 /* PBXContainerItemProxy */; + }; + 65ED3FAB235DEF6C0081F399 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = RSDatabase; + targetProxy = 65ED3FAC235DEF6C0081F399 /* PBXContainerItemProxy */; + }; + 65ED3FAD235DEF6C0081F399 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = ArticlesDatabase; + targetProxy = 65ED3FAE235DEF6C0081F399 /* PBXContainerItemProxy */; + }; + 65ED3FAF235DEF6C0081F399 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Articles; + targetProxy = 65ED3FB0235DEF6C0081F399 /* PBXContainerItemProxy */; + }; + 65ED3FB1235DEF6C0081F399 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Account; + targetProxy = 65ED3FB2235DEF6C0081F399 /* PBXContainerItemProxy */; + }; + 65ED3FB3235DEF6C0081F399 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = SyncDatabase; + targetProxy = 65ED3FB4235DEF6C0081F399 /* PBXContainerItemProxy */; + }; + 65ED41C5235E61550081F399 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 6581C73220CED60000F4AD34 /* Subscribe to Feed */; + targetProxy = 65ED41C4235E61550081F399 /* PBXContainerItemProxy */; + }; + 65ED41C7235E615E0081F399 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 65ED4090235DEF770081F399 /* Subscribe to Feed MAS */; + targetProxy = 65ED41C6235E615E0081F399 /* PBXContainerItemProxy */; + }; + 65ED42D0235E71F60081F399 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Sparkle; + targetProxy = 65ED42CF235E71F60081F399 /* PBXContainerItemProxy */; + }; + 65ED42D2235E72000081F399 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = SparkleDownloader; + targetProxy = 65ED42D1235E72000081F399 /* PBXContainerItemProxy */; + }; + 65ED42D4235E72000081F399 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = SparkleInstallerConnection; + targetProxy = 65ED42D3235E72000081F399 /* PBXContainerItemProxy */; + }; + 65ED42D6235E72000081F399 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = SparkleInstallerLauncher; + targetProxy = 65ED42D5235E72000081F399 /* PBXContainerItemProxy */; + }; + 65ED42D8235E72000081F399 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = SparkleInstallerStatus; + targetProxy = 65ED42D7235E72000081F399 /* PBXContainerItemProxy */; + }; 849C64731ED37A5D003D8FC0 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 849C645F1ED37A5D003D8FC0 /* NetNewsWire */; @@ -3203,6 +4308,15 @@ name = LaunchScreenPad.storyboard; sourceTree = ""; }; + 51314707235C41FC00387FDC /* Intents.intentdefinition */ = { + isa = PBXVariantGroup; + children = ( + 51314706235C41FC00387FDC /* Base */, + 51314714235C420900387FDC /* en */, + ); + name = Intents.intentdefinition; + sourceTree = ""; + }; 513C5CEA232571C2003D4054 /* MainInterface.storyboard */ = { isa = PBXVariantGroup; children = ( @@ -3286,6 +4400,27 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 51314640235A7BBE00387FDC /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 51314617235A797400387FDC /* NetNewsWire_iOSintentextension_target.xcconfig */; + buildSettings = { + }; + name = Debug; + }; + 51314641235A7BBE00387FDC /* Test */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 51314617235A797400387FDC /* NetNewsWire_iOSintentextension_target.xcconfig */; + buildSettings = { + }; + name = Test; + }; + 51314642235A7BBE00387FDC /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 51314617235A797400387FDC /* NetNewsWire_iOSintentextension_target.xcconfig */; + buildSettings = { + }; + name = Release; + }; 513C5CF2232571C2003D4054 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 515D4FCE2325B3D000EE1167 /* NetNewsWire_iOSshareextension_target.xcconfig */; @@ -3377,6 +4512,57 @@ }; name = Release; }; + 65ED4080235DEF6C0081F399 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 65ED40F2235DF5E00081F399 /* NetNewsWire_macapp_target_macappstore.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = "Apple Development"; + PRODUCT_NAME = NetNewsWire; + }; + name = Debug; + }; + 65ED4081235DEF6C0081F399 /* Test */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 65ED40F2235DF5E00081F399 /* NetNewsWire_macapp_target_macappstore.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = "Apple Development"; + PRODUCT_NAME = NetNewsWire; + }; + name = Test; + }; + 65ED4082235DEF6C0081F399 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 65ED40F2235DF5E00081F399 /* NetNewsWire_macapp_target_macappstore.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = "Apple Development"; + PRODUCT_NAME = NetNewsWire; + }; + name = Release; + }; + 65ED409A235DEF770081F399 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 65ED4186235E045B0081F399 /* NetNewsWire_safariextension_target_macappstore.xcconfig */; + buildSettings = { + PRODUCT_NAME = "Subscribe to Feed"; + }; + name = Debug; + }; + 65ED409B235DEF770081F399 /* Test */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 65ED4186235E045B0081F399 /* NetNewsWire_safariextension_target_macappstore.xcconfig */; + buildSettings = { + PRODUCT_NAME = "Subscribe to Feed"; + }; + name = Test; + }; + 65ED409C235DEF770081F399 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 65ED4186235E045B0081F399 /* NetNewsWire_safariextension_target_macappstore.xcconfig */; + buildSettings = { + PRODUCT_NAME = "Subscribe to Feed"; + }; + name = Release; + }; 840D61A42029031E009BC708 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 51121AA12265430A00BC0EC1 /* NetNewsWire_iOSapp_target.xcconfig */; @@ -3436,6 +4622,16 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 5131463F235A7BBE00387FDC /* Build configuration list for PBXNativeTarget "NetNewsWire iOS Intents Extension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 51314640235A7BBE00387FDC /* Debug */, + 51314641235A7BBE00387FDC /* Test */, + 51314642235A7BBE00387FDC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 513C5CFC232571C2003D4054 /* Build configuration list for PBXNativeTarget "NetNewsWire iOS Share Extension" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -3466,6 +4662,26 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 65ED407F235DEF6C0081F399 /* Build configuration list for PBXNativeTarget "NetNewsWire MAS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 65ED4080235DEF6C0081F399 /* Debug */, + 65ED4081235DEF6C0081F399 /* Test */, + 65ED4082235DEF6C0081F399 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 65ED4099235DEF770081F399 /* Build configuration list for PBXNativeTarget "Subscribe to Feed MAS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 65ED409A235DEF770081F399 /* Debug */, + 65ED409B235DEF770081F399 /* Test */, + 65ED409C235DEF770081F399 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 840D61A32029031E009BC708 /* Build configuration list for PBXNativeTarget "NetNewsWire-iOS" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/NetNewsWire.xcodeproj/xcshareddata/xcschemes/NetNewsWire MAS.xcscheme b/NetNewsWire.xcodeproj/xcshareddata/xcschemes/NetNewsWire MAS.xcscheme new file mode 100644 index 000000000..29320b85f --- /dev/null +++ b/NetNewsWire.xcodeproj/xcshareddata/xcschemes/NetNewsWire MAS.xcscheme @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/README.md b/README.md index 4cf518fe3..b8f9fe4d7 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ See the [Contributing](CONTRIBUTING.md) page for our process. It’s pretty stra ```bash git clone https://github.com/brentsimmons/NetNewsWire.git cd NetNewsWire -git submodule update --init +git submodule update --init --recursive ``` You can locally override the Xcode settings for code signing diff --git a/Shared/Activity/ActivityManager.swift b/Shared/Activity/ActivityManager.swift index 7eea80941..16cf6df2c 100644 --- a/Shared/Activity/ActivityManager.swift +++ b/Shared/Activity/ActivityManager.swift @@ -42,7 +42,7 @@ class ActivityManager { let title = NSLocalizedString("See articles for “Today”", comment: "Today") selectingActivity = makeSelectingActivity(type: ActivityType.selectToday, title: title, identifier: "smartfeed.today") - selectingActivity!.becomeCurrent() + donate(selectingActivity!) } func selectingAllUnread() { @@ -50,7 +50,7 @@ class ActivityManager { let title = NSLocalizedString("See articles in “All Unread”", comment: "All Unread") selectingActivity = makeSelectingActivity(type: ActivityType.selectAllUnread, title: title, identifier: "smartfeed.allUnread") - selectingActivity!.becomeCurrent() + donate(selectingActivity!) } func selectingStarred() { @@ -58,7 +58,7 @@ class ActivityManager { let title = NSLocalizedString("See articles in “Starred”", comment: "Starred") selectingActivity = makeSelectingActivity(type: ActivityType.selectStarred, title: title, identifier: "smartfeed.starred") - selectingActivity!.becomeCurrent() + donate(selectingActivity!) } func selectingFolder(_ folder: Folder) { @@ -68,8 +68,10 @@ class ActivityManager { let title = NSString.localizedStringWithFormat(localizedText as NSString, folder.nameForDisplay) as String selectingActivity = makeSelectingActivity(type: ActivityType.selectFolder, title: title, identifier: ActivityManager.identifer(for: folder)) - selectingActivity!.userInfo = folder.deepLinkUserInfo - selectingActivity!.becomeCurrent() + let userInfo = folder.deepLinkUserInfo + selectingActivity!.userInfo = userInfo + selectingActivity!.requiredUserInfoKeys = Set(userInfo.keys.map { $0 as! String }) + donate(selectingActivity!) } func selectingFeed(_ feed: Feed) { @@ -79,9 +81,11 @@ class ActivityManager { let title = NSString.localizedStringWithFormat(localizedText as NSString, feed.nameForDisplay) as String selectingActivity = makeSelectingActivity(type: ActivityType.selectFeed, title: title, identifier: ActivityManager.identifer(for: feed)) - selectingActivity!.userInfo = feed.deepLinkUserInfo + let userInfo = feed.deepLinkUserInfo + selectingActivity!.userInfo = userInfo + selectingActivity!.requiredUserInfoKeys = Set(userInfo.keys.map { $0 as! String }) updateSelectingActivityFeedSearchAttributes(with: feed) - selectingActivity!.becomeCurrent() + donate(selectingActivity!) } func invalidateSelecting() { @@ -93,7 +97,7 @@ class ActivityManager { guard nextUnreadActivity == nil else { return } let title = NSLocalizedString("See first unread article", comment: "First Unread") nextUnreadActivity = makeSelectingActivity(type: ActivityType.nextUnread, title: title, identifier: "action.nextUnread") - nextUnreadActivity!.becomeCurrent() + donate(nextUnreadActivity!) } func invalidateNextUnread() { @@ -112,7 +116,7 @@ class ActivityManager { updateReadArticleSearchAttributes(with: article) #endif - readingActivity?.becomeCurrent() + donate(readingActivity!) } func invalidateReading() { @@ -135,7 +139,7 @@ class ActivityManager { ids.append(contentsOf: identifers(for: feed)) } - NSUserActivity.deleteSavedUserActivities(withPersistentIdentifiers: ids) {} + CSSearchableIndex.default().deleteSearchableItems(withIdentifiers: ids) } static func cleanUp(_ folder: Folder) { @@ -146,11 +150,11 @@ class ActivityManager { ids.append(contentsOf: identifers(for: feed)) } - NSUserActivity.deleteSavedUserActivities(withPersistentIdentifiers: ids) {} + CSSearchableIndex.default().deleteSearchableItems(withIdentifiers: ids) } static func cleanUp(_ feed: Feed) { - NSUserActivity.deleteSavedUserActivities(withPersistentIdentifiers: identifers(for: feed)) {} + CSSearchableIndex.default().deleteSearchableItems(withIdentifiers: identifers(for: feed)) } #endif @@ -186,6 +190,7 @@ private extension ActivityManager { activity.suggestedInvocationPhrase = title activity.isEligibleForPrediction = true activity.persistentIdentifier = identifier + activity.contentAttributeSet?.relatedUniqueIdentifier = identifier #endif return activity @@ -193,8 +198,10 @@ private extension ActivityManager { func makeReadArticleActivity(_ article: Article) -> NSUserActivity { let activity = NSUserActivity(activityType: ActivityType.readArticle.rawValue) - activity.title = article.title - activity.userInfo = article.deepLinkUserInfo + activity.title = ArticleStringFormatter.truncatedTitle(article) + let userInfo = article.deepLinkUserInfo + activity.userInfo = userInfo + activity.requiredUserInfoKeys = Set(userInfo.keys.map { $0 as! String }) activity.isEligibleForHandoff = true #if os(iOS) @@ -214,10 +221,11 @@ private extension ActivityManager { func updateReadArticleSearchAttributes(with article: Article) { let attributeSet = CSSearchableItemAttributeSet(itemContentType: kUTTypeCompositeContent as String) - attributeSet.title = article.title + attributeSet.title = ArticleStringFormatter.truncatedTitle(article) attributeSet.contentDescription = article.summary attributeSet.keywords = makeKeywords(article) - + attributeSet.relatedUniqueIdentifier = ActivityManager.identifer(for: article) + if let image = article.avatarImage() { attributeSet.thumbnailData = image.pngData() } @@ -230,7 +238,7 @@ private extension ActivityManager { func makeKeywords(_ article: Article) -> [String] { let feedNameKeywords = makeKeywords(article.feed?.nameForDisplay) - let articleTitleKeywords = makeKeywords(article.title) + let articleTitleKeywords = makeKeywords(ArticleStringFormatter.truncatedTitle(article)) return feedNameKeywords + articleTitleKeywords } @@ -243,6 +251,7 @@ private extension ActivityManager { let attributeSet = CSSearchableItemAttributeSet(itemContentType: kUTTypeItem as String) attributeSet.title = feed.nameForDisplay attributeSet.keywords = makeKeywords(feed.nameForDisplay) + attributeSet.relatedUniqueIdentifier = ActivityManager.identifer(for: feed) if let image = appDelegate.feedIconDownloader.icon(for: feed) { #if os(iOS) attributeSet.thumbnailData = image.pngData() @@ -262,6 +271,19 @@ private extension ActivityManager { } + func donate(_ activity: NSUserActivity) { + // You have to put the search item in the index or the activity won't index + // itself because the relatedUniqueIdentifier on the activity attributeset is populated. + if let attributeSet = activity.contentAttributeSet { + let identifier = attributeSet.relatedUniqueIdentifier + let tempAttributeSet = CSSearchableItemAttributeSet(itemContentType: kUTTypeItem as String) + let searchableItem = CSSearchableItem(uniqueIdentifier: identifier, domainIdentifier: nil, attributeSet: tempAttributeSet) + CSSearchableIndex.default().indexSearchableItems([searchableItem]) + } + + activity.becomeCurrent() + } + static func identifer(for folder: Folder) -> String { return "account_\(folder.account!.accountID)_folder_\(folder.nameForDisplay)" } diff --git a/Shared/Activity/ActivityType.swift b/Shared/Activity/ActivityType.swift index be0254fb4..bce22877b 100644 --- a/Shared/Activity/ActivityType.swift +++ b/Shared/Activity/ActivityType.swift @@ -16,4 +16,5 @@ enum ActivityType: String { case selectFeed = "com.ranchero.NetNewsWire.SelectFeed" case nextUnread = "com.ranchero.NetNewsWire.NextUnread" case readArticle = "com.ranchero.NetNewsWire.ReadArticle" + case addFeedIntent = "AddFeedIntent" } diff --git a/Shared/Timeline/TimelineStringFormatter.swift b/Shared/Data/ArticleStringFormatter.swift similarity index 97% rename from Shared/Timeline/TimelineStringFormatter.swift rename to Shared/Data/ArticleStringFormatter.swift index 067d5542c..7fa6f808a 100644 --- a/Shared/Timeline/TimelineStringFormatter.swift +++ b/Shared/Data/ArticleStringFormatter.swift @@ -1,5 +1,5 @@ // -// TimelineStringFormatter.swift +// ArticleStringFormatter.swift // NetNewsWire // // Created by Brent Simmons on 8/31/15. @@ -10,7 +10,7 @@ import Foundation import Articles import RSParser -struct TimelineStringFormatter { +struct ArticleStringFormatter { private static var feedNameCache = [String: String]() private static var titleCache = [String: String]() diff --git a/Shared/Importers/DefaultFeedsImporter.swift b/Shared/Importers/DefaultFeedsImporter.swift index 63ec5aa71..b86d39e36 100644 --- a/Shared/Importers/DefaultFeedsImporter.swift +++ b/Shared/Importers/DefaultFeedsImporter.swift @@ -12,21 +12,10 @@ import RSCore struct DefaultFeedsImporter { - static func importIfNeeded(_ isFirstRun: Bool, account: Account) { - guard shouldImportDefaultFeeds(isFirstRun) else { - return - } - + static func importDefaultFeeds(account: Account) { appDelegate.logDebugMessage("Importing default feeds.") let defaultFeedsURL = Bundle.main.url(forResource: "DefaultFeeds", withExtension: "opml")! AccountManager.shared.defaultAccount.importOPML(defaultFeedsURL) { result in } } - - private static func shouldImportDefaultFeeds(_ isFirstRun: Bool) -> Bool { - if !isFirstRun || AccountManager.shared.anyAccountHasAtLeastOneFeed() { - return false - } - return true - } } diff --git a/Shared/UserNotifications/UserNotificationManager.swift b/Shared/UserNotifications/UserNotificationManager.swift index ce1838541..fbf3608f1 100644 --- a/Shared/UserNotifications/UserNotificationManager.swift +++ b/Shared/UserNotifications/UserNotificationManager.swift @@ -47,9 +47,9 @@ private extension UserNotificationManager { let content = UNMutableNotificationContent() content.title = feed.nameForDisplay - content.body = TimelineStringFormatter.truncatedTitle(article) + content.body = ArticleStringFormatter.truncatedTitle(article) if content.body.isEmpty { - content.body = TimelineStringFormatter.truncatedSummary(article) + content.body = ArticleStringFormatter.truncatedSummary(article) } content.sound = UNNotificationSound.default diff --git a/iOS/AppAssets.swift b/iOS/AppAssets.swift index 2ca4fda10..8f60395dd 100644 --- a/iOS/AppAssets.swift +++ b/iOS/AppAssets.swift @@ -7,9 +7,26 @@ // import UIKit import RSCore +import Account struct AppAssets { + static var accountLocalPadImage: UIImage = { + return UIImage(named: "accountLocalPad")! + }() + + static var accountLocalPhoneImage: UIImage = { + return UIImage(named: "accountLocalPhone")! + }() + + static var accountFeedbinImage: UIImage = { + return UIImage(named: "accountFeedbin")! + }() + + static var accountFreshRSSImage: UIImage = { + return UIImage(named: "accountFreshRSS")! + }() + static var articleExtractorError: UIImage = { return UIImage(named: "articleExtractorError")! }() @@ -140,10 +157,6 @@ struct AppAssets { return UIImage(systemName: "star.fill")! }() - static var tableViewCellHighlightedTextColor: UIColor = { - return UIColor(named: "tableViewCellHighlightedTextColor")! - }() - static var timelineStarImage: UIImage = { let image = UIImage(systemName: "star.fill")! return image.withTintColor(AppAssets.starColor, renderingMode: .alwaysOriginal) @@ -161,4 +174,25 @@ struct AppAssets { return UIImage(systemName: "largecircle.fill.circle")! }() + static var vibrantTextColor: UIColor = { + return UIColor(named: "vibrantTextColor")! + }() + + static func image(for accountType: AccountType) -> UIImage? { + switch accountType { + case .onMyMac: + if UIDevice.current.userInterfaceIdiom == .pad { + return AppAssets.accountLocalPadImage + } else { + return AppAssets.accountLocalPhoneImage + } + case .feedbin: + return AppAssets.accountFeedbinImage + case .freshRSS: + return AppAssets.accountFreshRSSImage + default: + return nil + } + } + } diff --git a/iOS/AppDefaults.swift b/iOS/AppDefaults.swift index 81a58a09c..31d006641 100644 --- a/iOS/AppDefaults.swift +++ b/iOS/AppDefaults.swift @@ -106,7 +106,7 @@ struct AppDefaults { let defaults: [String : Any] = [Key.lastImageCacheFlushDate: Date(), Key.refreshInterval: RefreshInterval.everyHour.rawValue, Key.timelineGroupByFeed: false, - Key.timelineNumberOfLines: 3, + Key.timelineNumberOfLines: 2, Key.timelineSortDirection: ComparisonResult.orderedDescending.rawValue, Key.displayUndoAvailableTip: true] AppDefaults.shared.register(defaults: defaults) diff --git a/iOS/AppDelegate.swift b/iOS/AppDelegate.swift index 39b5abe14..f0fe5936f 100644 --- a/iOS/AppDelegate.swift +++ b/iOS/AppDelegate.swift @@ -73,8 +73,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD os_log("Is first run.", log: log, type: .info) } - let localAccount = AccountManager.shared.defaultAccount - DefaultFeedsImporter.importIfNeeded(isFirstRun, account: localAccount) + if isFirstRun && !AccountManager.shared.anyAccountHasAtLeastOneFeed() { + let localAccount = AccountManager.shared.defaultAccount + DefaultFeedsImporter.importDefaultFeeds(account: localAccount) + } initializeDownloaders() initializeHomeScreenQuickActions() diff --git a/iOS/Article/ArticleViewController.swift b/iOS/Article/ArticleViewController.swift index 89396ac74..c73636727 100644 --- a/iOS/Article/ArticleViewController.swift +++ b/iOS/Article/ArticleViewController.swift @@ -117,7 +117,10 @@ class ArticleViewController: UIViewController { // Even though page.html should be loaded into this webview, we have to do it again // to work around this bug: http://www.openradar.me/22855188 - webView.loadHTMLString(ArticleRenderer.page.html, baseURL: ArticleRenderer.page.baseURL) + let url = Bundle.main.url(forResource: "page", withExtension: "html")! + webView.loadFileURL(url, allowingReadAccessTo: url.deletingLastPathComponent()) +// let request = URLRequest(url: url) +// webView.load(request) } diff --git a/iOS/Base.lproj/Main.storyboard b/iOS/Base.lproj/Main.storyboard index df20db9ac..994202c66 100644 --- a/iOS/Base.lproj/Main.storyboard +++ b/iOS/Base.lproj/Main.storyboard @@ -121,7 +121,7 @@ - + diff --git a/iOS/Intents/AddFeedIntentHandler.swift b/iOS/Intents/AddFeedIntentHandler.swift new file mode 100644 index 000000000..ab822fd16 --- /dev/null +++ b/iOS/Intents/AddFeedIntentHandler.swift @@ -0,0 +1,135 @@ +// +// AddFeedIntentHandler.swift +// NetNewsWire +// +// Created by Maurice Parker on 10/18/19. +// Copyright © 2019 Ranchero Software. All rights reserved. +// + +import Intents +import Account + +public class AddFeedIntentHandler: NSObject, AddFeedIntentHandling { + + override init() { + super.init() + DispatchQueue.main.sync { + AccountManager.shared = AccountManager() + } + } + + public func resolveUrl(for intent: AddFeedIntent, with completion: @escaping (AddFeedUrlResolutionResult) -> Void) { + guard let url = intent.url else { + completion(.unsupported(forReason: .required)) + return + } + completion(.success(with: url)) + } + + public func provideAccountNameOptions(for intent: AddFeedIntent, with completion: @escaping ([String]?, Error?) -> Void) { + DispatchQueue.main.async { + let accountNames = AccountManager.shared.activeAccounts.compactMap { $0.nameForDisplay } + completion(accountNames, nil) + } + } + + public func resolveAccountName(for intent: AddFeedIntent, with completion: @escaping (AddFeedAccountNameResolutionResult) -> Void) { + guard let accountName = intent.accountName else { + completion(AddFeedAccountNameResolutionResult.notRequired()) + return + } + DispatchQueue.main.async { + if AccountManager.shared.findActiveAccount(forDisplayName: accountName) == nil { + completion(.unsupported(forReason: .invalid)) + } else { + completion(.success(with: accountName)) + } + } + } + + public func provideFolderNameOptions(for intent: AddFeedIntent, with completion: @escaping ([String]?, Error?) -> Void) { + DispatchQueue.main.async { + guard let accountName = intent.accountName, let account = AccountManager.shared.findActiveAccount(forDisplayName: accountName) else { + completion([String](), nil) + return + } + + let folderNames = account.folders?.map { $0.nameForDisplay } + completion(folderNames, nil) + } + } + + public func resolveFolderName(for intent: AddFeedIntent, with completion: @escaping (AddFeedFolderNameResolutionResult) -> Void) { + guard let accountName = intent.accountName, let folderName = intent.folderName else { + completion(AddFeedFolderNameResolutionResult.notRequired()) + return + } + + DispatchQueue.main.async { + guard let account = AccountManager.shared.findActiveAccount(forDisplayName: accountName) else { + completion(.unsupported(forReason: .invalid)) + return + } + if account.findFolder(withDisplayName: folderName) == nil { + completion(.unsupported(forReason: .invalid)) + } else { + completion(.success(with: folderName)) + } + return + } + } + + public func handle(intent: AddFeedIntent, completion: @escaping (AddFeedIntentResponse) -> Void) { + guard let url = intent.url else { + completion(AddFeedIntentResponse(code: .failure, userActivity: nil)) + return + } + + DispatchQueue.main.async { + + let account: Account? = { + if let accountName = intent.accountName { + return AccountManager.shared.findActiveAccount(forDisplayName: accountName) + } else { + return AccountManager.shared.sortedActiveAccounts.first + } + }() + + guard let validAccount = account else { + completion(AddFeedIntentResponse(code: .failure, userActivity: nil)) + return + } + + let container: Container? = { + if let folderName = intent.folderName { + return validAccount.findFolder(withDisplayName: folderName) + } else { + return validAccount + } + }() + + guard let validContainer = container else { + completion(AddFeedIntentResponse(code: .failure, userActivity: nil)) + return + } + + validAccount.createFeed(url: url.absoluteString, name: nil, container: validContainer) { result in + switch result { + case .success: + completion(AddFeedIntentResponse(code: .success, userActivity: nil)) + case .failure(let error): + switch error { + case AccountError.createErrorNotFound: + completion(AddFeedIntentResponse(code: .feedNotFound, userActivity: nil)) + case AccountError.createErrorAlreadySubscribed: + completion(AddFeedIntentResponse(code: .alreadySubscribed, userActivity: nil)) + default: + completion(AddFeedIntentResponse(code: .failure, userActivity: nil)) + } + } + } + } + + } + +} diff --git a/iOS/Intents/Base.lproj/Intents.intentdefinition b/iOS/Intents/Base.lproj/Intents.intentdefinition new file mode 100644 index 000000000..7994aa105 --- /dev/null +++ b/iOS/Intents/Base.lproj/Intents.intentdefinition @@ -0,0 +1,318 @@ + + + + + INEnums + + INIntentDefinitionModelVersion + 1.1 + INIntentDefinitionNamespace + U6u7RF + INIntentDefinitionSystemVersion + 19A602 + INIntentDefinitionToolsBuildVersion + 11B41 + INIntentDefinitionToolsVersion + 11.2 + INIntents + + + INIntentCategory + create + INIntentConfigurable + + INIntentDescription + Add a feed + INIntentDescriptionID + IuAbef + INIntentIneligibleForSuggestions + + INIntentInput + url + INIntentKeyParameter + url + INIntentLastParameterTag + 4 + INIntentManagedParameterCombinations + + url,accountName + + INIntentParameterCombinationSupportsBackgroundExecution + + INIntentParameterCombinationTitle + Add ${url} to ${accountName} + INIntentParameterCombinationTitleID + kaKsEY + INIntentParameterCombinationUpdatesLinked + + + url,accountName,folderName + + INIntentParameterCombinationSupportsBackgroundExecution + + INIntentParameterCombinationTitle + Add ${url} to ${folderName} in ${accountName} + INIntentParameterCombinationTitleID + dkSFD2 + INIntentParameterCombinationUpdatesLinked + + + + INIntentName + AddFeed + INIntentParameters + + + INIntentParameterDisplayName + URL + INIntentParameterDisplayNameID + BCHr23 + INIntentParameterDisplayPriority + 1 + INIntentParameterName + url + INIntentParameterPromptDialogs + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogFormatString + What is the ${url} you would like add? + INIntentParameterPromptDialogFormatStringID + jLLidQ + INIntentParameterPromptDialogType + Primary + + + INIntentParameterSupportsResolution + + INIntentParameterTag + 2 + INIntentParameterType + URL + INIntentParameterUnsupportedReasons + + + INIntentParameterUnsupportedReasonCode + required + INIntentParameterUnsupportedReasonCustom + + INIntentParameterUnsupportedReasonFormatString + You must supply a URL. + INIntentParameterUnsupportedReasonFormatStringID + 4xjRes + + + + + INIntentParameterCustomDisambiguation + + INIntentParameterDisplayName + Account Name + INIntentParameterDisplayNameID + CSrgUY + INIntentParameterDisplayPriority + 2 + INIntentParameterMetadata + + INIntentParameterMetadataCapitalization + Sentences + + INIntentParameterName + accountName + INIntentParameterPromptDialogs + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Primary + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogFormatString + There are ${count} options matching ‘${accountName}’. + INIntentParameterPromptDialogFormatStringID + IbqUVS + INIntentParameterPromptDialogType + DisambiguationIntroduction + + + INIntentParameterPromptDialogFormatString + Which one? + INIntentParameterPromptDialogFormatStringID + fWs3li + INIntentParameterPromptDialogType + DisambiguationSelection + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogFormatString + Just to confirm, you wanted ‘${accountName}’? + INIntentParameterPromptDialogFormatStringID + HHiZUh + INIntentParameterPromptDialogType + Confirmation + + + INIntentParameterSupportsDynamicEnumeration + + INIntentParameterSupportsResolution + + INIntentParameterTag + 3 + INIntentParameterType + String + INIntentParameterUnsupportedReasons + + + INIntentParameterUnsupportedReasonCode + invalid + INIntentParameterUnsupportedReasonCustom + + INIntentParameterUnsupportedReasonFormatString + A valid Account Name is required. + INIntentParameterUnsupportedReasonFormatStringID + JGkCuS + + + + + INIntentParameterCustomDisambiguation + + INIntentParameterDisplayName + Folder Name + INIntentParameterDisplayNameID + zXhMPF + INIntentParameterDisplayPriority + 3 + INIntentParameterMetadata + + INIntentParameterMetadataCapitalization + Sentences + + INIntentParameterName + folderName + INIntentParameterPromptDialogs + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Primary + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogFormatString + There are ${count} options matching ‘${folderName}’. + INIntentParameterPromptDialogFormatStringID + 5CYbGL + INIntentParameterPromptDialogType + DisambiguationIntroduction + + + INIntentParameterPromptDialogFormatString + Which one? + INIntentParameterPromptDialogFormatStringID + gEzXaM + INIntentParameterPromptDialogType + DisambiguationSelection + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogFormatString + Just to confirm, you wanted ‘${folderName}’? + INIntentParameterPromptDialogFormatStringID + k5GTo0 + INIntentParameterPromptDialogType + Confirmation + + + INIntentParameterRelationship + + INIntentParameterRelationshipParentName + accountName + INIntentParameterRelationshipPredicateName + HasAnyValue + + INIntentParameterSupportsDynamicEnumeration + + INIntentParameterSupportsResolution + + INIntentParameterTag + 4 + INIntentParameterType + String + INIntentParameterUnsupportedReasons + + + INIntentParameterUnsupportedReasonCode + invalid + INIntentParameterUnsupportedReasonCustom + + INIntentParameterUnsupportedReasonFormatString + A valid Folder Name is required. + INIntentParameterUnsupportedReasonFormatStringID + ef5kBt + + + + + INIntentResponse + + INIntentResponseCodes + + + INIntentResponseCodeName + success + INIntentResponseCodeSuccess + + + + INIntentResponseCodeName + failure + + + INIntentResponseCodeConciseFormatString + You are already subscribed to this feed in this account. + INIntentResponseCodeConciseFormatStringID + srME8b + INIntentResponseCodeFormatString + You are already subscribed to this feed in this account. + INIntentResponseCodeFormatStringID + UGGPkp + INIntentResponseCodeName + alreadySubscribed + + + INIntentResponseCodeConciseFormatString + No feed was found at the specified URL. + INIntentResponseCodeConciseFormatStringID + 8Dh9Yy + INIntentResponseCodeFormatString + No feed was found at the specified URL. + INIntentResponseCodeFormatStringID + drQfaI + INIntentResponseCodeName + feedNotFound + + + + INIntentTitle + Add Feed + INIntentTitleID + oV681v + INIntentType + Custom + INIntentVerb + Add + + + INTypes + + + diff --git a/iOS/Intents/en.lproj/Intents.strings b/iOS/Intents/en.lproj/Intents.strings new file mode 100644 index 000000000..187512780 --- /dev/null +++ b/iOS/Intents/en.lproj/Intents.strings @@ -0,0 +1,30 @@ +"4xjRes" = "You must supply a URL."; + +"8Dh9Yy" = "No feed was found at the specified URL."; + +"BCHr23" = "URL"; + +"CSrgUY" = "Account Name"; + +"HHiZUh" = "Just to confirm, you wanted ‘${accountName}’?"; + +"IbqUVS" = "There are ${count} options matching ‘${accountName}’."; + +"IuAbef" = "Add a feed"; + +"JGkCuS" = "An account name is required."; + +"UGGPkp" = "You are already subscribed to this feed in this account."; + +"dkSFD2" = "Add${url}to ${accountName}"; + +"drQfaI" = "No feed was found at the specified URL."; + +"fWs3li" = "Which one?"; + +"jLLidQ" = "What is the ${url}you would like add?"; + +"oV681v" = "Add Feed"; + +"srME8b" = "You are already subscribed to this feed in this account."; + diff --git a/iOS/IntentsExtension/Info.plist b/iOS/IntentsExtension/Info.plist new file mode 100644 index 000000000..8c87f51c5 --- /dev/null +++ b/iOS/IntentsExtension/Info.plist @@ -0,0 +1,46 @@ + + + + + AppGroup + group.$(ORGANIZATION_IDENTIFIER).NetNewsWire.iOS + AppIdentifierPrefix + $(AppIdentifierPrefix) + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + NetNewsWire iOS Intents Extension + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSExtension + + NSExtensionAttributes + + IntentsRestrictedWhileLocked + + IntentsRestrictedWhileProtectedDataUnavailable + + IntentsSupported + + AddFeedIntent + + + NSExtensionPointIdentifier + com.apple.intents-service + NSExtensionPrincipalClass + $(PRODUCT_MODULE_NAME).IntentHandler + + + diff --git a/iOS/IntentsExtension/IntentHandler.swift b/iOS/IntentsExtension/IntentHandler.swift new file mode 100644 index 000000000..e3e1490a8 --- /dev/null +++ b/iOS/IntentsExtension/IntentHandler.swift @@ -0,0 +1,22 @@ +// +// IntentHandler.swift +// NetNewsWire iOS Intents Extension +// +// Created by Maurice Parker on 10/18/19. +// Copyright © 2019 Ranchero Software. All rights reserved. +// + +import Intents + +class IntentHandler: INExtension { + + override func handler(for intent: INIntent) -> Any { + switch intent { + case is AddFeedIntent: + return AddFeedIntentHandler() + default: + fatalError("Unhandled intent type: \(intent)") + } + } + +} diff --git a/iOS/IntentsExtension/NetNewsWire_iOS_IntentsExtension.entitlements b/iOS/IntentsExtension/NetNewsWire_iOS_IntentsExtension.entitlements new file mode 100644 index 000000000..05d04e805 --- /dev/null +++ b/iOS/IntentsExtension/NetNewsWire_iOS_IntentsExtension.entitlements @@ -0,0 +1,14 @@ + + + + + com.apple.security.application-groups + + group.$(ORGANIZATION_IDENTIFIER).NetNewsWire.iOS + + keychain-access-groups + + $(AppIdentifierPrefix)$(ORGANIZATION_IDENTIFIER).NetNewsWire.iOS + + + diff --git a/iOS/MasterFeed/Cell/MasterFeedTableViewCell.swift b/iOS/MasterFeed/Cell/MasterFeedTableViewCell.swift index 5f684ce8f..5dc3e3c3f 100644 --- a/iOS/MasterFeed/Cell/MasterFeedTableViewCell.swift +++ b/iOS/MasterFeed/Cell/MasterFeedTableViewCell.swift @@ -15,7 +15,7 @@ protocol MasterFeedTableViewCellDelegate: class { func disclosureSelected(_ sender: MasterFeedTableViewCell, expanding: Bool) } -class MasterFeedTableViewCell : NNWTableViewCell { +class MasterFeedTableViewCell : VibrantTableViewCell { weak var delegate: MasterFeedTableViewCellDelegate? @@ -128,23 +128,17 @@ class MasterFeedTableViewCell : NNWTableViewCell { override func applyThemeProperties() { super.applyThemeProperties() - titleView.highlightedTextColor = AppAssets.tableViewCellHighlightedTextColor + titleView.highlightedTextColor = AppAssets.vibrantTextColor } override func setHighlighted(_ highlighted: Bool, animated: Bool) { super.setHighlighted(highlighted, animated: animated) - - let tintColor = isHighlighted || isSelected ? AppAssets.tableViewCellHighlightedTextColor : AppAssets.secondaryAccentColor - disclosureButton?.tintColor = tintColor - faviconImageView.tintColor = tintColor + updateVibrancy(animated: animated) } override func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) - - let tintColor = isHighlighted || isSelected ? AppAssets.tableViewCellHighlightedTextColor : AppAssets.secondaryAccentColor - disclosureButton?.tintColor = tintColor - faviconImageView.tintColor = tintColor + updateVibrancy(animated: animated) } override func willTransition(to state: UITableViewCell.StateMask) { @@ -201,5 +195,14 @@ private extension MasterFeedTableViewCell { disclosureButton?.isHidden = !isDisclosureAvailable separatorInset = layout.separatorInsets } + + func updateVibrancy(animated: Bool) { + let tintColor = isHighlighted || isSelected ? AppAssets.vibrantTextColor : AppAssets.secondaryAccentColor + let duration = animated ? 0.6 : 0.0 + UIView.animate(withDuration: duration) { + self.disclosureButton?.tintColor = tintColor + self.faviconImageView.tintColor = tintColor + } + } } diff --git a/iOS/MasterFeed/Cell/MasterFeedTableViewCellLayout.swift b/iOS/MasterFeed/Cell/MasterFeedTableViewCellLayout.swift index 2df98fe02..b60177efb 100644 --- a/iOS/MasterFeed/Cell/MasterFeedTableViewCellLayout.swift +++ b/iOS/MasterFeed/Cell/MasterFeedTableViewCellLayout.swift @@ -17,6 +17,7 @@ struct MasterFeedTableViewCellLayout { private static let unreadCountMarginLeft = CGFloat(integerLiteral: 8) private static let unreadCountMarginRight = CGFloat(integerLiteral: 16) private static let disclosureButtonSize = CGSize(width: 44, height: 44) + private static let verticalPadding = CGFloat(integerLiteral: 11) private static let minRowHeight = CGFloat(integerLiteral: 44) @@ -53,7 +54,7 @@ struct MasterFeedTableViewCellLayout { var rFavicon = CGRect.zero if !shouldShowDisclosure { let x = bounds.origin.x + ((MasterFeedTableViewCellLayout.disclosureButtonSize.width - MasterFeedTableViewCellLayout.imageSize.width) / 2) - let y = UIFontMetrics.default.scaledValue(for: CGFloat(integerLiteral: 4)) + let y = UIFontMetrics.default.scaledValue(for: MasterFeedTableViewCellLayout.verticalPadding) rFavicon = CGRect(x: x, y: y, width: MasterFeedTableViewCellLayout.imageSize.width, height: MasterFeedTableViewCellLayout.imageSize.height) } @@ -82,31 +83,26 @@ struct MasterFeedTableViewCellLayout { let labelSizeInfo = MultilineUILabelSizer.size(for: label.text ?? "", font: label.font, numberOfLines: 0, width: Int(floor(labelWidth))) let rLabelx = bounds.minX + MasterFeedTableViewCellLayout.disclosureButtonSize.width - var rLabel = CGRect(x: rLabelx, y: 0.0, width: labelSizeInfo.size.width, height: labelSizeInfo.size.height) + let rLabely = UIFontMetrics.default.scaledValue(for: MasterFeedTableViewCellLayout.verticalPadding) + let rLabel = CGRect(x: rLabelx, y: rLabely, width: labelSizeInfo.size.width, height: labelSizeInfo.size.height) // Determine cell height - var cellHeight = [rFavicon, rLabel, rUnread, rDisclosure].maxY() + let paddedLabelHeight = rLabel.maxY + UIFontMetrics.default.scaledValue(for: MasterFeedTableViewCellLayout.verticalPadding) + let maxGraphicsHeight = [rFavicon, rUnread, rDisclosure].maxY() + var cellHeight = max(paddedLabelHeight, maxGraphicsHeight) if cellHeight < MasterFeedTableViewCellLayout.minRowHeight { cellHeight = MasterFeedTableViewCellLayout.minRowHeight } // Center in Cell let newBounds = CGRect(x: bounds.origin.x, y: bounds.origin.y, width: bounds.width, height: cellHeight) - - if !shouldShowDisclosure && labelSizeInfo.numberOfLinesUsed == 1 { - rFavicon = MasterFeedTableViewCellLayout.centerVertically(rFavicon, newBounds) - } - if !unreadCountIsHidden { rUnread = MasterFeedTableViewCellLayout.centerVertically(rUnread, newBounds) } - if shouldShowDisclosure { rDisclosure = MasterFeedTableViewCellLayout.centerVertically(rDisclosure, newBounds) } - rLabel = MasterFeedTableViewCellLayout.centerVertically(rLabel, newBounds) - // Assign the properties self.height = cellHeight self.faviconRect = rFavicon diff --git a/iOS/MasterFeed/Cell/MasterFeedTableViewSectionHeader.swift b/iOS/MasterFeed/Cell/MasterFeedTableViewSectionHeader.swift index 901184ec6..07d6ab35c 100644 --- a/iOS/MasterFeed/Cell/MasterFeedTableViewSectionHeader.swift +++ b/iOS/MasterFeed/Cell/MasterFeedTableViewSectionHeader.swift @@ -29,7 +29,7 @@ class MasterFeedTableViewSectionHeader: UITableViewHeaderFooterView { set { if unreadCountView.unreadCount != newValue { unreadCountView.unreadCount = newValue - unreadCountView.isHidden = (newValue < 1) + updateUnreadCountView() setNeedsLayout() } } @@ -51,6 +51,7 @@ class MasterFeedTableViewSectionHeader: UITableViewHeaderFooterView { var disclosureExpanded = false { didSet { updateDisclosureImage() + updateUnreadCountView() } } @@ -141,6 +142,14 @@ private extension MasterFeedTableViewSectionHeader { } } } + + func updateUnreadCountView() { + if !disclosureExpanded && unreadCount > 0 { + unreadCountView.isHidden = false + } else { + self.unreadCountView.isHidden = true + } + } func addSubviewAtInit(_ view: UIView) { addSubview(view) diff --git a/iOS/MasterFeed/MasterFeedViewController.swift b/iOS/MasterFeed/MasterFeedViewController.swift index 7022f7a7f..039e5b036 100644 --- a/iOS/MasterFeed/MasterFeedViewController.swift +++ b/iOS/MasterFeed/MasterFeedViewController.swift @@ -11,7 +11,6 @@ import Account import Articles import RSCore import RSTree -import SwiftUI class MasterFeedViewController: UITableViewController, UndoableCommandRunner { @@ -68,7 +67,6 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner { override func viewWillAppear(_ animated: Bool) { navigationController?.title = NSLocalizedString("Feeds", comment: "Feeds") - clearsSelectionOnViewWillAppear = coordinator.isRootSplitCollapsed applyChanges(animate: false) super.viewWillAppear(animated) } @@ -451,7 +449,7 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner { func restoreSelectionIfNecessary(adjustScroll: Bool) { if let indexPath = coordinator.masterFeedIndexPathForCurrentTimeline() { if adjustScroll { - tableView.selectRowAndScrollIfNotVisible(at: indexPath, animated: false, deselect: coordinator.isRootSplitCollapsed) + tableView.selectRowAndScrollIfNotVisible(at: indexPath, animated: false) } else { tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none) } @@ -462,7 +460,7 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner { if dataSource.snapshot().numberOfItems > 0 { if let indexPath = coordinator.currentFeedIndexPath { if tableView.indexPathForSelectedRow != indexPath { - tableView.selectRowAndScrollIfNotVisible(at: indexPath, animated: true, deselect: coordinator.isRootSplitCollapsed) + tableView.selectRowAndScrollIfNotVisible(at: indexPath, animated: true) } } else { tableView.selectRow(at: nil, animated: true, scrollPosition: .none) diff --git a/iOS/MasterTimeline/Cell/MasterTimelineCellData.swift b/iOS/MasterTimeline/Cell/MasterTimelineCellData.swift index 7ecdc8c59..26cc4f3d3 100644 --- a/iOS/MasterTimeline/Cell/MasterTimelineCellData.swift +++ b/iOS/MasterTimeline/Cell/MasterTimelineCellData.swift @@ -25,13 +25,13 @@ struct MasterTimelineCellData { init(article: Article, showFeedName: Bool, feedName: String?, avatar: UIImage?, showAvatar: Bool, featuredImage: UIImage?, numberOfLines: Int) { - self.title = TimelineStringFormatter.truncatedTitle(article) - self.summary = TimelineStringFormatter.truncatedSummary(article) + self.title = ArticleStringFormatter.truncatedTitle(article) + self.summary = ArticleStringFormatter.truncatedSummary(article) - self.dateString = TimelineStringFormatter.dateString(article.logicalDatePublished) + self.dateString = ArticleStringFormatter.dateString(article.logicalDatePublished) if let feedName = feedName { - self.feedName = TimelineStringFormatter.truncatedFeedName(feedName) + self.feedName = ArticleStringFormatter.truncatedFeedName(feedName) } else { self.feedName = "" diff --git a/iOS/MasterTimeline/Cell/MasterTimelineDefaultCellLayout.swift b/iOS/MasterTimeline/Cell/MasterTimelineDefaultCellLayout.swift index b1070a2eb..f7ca315c5 100644 --- a/iOS/MasterTimeline/Cell/MasterTimelineDefaultCellLayout.swift +++ b/iOS/MasterTimeline/Cell/MasterTimelineDefaultCellLayout.swift @@ -21,7 +21,7 @@ struct MasterTimelineDefaultCellLayout: MasterTimelineCellLayout { static let starDimension = CGFloat(integerLiteral: 16) static let starSize = CGSize(width: MasterTimelineDefaultCellLayout.starDimension, height: MasterTimelineDefaultCellLayout.starDimension) - static let avatarSize = CGSize(width: 48.0, height: 48.0) + static let avatarSize = CGSize(width: 32.0, height: 32.0) static let avatarMarginRight = CGFloat(integerLiteral: 8) static let avatarCornerRadius = CGFloat(integerLiteral: 4) diff --git a/iOS/MasterTimeline/Cell/MasterTimelineTableViewCell.swift b/iOS/MasterTimeline/Cell/MasterTimelineTableViewCell.swift index 7e55f3dfd..0a240370e 100644 --- a/iOS/MasterTimeline/Cell/MasterTimelineTableViewCell.swift +++ b/iOS/MasterTimeline/Cell/MasterTimelineTableViewCell.swift @@ -9,7 +9,7 @@ import UIKit import RSCore -class MasterTimelineTableViewCell: NNWTableViewCell { +class MasterTimelineTableViewCell: VibrantTableViewCell { private let titleView = MasterTimelineTableViewCell.multiLineUILabel() private let summaryView = MasterTimelineTableViewCell.multiLineUILabel() @@ -37,7 +37,7 @@ class MasterTimelineTableViewCell: NNWTableViewCell { override func applyThemeProperties() { super.applyThemeProperties() - let highlightedTextColor = AppAssets.tableViewCellHighlightedTextColor + let highlightedTextColor = AppAssets.vibrantTextColor titleView.highlightedTextColor = highlightedTextColor summaryView.highlightedTextColor = highlightedTextColor @@ -187,30 +187,12 @@ private extension MasterTimelineTableViewCell { } func updateUnreadIndicator() { - let hide = cellData.read || cellData.starred - self.unreadIndicatorView.isHidden = hide - self.unreadIndicatorView.frame.size = !hide ? CGSize.zero : MasterTimelineDefaultCellLayout.unreadCircleSize - UIView.animate( - withDuration: 0.5, - delay: 0.0, - usingSpringWithDamping: 0.5, - initialSpringVelocity: 0.2, - animations: { - self.unreadIndicatorView.frame.size = !hide ? MasterTimelineDefaultCellLayout.unreadCircleSize : CGSize.zero - }) + showOrHideView(unreadIndicatorView, cellData.read || cellData.starred) + unreadIndicatorView.setNeedsDisplay() } func updateStarView() { - self.starView.isHidden = !self.cellData.starred - self.starView.frame.size = self.cellData.starred ? CGSize.zero : MasterTimelineDefaultCellLayout.starSize - UIView.animate( - withDuration: 0.5, - delay: 0.0, - usingSpringWithDamping: 0.5, - initialSpringVelocity: 0.2, - animations: { - self.starView.frame.size = self.cellData.starred ? MasterTimelineDefaultCellLayout.starSize : CGSize.zero - }) + showOrHideView(starView, !cellData.starred) } func updateAvatar() { @@ -251,6 +233,10 @@ private extension MasterTimelineTableViewCell { } } + func showOrHideView(_ view: UIView, _ shouldHide: Bool) { + shouldHide ? hideView(view) : showView(view) + } + func updateSubviews() { updateTitleView() updateSummaryView() diff --git a/iOS/MasterTimeline/Cell/MasterUnreadIndicatorView.swift b/iOS/MasterTimeline/Cell/MasterUnreadIndicatorView.swift index 3c64e084e..88cb190f0 100644 --- a/iOS/MasterTimeline/Cell/MasterUnreadIndicatorView.swift +++ b/iOS/MasterTimeline/Cell/MasterUnreadIndicatorView.swift @@ -32,7 +32,7 @@ class MasterUnreadIndicatorView: UIView { }() override func draw(_ dirtyRect: CGRect) { - let color = isSelected ? AppAssets.tableViewCellHighlightedTextColor : AppAssets.secondaryAccentColor + let color = isSelected ? AppAssets.vibrantTextColor : AppAssets.secondaryAccentColor color.setFill() MasterUnreadIndicatorView.bezierPath.fill() } diff --git a/iOS/MasterTimeline/MasterTimelineViewController.swift b/iOS/MasterTimeline/MasterTimelineViewController.swift index 8c74296ab..2dd9a9a2a 100644 --- a/iOS/MasterTimeline/MasterTimelineViewController.swift +++ b/iOS/MasterTimeline/MasterTimelineViewController.swift @@ -76,7 +76,6 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner } override func viewWillAppear(_ animated: Bool) { - clearsSelectionOnViewWillAppear = coordinator.isRootSplitCollapsed applyChanges(animate: false) super.viewWillAppear(animated) } @@ -132,7 +131,7 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner func restoreSelectionIfNecessary(adjustScroll: Bool) { if let article = coordinator.currentArticle, let indexPath = dataSource.indexPath(for: article) { if adjustScroll { - tableView.selectRowAndScrollIfNotVisible(at: indexPath, animated: false, deselect: coordinator.isRootSplitCollapsed) + tableView.selectRowAndScrollIfNotVisible(at: indexPath, animated: false) } else { tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none) } @@ -150,7 +149,7 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner func updateArticleSelection(animated: Bool) { if let article = coordinator.currentArticle, let indexPath = dataSource.indexPath(for: article) { if tableView.indexPathForSelectedRow != indexPath { - tableView.selectRowAndScrollIfNotVisible(at: indexPath, animated: true, deselect: coordinator.isRootSplitCollapsed) + tableView.selectRowAndScrollIfNotVisible(at: indexPath, animated: true) } } else { tableView.selectRow(at: nil, animated: animated, scrollPosition: .none) diff --git a/iOS/Resources/About.rtf b/iOS/Resources/About.rtf index 810ed8e40..881fea1f3 100644 --- a/iOS/Resources/About.rtf +++ b/iOS/Resources/About.rtf @@ -1,7 +1,7 @@ -{\rtf1\ansi\ansicpg1252\cocoartf2507 +{\rtf1\ansi\ansicpg1252\cocoartf2509 \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 LucidaGrande-Bold;} -{\colortbl;\red255\green255\blue255;\red0\green0\blue0;} -{\*\expandedcolortbl;;\cssrgb\c0\c0\c0;} +{\colortbl;\red255\green255\blue255;\red0\green0\blue0;\red10\green96\blue255;} +{\*\expandedcolortbl;;\cssrgb\c0\c0\c0;\cssrgb\c0\c47843\c100000\cname systemBlueColor;} \margl1440\margr1440\vieww11860\viewh9620\viewkind0 \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0 @@ -9,4 +9,4 @@ \fs22 \ \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0 {\field{\*\fldinst{HYPERLINK "http://inessential.com/"}}{\fldrslt -\fs28 \cf2 inessential.com}}} \ No newline at end of file +\fs28 \cf3 inessential.com}}} \ No newline at end of file diff --git a/iOS/Resources/Acknowledgments.rtf b/iOS/Resources/Acknowledgments.rtf index 7f9f3d50f..5f8b59acd 100644 --- a/iOS/Resources/Acknowledgments.rtf +++ b/iOS/Resources/Acknowledgments.rtf @@ -1,13 +1,12 @@ -{\rtf1\ansi\ansicpg1252\cocoartf2507 +{\rtf1\ansi\ansicpg1252\cocoartf2509 \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 LucidaGrande;} {\colortbl;\red255\green255\blue255;\red0\green0\blue0;} {\*\expandedcolortbl;;\cssrgb\c0\c0\c0\cname textColor;} -\margl1440\margr1440\vieww9000\viewh8400\viewkind0 +\margl1440\margr1440\vieww8960\viewh8160\viewkind0 \deftab720 -\pard\pardeftab720\li360\fi-360\sa60\partightenfactor0 +\pard\tx0\pardeftab720\sa60\partightenfactor0 {\field{\*\fldinst{HYPERLINK "https://github.com/ccgus/fmdb"}}{\fldrslt \f0\fs22 \cf2 FMDB}} -\f0\fs22 \cf2 (greatest SQLite wrapper ever in\ -history) is by {\field{\*\fldinst{HYPERLINK "http://flyingmeat.com/"}}{\fldrslt Flying Meat Software}}.\ -\pard\pardeftab720\li360\fi-360\sa60\partightenfactor0 +\f0\fs22 \cf2 (greatest SQLite wrapper ever in history) is by {\field{\*\fldinst{HYPERLINK "http://flyingmeat.com/"}}{\fldrslt Flying Meat Software}}.\ +\pard\pardeftab720\sa60\partightenfactor0 {\field{\*\fldinst{HYPERLINK "https://sparkle-project.org/"}}{\fldrslt \cf2 Sparkle}} is by Sparkle Project.} \ No newline at end of file diff --git a/iOS/Resources/Assets.xcassets/accountLocal.imageset/Contents.json b/iOS/Resources/Assets.xcassets/accountLocalPad.imageset/Contents.json similarity index 84% rename from iOS/Resources/Assets.xcassets/accountLocal.imageset/Contents.json rename to iOS/Resources/Assets.xcassets/accountLocalPad.imageset/Contents.json index c48efa3f2..7fe4e483c 100644 --- a/iOS/Resources/Assets.xcassets/accountLocal.imageset/Contents.json +++ b/iOS/Resources/Assets.xcassets/accountLocalPad.imageset/Contents.json @@ -2,7 +2,7 @@ "images" : [ { "idiom" : "universal", - "filename" : "accountLocal.pdf" + "filename" : "localAccountPad.pdf" } ], "info" : { diff --git a/Mac/Resources/Assets.xcassets/accountLocal.imageset/accountLocal.pdf b/iOS/Resources/Assets.xcassets/accountLocalPad.imageset/localAccountPad.pdf similarity index 75% rename from Mac/Resources/Assets.xcassets/accountLocal.imageset/accountLocal.pdf rename to iOS/Resources/Assets.xcassets/accountLocalPad.imageset/localAccountPad.pdf index c32cc3b89..cfc6ca9f0 100644 Binary files a/Mac/Resources/Assets.xcassets/accountLocal.imageset/accountLocal.pdf and b/iOS/Resources/Assets.xcassets/accountLocalPad.imageset/localAccountPad.pdf differ diff --git a/iOS/Resources/Assets.xcassets/accountLocalPhone.imageset/Contents.json b/iOS/Resources/Assets.xcassets/accountLocalPhone.imageset/Contents.json new file mode 100644 index 000000000..05bb5e471 --- /dev/null +++ b/iOS/Resources/Assets.xcassets/accountLocalPhone.imageset/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "localAccountPhone.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template", + "preserves-vector-representation" : true + } +} \ No newline at end of file diff --git a/iOS/Resources/Assets.xcassets/accountLocalPhone.imageset/localAccountPhone.pdf b/iOS/Resources/Assets.xcassets/accountLocalPhone.imageset/localAccountPhone.pdf new file mode 100644 index 000000000..c807edece Binary files /dev/null and b/iOS/Resources/Assets.xcassets/accountLocalPhone.imageset/localAccountPhone.pdf differ diff --git a/iOS/Resources/Assets.xcassets/tableViewCellHighlightedTextColor.colorset/Contents.json b/iOS/Resources/Assets.xcassets/vibrantTextColor.colorset/Contents.json similarity index 100% rename from iOS/Resources/Assets.xcassets/tableViewCellHighlightedTextColor.colorset/Contents.json rename to iOS/Resources/Assets.xcassets/vibrantTextColor.colorset/Contents.json diff --git a/iOS/Resources/Info.plist b/iOS/Resources/Info.plist index f595adcba..dfcacffa8 100644 --- a/iOS/Resources/Info.plist +++ b/iOS/Resources/Info.plist @@ -23,7 +23,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 5.0 + $(MARKETING_VERSION) CFBundleURLTypes @@ -48,25 +48,26 @@ CFBundleVersion - 1 + $(CURRENT_PROJECT_VERSION) LSRequiresIPhoneOS - NSPhotoLibraryAddUsageDescription - Grant permission to save images from the article. NSAppTransportSecurity NSAllowsArbitraryLoads + NSPhotoLibraryAddUsageDescription + Grant permission to save images from the article. NSUserActivityTypes + AddFeedIntent com.ranchero.NetNewsWire.NextUnread + com.ranchero.NetNewsWire.ReadArticle + com.ranchero.NetNewsWire.SelectAllUnread com.ranchero.NetNewsWire.SelectFeed com.ranchero.NetNewsWire.SelectFolder - com.ranchero.NetNewsWire.SelectAllUnread com.ranchero.NetNewsWire.SelectStarred com.ranchero.NetNewsWire.SelectToday - com.ranchero.NetNewsWire.ReadArticle UIApplicationSceneManifest diff --git a/iOS/Resources/Thanks.rtf b/iOS/Resources/Thanks.rtf index 039738f66..3bcce8cd6 100644 --- a/iOS/Resources/Thanks.rtf +++ b/iOS/Resources/Thanks.rtf @@ -1,4 +1,4 @@ -{\rtf1\ansi\ansicpg1252\cocoartf2507 +{\rtf1\ansi\ansicpg1252\cocoartf2509 \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 LucidaGrande;} {\colortbl;\red255\green255\blue255;\red0\green0\blue0;} {\*\expandedcolortbl;;\cssrgb\c0\c0\c0\cname textColor;} @@ -6,4 +6,6 @@ \deftab720 \pard\pardeftab720\sa60\partightenfactor0 -\f0\fs22 \cf2 Thanks to Sheila and my family; thanks to my friends in Seattle and around the globe; thanks to my co-workers and friends at {\field{\*\fldinst{HYPERLINK "https://www.omnigroup.com/"}}{\fldrslt The Omni Group}}; thanks to the ever-patient and ever-awesome NetNewsWire beta testers. Thanks to {\field{\*\fldinst{HYPERLINK "https://github.com/"}}{\fldrslt GitHub}}, {\field{\*\fldinst{HYPERLINK "https://slack.com/"}}{\fldrslt Slack}}, and {\field{\*\fldinst{HYPERLINK "https://circleci.com/"}}{\fldrslt CircleCI}} for making open source collaboration easy and fun.} \ No newline at end of file +\f0\fs22 \cf2 Thanks to Sheila and my family; thanks to my friends in Seattle and around the globe; thanks to my co-workers and friends at {\field{\*\fldinst{HYPERLINK "https://www.omnigroup.com"}}{\fldrslt The Omni Group}}; thanks to the ever-patient and ever-awesome NetNewsWire beta testers. \ +\pard\tx0\pardeftab720\sa60\partightenfactor0 +\cf2 Thanks to {\field{\*\fldinst{HYPERLINK "https://github.com"}}{\fldrslt GitHub}} and {\field{\*\fldinst{HYPERLINK "https://slack.com"}}{\fldrslt Slack}} for making open source collaboration easy and fun.} \ No newline at end of file diff --git a/iOS/Resources/main_ios.js b/iOS/Resources/main_ios.js index 21d6bdb83..2af2e5a81 100644 --- a/iOS/Resources/main_ios.js +++ b/iOS/Resources/main_ios.js @@ -1,38 +1,73 @@ +var imageIsLoading = false; + // Used to pop a resizable image view async function imageWasClicked(img) { img.classList.add("nnwClicked"); - - const rect = img.getBoundingClientRect(); - - var message = { - x: rect.x, - y: rect.y, - width: rect.width, - height: rect.height - }; try { + showNetworkLoading(img); const response = await fetch(img.src); if (!response.ok) { throw new Error('Network response was not ok.'); } const imgBlob = await response.blob(); - + hideNetworkLoading(img); + var reader = new FileReader(); reader.readAsDataURL(imgBlob); - reader.onloadend = function() { + + const rect = img.getBoundingClientRect(); + var message = { + x: rect.x, + y: rect.y, + width: rect.width, + height: rect.height + }; message.imageURL = reader.result; + var jsonMessage = JSON.stringify(message); window.webkit.messageHandlers.imageWasClicked.postMessage(jsonMessage); + } } catch (error) { + hideNetworkLoading(img); console.log('There has been a problem with your fetch operation: ', error.message); } } +function showNetworkLoading(img) { + imageIsLoading = true; + + var wrapper = document.createElement("div"); + wrapper.classList.add("activityIndicatorWrap"); + img.parentNode.insertBefore(wrapper, img); + wrapper.appendChild(img); + + var activityIndicatorImg = document.createElement("img"); + activityIndicatorImg.classList.add("activityIndicator"); + activityIndicatorImg.style.opacity = 0; + activityIndicatorImg.src = activityIndicator; + wrapper.appendChild(activityIndicatorImg); + + // Wait a bit before showing the indicator + function showActivityIndicator() { + activityIndicatorImg.style.opacity = 1; + } + setTimeout(showActivityIndicator, 300); +} + +function hideNetworkLoading(img) { + var wrapper = img.parentNode; + var wrapperParent = wrapper.parentNode; + wrapperParent.insertBefore(img, wrapper); + wrapperParent.removeChild(wrapper); + + imageIsLoading = false; +} + // Used to animate the transition to a fullscreen image function hideClickedImage() { var img = document.querySelector('.nnwClicked') @@ -50,7 +85,7 @@ function showClickedImage() { // Add the click listener for images function imageClicks() { window.onclick = function(event) { - if (event.target.matches('img')) { + if (event.target.matches('img') && !imageIsLoading) { imageWasClicked(event.target); } } @@ -69,3 +104,5 @@ function postRenderProcessing() { imageClicks() inlineVideos() } + +const activityIndicator = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2ZXJzaW9uPSIxLjAiIHdpZHRoPSI2NHB4IiBoZWlnaHQ9IjY0cHgiIHZpZXdCb3g9IjAgMCAxMjggMTI4IiB4bWw6c3BhY2U9InByZXNlcnZlIj48Zz48cGF0aCBkPSJNNTkuNiAwaDh2NDBoLThWMHoiIGZpbGw9IiMwMDAwMDAiLz48cGF0aCBkPSJNNTkuNiAwaDh2NDBoLThWMHoiIGZpbGw9IiNjY2NjY2MiIHRyYW5zZm9ybT0icm90YXRlKDMwIDY0IDY0KSIvPjxwYXRoIGQ9Ik01OS42IDBoOHY0MGgtOFYweiIgZmlsbD0iI2NjY2NjYyIgdHJhbnNmb3JtPSJyb3RhdGUoNjAgNjQgNjQpIi8+PHBhdGggZD0iTTU5LjYgMGg4djQwaC04VjB6IiBmaWxsPSIjY2NjY2NjIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCA2NCA2NCkiLz48cGF0aCBkPSJNNTkuNiAwaDh2NDBoLThWMHoiIGZpbGw9IiNjY2NjY2MiIHRyYW5zZm9ybT0icm90YXRlKDEyMCA2NCA2NCkiLz48cGF0aCBkPSJNNTkuNiAwaDh2NDBoLThWMHoiIGZpbGw9IiNiMmIyYjIiIHRyYW5zZm9ybT0icm90YXRlKDE1MCA2NCA2NCkiLz48cGF0aCBkPSJNNTkuNiAwaDh2NDBoLThWMHoiIGZpbGw9IiM5OTk5OTkiIHRyYW5zZm9ybT0icm90YXRlKDE4MCA2NCA2NCkiLz48cGF0aCBkPSJNNTkuNiAwaDh2NDBoLThWMHoiIGZpbGw9IiM3ZjdmN2YiIHRyYW5zZm9ybT0icm90YXRlKDIxMCA2NCA2NCkiLz48cGF0aCBkPSJNNTkuNiAwaDh2NDBoLThWMHoiIGZpbGw9IiM2NjY2NjYiIHRyYW5zZm9ybT0icm90YXRlKDI0MCA2NCA2NCkiLz48cGF0aCBkPSJNNTkuNiAwaDh2NDBoLThWMHoiIGZpbGw9IiM0YzRjNGMiIHRyYW5zZm9ybT0icm90YXRlKDI3MCA2NCA2NCkiLz48cGF0aCBkPSJNNTkuNiAwaDh2NDBoLThWMHoiIGZpbGw9IiMzMzMzMzMiIHRyYW5zZm9ybT0icm90YXRlKDMwMCA2NCA2NCkiLz48cGF0aCBkPSJNNTkuNiAwaDh2NDBoLThWMHoiIGZpbGw9IiMxOTE5MTkiIHRyYW5zZm9ybT0icm90YXRlKDMzMCA2NCA2NCkiLz48YW5pbWF0ZVRyYW5zZm9ybSBhdHRyaWJ1dGVOYW1lPSJ0cmFuc2Zvcm0iIHR5cGU9InJvdGF0ZSIgdmFsdWVzPSIwIDY0IDY0OzMwIDY0IDY0OzYwIDY0IDY0OzkwIDY0IDY0OzEyMCA2NCA2NDsxNTAgNjQgNjQ7MTgwIDY0IDY0OzIxMCA2NCA2NDsyNDAgNjQgNjQ7MjcwIDY0IDY0OzMwMCA2NCA2NDszMzAgNjQgNjQiIGNhbGNNb2RlPSJkaXNjcmV0ZSIgZHVyPSIxMDgwbXMiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIj48L2FuaW1hdGVUcmFuc2Zvcm0+PC9nPjwvc3ZnPg=="; diff --git a/iOS/Resources/styleSheet.css b/iOS/Resources/styleSheet.css index df1c80612..fcf18608d 100644 --- a/iOS/Resources/styleSheet.css +++ b/iOS/Resources/styleSheet.css @@ -159,6 +159,20 @@ sub { padding-top: 56.25%; } +.activityIndicatorWrap { + position: relative; +} + +.activityIndicator { + z-index: 1; + width: 64px; + height: 64px; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + .iframeWrap iframe { position: absolute; top: 0; diff --git a/iOS/SceneCoordinator.swift b/iOS/SceneCoordinator.swift index 17c0dd94a..e97a63e19 100644 --- a/iOS/SceneCoordinator.swift +++ b/iOS/SceneCoordinator.swift @@ -8,7 +8,6 @@ import UIKit import UserNotifications -import SwiftUI import Account import Articles import RSCore @@ -328,6 +327,8 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider { selectFirstUnreadInAllUnread() case .readArticle: handleReadArticle(activity.userInfo) + case .addFeedIntent: + showAdd(.feed) } } @@ -784,9 +785,12 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider { } func showSettings() { - rootSplitViewController.present(style: .formSheet) { - SettingsView(viewModel: SettingsView.ViewModel()).environment(\.sceneCoordinator, self) - } + let settingsNavController = UIStoryboard.settings.instantiateInitialViewController() as! UINavigationController + let settingsViewController = settingsNavController.topViewController as! SettingsViewController + settingsNavController.modalPresentationStyle = .formSheet + settingsNavController.preferredContentSize = SettingsViewController.preferredContentSizeForFormSheetDisplay + settingsViewController.presentingParentController = rootSplitViewController + rootSplitViewController.present(settingsNavController, animated: true) } func showFeedInspector() { @@ -946,6 +950,7 @@ extension SceneCoordinator: UINavigationControllerDelegate { if viewController === masterTimelineViewController && !isThreePanelMode && rootSplitViewController.isCollapsed && !isArticleViewControllerPending { stopArticleExtractor() currentArticle = nil + masterTimelineViewController?.updateArticleSelection(animated: animated) activityManager.invalidateReading() return } @@ -1694,20 +1699,3 @@ private extension SceneCoordinator { } } - -// MARK: SwiftUI - -struct SceneCoordinatorHolder { - weak var value: SceneCoordinator? -} - -struct SceneCoordinatorKey: EnvironmentKey { - static var defaultValue: SceneCoordinatorHolder { return SceneCoordinatorHolder(value: nil ) } -} - -extension EnvironmentValues { - var sceneCoordinator: SceneCoordinator? { - get { return self[SceneCoordinatorKey.self].value } - set { self[SceneCoordinatorKey.self].value = newValue } - } -} diff --git a/iOS/SceneDelegate.swift b/iOS/SceneDelegate.swift index b34b95dca..82cb4e8bb 100644 --- a/iOS/SceneDelegate.swift +++ b/iOS/SceneDelegate.swift @@ -52,6 +52,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { } func sceneDidEnterBackground(_ scene: UIScene) { + ArticleStringFormatter.emptyCaches() appDelegate.prepareAccountsForBackground() } diff --git a/iOS/Settings/AboutViewController.swift b/iOS/Settings/AboutViewController.swift new file mode 100644 index 000000000..a472efd63 --- /dev/null +++ b/iOS/Settings/AboutViewController.swift @@ -0,0 +1,57 @@ +// +// AboutViewController.swift +// NetNewsWire-iOS +// +// Created by Maurice Parker on 4/25/19. +// Copyright © 2019 Ranchero Software. All rights reserved. +// + +import UIKit + +class AboutViewController: UITableViewController { + + @IBOutlet weak var aboutTextView: UITextView! + @IBOutlet weak var creditsTextView: UITextView! + @IBOutlet weak var acknowledgmentsTextView: UITextView! + @IBOutlet weak var thanksTextView: UITextView! + @IBOutlet weak var dedicationTextView: UITextView! + + override func viewDidLoad() { + + super.viewDidLoad() + + configureCell(file: "About", textView: aboutTextView) + configureCell(file: "Credits", textView: creditsTextView) + configureCell(file: "Acknowledgments", textView: acknowledgmentsTextView) + configureCell(file: "Thanks", textView: thanksTextView) + configureCell(file: "Dedication", textView: dedicationTextView) + + let buildLabel = NonIntrinsicLabel(frame: CGRect(x: 20.0, y: 0.0, width: 0.0, height: 0.0)) + buildLabel.font = UIFont.systemFont(ofSize: 11.0) + buildLabel.textColor = UIColor.gray + buildLabel.text = NSLocalizedString("Copyright © 2002-2019 Ranchero Software", comment: "Copyright") + buildLabel.numberOfLines = 0 + buildLabel.sizeToFit() + buildLabel.translatesAutoresizingMaskIntoConstraints = false + tableView.tableFooterView = buildLabel + + } + + override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return UITableView.automaticDimension + } + +} + +private extension AboutViewController { + + func configureCell(file: String, textView: UITextView) { + let url = Bundle.main.url(forResource: file, withExtension: "rtf")! + let string = try! NSAttributedString(url: url, options: [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.rtf], documentAttributes: nil) + textView.attributedText = string + textView.textColor = UIColor.label + textView.adjustsFontForContentSizeCategory = true + textView.font = .preferredFont(forTextStyle: .body) + } + +} diff --git a/iOS/Settings/Account/SettingsAccountLabelView.swift b/iOS/Settings/Account/SettingsAccountLabelView.swift deleted file mode 100644 index 0d5ead2e3..000000000 --- a/iOS/Settings/Account/SettingsAccountLabelView.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// SettingsAccountLabelView.swift -// NetNewsWire-iOS -// -// Created by Maurice Parker on 6/11/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import SwiftUI - -struct SettingsAccountLabelView : View { - let accountImage: String - let accountLabel: String - - var body: some View { - HStack { - Image(accountImage) - .resizable() - .aspectRatio(1, contentMode: .fit) - .frame(height: 32) - Text(verbatim: accountLabel).font(.title) - } - .foregroundColor(.primary).padding(4.0) - } -} - -#if DEBUG -struct SettingsAccountLabelView_Previews : PreviewProvider { - static var previews: some View { - SettingsAccountLabelView(accountImage: "accountLocal", accountLabel: "On My Device") - .previewLayout(.fixed(width: 300, height: 44)) - } -} -#endif diff --git a/iOS/Settings/Account/SettingsAddAccountView.swift b/iOS/Settings/Account/SettingsAddAccountView.swift deleted file mode 100644 index f26769971..000000000 --- a/iOS/Settings/Account/SettingsAddAccountView.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// SettingsAddAccountView.swift -// NetNewsWire-iOS -// -// Created by Maurice Parker on 6/11/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import SwiftUI -import Account - -struct SettingsAddAccountView : View { - @Environment(\.presentationMode) var presentation - @State private var accountAddAction: Int? = nil - - var body: some View { - Form { - - NavigationLink(destination: SettingsLocalAccountView(name: ""), tag: 1, selection: $accountAddAction) { - SettingsAccountLabelView(accountImage: "accountLocal", accountLabel: Account.defaultLocalAccountName) - } - .modifier(VibrantSelectAction(action: { - self.accountAddAction = 1 - })).padding(.vertical, 16) - - NavigationLink(destination: SettingsFeedbinAccountView(viewModel: SettingsFeedbinAccountView.ViewModel()), tag: 2, selection: $accountAddAction) { - SettingsAccountLabelView(accountImage: "accountFeedbin", accountLabel: "Feedbin") - - } - .modifier(VibrantSelectAction(action: { - self.accountAddAction = 2 - })).padding(.vertical, 16) - -// NavigationLink(destination: SettingsReaderAPIAccountView(viewModel: SettingsReaderAPIAccountView.ViewModel(accountType: .freshRSS)), tag: 3, selection: $accountAddAction) { -// SettingsAccountLabelView(accountImage: "accountFreshRSS", accountLabel: "Fresh RSS") -// } -// .modifier(VibrantSelectAction(action: { -// self.accountAddAction = 3 -// })) - - } - .navigationBarTitle(Text("Add Account"), displayMode: .inline) - } -} - -#if DEBUG -struct AddAccountView_Previews : PreviewProvider { - static var previews: some View { - SettingsAddAccountView() - } -} -#endif diff --git a/iOS/Settings/Account/SettingsDetailAccountView.swift b/iOS/Settings/Account/SettingsDetailAccountView.swift deleted file mode 100644 index f67b29833..000000000 --- a/iOS/Settings/Account/SettingsDetailAccountView.swift +++ /dev/null @@ -1,137 +0,0 @@ -// -// SettingsDetailAccountView.swift -// NetNewsWire -// -// Created by Maurice Parker on 6/13/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import SwiftUI -import Combine -import Account -import RSWeb - -struct SettingsDetailAccountView : View { - @Environment(\.presentationMode) var presentation - @ObservedObject var viewModel: ViewModel - @State private var credentialsAction: Int? = nil - @State private var isDeleteAlertPresented = false - - var body: some View { - Form { - Section { - HStack { - TextField("Name", text: $viewModel.name) - } - Toggle(isOn: $viewModel.isActive) { - Text("Active") - } - } - if viewModel.isCreditialsAvailable { - if viewModel.account.type == .feedbin { - NavigationLink(destination: self.settingsFeedbinAccountView, tag: 1, selection: $credentialsAction) { - Text("Credentials") - } - .modifier(VibrantSelectAction(action: { - self.credentialsAction = 1 - })) - } - if viewModel.account.type == .freshRSS { - NavigationLink(destination: self.settingsReaderAPIAccountView, tag: 1, selection: $credentialsAction) { - Text("Credentials") - } - .modifier(VibrantSelectAction(action: { - self.credentialsAction = 1 - })) - } - } - if viewModel.isDeletable { - Section { - Button(action: { - self.isDeleteAlertPresented.toggle() - }) { - Text("Delete Account").foregroundColor(.red) - } - .alert(isPresented: $isDeleteAlertPresented) { - Alert(title: Text("Are you sure you want to delete \"\(viewModel.nameForDisplay)\"?"), - primaryButton: Alert.Button.default(Text("Delete"), action: { - self.viewModel.delete() - self.presentation.wrappedValue.dismiss() - }), - secondaryButton: Alert.Button.cancel()) - } - } - } - } - .buttonStyle(VibrantButtonStyle(alignment: .center)) - .navigationBarTitle(Text(verbatim: viewModel.nameForDisplay), displayMode: .inline) - - } - - var settingsFeedbinAccountView: SettingsFeedbinAccountView { - let feedbinViewModel = SettingsFeedbinAccountView.ViewModel(account: viewModel.account) - return SettingsFeedbinAccountView(viewModel: feedbinViewModel) - } - - var settingsReaderAPIAccountView: SettingsReaderAPIAccountView { - let readerAPIModel = SettingsReaderAPIAccountView.ViewModel(account: viewModel.account) - return SettingsReaderAPIAccountView(viewModel: readerAPIModel) - } - - class ViewModel: ObservableObject { - - let objectWillChange = ObservableObjectPublisher() - - let account: Account - - init(_ account: Account) { - self.account = account - } - - var nameForDisplay: String { - account.nameForDisplay - } - - var name: String { - get { - account.name ?? "" - } - set { - objectWillChange.send() - account.name = newValue.isEmpty ? nil : newValue - } - } - - var isActive: Bool { - get { - account.isActive - } - set { - objectWillChange.send() - account.isActive = newValue - } - } - - var isCreditialsAvailable: Bool { - return account.type != .onMyMac - } - - var isDeletable: Bool { - return AccountManager.shared.defaultAccount != account - } - - func delete() { - AccountManager.shared.deleteAccount(account) - ActivityManager.cleanUp(account) - } - } -} - -#if DEBUG -struct SettingsDetailAccountView_Previews : PreviewProvider { - static var previews: some View { - let viewModel = SettingsDetailAccountView.ViewModel(AccountManager.shared.defaultAccount) - return SettingsDetailAccountView(viewModel: viewModel) - } -} -#endif diff --git a/iOS/Settings/Account/SettingsFeedbinAccountView.swift b/iOS/Settings/Account/SettingsFeedbinAccountView.swift deleted file mode 100644 index a685a8ada..000000000 --- a/iOS/Settings/Account/SettingsFeedbinAccountView.swift +++ /dev/null @@ -1,161 +0,0 @@ -// -// SettingsFeedbinAccountView.swift -// NetNewsWire-iOS -// -// Created by Maurice Parker on 6/11/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import SwiftUI -import Combine -import Account -import RSWeb - -struct SettingsFeedbinAccountView : View { - @Environment(\.presentationMode) var presentation - @ObservedObject var viewModel: ViewModel - @State var busy: Bool = false - @State var error: String = "" - - var body: some View { - Form { - Section(header: - HStack { - Spacer() - SettingsAccountLabelView(accountImage: "accountFeedbin", accountLabel: "Feedbin") - .padding() - .layoutPriority(1.0) - Spacer() - } - ) { - TextField("Email", text: $viewModel.email) - .keyboardType(.emailAddress) - .textContentType(.emailAddress) - PasswordField(password: $viewModel.password) - } - Section(footer: - HStack { - Spacer() - Text(verbatim: error).foregroundColor(.red) - Spacer() - } - ) { - Button(action: { self.addAccount() }) { - if viewModel.isUpdate { - Text("Update Account") - } else { - Text("Add Account") - } - } - .buttonStyle(VibrantButtonStyle(alignment: .center)) - .disabled(!viewModel.isValid) - } - } -// .disabled(busy) // Maybe someday we can do this, but right now it crashes on the iPad - .navigationBarTitle(Text(""), displayMode: .inline) - } - - private func addAccount() { - - busy = true - error = "" - - let emailAddress = viewModel.email.trimmingCharacters(in: .whitespaces) - let credentials = Credentials(type: .basic, username: emailAddress, secret: viewModel.password) - - Account.validateCredentials(type: .feedbin, credentials: credentials) { result in - - self.busy = false - - switch result { - case .success(let authenticated): - - if (authenticated != nil) { - - var newAccount = false - let workAccount: Account - if self.viewModel.account == nil { - workAccount = AccountManager.shared.createAccount(type: .feedbin) - newAccount = true - } else { - workAccount = self.viewModel.account! - } - - do { - - do { - try workAccount.removeCredentials(type: .basic) - } catch {} - try workAccount.storeCredentials(credentials) - - if newAccount { - workAccount.refreshAll() { result in } - } - - self.dismiss() - - } catch { - self.error = "Keychain error while storing credentials." - } - - } else { - self.error = "Invalid email/password combination." - } - - case .failure: - self.error = "Network error. Try again later." - } - - } - - } - - private func dismiss() { - presentation.wrappedValue.dismiss() - } - - class ViewModel: ObservableObject { - - let objectWillChange = ObservableObjectPublisher() - var account: Account? = nil - - init() { - } - - init(account: Account) { - self.account = account - if let credentials = try? account.retrieveCredentials(type: .basic) { - self.email = credentials.username - } - } - - var email: String = "" { - willSet { - objectWillChange.send() - } - } - - var password: String = "" { - willSet { - objectWillChange.send() - } - } - - var isUpdate: Bool { - return account != nil - } - - var isValid: Bool { - return !email.isEmpty && !password.isEmpty - } - } - -} - -#if DEBUG -struct SettingsFeedbinAccountView_Previews : PreviewProvider { - static var previews: some View { - SettingsFeedbinAccountView(viewModel: SettingsFeedbinAccountView.ViewModel()) - } -} -#endif diff --git a/iOS/Settings/Account/SettingsLocalAccountView.swift b/iOS/Settings/Account/SettingsLocalAccountView.swift deleted file mode 100644 index d92cd6f9b..000000000 --- a/iOS/Settings/Account/SettingsLocalAccountView.swift +++ /dev/null @@ -1,59 +0,0 @@ -// -// SettingsLocalAccountView.swift -// NetNewsWire-iOS -// -// Created by Maurice Parker on 6/11/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import SwiftUI -import Account - -struct SettingsLocalAccountView : View { - @Environment(\.presentationMode) var presentation - @State var name: String - - var body: some View { - Form { - Section(header: - HStack { - Spacer() - SettingsAccountLabelView(accountImage: "accountLocal", accountLabel: Account.defaultLocalAccountName) - .padding() - .layoutPriority(1.0) - Spacer() - } - ) { - HStack { - TextField("Name", text: $name) - } - } - Section { - Button(action: { self.addAccount() }) { - Text("Add Account") - } - .buttonStyle(VibrantButtonStyle(alignment: .center)) - } - } - .navigationBarTitle(Text(""), displayMode: .inline) - } - - private func addAccount() { - let account = AccountManager.shared.createAccount(type: .onMyMac) - account.name = name - dismiss() - } - - private func dismiss() { - presentation.wrappedValue.dismiss() - } - -} - -#if DEBUG -struct SettingsLocalAccountView_Previews : PreviewProvider { - static var previews: some View { - SettingsLocalAccountView(name: "") - } -} -#endif diff --git a/iOS/Settings/Account/SettingsReaderAPIAccountView.swift b/iOS/Settings/Account/SettingsReaderAPIAccountView.swift deleted file mode 100644 index 9e4218e9a..000000000 --- a/iOS/Settings/Account/SettingsReaderAPIAccountView.swift +++ /dev/null @@ -1,178 +0,0 @@ -// -// SettingsReaderAPIAccountView.swift -// NetNewsWire-iOS -// -// Created by Jeremy Beker on 5/28/2019. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import SwiftUI -import Combine -import Account -import RSWeb - -struct SettingsReaderAPIAccountView : View { - @Environment(\.presentationMode) var presentation - @ObservedObject var viewModel: ViewModel - - @State var busy: Bool = false - @State var error: String = "" - - var body: some View { - Form { - Section(header: - HStack { - Spacer() - SettingsAccountLabelView(accountImage: "accountFreshRSS", accountLabel: "FreshRSS") - .padding() - .layoutPriority(1.0) - Spacer() - } - ) { - TextField("Email", text: $viewModel.email) - .keyboardType(.emailAddress) - .textContentType(.emailAddress) - SecureField("Password", text: $viewModel.password) - TextField("API URL:", text: $viewModel.apiURL).textContentType(.URL) - } - - Section(footer: - HStack { - Spacer() - Text(verbatim: error).foregroundColor(.red) - Spacer() - } - ) { - Button(action: { self.addAccount() }) { - if viewModel.isUpdate { - Text("Update Account") - } else { - Text("Add Account") - } - } - .buttonStyle(VibrantButtonStyle(alignment: .center)) - .disabled(!viewModel.isValid) - } - } -// .disabled(busy) - } - - private func addAccount() { - - busy = true - error = "" - - let emailAddress = viewModel.email.trimmingCharacters(in: .whitespaces) - let credentials = Credentials(type: .readerBasic, username: emailAddress, secret: viewModel.password) - guard let apiURL = URL(string: viewModel.apiURL) else { - self.error = "Invalid API URL." - return - } - - Account.validateCredentials(type: viewModel.accountType, credentials: credentials, endpoint: apiURL) { result in - - self.busy = false - - switch result { - case .success(let validatedCredentials): - - guard let validatedCredentials = validatedCredentials else { - self.error = "Invalid email/password combination." - return - } - - var newAccount = false - let workAccount: Account - if self.viewModel.account == nil { - workAccount = AccountManager.shared.createAccount(type: self.viewModel.accountType) - newAccount = true - } else { - workAccount = self.viewModel.account! - } - - do { - - do { - try workAccount.removeCredentials(type: .readerBasic) - try workAccount.removeCredentials(type: .readerAPIKey) - } catch {} - - workAccount.endpointURL = apiURL - - try workAccount.storeCredentials(credentials) - try workAccount.storeCredentials(validatedCredentials) - - if newAccount { - workAccount.refreshAll() { result in } - } - - self.dismiss() - - } catch { - self.error = "Keychain error while storing credentials." - } - - case .failure: - self.error = "Network error. Try again later." - } - - } - - } - - private func dismiss() { - presentation.wrappedValue.dismiss() - } - - class ViewModel: ObservableObject { - - let objectWillChange = ObservableObjectPublisher() - var accountType: AccountType - var account: Account? = nil - - init(accountType: AccountType) { - self.accountType = accountType - } - - init(account: Account) { - self.account = account - self.accountType = account.type - if let credentials = try? account.retrieveCredentials(type: .readerBasic) { - self.email = credentials.username - self.apiURL = account.endpointURL?.absoluteString ?? "" - } - } - - var email: String = "" { - willSet { - objectWillChange.send() - } - } - var password: String = "" { - willSet { - objectWillChange.send() - } - } - var apiURL: String = "" { - willSet { - objectWillChange.send() - } - } - var isUpdate: Bool { - return account != nil - } - - var isValid: Bool { - return !email.isEmpty && !password.isEmpty - } - } - -} - -#if DEBUG -struct SettingsReaderAPIAccountView_Previews : PreviewProvider { - static var previews: some View { - SettingsReaderAPIAccountView(viewModel: SettingsReaderAPIAccountView.ViewModel(accountType: .freshRSS)) - } -} -#endif diff --git a/iOS/Settings/AddAccountViewController.swift b/iOS/Settings/AddAccountViewController.swift new file mode 100644 index 000000000..e0a18a590 --- /dev/null +++ b/iOS/Settings/AddAccountViewController.swift @@ -0,0 +1,50 @@ +// +// AddAccountViewController.swift +// NetNewsWire-iOS +// +// Created by Maurice Parker on 5/16/19. +// Copyright © 2019 Ranchero Software. All rights reserved. +// + +import Account +import UIKit + +protocol AddAccountDismissDelegate: UIViewController { + func dismiss() +} + +class AddAccountViewController: UITableViewController, AddAccountDismissDelegate { + + @IBOutlet private weak var localAccountImageView: UIImageView! + @IBOutlet private weak var localAccountNameLabel: UILabel! + + override func viewDidLoad() { + super.viewDidLoad() + localAccountImageView.image = AppAssets.image(for: .onMyMac) + localAccountNameLabel.text = Account.defaultLocalAccountName + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + switch indexPath.row { + case 0: + let navController = UIStoryboard.settings.instantiateViewController(withIdentifier: "AddLocalAccountNavigationViewController") as! UINavigationController + navController.modalPresentationStyle = .currentContext + let addViewController = navController.topViewController as! AddLocalAccountViewController + addViewController.delegate = self + present(navController, animated: true) + case 1: + let navController = UIStoryboard.settings.instantiateViewController(withIdentifier: "FeedbinAccountNavigationViewController") as! UINavigationController + navController.modalPresentationStyle = .currentContext + let addViewController = navController.topViewController as! FeedbinAccountViewController + addViewController.delegate = self + present(navController, animated: true) + default: + break + } + } + + func dismiss() { + navigationController?.popViewController(animated: false) + } + +} diff --git a/iOS/Settings/AddLocalAccountViewController.swift b/iOS/Settings/AddLocalAccountViewController.swift new file mode 100644 index 000000000..b9c092336 --- /dev/null +++ b/iOS/Settings/AddLocalAccountViewController.swift @@ -0,0 +1,45 @@ +// +// AddLocalAccountViewController.swift +// NetNewsWire-iOS +// +// Created by Maurice Parker on 5/19/19. +// Copyright © 2019 Ranchero Software. All rights reserved. +// + +import UIKit +import Account + +class AddLocalAccountViewController: UITableViewController { + + @IBOutlet weak var nameTextField: UITextField! + + weak var delegate: AddAccountDismissDelegate? + + override func viewDidLoad() { + super.viewDidLoad() + navigationItem.title = Account.defaultLocalAccountName + nameTextField.delegate = self + } + + @IBAction func cancel(_ sender: Any) { + dismiss(animated: true, completion: nil) + delegate?.dismiss() + } + + @IBAction func add(_ sender: Any) { + let account = AccountManager.shared.createAccount(type: .onMyMac) + account.name = nameTextField.text + dismiss(animated: true, completion: nil) + delegate?.dismiss() + } + +} + +extension AddLocalAccountViewController: UITextFieldDelegate { + + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + textField.resignFirstResponder() + return true + } + +} diff --git a/iOS/Settings/DetailAccountViewController.swift b/iOS/Settings/DetailAccountViewController.swift new file mode 100644 index 000000000..40dd698ee --- /dev/null +++ b/iOS/Settings/DetailAccountViewController.swift @@ -0,0 +1,117 @@ +// +// DetailAccountViewController.swift +// NetNewsWire-iOS +// +// Created by Maurice Parker on 5/17/19. +// Copyright © 2019 Ranchero Software. All rights reserved. +// + +import UIKit +import Account + +class DetailAccountViewController: UITableViewController { + + @IBOutlet weak var nameTextField: UITextField! + @IBOutlet weak var activeSwitch: UISwitch! + + weak var account: Account? + + override func viewDidLoad() { + super.viewDidLoad() + + guard let account = account else { return } + + nameTextField.placeholder = account.defaultName + nameTextField.text = account.name + nameTextField.delegate = self + activeSwitch.isOn = account.isActive + } + + override func viewWillDisappear(_ animated: Bool) { + account?.name = nameTextField.text + account?.isActive = activeSwitch.isOn + } + + @IBAction func credentials(_ sender: Any) { + guard let account = account else { return } + switch account.type { + case .feedbin: + let navController = UIStoryboard.settings.instantiateViewController(withIdentifier: "FeedbinAccountNavigationViewController") as! UINavigationController + let addViewController = navController.topViewController as! FeedbinAccountViewController + addViewController.account = account + navController.modalPresentationStyle = .currentContext + present(navController, animated: true) + default: + break + } + } + + @IBAction func deleteAccount(_ sender: Any) { + let title = NSLocalizedString("Delete Account", comment: "Delete Account") + let message = NSLocalizedString("Are you sure you want to delete this account? This can not be undone.", comment: "Delete Account") + let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) + + let cancelTitle = NSLocalizedString("Cancel", comment: "Cancel") + let cancelAction = UIAlertAction(title: cancelTitle, style: .cancel) + alertController.addAction(cancelAction) + + let markTitle = NSLocalizedString("Delete", comment: "Delete") + let markAction = UIAlertAction(title: markTitle, style: .default) { [weak self] (action) in + guard let account = self?.account else { return } + AccountManager.shared.deleteAccount(account) + self?.navigationController?.popViewController(animated: true) + } + alertController.addAction(markAction) + + present(alertController, animated: true) + } + +} + +extension DetailAccountViewController { + + override func numberOfSections(in tableView: UITableView) -> Int { + guard let account = account else { return 0 } + + if account == AccountManager.shared.defaultAccount { + return 1 + } else if account.type == .onMyMac { + return 2 + } else { + return super.numberOfSections(in: tableView) + } + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell: UITableViewCell + + if indexPath.section == 1, let account = account, account.type == .onMyMac { + cell = super.tableView(tableView, cellForRowAt: IndexPath(row: 0, section: 2)) + } else { + cell = super.tableView(tableView, cellForRowAt: indexPath) + } + + return cell + } + + override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool { + if indexPath.section > 0 { + return true + } + return false + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.selectRow(at: nil, animated: true, scrollPosition: .none) + } + +} + +extension DetailAccountViewController: UITextFieldDelegate { + + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + textField.resignFirstResponder() + return true + } + +} diff --git a/iOS/Settings/FeedbinAccountViewController.swift b/iOS/Settings/FeedbinAccountViewController.swift new file mode 100644 index 000000000..3196b5880 --- /dev/null +++ b/iOS/Settings/FeedbinAccountViewController.swift @@ -0,0 +1,156 @@ +// +// FeedbinAccountViewController.swift +// NetNewsWire-iOS +// +// Created by Maurice Parker on 5/19/19. +// Copyright © 2019 Ranchero Software. All rights reserved. +// + +import UIKit +import Account +import RSWeb + +class FeedbinAccountViewController: UITableViewController { + + @IBOutlet weak var activityIndicator: UIActivityIndicatorView! + @IBOutlet weak var cancelBarButtonItem: UIBarButtonItem! + @IBOutlet weak var emailTextField: UITextField! + @IBOutlet weak var passwordTextField: UITextField! + @IBOutlet weak var showHideButton: UIButton! + @IBOutlet weak var actionButton: UIButton! + + weak var account: Account? + weak var delegate: AddAccountDismissDelegate? + + override func viewDidLoad() { + super.viewDidLoad() + + activityIndicator.isHidden = true + emailTextField.delegate = self + passwordTextField.delegate = self + + if let account = account, let credentials = try? account.retrieveCredentials(type: .basic) { + actionButton.setTitle(NSLocalizedString("Update Credentials", comment: "Update Credentials"), for: .normal) + emailTextField.text = credentials.username + passwordTextField.text = credentials.secret + } else { + actionButton.setTitle(NSLocalizedString("Add Account", comment: "Update Credentials"), for: .normal) + } + + NotificationCenter.default.addObserver(self, selector: #selector(textDidChange(_:)), name: UITextField.textDidChangeNotification, object: emailTextField) + NotificationCenter.default.addObserver(self, selector: #selector(textDidChange(_:)), name: UITextField.textDidChangeNotification, object: passwordTextField) + } + + @IBAction func cancel(_ sender: Any) { + dismiss(animated: true, completion: nil) + delegate?.dismiss() + } + + @IBAction func showHidePassword(_ sender: Any) { + if passwordTextField.isSecureTextEntry { + passwordTextField.isSecureTextEntry = false + showHideButton.setTitle("Hide", for: .normal) + } else { + passwordTextField.isSecureTextEntry = true + showHideButton.setTitle("Show", for: .normal) + } + } + + @IBAction func action(_ sender: Any) { + + guard let email = emailTextField.text, let password = passwordTextField.text else { + showError(NSLocalizedString("Username & password required.", comment: "Credentials Error")) + return + } + + startAnimatingActivityIndicator() + disableNavigation() + + // When you fill in the email address via auto-complete it adds extra whitespace + let trimmedEmail = email.trimmingCharacters(in: .whitespaces) + let credentials = Credentials(type: .basic, username: trimmedEmail, secret: password) + Account.validateCredentials(type: .feedbin, credentials: credentials) { result in + + self.stopAnimtatingActivityIndicator() + self.enableNavigation() + + switch result { + case .success(let credentials): + if let credentials = credentials { + var newAccount = false + if self.account == nil { + self.account = AccountManager.shared.createAccount(type: .feedbin) + newAccount = true + } + + do { + + do { + try self.account?.removeCredentials(type: .basic) + } catch {} + try self.account?.storeCredentials(credentials) + + if newAccount { + self.account?.refreshAll() { result in + switch result { + case .success: + break + case .failure(let error): + self.presentError(error) + } + } + } + + self.dismiss(animated: true, completion: nil) + self.delegate?.dismiss() + } catch { + self.showError(NSLocalizedString("Keychain error while storing credentials.", comment: "Credentials Error")) + } + } else { + self.showError(NSLocalizedString("Invalid email/password combination.", comment: "Credentials Error")) + } + case .failure: + self.showError(NSLocalizedString("Network error. Try again later.", comment: "Credentials Error")) + } + + } + } + + @objc func textDidChange(_ note: Notification) { + actionButton.isEnabled = !(emailTextField.text?.isEmpty ?? false) && !(passwordTextField.text?.isEmpty ?? false) + } + + private func showError(_ message: String) { + presentError(title: "Error", message: message) + } + + private func enableNavigation() { + self.cancelBarButtonItem.isEnabled = true + self.actionButton.isEnabled = true + } + + private func disableNavigation() { + cancelBarButtonItem.isEnabled = false + actionButton.isEnabled = false + } + + private func startAnimatingActivityIndicator() { + activityIndicator.isHidden = false + activityIndicator.startAnimating() + } + + private func stopAnimtatingActivityIndicator() { + self.activityIndicator.isHidden = true + self.activityIndicator.stopAnimating() + } + +} + +extension FeedbinAccountViewController: UITextFieldDelegate { + + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + textField.resignFirstResponder() + return true + } + +} diff --git a/iOS/Settings/RefreshIntervalViewController.swift b/iOS/Settings/RefreshIntervalViewController.swift new file mode 100644 index 000000000..8f3d89ba9 --- /dev/null +++ b/iOS/Settings/RefreshIntervalViewController.swift @@ -0,0 +1,111 @@ +// +// RefreshIntervalViewController.swift +// NetNewsWire +// +// Created by Maurice Parker on 4/25/19. +// Copyright © 2019 Ranchero Software. All rights reserved. +// + +import UIKit + +class RefreshIntervalViewController: UITableViewController { + + override func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return 7 + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + + let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) + + cell.textLabel?.adjustsFontForContentSizeCategory = true + + let userRefreshInterval = AppDefaults.refreshInterval + + switch indexPath.row { + case 0: + cell.textLabel?.text = RefreshInterval.manually.description() + if userRefreshInterval == RefreshInterval.manually { + cell.accessoryType = .checkmark + } else { + cell.accessoryType = .none + } + case 1: + cell.textLabel?.text = RefreshInterval.every10Minutes.description() + if userRefreshInterval == RefreshInterval.every10Minutes { + cell.accessoryType = .checkmark + } else { + cell.accessoryType = .none + } + case 2: + cell.textLabel?.text = RefreshInterval.every30Minutes.description() + if userRefreshInterval == RefreshInterval.every30Minutes { + cell.accessoryType = .checkmark + } else { + cell.accessoryType = .none + } + case 3: + cell.textLabel?.text = RefreshInterval.everyHour.description() + if userRefreshInterval == RefreshInterval.everyHour { + cell.accessoryType = .checkmark + } else { + cell.accessoryType = .none + } + case 4: + cell.textLabel?.text = RefreshInterval.every2Hours.description() + if userRefreshInterval == RefreshInterval.every2Hours { + cell.accessoryType = .checkmark + } else { + cell.accessoryType = .none + } + case 5: + cell.textLabel?.text = RefreshInterval.every4Hours.description() + if userRefreshInterval == RefreshInterval.every4Hours { + cell.accessoryType = .checkmark + } else { + cell.accessoryType = .none + } + default: + cell.textLabel?.text = RefreshInterval.every8Hours.description() + if userRefreshInterval == RefreshInterval.every8Hours { + cell.accessoryType = .checkmark + } else { + cell.accessoryType = .none + } + } + + return cell + + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + + let refreshInterval: RefreshInterval + + switch indexPath.row { + case 0: + refreshInterval = RefreshInterval.manually + case 1: + refreshInterval = RefreshInterval.every10Minutes + case 2: + refreshInterval = RefreshInterval.every30Minutes + case 3: + refreshInterval = RefreshInterval.everyHour + case 4: + refreshInterval = RefreshInterval.every2Hours + case 5: + refreshInterval = RefreshInterval.every4Hours + default: + refreshInterval = RefreshInterval.every8Hours + } + + AppDefaults.refreshInterval = refreshInterval + self.navigationController?.popViewController(animated: true) + + } + +} diff --git a/iOS/Settings/Settings.storyboard b/iOS/Settings/Settings.storyboard new file mode 100644 index 000000000..5aa060786 --- /dev/null +++ b/iOS/Settings/Settings.storyboard @@ -0,0 +1,1087 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOS/Settings/SettingsAboutView.swift b/iOS/Settings/SettingsAboutView.swift deleted file mode 100644 index 1549f2d7d..000000000 --- a/iOS/Settings/SettingsAboutView.swift +++ /dev/null @@ -1,65 +0,0 @@ -// -// SettingsAboutView.swift -// NetNewsWire-iOS -// -// Created by Maurice Parker on 9/16/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import SwiftUI -import Combine - -struct SettingsAboutView: View { - - @ObservedObject var viewModel: ViewModel - - var body: some View { - Form { - Text("NetNewsWire").font(.largeTitle) - SettingsAttributedStringView(string: viewModel.about).frame(height: 54) - Section(header: Text("CREDITS")) { - SettingsAttributedStringView(string: viewModel.credits).frame(height: 135) - } - Section(header: Text("ACKNOWLEDGEMENTS")) { - SettingsAttributedStringView(string: viewModel.acknowledgements).frame(height: 81) - } - Section(header: Text("THANKS")) { - SettingsAttributedStringView(string: viewModel.thanks).frame(height: 189) - } - Section(header: Text("DEDICATION"), footer: Text("Copyright © 2002-2019 Ranchero Software").font(.footnote)) { - SettingsAttributedStringView(string: viewModel.dedication).frame(height: 108) - } - } - } - - class ViewModel: ObservableObject { - let objectWillChange = ObservableObjectPublisher() - - var about: NSAttributedString - var credits: NSAttributedString - var acknowledgements: NSAttributedString - var thanks: NSAttributedString - var dedication: NSAttributedString - - init() { - about = ViewModel.loadResource("About") - credits = ViewModel.loadResource("Credits") - acknowledgements = ViewModel.loadResource("Acknowledgments") - thanks = ViewModel.loadResource("Thanks") - dedication = ViewModel.loadResource("Dedication") - } - - private static func loadResource(_ resource: String) -> NSAttributedString { - let url = Bundle.main.url(forResource: resource, withExtension: "rtf")! - return try! NSAttributedString(url: url, options: [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.rtf], documentAttributes: nil) - - } - - } -} - -struct SettingsAboutView_Previews: PreviewProvider { - static var previews: some View { - SettingsAboutView(viewModel: SettingsAboutView.ViewModel()) - } -} diff --git a/iOS/Settings/SettingsAccountTableViewCell.swift b/iOS/Settings/SettingsAccountTableViewCell.swift new file mode 100644 index 000000000..0ae9a6ec2 --- /dev/null +++ b/iOS/Settings/SettingsAccountTableViewCell.swift @@ -0,0 +1,39 @@ +// +// SettingsAccountTableViewCell.swift +// NetNewsWire-iOS +// +// Created by Maurice Parker on 10/23/19. +// Copyright © 2019 Ranchero Software. All rights reserved. +// + +import UIKit + +class SettingsAccountTableViewCell: VibrantTableViewCell { + + @IBOutlet weak var accountImage: UIImageView! + @IBOutlet weak var accountNameLabel: UILabel! + + override func setHighlighted(_ highlighted: Bool, animated: Bool) { + super.setHighlighted(highlighted, animated: animated) + updateVibrancy(animated: animated) + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + updateVibrancy(animated: animated) + } + + override func applyThemeProperties() { + super.applyThemeProperties() + accountNameLabel?.highlightedTextColor = AppAssets.vibrantTextColor + } + + func updateVibrancy(animated: Bool) { + let tintColor = isHighlighted || isSelected ? AppAssets.vibrantTextColor : UIColor.label + let duration = animated ? 0.6 : 0.0 + UIView.animate(withDuration: duration) { + self.accountImage?.tintColor = tintColor + } + } + +} diff --git a/iOS/Settings/SettingsAccountTableViewCell.xib b/iOS/Settings/SettingsAccountTableViewCell.xib new file mode 100644 index 000000000..1b4d94da3 --- /dev/null +++ b/iOS/Settings/SettingsAccountTableViewCell.xib @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOS/Settings/SettingsAttributedStringView.swift b/iOS/Settings/SettingsAttributedStringView.swift deleted file mode 100644 index 21f9d1186..000000000 --- a/iOS/Settings/SettingsAttributedStringView.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// SettingsAttributedStringView.swift -// NetNewsWire-iOS -// -// Created by Maurice Parker on 9/16/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import SwiftUI - -struct SettingsAttributedStringView: UIViewRepresentable { - - let string: NSAttributedString - - func makeUIView(context: Context) -> UITextView { - let textView = UITextView() - - textView.attributedText = string - textView.translatesAutoresizingMaskIntoConstraints = false - textView.isEditable = false - - textView.adjustsFontForContentSizeCategory = true - textView.font = .preferredFont(forTextStyle: .body) - textView.textColor = UIColor.label - textView.tintColor = AppAssets.secondaryAccentColor - textView.backgroundColor = UIColor.secondarySystemGroupedBackground - - return textView - } - - func updateUIView(_ textView: UITextView, context: Context) { - } - -} diff --git a/iOS/Settings/SettingsRefreshSelectionView.swift b/iOS/Settings/SettingsRefreshSelectionView.swift deleted file mode 100644 index 22fcce129..000000000 --- a/iOS/Settings/SettingsRefreshSelectionView.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// SettingsRefreshSelectionView.swift -// NetNewsWire-iOS -// -// Created by Maurice Parker on 9/16/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import SwiftUI - -struct SettingsRefreshSelectionView: View { - - @Environment(\.presentationMode) var presentation - @Binding var selectedInterval: RefreshInterval - - var body: some View { - Form { - ForEach(RefreshInterval.allCases) { interval in - Button(action: { - self.selectedInterval = interval - self.presentation.wrappedValue.dismiss() - }) { - HStack { - Text(interval.description()) - Spacer() - if interval == self.selectedInterval { - Image(systemName: "checkmark") - } - } - }.buttonStyle(VibrantButtonStyle(alignment: .leading)) - } - } - } - -} diff --git a/iOS/Settings/SettingsSubscriptionsExportDocumentPickerView.swift b/iOS/Settings/SettingsSubscriptionsExportDocumentPickerView.swift deleted file mode 100644 index a471c7d27..000000000 --- a/iOS/Settings/SettingsSubscriptionsExportDocumentPickerView.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// SettingsSubscriptionsExportDocumentPickerView.swift -// NetNewsWire-iOS -// -// Created by Maurice Parker on 6/16/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import SwiftUI -import Account - -struct SettingsSubscriptionsExportDocumentPickerView : UIViewControllerRepresentable { - var account: Account - - func makeUIViewController(context: UIViewControllerRepresentableContext) -> UIDocumentPickerViewController { - - let accountName = account.nameForDisplay.replacingOccurrences(of: " ", with: "").trimmingCharacters(in: .whitespaces) - let filename = "Subscriptions-\(accountName).opml" - let tempFile = FileManager.default.temporaryDirectory.appendingPathComponent(filename) - - let opmlString = OPMLExporter.OPMLString(with: account, title: filename) - try? opmlString.write(to: tempFile, atomically: true, encoding: String.Encoding.utf8) - - return UIDocumentPickerViewController(url: tempFile, in: .exportToService) - } - - func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: UIViewControllerRepresentableContext) { - // - } - -} diff --git a/iOS/Settings/SettingsSubscriptionsImportDocumentPickerView.swift b/iOS/Settings/SettingsSubscriptionsImportDocumentPickerView.swift deleted file mode 100644 index 4f4043a92..000000000 --- a/iOS/Settings/SettingsSubscriptionsImportDocumentPickerView.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// SettingsSubscriptionsImportDocumentPickerView.swift -// NetNewsWire-iOS -// -// Created by Maurice Parker on 6/16/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import SwiftUI -import Account - -struct SettingsSubscriptionsImportDocumentPickerView : UIViewControllerRepresentable { - var account: Account - - func makeUIViewController(context: UIViewControllerRepresentableContext) -> UIDocumentPickerViewController { - let docPicker = UIDocumentPickerViewController(documentTypes: ["public.xml", "org.opml.opml"], in: .import) - docPicker.delegate = context.coordinator - return docPicker - } - - func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: UIViewControllerRepresentableContext) { - // - } - - func makeCoordinator() -> Coordinator { - return Coordinator(self) - } - - class Coordinator : NSObject, UIDocumentPickerDelegate { - var parent: SettingsSubscriptionsImportDocumentPickerView - - init(_ view: SettingsSubscriptionsImportDocumentPickerView) { - self.parent = view - } - - func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { - for url in urls { - parent.account.importOPML(url) { result in} - } - } - - } -} diff --git a/iOS/Settings/SettingsTableViewCell.xib b/iOS/Settings/SettingsTableViewCell.xib new file mode 100644 index 000000000..71f516107 --- /dev/null +++ b/iOS/Settings/SettingsTableViewCell.xib @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/iOS/Settings/SettingsView.swift b/iOS/Settings/SettingsView.swift deleted file mode 100644 index c853d60c4..000000000 --- a/iOS/Settings/SettingsView.swift +++ /dev/null @@ -1,314 +0,0 @@ -// -// SettingsView.swift -// NetNewsWire-iOS -// -// Created by Maurice Parker on 6/11/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import SwiftUI -import Combine -import Account - -struct SettingsView : View { - - @ObservedObject var viewModel: ViewModel - - @Environment(\.viewController) private var viewController: UIViewController? - @Environment(\.sceneCoordinator) private var coordinator: SceneCoordinator? - - @State private var accountAction: Int? = nil - @State private var refreshAction: Int? = nil - @State private var aboutAction: Int? = nil - - @State private var isWebsitePresented: Bool = false - @State private var website: String? = nil - - @State private var isOPMLImportPresented: Bool = false - @State private var isOPMLImportDocPickerPresented: Bool = false - @State private var isOPMLExportPresented: Bool = false - @State private var isOPMLExportDocPickerPresented: Bool = false - @State private var opmlAccount: Account? = nil - - var body: some View { - NavigationView { - Form { - buildAccountsSection() - buildTimelineSection() - buildDatabaseSection() - buildAboutSection() - } - .buttonStyle(VibrantButtonStyle(alignment: .leading)) - .navigationBarTitle(Text("Settings"), displayMode: .inline) - .navigationBarItems(leading: Button(action: { self.viewController?.dismiss(animated: true) }) { Text("Done") } ) - } - } - - func buildAccountsSection() -> some View { - Section(header: Text("ACCOUNTS").padding(.top, 22.0)) { - ForEach(viewModel.accounts.indices, id: \.self) { index in - NavigationLink(destination: SettingsDetailAccountView(viewModel: SettingsDetailAccountView.ViewModel(self.viewModel.accounts[index])), tag: index, selection: self.$accountAction) { - Text(verbatim: self.viewModel.accounts[index].nameForDisplay) - } - .modifier(VibrantSelectAction(action: { - self.accountAction = index - })) - } - NavigationLink(destination: SettingsAddAccountView(), tag: 1000, selection: $accountAction) { - Text("Add Account") - } - .modifier(VibrantSelectAction(action: { - self.accountAction = 1000 - })) - } - } - - func buildTimelineSection() -> some View { - Section(header: Text("TIMELINE")) { - Toggle(isOn: $viewModel.sortOldestToNewest) { - Text("Sort Newest to Oldest") - } - Toggle(isOn: $viewModel.groupByFeed) { - Text("Group By Feed") - } - Stepper(value: $viewModel.timelineNumberOfLines, in: 2...6) { - Text("Number of Text Lines: \(viewModel.timelineNumberOfLines)") - } - } - } - - func buildDatabaseSection() -> some View { - Section(header: Text("DATABASE")) { - - NavigationLink(destination: SettingsRefreshSelectionView(selectedInterval: $viewModel.refreshInterval), tag: 1, selection: $refreshAction) { - HStack { - Text("Refresh Interval") - Spacer() - Text(verbatim: self.viewModel.refreshInterval.description()).foregroundColor(.secondary) - } - } - .modifier(VibrantSelectAction(action: { - self.refreshAction = 1 - })) - - Button("Import Subscriptions...") { - if AccountManager.shared.activeAccounts.count == 1 { - self.opmlAccount = AccountManager.shared.activeAccounts.first - self.isOPMLImportDocPickerPresented = true - } else { - self.isOPMLImportPresented = true - } - }.actionSheet(isPresented: $isOPMLImportPresented) { - buildSubscriptionsImportAccounts() - }.sheet(isPresented: $isOPMLImportDocPickerPresented) { - SettingsSubscriptionsImportDocumentPickerView(account: self.opmlAccount!) - } - - Button("Export Subscriptions...") { - if AccountManager.shared.accounts.count == 1 { - self.opmlAccount = AccountManager.shared.accounts.first - self.isOPMLImportDocPickerPresented = true - } else { - self.isOPMLExportPresented = true - } - }.actionSheet(isPresented: $isOPMLExportPresented) { - buildSubscriptionsExportAccounts() - }.sheet(isPresented: $isOPMLExportDocPickerPresented) { - SettingsSubscriptionsExportDocumentPickerView(account: self.opmlAccount!) - } - } - } - - func buildAboutSection() -> some View { - Section(header: Text("ABOUT"), footer: buildFooter()) { - - NavigationLink(destination: SettingsAboutView(viewModel: SettingsAboutView.ViewModel()), tag: 1, selection: $aboutAction) { - Text("About NetNewsWire") - } - .modifier(VibrantSelectAction(action: { - self.aboutAction = 1 - })) - - Button(action: { - self.isWebsitePresented.toggle() - self.website = "https://ranchero.com/netnewswire/" - }) { - Text("Website") - } - - Button(action: { - self.isWebsitePresented.toggle() - self.website = "https://github.com/brentsimmons/NetNewsWire" - }) { - Text("Github Repository") - } - - Button(action: { - self.isWebsitePresented.toggle() - self.website = "https://github.com/brentsimmons/NetNewsWire/issues" - }) { - Text("Bug Tracker") - } - - Button(action: { - self.isWebsitePresented.toggle() - self.website = "https://github.com/brentsimmons/NetNewsWire/tree/master/Technotes" - }) { - Text("Technotes") - } - - Button(action: { - self.isWebsitePresented.toggle() - self.website = "https://github.com/brentsimmons/NetNewsWire/blob/master/Technotes/HowToSupportNetNewsWire.markdown" - }) { - Text("How To Support NetNewsWire") - } - - if !AccountManager.shared.anyAccountHasFeedWithURL("https://nnw.ranchero.com/feed.json") { - Button(action: { - self.viewController?.dismiss(animated: true) { - let feedName = NSLocalizedString("NetNewsWire News", comment: "NetNewsWire News") - self.coordinator?.showAdd(.feed, initialFeed: "https://nnw.ranchero.com/feed.json", initialFeedName: feedName) - } - }) { - Text("Add NetNewsWire News Feed") - } - } - - }.sheet(isPresented: $isWebsitePresented) { - SafariView(url: URL(string: self.website!)!) - } - } - - func buildSubscriptionsImportAccounts() -> ActionSheet { - var buttons = [ActionSheet.Button]() - - for account in viewModel.activeAccounts { - if account.behaviors.contains(.disallowOPMLImports) { - continue - } - - let button = ActionSheet.Button.default(Text(verbatim: account.nameForDisplay)) { - self.opmlAccount = account - self.isOPMLImportDocPickerPresented = true - } - - buttons.append(button) - } - - buttons.append(.cancel()) - return ActionSheet(title: Text("Import Subscriptions..."), message: Text("Select the account to import your OPML file into."), buttons: buttons) - } - - func buildSubscriptionsExportAccounts() -> ActionSheet { - var buttons = [ActionSheet.Button]() - - for account in viewModel.accounts { - let button = ActionSheet.Button.default(Text(verbatim: account.nameForDisplay)) { - self.opmlAccount = account - self.isOPMLExportDocPickerPresented = true - } - buttons.append(button) - } - - buttons.append(.cancel()) - return ActionSheet(title: Text("Export Subscriptions..."), message: Text("Select the account to export out of."), buttons: buttons) - } - - func buildFooter() -> some View { - return Text(verbatim: "\(Bundle.main.appName) v \(Bundle.main.versionNumber) (Build \(Bundle.main.buildNumber))") - .font(.footnote) - .foregroundColor(.secondary) - } - - // MARK: ViewModel - - class ViewModel: ObservableObject { - - let objectWillChange = ObservableObjectPublisher() - - init() { - NotificationCenter.default.addObserver(self, selector: #selector(accountsDidChange(_:)), name: .UserDidAddAccount, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(accountsDidChange(_:)), name: .UserDidDeleteAccount, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(displayNameDidChange(_:)), name: .DisplayNameDidChange, object: nil) - } - - var accounts: [Account] { - get { - return AccountManager.shared.sortedAccounts - } - set { - } - } - - var activeAccounts: [Account] { - get { - return AccountManager.shared.sortedActiveAccounts - } - set { - } - } - - var sortOldestToNewest: Bool { - get { - return AppDefaults.timelineSortDirection == .orderedDescending - } - set { - objectWillChange.send() - if newValue == true { - AppDefaults.timelineSortDirection = .orderedDescending - } else { - AppDefaults.timelineSortDirection = .orderedAscending - } - } - } - - var groupByFeed: Bool { - get { - return AppDefaults.timelineGroupByFeed - } - set { - objectWillChange.send() - AppDefaults.timelineGroupByFeed = newValue - } - } - - var timelineNumberOfLines: Int { - get { - return AppDefaults.timelineNumberOfLines - } - set { - objectWillChange.send() - AppDefaults.timelineNumberOfLines = newValue - } - } - - var refreshInterval: RefreshInterval { - get { - return AppDefaults.refreshInterval - } - set { - objectWillChange.send() - AppDefaults.refreshInterval = newValue - } - } - - @objc func accountsDidChange(_ notification: Notification) { - objectWillChange.send() - } - - @objc func displayNameDidChange(_ notification: Notification) { - objectWillChange.send() - } - - } - -} - -#if DEBUG -struct SettingsView_Previews : PreviewProvider { - static var previews: some View { - SettingsView(viewModel: SettingsView.ViewModel()) - } -} -#endif diff --git a/iOS/Settings/SettingsViewController.swift b/iOS/Settings/SettingsViewController.swift new file mode 100644 index 000000000..be8f7683c --- /dev/null +++ b/iOS/Settings/SettingsViewController.swift @@ -0,0 +1,388 @@ +// +// SettingsViewController.swift +// NetNewsWire-iOS +// +// Created by Maurice Parker on 4/24/19. +// Copyright © 2019 Ranchero Software. All rights reserved. +// + +import UIKit +import Account +import SafariServices + +class SettingsViewController: UITableViewController { + + private let appNewsURLString = "https://nnw.ranchero.com/feed.json" + private weak var opmlAccount: Account? + + static let preferredContentSizeForFormSheetDisplay = CGSize(width: 460.0, height: 400.0) + + @IBOutlet weak var refreshIntervalLabel: UILabel! + @IBOutlet weak var timelineSortOrderSwitch: UISwitch! + @IBOutlet weak var groupByFeedSwitch: UISwitch! + @IBOutlet weak var numberOfTextLinesLabel: UILabel! + @IBOutlet weak var numberOfTextLinesSteppper: UIStepper! + + weak var presentingParentController: UIViewController? + + override func viewDidLoad() { + // This hack mostly works around a bug in static tables with dynamic type. See: https://spin.atomicobject.com/2018/10/15/dynamic-type-static-uitableview/ + NotificationCenter.default.removeObserver(tableView!, name: UIContentSizeCategory.didChangeNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(contentSizeCategoryDidChange), name: UIContentSizeCategory.didChangeNotification, object: nil) + + NotificationCenter.default.addObserver(self, selector: #selector(accountsDidChange), name: .UserDidAddAccount, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(accountsDidChange), name: .UserDidDeleteAccount, object: nil) + + tableView.register(UINib(nibName: "SettingsAccountTableViewCell", bundle: nil), forCellReuseIdentifier: "SettingsAccountTableViewCell") + tableView.register(UINib(nibName: "SettingsTableViewCell", bundle: nil), forCellReuseIdentifier: "SettingsTableViewCell") + + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + if AppDefaults.timelineSortDirection == .orderedAscending { + timelineSortOrderSwitch.isOn = true + } else { + timelineSortOrderSwitch.isOn = false + } + + if AppDefaults.timelineGroupByFeed { + groupByFeedSwitch.isOn = true + } else { + groupByFeedSwitch.isOn = false + } + + refreshIntervalLabel.text = AppDefaults.refreshInterval.description() + + let numberOfTextLines = AppDefaults.timelineNumberOfLines + numberOfTextLinesSteppper.value = Double(numberOfTextLines) + updateNumberOfTextLinesLabel(value: numberOfTextLines) + + let buildLabel = NonIntrinsicLabel(frame: CGRect(x: 20.0, y: 0.0, width: 0.0, height: 0.0)) + buildLabel.font = UIFont.systemFont(ofSize: 11.0) + buildLabel.textColor = UIColor.gray + buildLabel.text = "\(Bundle.main.appName) v \(Bundle.main.versionNumber) (Build \(Bundle.main.buildNumber))" + buildLabel.sizeToFit() + buildLabel.translatesAutoresizingMaskIntoConstraints = false + tableView.tableFooterView = buildLabel + + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + self.tableView.selectRow(at: nil, animated: true, scrollPosition: .none) + } + + // MARK: UITableView + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + switch section { + case 1: + return AccountManager.shared.accounts.count + 1 + case 4: + let defaultNumberOfRows = super.tableView(tableView, numberOfRowsInSection: section) + if AccountManager.shared.activeAccounts.isEmpty || AccountManager.shared.anyAccountHasFeedWithURL(appNewsURLString) { + return defaultNumberOfRows - 1 + } + return defaultNumberOfRows + default: + return super.tableView(tableView, numberOfRowsInSection: section) + } + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell: UITableViewCell + switch indexPath.section { + case 1: + + let sortedAccounts = AccountManager.shared.sortedAccounts + if indexPath.row == sortedAccounts.count { + cell = tableView.dequeueReusableCell(withIdentifier: "SettingsTableViewCell", for: indexPath) + cell.textLabel?.adjustsFontForContentSizeCategory = true + cell.textLabel?.text = NSLocalizedString("Add Account", comment: "Accounts") + } else { + let acctCell = tableView.dequeueReusableCell(withIdentifier: "SettingsAccountTableViewCell", for: indexPath) as! SettingsAccountTableViewCell + acctCell.applyThemeProperties() + let account = sortedAccounts[indexPath.row] + acctCell.accountImage?.image = AppAssets.image(for: account.type) + acctCell.accountNameLabel?.text = account.nameForDisplay + cell = acctCell + } + + default: + + cell = super.tableView(tableView, cellForRowAt: indexPath) + + } + + return cell + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + switch indexPath.section { + case 0: + UIApplication.shared.open(URL(string: "\(UIApplication.openSettingsURLString)")!) + tableView.selectRow(at: nil, animated: true, scrollPosition: .none) + case 1: + let sortedAccounts = AccountManager.shared.sortedAccounts + if indexPath.row == sortedAccounts.count { + let controller = UIStoryboard.settings.instantiateController(ofType: AddAccountViewController.self) + self.navigationController?.pushViewController(controller, animated: true) + } else { + let controller = UIStoryboard.settings.instantiateController(ofType: DetailAccountViewController.self) + controller.account = sortedAccounts[indexPath.row] + self.navigationController?.pushViewController(controller, animated: true) + } + case 3: + switch indexPath.row { + case 0: + let timeline = UIStoryboard.settings.instantiateController(ofType: RefreshIntervalViewController.self) + self.navigationController?.pushViewController(timeline, animated: true) + case 1: + tableView.selectRow(at: nil, animated: true, scrollPosition: .none) + if let sourceView = tableView.cellForRow(at: indexPath) { + let sourceRect = tableView.rectForRow(at: indexPath) + importOPML(sourceView: sourceView, sourceRect: sourceRect) + } + case 2: + tableView.selectRow(at: nil, animated: true, scrollPosition: .none) + if let sourceView = tableView.cellForRow(at: indexPath) { + let sourceRect = tableView.rectForRow(at: indexPath) + exportOPML(sourceView: sourceView, sourceRect: sourceRect) + } + default: + break + } + case 4: + switch indexPath.row { + case 0: + let timeline = UIStoryboard.settings.instantiateController(ofType: AboutViewController.self) + self.navigationController?.pushViewController(timeline, animated: true) + case 1: + openURL("https://ranchero.com/netnewswire/") + tableView.selectRow(at: nil, animated: true, scrollPosition: .none) + case 2: + openURL("https://github.com/brentsimmons/NetNewsWire/blob/master/Technotes/HowToSupportNetNewsWire.markdown") + tableView.selectRow(at: nil, animated: true, scrollPosition: .none) + case 3: + openURL("https://github.com/brentsimmons/NetNewsWire") + tableView.selectRow(at: nil, animated: true, scrollPosition: .none) + case 4: + openURL("https://github.com/brentsimmons/NetNewsWire/issues") + tableView.selectRow(at: nil, animated: true, scrollPosition: .none) + case 5: + openURL("https://github.com/brentsimmons/NetNewsWire/tree/master/Technotes") + tableView.selectRow(at: nil, animated: true, scrollPosition: .none) + case 6: + addFeed() + tableView.selectRow(at: nil, animated: true, scrollPosition: .none) + default: + break + } + default: + tableView.selectRow(at: nil, animated: true, scrollPosition: .none) + } + } + + override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { + return false + } + + override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool { + return false + } + + override func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle { + return .none + } + + override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + if indexPath.section == 1 { + return super.tableView(tableView, heightForRowAt: IndexPath(row: 0, section: 1)) + } else { + return super.tableView(tableView, heightForRowAt: indexPath) + } + } + + override func tableView(_ tableView: UITableView, indentationLevelForRowAt indexPath: IndexPath) -> Int { + if indexPath.section == 1 { + return super.tableView(tableView, indentationLevelForRowAt: IndexPath(row: 0, section: 1)) + } else { + return super.tableView(tableView, indentationLevelForRowAt: indexPath) + } + } + + // MARK: Actions + + @IBAction func done(_ sender: Any) { + dismiss(animated: true) + } + + @IBAction func switchTimelineOrder(_ sender: Any) { + if timelineSortOrderSwitch.isOn { + AppDefaults.timelineSortDirection = .orderedAscending + } else { + AppDefaults.timelineSortDirection = .orderedDescending + } + } + + @IBAction func switchGroupByFeed(_ sender: Any) { + if groupByFeedSwitch.isOn { + AppDefaults.timelineGroupByFeed = true + } else { + AppDefaults.timelineGroupByFeed = false + } + } + + @IBAction func stepNumberOfTextLines(_ sender: UIStepper) { + let numberOfLines = Int(sender.value) + AppDefaults.timelineNumberOfLines = numberOfLines + updateNumberOfTextLinesLabel(value: numberOfLines) + } + + // MARK: Notifications + + @objc func contentSizeCategoryDidChange() { + tableView.reloadData() + } + + @objc func accountsDidChange() { + tableView.reloadData() + } + +} + +// MARK: OPML Document Picker + +extension SettingsViewController: UIDocumentPickerDelegate { + + func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { + for url in urls { + opmlAccount?.importOPML(url) { result in} + } + } + +} + +// MARK: Private + +private extension SettingsViewController { + + func updateNumberOfTextLinesLabel(value: Int) { + let localizedText = NSLocalizedString("Number of Text Lines: %d", comment: "Number of Text Lines") + numberOfTextLinesLabel.text = NSString.localizedStringWithFormat(localizedText as NSString, value) as String + } + + func addFeed() { + self.dismiss(animated: true) + + let addNavViewController = UIStoryboard.add.instantiateInitialViewController() as! UINavigationController + let addViewController = addNavViewController.topViewController as! AddContainerViewController + addNavViewController.modalPresentationStyle = .formSheet + addNavViewController.preferredContentSize = AddContainerViewController.preferredContentSizeForFormSheetDisplay + addViewController.initialControllerType = .feed + addViewController.initialFeed = appNewsURLString + addViewController.initialFeedName = "NetNewsWire News" + + presentingParentController?.present(addNavViewController, animated: true) + } + + func importOPML(sourceView: UIView, sourceRect: CGRect) { + switch AccountManager.shared.activeAccounts.count { + case 0: + presentError(title: "Error", message: NSLocalizedString("You must have at least one active account.", comment: "Missing active account")) + case 1: + opmlAccount = AccountManager.shared.activeAccounts.first + importOPMLDocumentPicker() + default: + importOPMLAccountPicker(sourceView: sourceView, sourceRect: sourceRect) + } + } + + func importOPMLAccountPicker(sourceView: UIView, sourceRect: CGRect) { + let title = NSLocalizedString("Select an Import Account", comment: "Select an Import Account") + let alert = UIAlertController(title: title, message: nil, preferredStyle: .actionSheet) + + if let popoverController = alert.popoverPresentationController { + popoverController.sourceView = view + popoverController.sourceRect = sourceRect + } + + for account in AccountManager.shared.sortedActiveAccounts { + let action = UIAlertAction(title: account.nameForDisplay, style: .default) { [weak self] action in + self?.opmlAccount = account + self?.importOPMLDocumentPicker() + } + alert.addAction(action) + } + + let cancelTitle = NSLocalizedString("Cancel", comment: "Cancel") + alert.addAction(UIAlertAction(title: cancelTitle, style: .cancel)) + + self.present(alert, animated: true) + } + + func importOPMLDocumentPicker() { + let docPicker = UIDocumentPickerViewController(documentTypes: ["public.xml", "org.opml.opml"], in: .import) + docPicker.delegate = self + docPicker.modalPresentationStyle = .formSheet + self.present(docPicker, animated: true) + } + + func exportOPML(sourceView: UIView, sourceRect: CGRect) { + if AccountManager.shared.accounts.count == 1 { + exportOPMLDocumentPicker() + } else { + exportOPMLAccountPicker(sourceView: sourceView, sourceRect: sourceRect) + } + } + + func exportOPMLAccountPicker(sourceView: UIView, sourceRect: CGRect) { + let title = NSLocalizedString("Select an Export Account", comment: "Select an Export Account") + let alert = UIAlertController(title: title, message: nil, preferredStyle: .actionSheet) + + if let popoverController = alert.popoverPresentationController { + popoverController.sourceView = view + popoverController.sourceRect = sourceRect + } + + for account in AccountManager.shared.sortedAccounts { + let action = UIAlertAction(title: account.nameForDisplay, style: .default) { [weak self] action in + self?.opmlAccount = account + self?.exportOPMLDocumentPicker() + } + alert.addAction(action) + } + + let cancelTitle = NSLocalizedString("Cancel", comment: "Cancel") + alert.addAction(UIAlertAction(title: cancelTitle, style: .cancel)) + + self.present(alert, animated: true) + } + + func exportOPMLDocumentPicker() { + guard let account = opmlAccount else { return } + + let accountName = account.nameForDisplay.replacingOccurrences(of: " ", with: "").trimmingCharacters(in: .whitespaces) + let filename = "Subscriptions-\(accountName).opml" + let tempFile = FileManager.default.temporaryDirectory.appendingPathComponent(filename) + let opmlString = OPMLExporter.OPMLString(with: account, title: filename) + do { + try opmlString.write(to: tempFile, atomically: true, encoding: String.Encoding.utf8) + } catch { + self.presentError(title: "OPML Export Error", message: error.localizedDescription) + } + + let docPicker = UIDocumentPickerViewController(url: tempFile, in: .exportToService) + docPicker.modalPresentationStyle = .formSheet + self.present(docPicker, animated: true) + } + + func openURL(_ urlString: String) { + let vc = SFSafariViewController(url: URL(string: urlString)!) + vc.modalPresentationStyle = .pageSheet + present(vc, animated: true) + } + +} diff --git a/iOS/ShareExtension/Info.plist b/iOS/ShareExtension/Info.plist index d25defda1..fc1cd201d 100644 --- a/iOS/ShareExtension/Info.plist +++ b/iOS/ShareExtension/Info.plist @@ -21,9 +21,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.0 + $(MARKETING_VERSION) CFBundleVersion - 1 + $(CURRENT_PROJECT_VERSION) NSExtension NSExtensionAttributes @@ -31,7 +31,7 @@ NSExtensionActivationRule NSExtensionActivationSupportsWebURLWithMaxCount - 1 + 1 NSExtensionJavaScriptPreprocessingFile SafariExt diff --git a/iOS/SwiftUI Extensions/PasswordField.swift b/iOS/SwiftUI Extensions/PasswordField.swift deleted file mode 100644 index 8875837ae..000000000 --- a/iOS/SwiftUI Extensions/PasswordField.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// PasswordField.swift -// NetNewsWire-iOS -// -// Created by Maurice Parker on 10/8/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import SwiftUI - -struct PasswordField: UIViewRepresentable { - - let password: Binding - - func makeUIView(context: Context) -> ShowHidePasswordView { - let showHideView = Bundle.main.loadNibNamed("ShowHidePasswordView", owner: Self.self, options: nil)?[0] as! ShowHidePasswordView - showHideView.passwordTextField.bindingString = password - return showHideView - } - - func updateUIView(_ showHideView: ShowHidePasswordView, context: Context) { - showHideView.passwordTextField.bindingString = password - } - -} diff --git a/iOS/SwiftUI Extensions/SafariView.swift b/iOS/SwiftUI Extensions/SafariView.swift deleted file mode 100644 index 6b5d78334..000000000 --- a/iOS/SwiftUI Extensions/SafariView.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// SafariView.swift -// NetNewsWire-iOS -// -// Created by Stuart Breckenridge on 16/6/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import SwiftUI -import SafariServices - -struct SafariView : UIViewControllerRepresentable { - - let url: URL - - func makeUIViewController(context: UIViewControllerRepresentableContext) -> SFSafariViewController { - let safari = SFSafariViewController(url: url) - safari.delegate = context.coordinator - return safari - } - - func updateUIViewController(_ uiViewController: SFSafariViewController, context: UIViewControllerRepresentableContext) { - // - } - - func makeCoordinator() -> Coordinator { - return Coordinator(self) - } - - class Coordinator : NSObject, SFSafariViewControllerDelegate { - var parent: SafariView - - init(_ safariView: SafariView) { - self.parent = safariView - } - - // MARK: SFSafariViewControllerDelegate - func safariViewControllerDidFinish(_ controller: SFSafariViewController) { - - } - - func safariViewController(_ controller: SFSafariViewController, initialLoadDidRedirectTo URL: URL) { - - } - - func safariViewController(_ controller: SFSafariViewController, didCompleteInitialLoad didLoadSuccessfully: Bool) { - - } - } -} - - diff --git a/iOS/SwiftUI Extensions/ShowHidePasswordView.swift b/iOS/SwiftUI Extensions/ShowHidePasswordView.swift deleted file mode 100644 index fe6b10d02..000000000 --- a/iOS/SwiftUI Extensions/ShowHidePasswordView.swift +++ /dev/null @@ -1,51 +0,0 @@ -// -// ShowHidePasswordView.swift -// NetNewsWire-iOS -// -// Created by Maurice Parker on 10/8/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import UIKit -import SwiftUI - -class ShowHidePasswordView: UIView { - - @IBOutlet weak var passwordTextField: BindingTextField! - @IBOutlet weak var showHideButton: UIButton! - - @IBAction func toggleShowHideButton(_ sender: Any) { - if passwordTextField.isSecureTextEntry { - passwordTextField.isSecureTextEntry = false - showHideButton.setTitle(NSLocalizedString("Hide", comment: "Hide"), for: .normal) - } else { - passwordTextField.isSecureTextEntry = true - showHideButton.setTitle(NSLocalizedString("Show", comment: "Show"), for: .normal) - } - } - -} - -class BindingTextField: UITextField, UITextFieldDelegate { - - var bindingString: Binding? = nil - - override init(frame: CGRect) { - super.init(frame: frame) - delegate = self - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - delegate = self - } - - func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { - if let currentValue = textField.text as NSString? { - let proposedValue = currentValue.replacingCharacters(in: range, with: string) - bindingString?.wrappedValue = proposedValue - } - return true - } - -} diff --git a/iOS/SwiftUI Extensions/ShowHidePasswordView.xib b/iOS/SwiftUI Extensions/ShowHidePasswordView.xib deleted file mode 100644 index d68686200..000000000 --- a/iOS/SwiftUI Extensions/ShowHidePasswordView.xib +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/iOS/SwiftUI Extensions/VibrantButtonStyle.swift b/iOS/SwiftUI Extensions/VibrantButtonStyle.swift deleted file mode 100644 index 61ffd9517..000000000 --- a/iOS/SwiftUI Extensions/VibrantButtonStyle.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// VibrantButtonStyle.swift -// NetNewsWire-iOS -// -// Created by Maurice Parker on 9/16/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import SwiftUI - -struct VibrantButtonStyle: ButtonStyle { - - let alignment: Alignment - - func makeBody(configuration: Configuration) -> some View { - GeometryReader { geometry in - configuration.label - .frame(width: geometry.size.width, height: geometry.size.height, alignment: self.alignment) - } - .foregroundColor(configuration.isPressed ? Color(AppAssets.tableViewCellHighlightedTextColor) : .primary) - .listRowBackground(configuration.isPressed ? Color(AppAssets.primaryAccentColor) : Color(.secondarySystemGroupedBackground)) - .background(configuration.isPressed ? Color(AppAssets.primaryAccentColor) : Color(.secondarySystemGroupedBackground)) - } - -} diff --git a/iOS/SwiftUI Extensions/VibrantSelectAction.swift b/iOS/SwiftUI Extensions/VibrantSelectAction.swift deleted file mode 100644 index 45471d5e1..000000000 --- a/iOS/SwiftUI Extensions/VibrantSelectAction.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// VibrantSelectAction.swift -// NetNewsWire-iOS -// -// Created by Maurice Parker on 9/15/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import SwiftUI - -struct VibrantSelectAction: ViewModifier { - - let action: () -> Void - @State var isTapped = false - @GestureState var isLongPressed = false - - func body(content: Content) -> some View { - GeometryReader { geometry in - content - .frame(width: geometry.size.width, height: geometry.size.height, alignment: .leading) - .background(self.isLongPressed || self.isTapped ? Color(AppAssets.primaryAccentColor) : Color(.secondarySystemGroupedBackground)) - } - .foregroundColor(isLongPressed || isTapped ? Color(AppAssets.tableViewCellHighlightedTextColor) : .primary) - .listRowBackground(isLongPressed || isTapped ? Color(AppAssets.primaryAccentColor) : nil) - .gesture( - LongPressGesture().onEnded( { _ in self.action() }) - .updating($isLongPressed) { value, state, transcation in state = value } - .simultaneously(with: - TapGesture().onEnded( { - self.isTapped = true - self.action() - DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) { - self.isTapped = false - } - } - )) - ) - } - -} diff --git a/iOS/UIKit Extensions/ThemedNavigationController.swift b/iOS/UIKit Extensions/ThemedNavigationController.swift index 979d83b78..058e6afa5 100644 --- a/iOS/UIKit Extensions/ThemedNavigationController.swift +++ b/iOS/UIKit Extensions/ThemedNavigationController.swift @@ -34,10 +34,10 @@ class ThemedNavigationController: UINavigationController { if traitCollection.userInterfaceStyle == .dark { navigationBar.standardAppearance = UINavigationBarAppearance() - navigationBar.tintColor = view.tintColor + navigationBar.tintColor = AppAssets.primaryAccentColor toolbar.standardAppearance = UIToolbarAppearance() toolbar.compactAppearance = UIToolbarAppearance() - toolbar.tintColor = view.tintColor + toolbar.tintColor = AppAssets.primaryAccentColor } else { let navigationAppearance = UINavigationBarAppearance() navigationAppearance.backgroundColor = AppAssets.barBackgroundColor diff --git a/iOS/UIKit Extensions/UIStoryboard-Extensions.swift b/iOS/UIKit Extensions/UIStoryboard-Extensions.swift index f0b67d6ff..4d309a729 100644 --- a/iOS/UIKit Extensions/UIStoryboard-Extensions.swift +++ b/iOS/UIKit Extensions/UIStoryboard-Extensions.swift @@ -10,6 +10,8 @@ import UIKit extension UIStoryboard { + static let preferredContentSizeForFormSheetDisplay = CGSize(width: 460.0, height: 400.0) + static var main: UIStoryboard { return UIStoryboard(name: "Main", bundle: nil) } diff --git a/iOS/UIKit Extensions/VibrantButton.swift b/iOS/UIKit Extensions/VibrantButton.swift new file mode 100644 index 000000000..dc311d549 --- /dev/null +++ b/iOS/UIKit Extensions/VibrantButton.swift @@ -0,0 +1,48 @@ +// +// VibrantButton.swift +// NetNewsWire-iOS +// +// Created by Maurice Parker on 10/22/19. +// Copyright © 2019 Ranchero Software. All rights reserved. +// + +import UIKit + +class VibrantButton: UIButton { + + override init(frame: CGRect) { + super.init(frame: frame) + commonInit() + } + required init?(coder: NSCoder) { + super.init(coder: coder) + commonInit() + } + + private func commonInit() { + setTitleColor(AppAssets.vibrantTextColor, for: .highlighted) + } + + override var isHighlighted: Bool { + didSet { + backgroundColor = isHighlighted ? AppAssets.secondaryAccentColor : nil + titleLabel?.alpha = 1 + } + } + + override func touchesBegan(_ touches: Set, with event: UIEvent?) { + isHighlighted = true + super.touchesBegan(touches, with: event) + } + + override func touchesEnded(_ touches: Set, with event: UIEvent?) { + isHighlighted = false + super.touchesEnded(touches, with: event) + } + + override func touchesCancelled(_ touches: Set, with event: UIEvent?) { + isHighlighted = false + super.touchesCancelled(touches, with: event) + } + +} diff --git a/iOS/UIKit Extensions/VibrantLabel.swift b/iOS/UIKit Extensions/VibrantLabel.swift new file mode 100644 index 000000000..9e480a7c4 --- /dev/null +++ b/iOS/UIKit Extensions/VibrantLabel.swift @@ -0,0 +1,27 @@ +// +// VibrantLabel.swift +// NetNewsWire-iOS +// +// Created by Maurice Parker on 10/22/19. +// Copyright © 2019 Ranchero Software. All rights reserved. +// + +import UIKit + +class VibrantLabel: UILabel { + + override init(frame: CGRect) { + super.init(frame: frame) + commonInit() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + commonInit() + } + + private func commonInit() { + highlightedTextColor = AppAssets.vibrantTextColor + } + +} diff --git a/iOS/UIKit Extensions/NNWTableViewCell.swift b/iOS/UIKit Extensions/VibrantTableViewCell.swift similarity index 74% rename from iOS/UIKit Extensions/NNWTableViewCell.swift rename to iOS/UIKit Extensions/VibrantTableViewCell.swift index 1cea8c90c..bd6998bca 100644 --- a/iOS/UIKit Extensions/NNWTableViewCell.swift +++ b/iOS/UIKit Extensions/VibrantTableViewCell.swift @@ -1,5 +1,5 @@ // -// NNWTableViewCell.swift +// VibrantTableViewCell.swift // NetNewsWire-iOS // // Created by Jim Correia on 9/2/19. @@ -8,7 +8,8 @@ import UIKit -class NNWTableViewCell: UITableViewCell { +class VibrantTableViewCell: UITableViewCell { + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) commonInit() @@ -26,7 +27,9 @@ class NNWTableViewCell: UITableViewCell { /// Subclass overrides should call super func applyThemeProperties() { let selectedBackgroundView = UIView(frame: .zero) - selectedBackgroundView.backgroundColor = AppAssets.primaryAccentColor + selectedBackgroundView.backgroundColor = AppAssets.secondaryAccentColor self.selectedBackgroundView = selectedBackgroundView + + textLabel?.highlightedTextColor = AppAssets.vibrantTextColor } } diff --git a/submodules/Sparkle b/submodules/Sparkle new file mode 160000 index 000000000..67819be18 --- /dev/null +++ b/submodules/Sparkle @@ -0,0 +1 @@ +Subproject commit 67819be18a4ef48e85ea30dbbf8de582f5ef405c diff --git a/xcconfig/NetNewsWire_iOSapp_target.xcconfig b/xcconfig/NetNewsWire_iOSapp_target.xcconfig index 3caf8ea44..1b099b259 100644 --- a/xcconfig/NetNewsWire_iOSapp_target.xcconfig +++ b/xcconfig/NetNewsWire_iOSapp_target.xcconfig @@ -32,19 +32,10 @@ PROVISIONING_PROFILE_SPECIFIER = #include? "../../SharedXcodeSettings/ProjectSettings.xcconfig" #include? "../../SharedXcodeSettings/DeveloperSettings.xcconfig" - -ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES -ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon -CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - -COMBINE_HIDPI_IMAGES = YES -FRAMEWORK_SEARCH_PATHS = $(inherited) $(PROJECT_DIR)/Frameworks/Vendor -GCC_C_LANGUAGE_STANDARD = gnu11; +#include "./common/NetNewsWire_ios_target_common.xcconfig" LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks INFOPLIST_FILE = iOS/Resources/Info.plist CODE_SIGN_ENTITLEMENTS = iOS/Resources/NetNewsWire.entitlements PRODUCT_BUNDLE_IDENTIFIER = $(ORGANIZATION_IDENTIFIER).NetNewsWire.iOS PRODUCT_NAME = NetNewsWire -SDKROOT = iphoneos; -TARGETED_DEVICE_FAMILY = 1,2 diff --git a/xcconfig/NetNewsWire_iOSintentextension_target.xcconfig b/xcconfig/NetNewsWire_iOSintentextension_target.xcconfig new file mode 100644 index 000000000..52b19615c --- /dev/null +++ b/xcconfig/NetNewsWire_iOSintentextension_target.xcconfig @@ -0,0 +1,41 @@ +CODE_SIGN_IDENTITY= iPhone Developer +DEVELOPMENT_TEAM = M8L2WTLA8W +CODE_SIGN_STYLE = Automatic +ORGANIZATION_IDENTIFIER = com.ranchero +PROVISIONING_PROFILE_SPECIFIER = + +// developers can locally override the Xcode settings for code signing +// by creating a DeveloperSettings.xcconfig file locally at the appropriate path +// This allows a pristine project to have code signing set up with the appropriate +// developer ID and certificates, and for dev to be able to have local settings +// without needing to check in anything into source control +// +// As an example, make a ../../SharedXcodeSettings/DeveloperSettings.xcconfig file and +// give it the contents +// +// CODE_SIGN_IDENTITY[sdk=macosx*] = Mac Developer +// CODE_SIGN_IDENTITY[sdk=iphoneos*] = iPhone Developer +// CODE_SIGN_IDENTITY[sdk=iphonesimulator*] = iPhone Developer +// DEVELOPMENT_TEAM = +// BUNDLE_ROOT = +// CODE_SIGN_STYLE = Automatic +// PROVISIONING_PROFILE_SPECIFIER = +// +// And you should be able to build without code signing errors and without modifying +// the NetNewsWire Xcode project. +// +// Example: if your NetNewsWire Xcode project file is at +// /Users/Shared/git/NetNewsWire/NetNewsWire.xcodeproj +// create your DeveloperSettings.xcconfig file at +// /Users/Shared/git/SharedXcodeSettings/DeveloperSettings.xcconfig +// + +#include? "../../SharedXcodeSettings/ProjectSettings.xcconfig" +#include? "../../SharedXcodeSettings/DeveloperSettings.xcconfig" +#include "./common/NetNewsWire_ios_target_common.xcconfig" + +LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/../../Frameworks +CODE_SIGN_ENTITLEMENTS = iOS/ShareExtension/NetNewsWire_iOS_ShareExtension.entitlements +INFOPLIST_FILE = iOS/IntentsExtension/Info.plist +PRODUCT_BUNDLE_IDENTIFIER = $(ORGANIZATION_IDENTIFIER).NetNewsWire.iOS.IntentsExtension +PRODUCT_NAME = $(TARGET_NAME) diff --git a/xcconfig/NetNewsWire_iOSshareextension_target.xcconfig b/xcconfig/NetNewsWire_iOSshareextension_target.xcconfig index f68f620e8..8e17d8de9 100644 --- a/xcconfig/NetNewsWire_iOSshareextension_target.xcconfig +++ b/xcconfig/NetNewsWire_iOSshareextension_target.xcconfig @@ -1,6 +1,40 @@ +CODE_SIGN_IDENTITY= iPhone Developer +DEVELOPMENT_TEAM = M8L2WTLA8W +CODE_SIGN_STYLE = Automatic +ORGANIZATION_IDENTIFIER = com.ranchero +PROVISIONING_PROFILE_SPECIFIER = -#include "./NetNewsWire_iOSapp_target.xcconfig" +// developers can locally override the Xcode settings for code signing +// by creating a DeveloperSettings.xcconfig file locally at the appropriate path +// This allows a pristine project to have code signing set up with the appropriate +// developer ID and certificates, and for dev to be able to have local settings +// without needing to check in anything into source control +// +// As an example, make a ../../SharedXcodeSettings/DeveloperSettings.xcconfig file and +// give it the contents +// +// CODE_SIGN_IDENTITY[sdk=macosx*] = Mac Developer +// CODE_SIGN_IDENTITY[sdk=iphoneos*] = iPhone Developer +// CODE_SIGN_IDENTITY[sdk=iphonesimulator*] = iPhone Developer +// DEVELOPMENT_TEAM = +// BUNDLE_ROOT = +// CODE_SIGN_STYLE = Automatic +// PROVISIONING_PROFILE_SPECIFIER = +// +// And you should be able to build without code signing errors and without modifying +// the NetNewsWire Xcode project. +// +// Example: if your NetNewsWire Xcode project file is at +// /Users/Shared/git/NetNewsWire/NetNewsWire.xcodeproj +// create your DeveloperSettings.xcconfig file at +// /Users/Shared/git/SharedXcodeSettings/DeveloperSettings.xcconfig +// +#include? "../../SharedXcodeSettings/ProjectSettings.xcconfig" +#include? "../../SharedXcodeSettings/DeveloperSettings.xcconfig" +#include "./common/NetNewsWire_ios_target_common.xcconfig" + +LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/../../Frameworks CODE_SIGN_ENTITLEMENTS = iOS/ShareExtension/NetNewsWire_iOS_ShareExtension.entitlements INFOPLIST_FILE = iOS/ShareExtension/Info.plist PRODUCT_BUNDLE_IDENTIFIER = $(ORGANIZATION_IDENTIFIER).NetNewsWire.iOS.Share-Extension diff --git a/xcconfig/NetNewsWire_macapp_target.xcconfig b/xcconfig/NetNewsWire_macapp_target.xcconfig index f69cff222..b53dbe79b 100644 --- a/xcconfig/NetNewsWire_macapp_target.xcconfig +++ b/xcconfig/NetNewsWire_macapp_target.xcconfig @@ -31,13 +31,8 @@ PROVISIONING_PROFILE_SPECIFIER = NetNewsWire // #include? "../../SharedXcodeSettings/DeveloperSettings.xcconfig" -#include "./common/NetNewsWire_mac_target_common.xcconfig" +#include "./common/NetNewsWire_macapp_target_common.xcconfig" -ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO -ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon CODE_SIGN_ENTITLEMENTS = Mac/Resources/NetNewsWire.entitlements -INFOPLIST_FILE = Mac/Resources/Info.plist -LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/../Frameworks PRODUCT_BUNDLE_IDENTIFIER = $(ORGANIZATION_IDENTIFIER).NetNewsWire-Evergreen -PRODUCT_NAME = NetNewsWire -SWIFT_OBJC_BRIDGING_HEADER = Mac/NetNewsWire-Bridging-Header.h + diff --git a/xcconfig/NetNewsWire_macapp_target_macappstore.xcconfig b/xcconfig/NetNewsWire_macapp_target_macappstore.xcconfig new file mode 100644 index 000000000..3c4646cec --- /dev/null +++ b/xcconfig/NetNewsWire_macapp_target_macappstore.xcconfig @@ -0,0 +1,37 @@ +CODE_SIGN_IDENTITY[config=Release] = 3rd Party Mac Developer Application +CODE_SIGN_IDENTITY[config=Debug] = - +DEVELOPMENT_TEAM[config=Release] = M8L2WTLA8W +CODE_SIGN_STYLE = Manual +PROVISIONING_PROFILE_SPECIFIER = + +// developers can locally override the Xcode settings for code signing +// by creating a DeveloperSettings.xcconfig file locally at the appropriate path +// This allows a pristine project to have code signing set up with the appropriate +// developer ID and certificates, and for dev to be able to have local settings +// without needing to check in anything into source control +// +// As an example, make a ../../SharedXcodeSettings/DeveloperSettings.xcconfig file and +// give it the contents +// +// CODE_SIGN_IDENTITY[sdk=macosx*] = Mac Developer +// CODE_SIGN_IDENTITY[sdk=iphoneos*] = iPhone Developer +// CODE_SIGN_IDENTITY[sdk=iphonesimulator*] = iPhone Developer +// DEVELOPMENT_TEAM = +// CODE_SIGN_STYLE = Automatic +// PROVISIONING_PROFILE_SPECIFIER = +// +// And you should be able to build without code signing errors and without modifying +// the NetNewsWire Xcode project. +// +// Example: if your NetNewsWire Xcode project file is at +// /Users/Shared/git/NetNewsWire/NetNewsWire.xcodeproj +// create your DeveloperSettings.xcconfig file at +// /Users/Shared/git/SharedXcodeSettings/DeveloperSettings.xcconfig +// + +#include? "../../SharedXcodeSettings/DeveloperSettings.xcconfig" +#include "./common/NetNewsWire_macapp_target_common.xcconfig" + +CODE_SIGN_ENTITLEMENTS = Mac/Resources/NetNewsWire.entitlements +PRODUCT_BUNDLE_IDENTIFIER = $(ORGANIZATION_IDENTIFIER).NetNewsWire-Evergreen.MAS +OTHER_SWIFT_FLAGS = -DMAC_APP_STORE $(inherited) diff --git a/xcconfig/NetNewsWire_project_test.xcconfig b/xcconfig/NetNewsWire_project_test.xcconfig index ad10a9ae1..fa08e7ae8 100644 --- a/xcconfig/NetNewsWire_project_test.xcconfig +++ b/xcconfig/NetNewsWire_project_test.xcconfig @@ -1,3 +1,4 @@ #include "./NetNewsWire_project_debug.xcconfig" OTHER_SWIFT_FLAGS = -DTEST $(inherited) +FRAMEWORK_SEARCH_PATHS = $(inherited) $(SYMROOT)/Release$(EFFECTIVE_PLATFORM_NAME) diff --git a/xcconfig/NetNewsWire_safariextension_target.xcconfig b/xcconfig/NetNewsWire_safariextension_target.xcconfig index b3b4bd03d..3dd3ed951 100644 --- a/xcconfig/NetNewsWire_safariextension_target.xcconfig +++ b/xcconfig/NetNewsWire_safariextension_target.xcconfig @@ -1,3 +1,4 @@ + CODE_SIGN_IDENTITY = Developer ID Application DEVELOPMENT_TEAM = M8L2WTLA8W CODE_SIGN_STYLE = Manual @@ -39,6 +40,4 @@ LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/../Frameworks @executabl PRODUCT_BUNDLE_IDENTIFIER = $(ORGANIZATION_IDENTIFIER).NetNewsWire-Evergreen.Subscribe-to-Feed PRODUCT_NAME = $(TARGET_NAME) -SDKROOT = macosx - - +SDKROOT = macosx \ No newline at end of file diff --git a/xcconfig/NetNewsWire_safariextension_target_macappstore.xcconfig b/xcconfig/NetNewsWire_safariextension_target_macappstore.xcconfig new file mode 100644 index 000000000..c9f4822a1 --- /dev/null +++ b/xcconfig/NetNewsWire_safariextension_target_macappstore.xcconfig @@ -0,0 +1,44 @@ +CODE_SIGN_IDENTITY[config=Release] = 3rd Party Mac Developer Application +CODE_SIGN_IDENTITY[config=Debug] = - +DEVELOPMENT_TEAM = M8L2WTLA8W +CODE_SIGN_STYLE = Manual +ORGANIZATION_IDENTIFIER = com.ranchero +PROVISIONING_PROFILE_SPECIFIER = + +// developers can locally override the Xcode settings for code signing +// by creating a DeveloperSettings.xcconfig file locally at the appropriate path +// This allows a pristine project to have code signing set up with the appropriate +// developer ID and certificates, and for dev to be able to have local settings +// without needing to check in anything into source control +// +// As an example, make a ../../SharedXcodeSettings/DeveloperSettings.xcconfig file and +// give it the contents +// +// CODE_SIGN_IDENTITY[sdk=macosx*] = Mac Developer +// CODE_SIGN_IDENTITY[sdk=iphoneos*] = iPhone Developer +// CODE_SIGN_IDENTITY[sdk=iphonesimulator*] = iPhone Developer +// DEVELOPMENT_TEAM = +// ORGANIZATION_IDENTIFIER = +// CODE_SIGN_STYLE = Automatic +// PROVISIONING_PROFILE_SPECIFIER = +// +// And you should be able to build without code signing errors and without modifying +// the NetNewsWire Xcode project. +// +// Example: if your NetNewsWire Xcode project file is at +// /Users/Shared/git/NetNewsWire/NetNewsWire.xcodeproj +// create your DeveloperSettings.xcconfig file at +// /Users/Shared/git/SharedXcodeSettings/DeveloperSettings.xcconfig +// + +#include? "../../SharedXcodeSettings/DeveloperSettings.xcconfig" +#include "./common/NetNewsWire_mac_target_common.xcconfig" + +CODE_SIGN_ENTITLEMENTS = Mac/SafariExtension/Subscribe_to_Feed.entitlements +INFOPLIST_FILE = Mac/SafariExtension/Info.plist +LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/../Frameworks @executable_path/../../../../Frameworks +PRODUCT_BUNDLE_IDENTIFIER = $(ORGANIZATION_IDENTIFIER).NetNewsWire-Evergreen.MAS.Subscribe-to-Feed +PRODUCT_NAME = $(TARGET_NAME) +OTHER_SWIFT_FLAGS = -DMAC_APP_STORE $(inherited) + +SDKROOT = macosx diff --git a/xcconfig/common/NetNewsWire_ios_target_common.xcconfig b/xcconfig/common/NetNewsWire_ios_target_common.xcconfig new file mode 100644 index 000000000..465a72ef3 --- /dev/null +++ b/xcconfig/common/NetNewsWire_ios_target_common.xcconfig @@ -0,0 +1,12 @@ + +// High Level Settings common to both the iOS application and any extensions we bundle with it +MARKETING_VERSION = 5.0 +CURRENT_PROJECT_VERSION = 2 + +ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES +ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon +CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; +COMBINE_HIDPI_IMAGES = YES +GCC_C_LANGUAGE_STANDARD = gnu11; +SDKROOT = iphoneos; +TARGETED_DEVICE_FAMILY = 1,2 diff --git a/xcconfig/common/NetNewsWire_mac_target_common.xcconfig b/xcconfig/common/NetNewsWire_mac_target_common.xcconfig index b2da183e4..081ef96e7 100644 --- a/xcconfig/common/NetNewsWire_mac_target_common.xcconfig +++ b/xcconfig/common/NetNewsWire_mac_target_common.xcconfig @@ -1,10 +1,8 @@ - // High Level Settings common to both the Mac application and any extensions we bundle with it -MARKETING_VERSION = 5.0.1d1 -CURRENT_PROJECT_VERSION = 2611 +MARKETING_VERSION = 5.1d1 +CURRENT_PROJECT_VERSION = 2612 ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon COMBINE_HIDPI_IMAGES = YES -FRAMEWORK_SEARCH_PATHS = $(inherited) $(PROJECT_DIR)/Frameworks/Vendor MACOSX_DEPLOYMENT_TARGET = 10.14.4 diff --git a/xcconfig/common/NetNewsWire_macapp_target_common.xcconfig b/xcconfig/common/NetNewsWire_macapp_target_common.xcconfig new file mode 100644 index 000000000..ef3ca3ee6 --- /dev/null +++ b/xcconfig/common/NetNewsWire_macapp_target_common.xcconfig @@ -0,0 +1,9 @@ +#include "./NetNewsWire_mac_target_common.xcconfig" + +// Settings common to both the Mac Direct and Mac App Store targets +ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO +ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon +INFOPLIST_FILE = Mac/Resources/Info.plist +PRODUCT_NAME = NetNewsWire +SWIFT_OBJC_BRIDGING_HEADER = Mac/NetNewsWire-Bridging-Header.h +LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/../Frameworks