Id -> ID renaming.
This commit is contained in:
parent
c62e3293a6
commit
53215c1f80
|
@ -1038,13 +1038,13 @@ private extension FeedbinAccountDelegate {
|
|||
|
||||
os_log(.debug, log: log, "Syncing feeds with %ld subscriptions.", subscriptions.count)
|
||||
|
||||
let subFeedIds = subscriptions.map { String($0.feedID) }
|
||||
let subFeedIDs = subscriptions.map { String($0.feedID) }
|
||||
|
||||
// Remove any feeds that are no longer in the subscriptions
|
||||
if let folders = account.folders {
|
||||
for folder in folders {
|
||||
for feed in folder.topLevelFeeds {
|
||||
if !subFeedIds.contains(feed.feedID) {
|
||||
if !subFeedIDs.contains(feed.feedID) {
|
||||
folder.removeFeed(feed)
|
||||
}
|
||||
}
|
||||
|
@ -1052,7 +1052,7 @@ private extension FeedbinAccountDelegate {
|
|||
}
|
||||
|
||||
for feed in account.topLevelFeeds {
|
||||
if !subFeedIds.contains(feed.feedID) {
|
||||
if !subFeedIDs.contains(feed.feedID) {
|
||||
account.removeFeed(feed)
|
||||
}
|
||||
}
|
||||
|
@ -1061,9 +1061,9 @@ private extension FeedbinAccountDelegate {
|
|||
var subscriptionsToAdd = Set<FeedbinSubscription>()
|
||||
subscriptions.forEach { subscription in
|
||||
|
||||
let subFeedId = String(subscription.feedID)
|
||||
let subFeedID = String(subscription.feedID)
|
||||
|
||||
if let feed = account.existingFeed(withFeedID: subFeedId) {
|
||||
if let feed = account.existingFeed(withFeedID: subFeedID) {
|
||||
feed.name = subscription.name
|
||||
// If the name has been changed on the server remove the locally edited name
|
||||
feed.editedName = nil
|
||||
|
@ -1122,11 +1122,11 @@ private extension FeedbinAccountDelegate {
|
|||
}
|
||||
|
||||
// Add any feeds not in the folder
|
||||
let folderFeedIds = folder.topLevelFeeds.map { $0.feedID }
|
||||
let folderFeedIDs = folder.topLevelFeeds.map { $0.feedID }
|
||||
|
||||
for tagging in groupedTaggings {
|
||||
let taggingFeedID = String(tagging.feedID)
|
||||
if !folderFeedIds.contains(taggingFeedID) {
|
||||
if !folderFeedIDs.contains(taggingFeedID) {
|
||||
guard let feed = account.existingFeed(withFeedID: taggingFeedID) else {
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -84,13 +84,13 @@ extension NewsBlurAccountDelegate {
|
|||
|
||||
os_log(.debug, log: log, "Syncing feeds with %ld feeds.", feeds.count)
|
||||
|
||||
let newsBlurFeedIds = feeds.map { String($0.feedID) }
|
||||
let newsBlurFeedIDs = feeds.map { String($0.feedID) }
|
||||
|
||||
// Remove any feeds that are no longer in the subscriptions
|
||||
if let folders = account.folders {
|
||||
for folder in folders {
|
||||
for feed in folder.topLevelFeeds {
|
||||
if !newsBlurFeedIds.contains(feed.feedID) {
|
||||
if !newsBlurFeedIDs.contains(feed.feedID) {
|
||||
folder.removeFeed(feed)
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ extension NewsBlurAccountDelegate {
|
|||
}
|
||||
|
||||
for feed in account.topLevelFeeds {
|
||||
if !newsBlurFeedIds.contains(feed.feedID) {
|
||||
if !newsBlurFeedIDs.contains(feed.feedID) {
|
||||
account.removeFeed(feed)
|
||||
}
|
||||
}
|
||||
|
@ -106,9 +106,9 @@ extension NewsBlurAccountDelegate {
|
|||
// Add any feeds we don't have and update any we do
|
||||
var feedsToAdd = Set<NewsBlurFeed>()
|
||||
feeds.forEach { feed in
|
||||
let subFeedId = String(feed.feedID)
|
||||
let subFeedID = String(feed.feedID)
|
||||
|
||||
if let feed = account.existingFeed(withFeedID: subFeedId) {
|
||||
if let feed = account.existingFeed(withFeedID: subFeedID) {
|
||||
feed.name = feed.name
|
||||
// If the name has been changed on the server remove the locally edited name
|
||||
feed.editedName = nil
|
||||
|
@ -169,11 +169,11 @@ extension NewsBlurAccountDelegate {
|
|||
}
|
||||
|
||||
// Add any feeds not in the folder
|
||||
let folderFeedIds = folder.topLevelFeeds.map { $0.feedID }
|
||||
let folderFeedIDs = folder.topLevelFeeds.map { $0.feedID }
|
||||
|
||||
for relationship in folderRelationships {
|
||||
let folderFeedID = String(relationship.feedID)
|
||||
if !folderFeedIds.contains(folderFeedID) {
|
||||
if !folderFeedIDs.contains(folderFeedID) {
|
||||
guard let feed = account.existingFeed(withFeedID: folderFeedID) else {
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -816,7 +816,7 @@ final class NewsBlurAccountDelegate: AccountDelegate {
|
|||
}
|
||||
|
||||
func accountDidInitialize(_ account: Account) {
|
||||
credentials = try? account.retrieveCredentials(type: .newsBlurSessionId)
|
||||
credentials = try? account.retrieveCredentials(type: .newsBlurSessionID)
|
||||
}
|
||||
|
||||
func accountWillBeDeleted(_ account: Account) {
|
||||
|
|
|
@ -570,13 +570,13 @@ private extension ReaderAPIAccountDelegate {
|
|||
|
||||
os_log(.debug, log: log, "Syncing feeds with %ld subscriptions.", subscriptions.count)
|
||||
|
||||
let subFeedIds = subscriptions.map { $0.feedID }
|
||||
let subFeedIDs = subscriptions.map { $0.feedID }
|
||||
|
||||
// Remove any feeds that are no longer in the subscriptions
|
||||
if let folders = account.folders {
|
||||
for folder in folders {
|
||||
for feed in folder.topLevelFeeds {
|
||||
if !subFeedIds.contains(feed.feedID) {
|
||||
if !subFeedIDs.contains(feed.feedID) {
|
||||
folder.removeFeed(feed)
|
||||
}
|
||||
}
|
||||
|
@ -584,7 +584,7 @@ private extension ReaderAPIAccountDelegate {
|
|||
}
|
||||
|
||||
for feed in account.topLevelFeeds {
|
||||
if !subFeedIds.contains(feed.feedID) {
|
||||
if !subFeedIDs.contains(feed.feedID) {
|
||||
account.clearFeedMetadata(feed)
|
||||
account.removeFeed(feed)
|
||||
}
|
||||
|
@ -644,11 +644,11 @@ private extension ReaderAPIAccountDelegate {
|
|||
}
|
||||
|
||||
// Add any feeds not in the folder
|
||||
let folderFeedIds = folder.topLevelFeeds.map { $0.feedID }
|
||||
let folderFeedIDs = folder.topLevelFeeds.map { $0.feedID }
|
||||
|
||||
for subscription in groupedTaggings {
|
||||
let taggingFeedID = subscription.feedID
|
||||
if !folderFeedIds.contains(taggingFeedID) {
|
||||
if !folderFeedIDs.contains(taggingFeedID) {
|
||||
guard let feed = account.existingFeed(withFeedID: taggingFeedID) else {
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -247,8 +247,8 @@ enum CloudKitAccountZoneError: LocalizedError {
|
|||
query(ckQuery) { result in
|
||||
switch result {
|
||||
case .success(let records):
|
||||
let feedExternalIds = records.map { $0.externalID }
|
||||
completion(.success(feedExternalIds))
|
||||
let feedExternalIDs = records.map { $0.externalID }
|
||||
completion(.success(feedExternalIDs))
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
}
|
||||
|
|
|
@ -147,9 +147,9 @@ private extension CloudKitAcountZoneDelegate {
|
|||
feed.homePageURL = homePageURL
|
||||
|
||||
let existingContainers = account.existingContainers(withFeed: feed)
|
||||
let existingContainerExternalIds = existingContainers.compactMap { $0.externalID }
|
||||
let existingContainerExternalIDs = existingContainers.compactMap { $0.externalID }
|
||||
|
||||
let diff = containerExternalIDs.difference(from: existingContainerExternalIds)
|
||||
let diff = containerExternalIDs.difference(from: existingContainerExternalIDs)
|
||||
|
||||
for change in diff {
|
||||
switch change {
|
||||
|
|
|
@ -294,13 +294,13 @@ final class FeedlyAPICaller {
|
|||
completion(.failure(CredentialsError.incompleteCredentials))
|
||||
}
|
||||
}
|
||||
guard let encodedId = encodeForURLPath(id) else {
|
||||
guard let encodedID = encodeForURLPath(id) else {
|
||||
return DispatchQueue.main.async {
|
||||
completion(.failure(FeedlyAccountDelegateError.unexpectedResourceId(id)))
|
||||
completion(.failure(FeedlyAccountDelegateError.unexpectedResourceID(id)))
|
||||
}
|
||||
}
|
||||
var components = baseUrlComponents
|
||||
components.percentEncodedPath = "/v3/collections/\(encodedId)"
|
||||
components.percentEncodedPath = "/v3/collections/\(encodedID)"
|
||||
|
||||
guard let url = components.url else {
|
||||
fatalError("\(components) does not produce a valid URL.")
|
||||
|
@ -326,7 +326,7 @@ final class FeedlyAPICaller {
|
|||
}
|
||||
}
|
||||
|
||||
func removeFeed(_ feedId: String, fromCollectionWith collectionId: String, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
func removeFeed(_ feedId: String, fromCollectionWith collectionID: String, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
guard !isSuspended else {
|
||||
return DispatchQueue.main.async {
|
||||
completion(.failure(TransportError.suspended))
|
||||
|
@ -339,14 +339,14 @@ final class FeedlyAPICaller {
|
|||
}
|
||||
}
|
||||
|
||||
guard let encodedCollectionId = encodeForURLPath(collectionId) else {
|
||||
guard let encodedCollectionID = encodeForURLPath(collectionID) else {
|
||||
return DispatchQueue.main.async {
|
||||
completion(.failure(FeedlyAccountDelegateError.unexpectedResourceId(collectionId)))
|
||||
completion(.failure(FeedlyAccountDelegateError.unexpectedResourceID(collectionID)))
|
||||
}
|
||||
}
|
||||
|
||||
var components = baseUrlComponents
|
||||
components.percentEncodedPath = "/v3/collections/\(encodedCollectionId)/feeds/.mdelete"
|
||||
components.percentEncodedPath = "/v3/collections/\(encodedCollectionID)/feeds/.mdelete"
|
||||
|
||||
guard let url = components.url else {
|
||||
fatalError("\(components) does not produce a valid URL.")
|
||||
|
@ -390,7 +390,7 @@ final class FeedlyAPICaller {
|
|||
|
||||
extension FeedlyAPICaller: FeedlyAddFeedToCollectionService {
|
||||
|
||||
func addFeed(with feedId: FeedlyFeedResourceId, title: String? = nil, toCollectionWith collectionId: String, completion: @escaping (Result<[FeedlyFeed], Error>) -> ()) {
|
||||
func addFeed(with feedId: FeedlyFeedResourceID, title: String? = nil, toCollectionWith collectionID: String, completion: @escaping (Result<[FeedlyFeed], Error>) -> ()) {
|
||||
guard !isSuspended else {
|
||||
return DispatchQueue.main.async {
|
||||
completion(.failure(TransportError.suspended))
|
||||
|
@ -403,13 +403,13 @@ extension FeedlyAPICaller: FeedlyAddFeedToCollectionService {
|
|||
}
|
||||
}
|
||||
|
||||
guard let encodedId = encodeForURLPath(collectionId) else {
|
||||
guard let encodedID = encodeForURLPath(collectionID) else {
|
||||
return DispatchQueue.main.async {
|
||||
completion(.failure(FeedlyAccountDelegateError.unexpectedResourceId(collectionId)))
|
||||
completion(.failure(FeedlyAccountDelegateError.unexpectedResourceID(collectionID)))
|
||||
}
|
||||
}
|
||||
var components = baseUrlComponents
|
||||
components.percentEncodedPath = "/v3/collections/\(encodedId)/feeds"
|
||||
components.percentEncodedPath = "/v3/collections/\(encodedID)/feeds"
|
||||
|
||||
guard let url = components.url else {
|
||||
fatalError("\(components) does not produce a valid URL.")
|
||||
|
@ -606,7 +606,7 @@ extension FeedlyAPICaller: FeedlyGetCollectionsService {
|
|||
|
||||
extension FeedlyAPICaller: FeedlyGetStreamContentsService {
|
||||
|
||||
@MainActor func getStreamContents(for resource: FeedlyResourceId, continuation: String? = nil, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStream, Error>) -> ()) {
|
||||
@MainActor func getStreamContents(for resource: FeedlyResourceID, continuation: String? = nil, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStream, Error>) -> ()) {
|
||||
guard !isSuspended else {
|
||||
return DispatchQueue.main.async {
|
||||
completion(.failure(TransportError.suspended))
|
||||
|
@ -672,9 +672,9 @@ extension FeedlyAPICaller: FeedlyGetStreamContentsService {
|
|||
}
|
||||
}
|
||||
|
||||
extension FeedlyAPICaller: FeedlyGetStreamIdsService {
|
||||
extension FeedlyAPICaller: FeedlyGetStreamIDsService {
|
||||
|
||||
@MainActor func getStreamIds(for resource: FeedlyResourceId, continuation: String? = nil, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStreamIds, Error>) -> ()) {
|
||||
@MainActor func getStreamIDs(for resource: FeedlyResourceID, continuation: String? = nil, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStreamIDs, Error>) -> ()) {
|
||||
guard !isSuspended else {
|
||||
return DispatchQueue.main.async {
|
||||
completion(.failure(TransportError.suspended))
|
||||
|
@ -725,7 +725,7 @@ extension FeedlyAPICaller: FeedlyGetStreamIdsService {
|
|||
request.addValue("application/json", forHTTPHeaderField: "Accept-Type")
|
||||
request.addValue("OAuth \(accessToken)", forHTTPHeaderField: HTTPRequestHeader.authorization)
|
||||
|
||||
send(request: request, resultType: FeedlyStreamIds.self, dateDecoding: .millisecondsSince1970, keyDecoding: .convertFromSnakeCase) { result in
|
||||
send(request: request, resultType: FeedlyStreamIDs.self, dateDecoding: .millisecondsSince1970, keyDecoding: .convertFromSnakeCase) { result in
|
||||
switch result {
|
||||
case .success(let (_, collections)):
|
||||
if let response = collections {
|
||||
|
@ -800,10 +800,10 @@ extension FeedlyAPICaller: FeedlyMarkArticlesService {
|
|||
private struct MarkerEntriesBody: Encodable {
|
||||
let type = "entries"
|
||||
var action: String
|
||||
var entryIds: [String]
|
||||
var entryIDs: [String]
|
||||
}
|
||||
|
||||
func mark(_ articleIds: Set<String>, as action: FeedlyMarkAction, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
func mark(_ articleIDs: Set<String>, as action: FeedlyMarkAction, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
guard !isSuspended else {
|
||||
return DispatchQueue.main.async {
|
||||
completion(.failure(TransportError.suspended))
|
||||
|
@ -822,11 +822,11 @@ extension FeedlyAPICaller: FeedlyMarkArticlesService {
|
|||
fatalError("\(components) does not produce a valid URL.")
|
||||
}
|
||||
|
||||
let articleIdChunks = Array(articleIds).chunked(into: 300)
|
||||
let articleIDChunks = Array(articleIDs).chunked(into: 300)
|
||||
let dispatchGroup = DispatchGroup()
|
||||
var groupError: Error? = nil
|
||||
|
||||
for articleIdChunk in articleIdChunks {
|
||||
for articleIDChunk in articleIDChunks {
|
||||
|
||||
var request = URLRequest(url: url)
|
||||
request.httpMethod = "POST"
|
||||
|
@ -835,7 +835,7 @@ extension FeedlyAPICaller: FeedlyMarkArticlesService {
|
|||
request.addValue("OAuth \(accessToken)", forHTTPHeaderField: HTTPRequestHeader.authorization)
|
||||
|
||||
do {
|
||||
let body = MarkerEntriesBody(action: action.actionValue, entryIds: Array(articleIdChunk))
|
||||
let body = MarkerEntriesBody(action: action.actionValue, entryIDs: Array(articleIDChunk))
|
||||
let encoder = JSONEncoder()
|
||||
let data = try encoder.encode(body)
|
||||
request.httpBody = data
|
||||
|
|
|
@ -30,7 +30,7 @@ extension FeedlyAccountDelegate: OAuthAuthorizationGranting {
|
|||
|
||||
static func oauthAuthorizationCodeGrantRequest(secretsProvider: SecretsProvider) -> URLRequest {
|
||||
let client = environment.oauthAuthorizationClient(secretsProvider: secretsProvider)
|
||||
let authorizationRequest = OAuthAuthorizationRequest(clientId: client.id,
|
||||
let authorizationRequest = OAuthAuthorizationRequest(clientID: client.id,
|
||||
redirectUri: client.redirectUri,
|
||||
scope: oauthAuthorizationGrantScope,
|
||||
state: client.state)
|
||||
|
|
|
@ -139,7 +139,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
|||
|
||||
let log = self.log
|
||||
|
||||
let syncAllOperation = FeedlySyncAllOperation(account: account, feedlyUserId: credentials.username, caller: caller, database: database, lastSuccessfulFetchStartDate: accountMetadata?.lastArticleFetchStartTime, downloadProgress: refreshProgress, log: log)
|
||||
let syncAllOperation = FeedlySyncAllOperation(account: account, feedlyUserID: credentials.username, caller: caller, database: database, lastSuccessfulFetchStartDate: accountMetadata?.lastArticleFetchStartTime, downloadProgress: refreshProgress, log: log)
|
||||
|
||||
syncAllOperation.downloadProgress = refreshProgress
|
||||
|
||||
|
@ -234,7 +234,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
|||
|
||||
let group = DispatchGroup()
|
||||
|
||||
let ingestUnread = FeedlyIngestUnreadArticleIdsOperation(account: account, userId: credentials.username, service: caller, database: database, newerThan: nil, log: log)
|
||||
let ingestUnread = FeedlyIngestUnreadArticleIDsOperation(account: account, userID: credentials.username, service: caller, database: database, newerThan: nil, log: log)
|
||||
|
||||
group.enter()
|
||||
ingestUnread.completionBlock = { _ in
|
||||
|
@ -242,7 +242,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
|||
|
||||
}
|
||||
|
||||
let ingestStarred = FeedlyIngestStarredArticleIdsOperation(account: account, userId: credentials.username, service: caller, database: database, newerThan: nil, log: log)
|
||||
let ingestStarred = FeedlyIngestStarredArticleIDsOperation(account: account, userID: credentials.username, service: caller, database: database, newerThan: nil, log: log)
|
||||
|
||||
group.enter()
|
||||
ingestStarred.completionBlock = { _ in
|
||||
|
@ -447,7 +447,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
|||
feedName: name,
|
||||
searchService: caller,
|
||||
addToCollectionService: caller,
|
||||
syncUnreadIdsService: caller,
|
||||
syncUnreadIDsService: caller,
|
||||
getStreamContentsService: caller,
|
||||
database: database,
|
||||
container: container,
|
||||
|
@ -483,18 +483,18 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
|||
}
|
||||
|
||||
func renameFeed(for account: Account, with feed: Feed, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
let folderCollectionIds = account.folders?.filter { $0.has(feed) }.compactMap { $0.externalID }
|
||||
guard let collectionIds = folderCollectionIds, let collectionId = collectionIds.first else {
|
||||
let folderCollectionIDs = account.folders?.filter { $0.has(feed) }.compactMap { $0.externalID }
|
||||
guard let collectionIDs = folderCollectionIDs, let collectionID = collectionIDs.first else {
|
||||
completion(.failure(FeedlyAccountDelegateError.unableToRenameFeed(feed.nameForDisplay, name)))
|
||||
return
|
||||
}
|
||||
|
||||
let feedId = FeedlyFeedResourceId(id: feed.feedID)
|
||||
let feedID = FeedlyFeedResourceID(id: feed.feedID)
|
||||
let editedNameBefore = feed.editedName
|
||||
|
||||
// Adding an existing feed updates it.
|
||||
// Updating feed name in one folder/collection updates it for all folders/collections.
|
||||
caller.addFeed(with: feedId, title: name, toCollectionWith: collectionId) { result in
|
||||
caller.addFeed(with: feedID, title: name, toCollectionWith: collectionID) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
completion(.success(()))
|
||||
|
@ -531,7 +531,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
|||
throw FeedlyAccountDelegateError.notLoggedIn
|
||||
}
|
||||
|
||||
let resource = FeedlyFeedResourceId(id: feed.feedID)
|
||||
let resource = FeedlyFeedResourceID(id: feed.feedID)
|
||||
let addExistingFeed = try FeedlyAddExistingFeedOperation(account: account,
|
||||
credentials: credentials,
|
||||
resource: resource,
|
||||
|
@ -571,13 +571,13 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
|||
}
|
||||
|
||||
private func removeFeed(for account: Account, with feed: Feed, from container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
guard let folder = container as? Folder, let collectionId = folder.externalID else {
|
||||
guard let folder = container as? Folder, let collectionID = folder.externalID else {
|
||||
return DispatchQueue.main.async {
|
||||
completion(.failure(FeedlyAccountDelegateError.unableToRemoveFeed(feed.nameForDisplay)))
|
||||
}
|
||||
}
|
||||
|
||||
caller.removeFeed(feed.feedID, fromCollectionWith: collectionId) { result in
|
||||
caller.removeFeed(feed.feedID, fromCollectionWith: collectionID) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
completion(.success(()))
|
||||
|
|
|
@ -10,7 +10,7 @@ import Foundation
|
|||
|
||||
enum FeedlyAccountDelegateError: LocalizedError {
|
||||
case notLoggedIn
|
||||
case unexpectedResourceId(String)
|
||||
case unexpectedResourceID(String)
|
||||
case unableToAddFolder(String)
|
||||
case unableToRenameFolder(String, String)
|
||||
case unableToRemoveFolder(String)
|
||||
|
@ -25,9 +25,9 @@ enum FeedlyAccountDelegateError: LocalizedError {
|
|||
case .notLoggedIn:
|
||||
return NSLocalizedString("Please add the Feedly account again. If this problem persists, open Keychain Access and delete all feedly.com entries, then try again.", comment: "Feedly – Credentials not found.")
|
||||
|
||||
case .unexpectedResourceId(let resourceId):
|
||||
case .unexpectedResourceID(let resourceID):
|
||||
let template = NSLocalizedString("Could not encode the identifier “%@”.", comment: "Feedly – Could not encode resource id to send to Feedly.")
|
||||
return String(format: template, resourceId)
|
||||
return String(format: template, resourceID)
|
||||
|
||||
case .unableToAddFolder(let name):
|
||||
let template = NSLocalizedString("Could not create a folder named “%@”.", comment: "Feedly – Could not create a folder/collection.")
|
||||
|
@ -67,7 +67,7 @@ enum FeedlyAccountDelegateError: LocalizedError {
|
|||
case .notLoggedIn:
|
||||
return nil
|
||||
|
||||
case .unexpectedResourceId:
|
||||
case .unexpectedResourceID:
|
||||
let template = NSLocalizedString("Please contact NetNewsWire support.", comment: "Feedly – Recovery suggestion for not being able to encode a resource id to send to Feedly..")
|
||||
return String(format: template)
|
||||
|
||||
|
|
|
@ -16,10 +16,10 @@ import Foundation
|
|||
throw FeedlyAccountDelegateError.addFeedChooseFolder
|
||||
}
|
||||
|
||||
guard let collectionId = folder.externalID else {
|
||||
guard let collectionID = folder.externalID else {
|
||||
throw FeedlyAccountDelegateError.addFeedInvalidFolder(folder.nameForDisplay)
|
||||
}
|
||||
|
||||
return (folder, collectionId)
|
||||
return (folder, collectionID)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,12 +9,12 @@
|
|||
import Foundation
|
||||
|
||||
protocol FeedlyResourceProviding {
|
||||
@MainActor var resource: FeedlyResourceId { get }
|
||||
@MainActor var resource: FeedlyResourceID { get }
|
||||
}
|
||||
|
||||
extension FeedlyFeedResourceId: FeedlyResourceProviding {
|
||||
extension FeedlyFeedResourceID: FeedlyResourceProviding {
|
||||
|
||||
var resource: FeedlyResourceId {
|
||||
var resource: FeedlyResourceID {
|
||||
return self
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ final class FeedlyEntryIdentifierProvider: FeedlyEntryIdentifierProviding {
|
|||
entryIDs.formUnion(provider.entryIDs)
|
||||
}
|
||||
|
||||
@MainActor func addEntryIDs(in articleIds: [String]) {
|
||||
entryIDs.formUnion(articleIds)
|
||||
@MainActor func addEntryIDs(in articleIDs: [String]) {
|
||||
entryIDs.formUnion(articleIDs)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ struct FeedlyEntryParser {
|
|||
|
||||
/// When ingesting articles, the feedURL must match a feed's `feedID` for the article to be reachable between it and its matching feed. It reminds me of a foreign key.
|
||||
var feedUrl: String? {
|
||||
guard let id = entry.origin?.streamId else {
|
||||
guard let id = entry.origin?.streamID else {
|
||||
// At this point, check Feedly's API isn't glitching or the response has not changed structure.
|
||||
assertionFailure("Entries need to be traceable to a feed or this entry will be dropped.")
|
||||
return nil
|
||||
|
|
|
@ -22,7 +22,7 @@ struct FeedlyFeedParser {
|
|||
}
|
||||
|
||||
var url: String {
|
||||
let resource = FeedlyFeedResourceId(id: feed.id)
|
||||
let resource = FeedlyFeedResourceID(id: feed.id)
|
||||
return resource.url
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,6 @@ import Foundation
|
|||
|
||||
struct FeedlyOrigin: Decodable {
|
||||
let title: String?
|
||||
let streamId: String?
|
||||
let streamID: String?
|
||||
let htmlUrl: String?
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// FeedlyResourceId.swift
|
||||
// FeedlyResourceID.swift
|
||||
// Account
|
||||
//
|
||||
// Created by Kiel Gillard on 3/10/19.
|
||||
|
@ -8,20 +8,20 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
/// The kinds of Resource Ids is documented here: https://developer.feedly.com/cloud/
|
||||
protocol FeedlyResourceId {
|
||||
/// The kinds of Resource IDs is documented here: https://developer.feedly.com/cloud/
|
||||
protocol FeedlyResourceID {
|
||||
|
||||
/// The resource Id from Feedly.
|
||||
/// The resource ID from Feedly.
|
||||
@MainActor var id: String { get }
|
||||
}
|
||||
|
||||
/// The Feed Resource is documented here: https://developer.feedly.com/cloud/
|
||||
struct FeedlyFeedResourceId: FeedlyResourceId {
|
||||
struct FeedlyFeedResourceID: FeedlyResourceID {
|
||||
let id: String
|
||||
|
||||
/// The location of the kind of resource a concrete type represents.
|
||||
/// If the concrete type cannot strip the resource type from the Id, it should just return the Id
|
||||
/// since the Id is a legitimate URL.
|
||||
/// If the concrete type cannot strip the resource type from the ID, it should just return the ID
|
||||
/// since the ID is a legitimate URL.
|
||||
/// This is basically assuming Feedly prefixes source feed URLs with `feed/`.
|
||||
/// It is not documented as such and could potentially change.
|
||||
/// Feedly does not include the source feed URL as a separate field.
|
||||
|
@ -38,48 +38,48 @@ struct FeedlyFeedResourceId: FeedlyResourceId {
|
|||
}
|
||||
}
|
||||
|
||||
extension FeedlyFeedResourceId {
|
||||
extension FeedlyFeedResourceID {
|
||||
init(url: String) {
|
||||
self.id = "feed/\(url)"
|
||||
}
|
||||
}
|
||||
|
||||
struct FeedlyCategoryResourceId: FeedlyResourceId {
|
||||
struct FeedlyCategoryResourceID: FeedlyResourceID {
|
||||
let id: String
|
||||
|
||||
enum Global {
|
||||
|
||||
static func uncategorized(for userId: String) -> FeedlyCategoryResourceId {
|
||||
static func uncategorized(for userID: String) -> FeedlyCategoryResourceID {
|
||||
// https://developer.feedly.com/cloud/#global-resource-ids
|
||||
let id = "user/\(userId)/category/global.uncategorized"
|
||||
return FeedlyCategoryResourceId(id: id)
|
||||
let id = "user/\(userID)/category/global.uncategorized"
|
||||
return FeedlyCategoryResourceID(id: id)
|
||||
}
|
||||
|
||||
/// All articles from all the feeds the user subscribes to.
|
||||
static func all(for userId: String) -> FeedlyCategoryResourceId {
|
||||
static func all(for userID: String) -> FeedlyCategoryResourceID {
|
||||
// https://developer.feedly.com/cloud/#global-resource-ids
|
||||
let id = "user/\(userId)/category/global.all"
|
||||
return FeedlyCategoryResourceId(id: id)
|
||||
let id = "user/\(userID)/category/global.all"
|
||||
return FeedlyCategoryResourceID(id: id)
|
||||
}
|
||||
|
||||
/// All articles from all the feeds the user loves most.
|
||||
static func mustRead(for userId: String) -> FeedlyCategoryResourceId {
|
||||
static func mustRead(for userID: String) -> FeedlyCategoryResourceID {
|
||||
// https://developer.feedly.com/cloud/#global-resource-ids
|
||||
let id = "user/\(userId)/category/global.must"
|
||||
return FeedlyCategoryResourceId(id: id)
|
||||
let id = "user/\(userID)/category/global.must"
|
||||
return FeedlyCategoryResourceID(id: id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct FeedlyTagResourceId: FeedlyResourceId {
|
||||
struct FeedlyTagResourceID: FeedlyResourceID {
|
||||
let id: String
|
||||
|
||||
enum Global {
|
||||
|
||||
static func saved(for userId: String) -> FeedlyTagResourceId {
|
||||
static func saved(for userID: String) -> FeedlyTagResourceID {
|
||||
// https://developer.feedly.com/cloud/#global-resource-ids
|
||||
let id = "user/\(userId)/tag/global.saved"
|
||||
return FeedlyTagResourceId(id: id)
|
||||
let id = "user/\(userID)/tag/global.saved"
|
||||
return FeedlyTagResourceID(id: id)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// FeedlyStreamIds.swift
|
||||
// FeedlyStreamIDs.swift
|
||||
// Account
|
||||
//
|
||||
// Created by Kiel Gillard on 18/10/19.
|
||||
|
@ -8,7 +8,7 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
struct FeedlyStreamIds: Decodable {
|
||||
struct FeedlyStreamIDs: Decodable {
|
||||
let continuation: String?
|
||||
let ids: [String]
|
||||
|
|
@ -17,13 +17,13 @@ public struct OAuthRefreshAccessTokenRequest: Encodable {
|
|||
public var scope: String?
|
||||
|
||||
// Possibly not part of the standard but specific to certain implementations (e.g.: Feedly).
|
||||
public var clientId: String
|
||||
public var clientID: String
|
||||
public var clientSecret: String
|
||||
|
||||
public init(refreshToken: String, scope: String?, client: OAuthAuthorizationClient) {
|
||||
self.refreshToken = refreshToken
|
||||
self.scope = scope
|
||||
self.clientId = client.id
|
||||
self.clientID = client.id
|
||||
self.clientSecret = client.secret
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,13 +30,13 @@ public struct OAuthAuthorizationClient: Equatable {
|
|||
/// https://tools.ietf.org/html/rfc6749#section-4.1.1
|
||||
public struct OAuthAuthorizationRequest {
|
||||
public let responseType = "code"
|
||||
public var clientId: String
|
||||
public var clientID: String
|
||||
public var redirectUri: String
|
||||
public var scope: String
|
||||
public var state: String?
|
||||
|
||||
public init(clientId: String, redirectUri: String, scope: String, state: String?) {
|
||||
self.clientId = clientId
|
||||
public init(clientID: String, redirectUri: String, scope: String, state: String?) {
|
||||
self.clientID = clientID
|
||||
self.redirectUri = redirectUri
|
||||
self.scope = scope
|
||||
self.state = state
|
||||
|
@ -45,7 +45,7 @@ public struct OAuthAuthorizationRequest {
|
|||
public var queryItems: [URLQueryItem] {
|
||||
return [
|
||||
URLQueryItem(name: "response_type", value: responseType),
|
||||
URLQueryItem(name: "client_id", value: clientId),
|
||||
URLQueryItem(name: "client_id", value: clientID),
|
||||
URLQueryItem(name: "scope", value: scope),
|
||||
URLQueryItem(name: "redirect_uri", value: redirectUri),
|
||||
]
|
||||
|
@ -114,7 +114,7 @@ public struct OAuthAccessTokenRequest: Encodable {
|
|||
public var code: String
|
||||
public var redirectUri: String
|
||||
public var state: String?
|
||||
public var clientId: String
|
||||
public var clientID: String
|
||||
|
||||
// Possibly not part of the standard but specific to certain implementations (e.g.: Feedly).
|
||||
public var clientSecret: String
|
||||
|
@ -124,7 +124,7 @@ public struct OAuthAccessTokenRequest: Encodable {
|
|||
self.code = authorizationResponse.code
|
||||
self.redirectUri = client.redirectUri
|
||||
self.state = authorizationResponse.state
|
||||
self.clientId = client.id
|
||||
self.clientID = client.id
|
||||
self.clientSecret = client.secret
|
||||
self.scope = scope
|
||||
}
|
||||
|
|
|
@ -17,10 +17,10 @@ import Core
|
|||
private let operationQueue = MainThreadOperationQueue()
|
||||
var addCompletionHandler: ((Result<Void, Error>) -> ())?
|
||||
|
||||
@MainActor init(account: Account, credentials: Credentials, resource: FeedlyFeedResourceId, service: FeedlyAddFeedToCollectionService, container: Container, progress: DownloadProgress, log: OSLog, customFeedName: String? = nil) throws {
|
||||
@MainActor init(account: Account, credentials: Credentials, resource: FeedlyFeedResourceID, service: FeedlyAddFeedToCollectionService, container: Container, progress: DownloadProgress, log: OSLog, customFeedName: String? = nil) throws {
|
||||
|
||||
let validator = FeedlyFeedContainerValidator(container: container)
|
||||
let (folder, collectionId) = try validator.getValidContainer()
|
||||
let (folder, collectionID) = try validator.getValidContainer()
|
||||
|
||||
self.operationQueue.suspend()
|
||||
|
||||
|
@ -28,7 +28,7 @@ import Core
|
|||
|
||||
self.downloadProgress = progress
|
||||
|
||||
let addRequest = FeedlyAddFeedToCollectionOperation(folder: folder, feedResource: resource, feedName: customFeedName, collectionId: collectionId, service: service)
|
||||
let addRequest = FeedlyAddFeedToCollectionOperation(folder: folder, feedResource: resource, feedName: customFeedName, collectionID: collectionID, service: service)
|
||||
addRequest.delegate = self
|
||||
addRequest.downloadProgress = progress
|
||||
self.operationQueue.add(addRequest)
|
||||
|
|
|
@ -10,33 +10,33 @@ import Foundation
|
|||
import CommonErrors
|
||||
|
||||
protocol FeedlyAddFeedToCollectionService {
|
||||
func addFeed(with feedId: FeedlyFeedResourceId, title: String?, toCollectionWith collectionId: String, completion: @escaping (Result<[FeedlyFeed], Error>) -> ())
|
||||
func addFeed(with feedId: FeedlyFeedResourceID, title: String?, toCollectionWith collectionID: String, completion: @escaping (Result<[FeedlyFeed], Error>) -> ())
|
||||
}
|
||||
|
||||
final class FeedlyAddFeedToCollectionOperation: FeedlyOperation, FeedlyFeedsAndFoldersProviding, FeedlyResourceProviding {
|
||||
|
||||
let feedName: String?
|
||||
let collectionId: String
|
||||
let collectionID: String
|
||||
let service: FeedlyAddFeedToCollectionService
|
||||
let folder: Folder
|
||||
let feedResource: FeedlyFeedResourceId
|
||||
let feedResource: FeedlyFeedResourceID
|
||||
|
||||
init(folder: Folder, feedResource: FeedlyFeedResourceId, feedName: String? = nil, collectionId: String, service: FeedlyAddFeedToCollectionService) {
|
||||
init(folder: Folder, feedResource: FeedlyFeedResourceID, feedName: String? = nil, collectionID: String, service: FeedlyAddFeedToCollectionService) {
|
||||
self.folder = folder
|
||||
self.feedResource = feedResource
|
||||
self.feedName = feedName
|
||||
self.collectionId = collectionId
|
||||
self.collectionID = collectionID
|
||||
self.service = service
|
||||
}
|
||||
|
||||
private(set) var feedsAndFolders = [([FeedlyFeed], Folder)]()
|
||||
|
||||
var resource: FeedlyResourceId {
|
||||
var resource: FeedlyResourceID {
|
||||
return feedResource
|
||||
}
|
||||
|
||||
override func run() {
|
||||
service.addFeed(with: feedResource, title: feedName, toCollectionWith: collectionId) { [weak self] result in
|
||||
service.addFeed(with: feedResource, title: feedName, toCollectionWith: collectionID) { [weak self] result in
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
|
@ -56,9 +56,9 @@ private extension FeedlyAddFeedToCollectionOperation {
|
|||
case .success(let feedlyFeeds):
|
||||
feedsAndFolders = [(feedlyFeeds, folder)]
|
||||
|
||||
let feedsWithCreatedFeedId = feedlyFeeds.filter { $0.id == resource.id }
|
||||
let feedsWithCreatedFeedID = feedlyFeeds.filter { $0.id == resource.id }
|
||||
|
||||
if feedsWithCreatedFeedId.isEmpty {
|
||||
if feedsWithCreatedFeedID.isEmpty {
|
||||
didFinish(with: AccountError.createErrorNotFound)
|
||||
} else {
|
||||
didFinish()
|
||||
|
|
|
@ -18,24 +18,24 @@ class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, Feedl
|
|||
|
||||
private let operationQueue = MainThreadOperationQueue()
|
||||
private let folder: Folder
|
||||
private let collectionId: String
|
||||
private let collectionID: String
|
||||
private let url: String
|
||||
private let account: Account
|
||||
private let credentials: Credentials
|
||||
private let database: SyncDatabase
|
||||
private let feedName: String?
|
||||
private let addToCollectionService: FeedlyAddFeedToCollectionService
|
||||
private let syncUnreadIdsService: FeedlyGetStreamIdsService
|
||||
private let syncUnreadIDsService: FeedlyGetStreamIDsService
|
||||
private let getStreamContentsService: FeedlyGetStreamContentsService
|
||||
private let log: OSLog
|
||||
private var feedResourceId: FeedlyFeedResourceId?
|
||||
private var feedResourceID: FeedlyFeedResourceID?
|
||||
var addCompletionHandler: ((Result<Feed, Error>) -> ())?
|
||||
|
||||
@MainActor init(account: Account, credentials: Credentials, url: String, feedName: String?, searchService: FeedlySearchService, addToCollectionService: FeedlyAddFeedToCollectionService, syncUnreadIdsService: FeedlyGetStreamIdsService, getStreamContentsService: FeedlyGetStreamContentsService, database: SyncDatabase, container: Container, progress: DownloadProgress, log: OSLog) throws {
|
||||
@MainActor init(account: Account, credentials: Credentials, url: String, feedName: String?, searchService: FeedlySearchService, addToCollectionService: FeedlyAddFeedToCollectionService, syncUnreadIDsService: FeedlyGetStreamIDsService, getStreamContentsService: FeedlyGetStreamContentsService, database: SyncDatabase, container: Container, progress: DownloadProgress, log: OSLog) throws {
|
||||
|
||||
|
||||
let validator = FeedlyFeedContainerValidator(container: container)
|
||||
(self.folder, self.collectionId) = try validator.getValidContainer()
|
||||
(self.folder, self.collectionID) = try validator.getValidContainer()
|
||||
|
||||
self.url = url
|
||||
self.operationQueue.suspend()
|
||||
|
@ -44,7 +44,7 @@ class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, Feedl
|
|||
self.database = database
|
||||
self.feedName = feedName
|
||||
self.addToCollectionService = addToCollectionService
|
||||
self.syncUnreadIdsService = syncUnreadIdsService
|
||||
self.syncUnreadIDsService = syncUnreadIDsService
|
||||
self.getStreamContentsService = getStreamContentsService
|
||||
self.log = log
|
||||
|
||||
|
@ -84,10 +84,10 @@ class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, Feedl
|
|||
return didFinish(with: AccountError.createErrorNotFound)
|
||||
}
|
||||
|
||||
let feedResourceId = FeedlyFeedResourceId(id: first.feedId)
|
||||
self.feedResourceId = feedResourceId
|
||||
let feedResourceID = FeedlyFeedResourceID(id: first.feedId)
|
||||
self.feedResourceID = feedResourceID
|
||||
|
||||
let addRequest = FeedlyAddFeedToCollectionOperation(folder: folder, feedResource: feedResourceId, feedName: feedName, collectionId: collectionId, service: addToCollectionService)
|
||||
let addRequest = FeedlyAddFeedToCollectionOperation(folder: folder, feedResource: feedResourceID, feedName: feedName, collectionID: collectionID, service: addToCollectionService)
|
||||
addRequest.delegate = self
|
||||
addRequest.downloadProgress = downloadProgress
|
||||
operationQueue.add(addRequest)
|
||||
|
@ -98,13 +98,13 @@ class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, Feedl
|
|||
createFeeds.downloadProgress = downloadProgress
|
||||
operationQueue.add(createFeeds)
|
||||
|
||||
let syncUnread = FeedlyIngestUnreadArticleIdsOperation(account: account, userId: credentials.username, service: syncUnreadIdsService, database: database, newerThan: nil, log: log)
|
||||
let syncUnread = FeedlyIngestUnreadArticleIDsOperation(account: account, userID: credentials.username, service: syncUnreadIDsService, database: database, newerThan: nil, log: log)
|
||||
syncUnread.addDependency(createFeeds)
|
||||
syncUnread.downloadProgress = downloadProgress
|
||||
syncUnread.delegate = self
|
||||
operationQueue.add(syncUnread)
|
||||
|
||||
let syncFeed = FeedlySyncStreamContentsOperation(account: account, resource: feedResourceId, service: getStreamContentsService, isPagingEnabled: false, newerThan: nil, log: log)
|
||||
let syncFeed = FeedlySyncStreamContentsOperation(account: account, resource: feedResourceID, service: getStreamContentsService, isPagingEnabled: false, newerThan: nil, log: log)
|
||||
syncFeed.addDependency(syncUnread)
|
||||
syncFeed.downloadProgress = downloadProgress
|
||||
syncFeed.delegate = self
|
||||
|
@ -138,7 +138,7 @@ class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, Feedl
|
|||
guard let handler = addCompletionHandler else {
|
||||
return
|
||||
}
|
||||
if let feedResource = feedResourceId, let feed = folder.existingFeed(withFeedID: feedResource.id) {
|
||||
if let feedResource = feedResourceID, let feed = folder.existingFeed(withFeedID: feedResource.id) {
|
||||
handler(.success(feed))
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -15,17 +15,17 @@ class FeedlyDownloadArticlesOperation: FeedlyOperation {
|
|||
|
||||
private let account: Account
|
||||
private let log: OSLog
|
||||
private let missingArticleEntryIdProvider: FeedlyEntryIdentifierProviding
|
||||
private let updatedArticleEntryIdProvider: FeedlyEntryIdentifierProviding
|
||||
private let missingArticleEntryIDProvider: FeedlyEntryIdentifierProviding
|
||||
private let updatedArticleEntryIDProvider: FeedlyEntryIdentifierProviding
|
||||
private let getEntriesService: FeedlyGetEntriesService
|
||||
private let operationQueue = MainThreadOperationQueue()
|
||||
private let finishOperation: FeedlyCheckpointOperation
|
||||
|
||||
@MainActor init(account: Account, missingArticleEntryIdProvider: FeedlyEntryIdentifierProviding, updatedArticleEntryIdProvider: FeedlyEntryIdentifierProviding, getEntriesService: FeedlyGetEntriesService, log: OSLog) {
|
||||
@MainActor init(account: Account, missingArticleEntryIDProvider: FeedlyEntryIdentifierProviding, updatedArticleEntryIDProvider: FeedlyEntryIdentifierProviding, getEntriesService: FeedlyGetEntriesService, log: OSLog) {
|
||||
self.account = account
|
||||
self.operationQueue.suspend()
|
||||
self.missingArticleEntryIdProvider = missingArticleEntryIdProvider
|
||||
self.updatedArticleEntryIdProvider = updatedArticleEntryIdProvider
|
||||
self.missingArticleEntryIDProvider = missingArticleEntryIDProvider
|
||||
self.updatedArticleEntryIDProvider = updatedArticleEntryIDProvider
|
||||
self.getEntriesService = getEntriesService
|
||||
self.finishOperation = FeedlyCheckpointOperation()
|
||||
self.log = log
|
||||
|
@ -35,16 +35,16 @@ class FeedlyDownloadArticlesOperation: FeedlyOperation {
|
|||
}
|
||||
|
||||
override func run() {
|
||||
var articleIds = missingArticleEntryIdProvider.entryIDs
|
||||
articleIds.formUnion(updatedArticleEntryIdProvider.entryIDs)
|
||||
var articleIDs = missingArticleEntryIDProvider.entryIDs
|
||||
articleIDs.formUnion(updatedArticleEntryIDProvider.entryIDs)
|
||||
|
||||
os_log(.debug, log: log, "Requesting %{public}i articles.", articleIds.count)
|
||||
os_log(.debug, log: log, "Requesting %{public}i articles.", articleIDs.count)
|
||||
|
||||
let feedlyAPILimitBatchSize = 1000
|
||||
for articleIds in Array(articleIds).chunked(into: feedlyAPILimitBatchSize) {
|
||||
for articleIDs in Array(articleIDs).chunked(into: feedlyAPILimitBatchSize) {
|
||||
|
||||
Task { @MainActor in
|
||||
let provider = FeedlyEntryIdentifierProvider(entryIDs: Set(articleIds))
|
||||
let provider = FeedlyEntryIdentifierProvider(entryIDs: Set(articleIDs))
|
||||
let getEntries = FeedlyGetEntriesOperation(service: getEntriesService, provider: provider, log: log)
|
||||
getEntries.delegate = self
|
||||
self.operationQueue.add(getEntries)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// FeedlyFetchIdsForMissingArticlesOperation.swift
|
||||
// FeedlyFetchIDsForMissingArticlesOperation.swift
|
||||
// Account
|
||||
//
|
||||
// Created by Kiel Gillard on 7/1/20.
|
||||
|
@ -9,7 +9,7 @@
|
|||
import Foundation
|
||||
import os.log
|
||||
|
||||
final class FeedlyFetchIdsForMissingArticlesOperation: FeedlyOperation, FeedlyEntryIdentifierProviding {
|
||||
final class FeedlyFetchIDsForMissingArticlesOperation: FeedlyOperation, FeedlyEntryIdentifierProviding {
|
||||
|
||||
private let account: Account
|
||||
|
|
@ -38,9 +38,9 @@ final class FeedlyGetEntriesOperation: FeedlyOperation, FeedlyEntryProviding, Fe
|
|||
|
||||
// TODO: Fix the below. There’s an error on the os.log line: "Expression type '()' is ambiguous without more context"
|
||||
// if parsed.count != entries.count {
|
||||
// let entryIds = Set(entries.map { $0.id })
|
||||
// let parsedIds = Set(parsed.map { $0.uniqueID })
|
||||
// let difference = entryIds.subtracting(parsedIds)
|
||||
// let entryIDs = Set(entries.map { $0.id })
|
||||
// let parsedIDs = Set(parsed.map { $0.uniqueID })
|
||||
// let difference = entryIDs.subtracting(parsedIDs)
|
||||
// os_log(.debug, log: log, "%{public}@ dropping articles with ids: %{public}@.", self, difference)
|
||||
// }
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ protocol FeedlyGetStreamContentsOperationDelegate: AnyObject {
|
|||
final class FeedlyGetStreamContentsOperation: FeedlyOperation, FeedlyEntryProviding, FeedlyParsedItemProviding {
|
||||
|
||||
@MainActor struct ResourceProvider: FeedlyResourceProviding {
|
||||
var resource: FeedlyResourceId
|
||||
var resource: FeedlyResourceID
|
||||
}
|
||||
|
||||
let resourceProvider: FeedlyResourceProviding
|
||||
|
@ -55,9 +55,9 @@ final class FeedlyGetStreamContentsOperation: FeedlyOperation, FeedlyEntryProvid
|
|||
})
|
||||
|
||||
if parsed.count != entries.count {
|
||||
let entryIds = Set(entries.map { $0.id })
|
||||
let parsedIds = Set(parsed.map { $0.uniqueID })
|
||||
let difference = entryIds.subtracting(parsedIds)
|
||||
let entryIDs = Set(entries.map { $0.id })
|
||||
let parsedIDs = Set(parsed.map { $0.uniqueID })
|
||||
let difference = entryIDs.subtracting(parsedIDs)
|
||||
os_log(.debug, log: log, "Dropping articles with ids: %{public}@.", difference)
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,7 @@ final class FeedlyGetStreamContentsOperation: FeedlyOperation, FeedlyEntryProvid
|
|||
|
||||
weak var streamDelegate: FeedlyGetStreamContentsOperationDelegate?
|
||||
|
||||
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamContentsService, continuation: String? = nil, newerThan: Date?, unreadOnly: Bool? = nil, log: OSLog) {
|
||||
init(account: Account, resource: FeedlyResourceID, service: FeedlyGetStreamContentsService, continuation: String? = nil, newerThan: Date?, unreadOnly: Bool? = nil, log: OSLog) {
|
||||
self.account = account
|
||||
self.resourceProvider = ResourceProvider(resource: resource)
|
||||
self.service = service
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// FeedlyGetStreamIdsOperation.swift
|
||||
// FeedlyGetStreamIDsOperation.swift
|
||||
// Account
|
||||
//
|
||||
// Created by Kiel Gillard on 18/10/19.
|
||||
|
@ -9,32 +9,32 @@
|
|||
import Foundation
|
||||
import os.log
|
||||
|
||||
protocol FeedlyGetStreamIdsOperationDelegate: AnyObject {
|
||||
func feedlyGetStreamIdsOperation(_ operation: FeedlyGetStreamIdsOperation, didGet streamIds: FeedlyStreamIds)
|
||||
protocol FeedlyGetStreamIDsOperationDelegate: AnyObject {
|
||||
func feedlyGetStreamIDsOperation(_ operation: FeedlyGetStreamIDsOperation, didGet streamIDs: FeedlyStreamIDs)
|
||||
}
|
||||
|
||||
/// Single responsibility is to get the stream ids from Feedly.
|
||||
final class FeedlyGetStreamIdsOperation: FeedlyOperation, FeedlyEntryIdentifierProviding {
|
||||
final class FeedlyGetStreamIDsOperation: FeedlyOperation, FeedlyEntryIdentifierProviding {
|
||||
|
||||
var entryIDs: Set<String> {
|
||||
guard let ids = streamIds?.ids else {
|
||||
guard let ids = streamIDs?.ids else {
|
||||
assertionFailure("Has this operation been addeded as a dependency on the caller?")
|
||||
return []
|
||||
}
|
||||
return Set(ids)
|
||||
}
|
||||
|
||||
private(set) var streamIds: FeedlyStreamIds?
|
||||
private(set) var streamIDs: FeedlyStreamIDs?
|
||||
|
||||
let account: Account
|
||||
let service: FeedlyGetStreamIdsService
|
||||
let service: FeedlyGetStreamIDsService
|
||||
let continuation: String?
|
||||
let resource: FeedlyResourceId
|
||||
let resource: FeedlyResourceID
|
||||
let unreadOnly: Bool?
|
||||
let newerThan: Date?
|
||||
let log: OSLog
|
||||
|
||||
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, continuation: String? = nil, newerThan: Date? = nil, unreadOnly: Bool?, log: OSLog) {
|
||||
init(account: Account, resource: FeedlyResourceID, service: FeedlyGetStreamIDsService, continuation: String? = nil, newerThan: Date? = nil, unreadOnly: Bool?, log: OSLog) {
|
||||
self.account = account
|
||||
self.resource = resource
|
||||
self.service = service
|
||||
|
@ -44,15 +44,15 @@ final class FeedlyGetStreamIdsOperation: FeedlyOperation, FeedlyEntryIdentifierP
|
|||
self.log = log
|
||||
}
|
||||
|
||||
weak var streamIdsDelegate: FeedlyGetStreamIdsOperationDelegate?
|
||||
weak var streamIDsDelegate: FeedlyGetStreamIDsOperationDelegate?
|
||||
|
||||
override func run() {
|
||||
service.getStreamIds(for: resource, continuation: continuation, newerThan: newerThan, unreadOnly: unreadOnly) { result in
|
||||
service.getStreamIDs(for: resource, continuation: continuation, newerThan: newerThan, unreadOnly: unreadOnly) { result in
|
||||
switch result {
|
||||
case .success(let stream):
|
||||
self.streamIds = stream
|
||||
self.streamIDs = stream
|
||||
|
||||
self.streamIdsDelegate?.feedlyGetStreamIdsOperation(self, didGet: stream)
|
||||
self.streamIDsDelegate?.feedlyGetStreamIDsOperation(self, didGet: stream)
|
||||
|
||||
self.didFinish()
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// FeedlyGetUpdatedArticleIdsOperation.swift
|
||||
// FeedlyGetUpdatedArticleIDsOperation.swift
|
||||
// Account
|
||||
//
|
||||
// Created by Kiel Gillard on 11/1/20.
|
||||
|
@ -14,15 +14,15 @@ import Secrets
|
|||
///
|
||||
/// Typically, it pages through the article ids of the global.all stream.
|
||||
/// When all the article ids are collected, it is the responsibility of another operation to download them when appropriate.
|
||||
class FeedlyGetUpdatedArticleIdsOperation: FeedlyOperation, FeedlyEntryIdentifierProviding {
|
||||
class FeedlyGetUpdatedArticleIDsOperation: FeedlyOperation, FeedlyEntryIdentifierProviding {
|
||||
|
||||
private let account: Account
|
||||
private let resource: FeedlyResourceId
|
||||
private let service: FeedlyGetStreamIdsService
|
||||
private let resource: FeedlyResourceID
|
||||
private let service: FeedlyGetStreamIDsService
|
||||
private let newerThan: Date?
|
||||
private let log: OSLog
|
||||
|
||||
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, newerThan: Date?, log: OSLog) {
|
||||
init(account: Account, resource: FeedlyResourceID, service: FeedlyGetStreamIDsService, newerThan: Date?, log: OSLog) {
|
||||
self.account = account
|
||||
self.resource = resource
|
||||
self.service = service
|
||||
|
@ -30,48 +30,48 @@ class FeedlyGetUpdatedArticleIdsOperation: FeedlyOperation, FeedlyEntryIdentifie
|
|||
self.log = log
|
||||
}
|
||||
|
||||
convenience init(account: Account, userId: String, service: FeedlyGetStreamIdsService, newerThan: Date?, log: OSLog) {
|
||||
let all = FeedlyCategoryResourceId.Global.all(for: userId)
|
||||
convenience init(account: Account, userID: String, service: FeedlyGetStreamIDsService, newerThan: Date?, log: OSLog) {
|
||||
let all = FeedlyCategoryResourceID.Global.all(for: userID)
|
||||
self.init(account: account, resource: all, service: service, newerThan: newerThan, log: log)
|
||||
}
|
||||
|
||||
var entryIDs: Set<String> {
|
||||
return storedUpdatedArticleIds
|
||||
return storedUpdatedArticleIDs
|
||||
}
|
||||
|
||||
private var storedUpdatedArticleIds = Set<String>()
|
||||
private var storedUpdatedArticleIDs = Set<String>()
|
||||
|
||||
override func run() {
|
||||
getStreamIds(nil)
|
||||
getStreamIDs(nil)
|
||||
}
|
||||
|
||||
private func getStreamIds(_ continuation: String?) {
|
||||
private func getStreamIDs(_ continuation: String?) {
|
||||
guard let date = newerThan else {
|
||||
os_log(.debug, log: log, "No date provided so everything must be new (nothing is updated).")
|
||||
didFinish()
|
||||
return
|
||||
}
|
||||
|
||||
service.getStreamIds(for: resource, continuation: continuation, newerThan: date, unreadOnly: nil, completion: didGetStreamIds(_:))
|
||||
service.getStreamIDs(for: resource, continuation: continuation, newerThan: date, unreadOnly: nil, completion: didGetStreamIDs(_:))
|
||||
}
|
||||
|
||||
private func didGetStreamIds(_ result: Result<FeedlyStreamIds, Error>) {
|
||||
private func didGetStreamIDs(_ result: Result<FeedlyStreamIDs, Error>) {
|
||||
guard !isCanceled else {
|
||||
didFinish()
|
||||
return
|
||||
}
|
||||
|
||||
switch result {
|
||||
case .success(let streamIds):
|
||||
storedUpdatedArticleIds.formUnion(streamIds.ids)
|
||||
case .success(let streamIDs):
|
||||
storedUpdatedArticleIDs.formUnion(streamIDs.ids)
|
||||
|
||||
guard let continuation = streamIds.continuation else {
|
||||
os_log(.debug, log: log, "%{public}i articles updated since last successful sync start date.", storedUpdatedArticleIds.count)
|
||||
guard let continuation = streamIDs.continuation else {
|
||||
os_log(.debug, log: log, "%{public}i articles updated since last successful sync start date.", storedUpdatedArticleIDs.count)
|
||||
didFinish()
|
||||
return
|
||||
}
|
||||
|
||||
getStreamIds(continuation)
|
||||
getStreamIDs(continuation)
|
||||
|
||||
case .failure(let error):
|
||||
didFinish(with: error)
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// FeedlyIngestStarredArticleIdsOperation.swift
|
||||
// FeedlyIngestStarredArticleIDsOperation.swift
|
||||
// Account
|
||||
//
|
||||
// Created by Kiel Gillard on 15/10/19.
|
||||
|
@ -17,21 +17,21 @@ import Secrets
|
|||
/// When all the article ids are collected, a status is created for each.
|
||||
/// The article ids previously marked as starred but not collected become unstarred.
|
||||
/// So this operation has side effects *for the entire account* it operates on.
|
||||
final class FeedlyIngestStarredArticleIdsOperation: FeedlyOperation {
|
||||
final class FeedlyIngestStarredArticleIDsOperation: FeedlyOperation {
|
||||
|
||||
private let account: Account
|
||||
private let resource: FeedlyResourceId
|
||||
private let service: FeedlyGetStreamIdsService
|
||||
private let resource: FeedlyResourceID
|
||||
private let service: FeedlyGetStreamIDsService
|
||||
private let database: SyncDatabase
|
||||
private var remoteEntryIds = Set<String>()
|
||||
private var remoteEntryIDs = Set<String>()
|
||||
private let log: OSLog
|
||||
|
||||
convenience init(account: Account, userId: String, service: FeedlyGetStreamIdsService, database: SyncDatabase, newerThan: Date?, log: OSLog) {
|
||||
let resource = FeedlyTagResourceId.Global.saved(for: userId)
|
||||
convenience init(account: Account, userID: String, service: FeedlyGetStreamIDsService, database: SyncDatabase, newerThan: Date?, log: OSLog) {
|
||||
let resource = FeedlyTagResourceID.Global.saved(for: userID)
|
||||
self.init(account: account, resource: resource, service: service, database: database, newerThan: newerThan, log: log)
|
||||
}
|
||||
|
||||
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, database: SyncDatabase, newerThan: Date?, log: OSLog) {
|
||||
init(account: Account, resource: FeedlyResourceID, service: FeedlyGetStreamIDsService, database: SyncDatabase, newerThan: Date?, log: OSLog) {
|
||||
self.account = account
|
||||
self.resource = resource
|
||||
self.service = service
|
||||
|
@ -40,30 +40,30 @@ final class FeedlyIngestStarredArticleIdsOperation: FeedlyOperation {
|
|||
}
|
||||
|
||||
override func run() {
|
||||
getStreamIds(nil)
|
||||
getStreamIDs(nil)
|
||||
}
|
||||
|
||||
private func getStreamIds(_ continuation: String?) {
|
||||
service.getStreamIds(for: resource, continuation: continuation, newerThan: nil, unreadOnly: nil, completion: didGetStreamIds(_:))
|
||||
private func getStreamIDs(_ continuation: String?) {
|
||||
service.getStreamIDs(for: resource, continuation: continuation, newerThan: nil, unreadOnly: nil, completion: didGetStreamIDs(_:))
|
||||
}
|
||||
|
||||
private func didGetStreamIds(_ result: Result<FeedlyStreamIds, Error>) {
|
||||
private func didGetStreamIDs(_ result: Result<FeedlyStreamIDs, Error>) {
|
||||
guard !isCanceled else {
|
||||
didFinish()
|
||||
return
|
||||
}
|
||||
|
||||
switch result {
|
||||
case .success(let streamIds):
|
||||
case .success(let streamIDs):
|
||||
|
||||
remoteEntryIds.formUnion(streamIds.ids)
|
||||
remoteEntryIDs.formUnion(streamIDs.ids)
|
||||
|
||||
guard let continuation = streamIds.continuation else {
|
||||
removeEntryIdsWithPendingStatus()
|
||||
guard let continuation = streamIDs.continuation else {
|
||||
removeEntryIDsWithPendingStatus()
|
||||
return
|
||||
}
|
||||
|
||||
getStreamIds(continuation)
|
||||
getStreamIDs(continuation)
|
||||
|
||||
case .failure(let error):
|
||||
didFinish(with: error)
|
||||
|
@ -71,7 +71,7 @@ final class FeedlyIngestStarredArticleIdsOperation: FeedlyOperation {
|
|||
}
|
||||
|
||||
/// Do not override pending statuses with the remote statuses of the same articles, otherwise an article will temporarily re-acquire the remote status before the pending status is pushed and subseqently pulled.
|
||||
private func removeEntryIdsWithPendingStatus() {
|
||||
private func removeEntryIDsWithPendingStatus() {
|
||||
guard !isCanceled else {
|
||||
didFinish()
|
||||
return
|
||||
|
@ -81,7 +81,7 @@ final class FeedlyIngestStarredArticleIdsOperation: FeedlyOperation {
|
|||
|
||||
do {
|
||||
if let pendingArticleIDs = try await self.database.selectPendingStarredStatusArticleIDs() {
|
||||
self.remoteEntryIds.subtract(pendingArticleIDs)
|
||||
self.remoteEntryIDs.subtract(pendingArticleIDs)
|
||||
}
|
||||
self.updateStarredStatuses()
|
||||
} catch {
|
||||
|
@ -120,7 +120,7 @@ final class FeedlyIngestStarredArticleIdsOperation: FeedlyOperation {
|
|||
var markAsStarredError: Error?
|
||||
var markAsUnstarredError: Error?
|
||||
|
||||
let remoteStarredArticleIDs = remoteEntryIds
|
||||
let remoteStarredArticleIDs = remoteEntryIDs
|
||||
do {
|
||||
try await account.markAsStarred(remoteStarredArticleIDs)
|
||||
} catch {
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// FeedlyIngestStreamArticleIdsOperation.swift
|
||||
// FeedlyIngestStreamArticleIDsOperation.swift
|
||||
// Account
|
||||
//
|
||||
// Created by Kiel Gillard on 9/1/20.
|
||||
|
@ -16,34 +16,34 @@ import Database
|
|||
/// Typically, it pages through the article ids of the global.all stream.
|
||||
/// As the article ids are collected, a default read status is created for each.
|
||||
/// So this operation has side effects *for the entire account* it operates on.
|
||||
class FeedlyIngestStreamArticleIdsOperation: FeedlyOperation {
|
||||
class FeedlyIngestStreamArticleIDsOperation: FeedlyOperation {
|
||||
|
||||
private let account: Account
|
||||
private let resource: FeedlyResourceId
|
||||
private let service: FeedlyGetStreamIdsService
|
||||
private let resource: FeedlyResourceID
|
||||
private let service: FeedlyGetStreamIDsService
|
||||
private let log: OSLog
|
||||
|
||||
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, log: OSLog) {
|
||||
init(account: Account, resource: FeedlyResourceID, service: FeedlyGetStreamIDsService, log: OSLog) {
|
||||
self.account = account
|
||||
self.resource = resource
|
||||
self.service = service
|
||||
self.log = log
|
||||
}
|
||||
|
||||
convenience init(account: Account, userId: String, service: FeedlyGetStreamIdsService, log: OSLog) {
|
||||
let all = FeedlyCategoryResourceId.Global.all(for: userId)
|
||||
convenience init(account: Account, userID: String, service: FeedlyGetStreamIDsService, log: OSLog) {
|
||||
let all = FeedlyCategoryResourceID.Global.all(for: userID)
|
||||
self.init(account: account, resource: all, service: service, log: log)
|
||||
}
|
||||
|
||||
override func run() {
|
||||
getStreamIds(nil)
|
||||
getStreamIDs(nil)
|
||||
}
|
||||
|
||||
private func getStreamIds(_ continuation: String?) {
|
||||
service.getStreamIds(for: resource, continuation: continuation, newerThan: nil, unreadOnly: nil, completion: didGetStreamIds(_:))
|
||||
private func getStreamIDs(_ continuation: String?) {
|
||||
service.getStreamIDs(for: resource, continuation: continuation, newerThan: nil, unreadOnly: nil, completion: didGetStreamIDs(_:))
|
||||
}
|
||||
|
||||
private func didGetStreamIds(_ result: Result<FeedlyStreamIds, Error>) {
|
||||
private func didGetStreamIDs(_ result: Result<FeedlyStreamIDs, Error>) {
|
||||
guard !isCanceled else {
|
||||
didFinish()
|
||||
return
|
||||
|
@ -62,7 +62,7 @@ class FeedlyIngestStreamArticleIdsOperation: FeedlyOperation {
|
|||
return
|
||||
}
|
||||
|
||||
self.getStreamIds(continuation)
|
||||
self.getStreamIDs(continuation)
|
||||
} catch {
|
||||
self.didFinish(with: error)
|
||||
return
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// FeedlyIngestUnreadArticleIdsOperation.swift
|
||||
// FeedlyIngestUnreadArticleIDsOperation.swift
|
||||
// Account
|
||||
//
|
||||
// Created by Kiel Gillard on 18/10/19.
|
||||
|
@ -18,21 +18,21 @@ import Secrets
|
|||
/// When all the unread article ids are collected, a status is created for each.
|
||||
/// The article ids previously marked as unread but not collected become read.
|
||||
/// So this operation has side effects *for the entire account* it operates on.
|
||||
final class FeedlyIngestUnreadArticleIdsOperation: FeedlyOperation {
|
||||
final class FeedlyIngestUnreadArticleIDsOperation: FeedlyOperation {
|
||||
|
||||
private let account: Account
|
||||
private let resource: FeedlyResourceId
|
||||
private let service: FeedlyGetStreamIdsService
|
||||
private let resource: FeedlyResourceID
|
||||
private let service: FeedlyGetStreamIDsService
|
||||
private let database: SyncDatabase
|
||||
private var remoteEntryIds = Set<String>()
|
||||
private var remoteEntryIDs = Set<String>()
|
||||
private let log: OSLog
|
||||
|
||||
convenience init(account: Account, userId: String, service: FeedlyGetStreamIdsService, database: SyncDatabase, newerThan: Date?, log: OSLog) {
|
||||
let resource = FeedlyCategoryResourceId.Global.all(for: userId)
|
||||
convenience init(account: Account, userID: String, service: FeedlyGetStreamIDsService, database: SyncDatabase, newerThan: Date?, log: OSLog) {
|
||||
let resource = FeedlyCategoryResourceID.Global.all(for: userID)
|
||||
self.init(account: account, resource: resource, service: service, database: database, newerThan: newerThan, log: log)
|
||||
}
|
||||
|
||||
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, database: SyncDatabase, newerThan: Date?, log: OSLog) {
|
||||
init(account: Account, resource: FeedlyResourceID, service: FeedlyGetStreamIDsService, database: SyncDatabase, newerThan: Date?, log: OSLog) {
|
||||
self.account = account
|
||||
self.resource = resource
|
||||
self.service = service
|
||||
|
@ -41,30 +41,30 @@ final class FeedlyIngestUnreadArticleIdsOperation: FeedlyOperation {
|
|||
}
|
||||
|
||||
override func run() {
|
||||
getStreamIds(nil)
|
||||
getStreamIDs(nil)
|
||||
}
|
||||
|
||||
private func getStreamIds(_ continuation: String?) {
|
||||
service.getStreamIds(for: resource, continuation: continuation, newerThan: nil, unreadOnly: true, completion: didGetStreamIds(_:))
|
||||
private func getStreamIDs(_ continuation: String?) {
|
||||
service.getStreamIDs(for: resource, continuation: continuation, newerThan: nil, unreadOnly: true, completion: didGetStreamIDs(_:))
|
||||
}
|
||||
|
||||
private func didGetStreamIds(_ result: Result<FeedlyStreamIds, Error>) {
|
||||
private func didGetStreamIDs(_ result: Result<FeedlyStreamIDs, Error>) {
|
||||
guard !isCanceled else {
|
||||
didFinish()
|
||||
return
|
||||
}
|
||||
|
||||
switch result {
|
||||
case .success(let streamIds):
|
||||
case .success(let streamIDs):
|
||||
|
||||
remoteEntryIds.formUnion(streamIds.ids)
|
||||
remoteEntryIDs.formUnion(streamIDs.ids)
|
||||
|
||||
guard let continuation = streamIds.continuation else {
|
||||
removeEntryIdsWithPendingStatus()
|
||||
guard let continuation = streamIDs.continuation else {
|
||||
removeEntryIDsWithPendingStatus()
|
||||
return
|
||||
}
|
||||
|
||||
getStreamIds(continuation)
|
||||
getStreamIDs(continuation)
|
||||
|
||||
case .failure(let error):
|
||||
didFinish(with: error)
|
||||
|
@ -72,7 +72,7 @@ final class FeedlyIngestUnreadArticleIdsOperation: FeedlyOperation {
|
|||
}
|
||||
|
||||
/// Do not override pending statuses with the remote statuses of the same articles, otherwise an article will temporarily re-acquire the remote status before the pending status is pushed and subseqently pulled.
|
||||
private func removeEntryIdsWithPendingStatus() {
|
||||
private func removeEntryIDsWithPendingStatus() {
|
||||
guard !isCanceled else {
|
||||
didFinish()
|
||||
return
|
||||
|
@ -82,7 +82,7 @@ final class FeedlyIngestUnreadArticleIdsOperation: FeedlyOperation {
|
|||
|
||||
do {
|
||||
if let pendingArticleIDs = try await self.database.selectPendingReadStatusArticleIDs() {
|
||||
self.remoteEntryIds.subtract(pendingArticleIDs)
|
||||
self.remoteEntryIDs.subtract(pendingArticleIDs)
|
||||
}
|
||||
self.updateUnreadStatuses()
|
||||
} catch {
|
||||
|
@ -116,7 +116,7 @@ final class FeedlyIngestUnreadArticleIdsOperation: FeedlyOperation {
|
|||
return
|
||||
}
|
||||
|
||||
let remoteUnreadArticleIDs = remoteEntryIds
|
||||
let remoteUnreadArticleIDs = remoteEntryIDs
|
||||
|
||||
Task { @MainActor in
|
||||
|
|
@ -12,7 +12,7 @@ import os.log
|
|||
|
||||
protocol FeedlyParsedItemsByFeedProviding {
|
||||
var parsedItemsByFeedProviderName: String { get }
|
||||
var parsedItemsKeyedByFeedId: [String: Set<ParsedItem>] { get }
|
||||
var parsedItemsKeyedByFeedID: [String: Set<ParsedItem>] { get }
|
||||
}
|
||||
|
||||
/// Group articles by their feeds.
|
||||
|
@ -26,12 +26,12 @@ final class FeedlyOrganiseParsedItemsByFeedOperation: FeedlyOperation, FeedlyPar
|
|||
return name ?? String(describing: Self.self)
|
||||
}
|
||||
|
||||
var parsedItemsKeyedByFeedId: [String : Set<ParsedItem>] {
|
||||
var parsedItemsKeyedByFeedID: [String : Set<ParsedItem>] {
|
||||
precondition(Thread.isMainThread) // Needs to be on main thread because Feed is a main-thread-only model type.
|
||||
return itemsKeyedByFeedId
|
||||
return itemsKeyedByFeedID
|
||||
}
|
||||
|
||||
private var itemsKeyedByFeedId = [String: Set<ParsedItem>]()
|
||||
private var itemsKeyedByFeedID = [String: Set<ParsedItem>]()
|
||||
|
||||
init(account: Account, parsedItemProvider: FeedlyParsedItemProviding, log: OSLog) {
|
||||
self.account = account
|
||||
|
@ -62,6 +62,6 @@ final class FeedlyOrganiseParsedItemsByFeedOperation: FeedlyOperation, FeedlyPar
|
|||
|
||||
os_log(.debug, log: log, "Grouped %i items by %i feeds for %@", items.count, dict.count, parsedItemProvider.parsedItemProviderName)
|
||||
|
||||
itemsKeyedByFeedId = dict
|
||||
itemsKeyedByFeedID = dict
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ final class FeedlyRequestStreamsOperation: FeedlyOperation {
|
|||
// TODO: Prioritise the must read collection/category before others so the most important content for the user loads first.
|
||||
|
||||
for collection in collectionsProvider.collections {
|
||||
let resource = FeedlyCategoryResourceId(id: collection.id)
|
||||
let resource = FeedlyCategoryResourceID(id: collection.id)
|
||||
let operation = FeedlyGetStreamContentsOperation(account: account,
|
||||
resource: resource,
|
||||
service: service,
|
||||
|
|
|
@ -53,12 +53,12 @@ private extension FeedlySendArticleStatusesOperation {
|
|||
let group = DispatchGroup()
|
||||
|
||||
for pairing in statuses {
|
||||
let articleIds = pending.filter { $0.key == pairing.status && $0.flag == pairing.flag }
|
||||
guard !articleIds.isEmpty else {
|
||||
let articleIDs = pending.filter { $0.key == pairing.status && $0.flag == pairing.flag }
|
||||
guard !articleIDs.isEmpty else {
|
||||
continue
|
||||
}
|
||||
|
||||
let ids = Set(articleIds.map { $0.articleID })
|
||||
let ids = Set(articleIDs.map { $0.articleID })
|
||||
let database = self.database
|
||||
group.enter()
|
||||
service.mark(ids, as: pairing.action) { result in
|
||||
|
|
|
@ -34,7 +34,7 @@ final class FeedlySyncAllOperation: FeedlyOperation {
|
|||
///
|
||||
/// Download articles for statuses at the union of those statuses without its corresponding article and those included in 3 (changed since last successful sync).
|
||||
///
|
||||
@MainActor init(account: Account, feedlyUserId: String, lastSuccessfulFetchStartDate: Date?, markArticlesService: FeedlyMarkArticlesService, getUnreadService: FeedlyGetStreamIdsService, getCollectionsService: FeedlyGetCollectionsService, getStreamContentsService: FeedlyGetStreamContentsService, getStarredService: FeedlyGetStreamIdsService, getStreamIdsService: FeedlyGetStreamIdsService, getEntriesService: FeedlyGetEntriesService, database: SyncDatabase, downloadProgress: DownloadProgress, log: OSLog) {
|
||||
@MainActor init(account: Account, feedlyUserID: String, lastSuccessfulFetchStartDate: Date?, markArticlesService: FeedlyMarkArticlesService, getUnreadService: FeedlyGetStreamIDsService, getCollectionsService: FeedlyGetCollectionsService, getStreamContentsService: FeedlyGetStreamContentsService, getStarredService: FeedlyGetStreamIDsService, getStreamIDsService: FeedlyGetStreamIDsService, getEntriesService: FeedlyGetEntriesService, database: SyncDatabase, downloadProgress: DownloadProgress, log: OSLog) {
|
||||
self.syncUUID = UUID()
|
||||
self.log = log
|
||||
self.operationQueue.suspend()
|
||||
|
@ -68,53 +68,53 @@ final class FeedlySyncAllOperation: FeedlyOperation {
|
|||
createFeedsOperation.addDependency(mirrorCollectionsAsFolders)
|
||||
self.operationQueue.add(createFeedsOperation)
|
||||
|
||||
let getAllArticleIds = FeedlyIngestStreamArticleIdsOperation(account: account, userId: feedlyUserId, service: getStreamIdsService, log: log)
|
||||
getAllArticleIds.delegate = self
|
||||
getAllArticleIds.downloadProgress = downloadProgress
|
||||
getAllArticleIds.addDependency(createFeedsOperation)
|
||||
self.operationQueue.add(getAllArticleIds)
|
||||
let getAllArticleIDs = FeedlyIngestStreamArticleIDsOperation(account: account, userID: feedlyUserID, service: getStreamIDsService, log: log)
|
||||
getAllArticleIDs.delegate = self
|
||||
getAllArticleIDs.downloadProgress = downloadProgress
|
||||
getAllArticleIDs.addDependency(createFeedsOperation)
|
||||
self.operationQueue.add(getAllArticleIDs)
|
||||
|
||||
// Get each page of unread article ids in the global.all stream for the last 31 days (nil = Feedly API default).
|
||||
let getUnread = FeedlyIngestUnreadArticleIdsOperation(account: account, userId: feedlyUserId, service: getUnreadService, database: database, newerThan: nil, log: log)
|
||||
let getUnread = FeedlyIngestUnreadArticleIDsOperation(account: account, userID: feedlyUserID, service: getUnreadService, database: database, newerThan: nil, log: log)
|
||||
getUnread.delegate = self
|
||||
getUnread.addDependency(getAllArticleIds)
|
||||
getUnread.addDependency(getAllArticleIDs)
|
||||
getUnread.downloadProgress = downloadProgress
|
||||
self.operationQueue.add(getUnread)
|
||||
|
||||
// Get each page of the article ids which have been update since the last successful fetch start date.
|
||||
// If the date is nil, this operation provides an empty set (everything is new, nothing is updated).
|
||||
let getUpdated = FeedlyGetUpdatedArticleIdsOperation(account: account, userId: feedlyUserId, service: getStreamIdsService, newerThan: lastSuccessfulFetchStartDate, log: log)
|
||||
let getUpdated = FeedlyGetUpdatedArticleIDsOperation(account: account, userID: feedlyUserID, service: getStreamIDsService, newerThan: lastSuccessfulFetchStartDate, log: log)
|
||||
getUpdated.delegate = self
|
||||
getUpdated.downloadProgress = downloadProgress
|
||||
getUpdated.addDependency(createFeedsOperation)
|
||||
self.operationQueue.add(getUpdated)
|
||||
|
||||
// Get each page of the article ids for starred articles.
|
||||
let getStarred = FeedlyIngestStarredArticleIdsOperation(account: account, userId: feedlyUserId, service: getStarredService, database: database, newerThan: nil, log: log)
|
||||
let getStarred = FeedlyIngestStarredArticleIDsOperation(account: account, userID: feedlyUserID, service: getStarredService, database: database, newerThan: nil, log: log)
|
||||
getStarred.delegate = self
|
||||
getStarred.downloadProgress = downloadProgress
|
||||
getStarred.addDependency(createFeedsOperation)
|
||||
self.operationQueue.add(getStarred)
|
||||
|
||||
// Now all the possible article ids we need have a status, fetch the article ids for missing articles.
|
||||
let getMissingIds = FeedlyFetchIdsForMissingArticlesOperation(account: account)
|
||||
getMissingIds.delegate = self
|
||||
getMissingIds.downloadProgress = downloadProgress
|
||||
getMissingIds.addDependency(getAllArticleIds)
|
||||
getMissingIds.addDependency(getUnread)
|
||||
getMissingIds.addDependency(getStarred)
|
||||
getMissingIds.addDependency(getUpdated)
|
||||
self.operationQueue.add(getMissingIds)
|
||||
let getMissingIDs = FeedlyFetchIDsForMissingArticlesOperation(account: account)
|
||||
getMissingIDs.delegate = self
|
||||
getMissingIDs.downloadProgress = downloadProgress
|
||||
getMissingIDs.addDependency(getAllArticleIDs)
|
||||
getMissingIDs.addDependency(getUnread)
|
||||
getMissingIDs.addDependency(getStarred)
|
||||
getMissingIDs.addDependency(getUpdated)
|
||||
self.operationQueue.add(getMissingIDs)
|
||||
|
||||
// Download all the missing and updated articles
|
||||
let downloadMissingArticles = FeedlyDownloadArticlesOperation(account: account,
|
||||
missingArticleEntryIdProvider: getMissingIds,
|
||||
updatedArticleEntryIdProvider: getUpdated,
|
||||
missingArticleEntryIDProvider: getMissingIDs,
|
||||
updatedArticleEntryIDProvider: getUpdated,
|
||||
getEntriesService: getEntriesService,
|
||||
log: log)
|
||||
downloadMissingArticles.delegate = self
|
||||
downloadMissingArticles.downloadProgress = downloadProgress
|
||||
downloadMissingArticles.addDependency(getMissingIds)
|
||||
downloadMissingArticles.addDependency(getMissingIDs)
|
||||
downloadMissingArticles.addDependency(getUpdated)
|
||||
self.operationQueue.add(downloadMissingArticles)
|
||||
|
||||
|
@ -126,8 +126,8 @@ final class FeedlySyncAllOperation: FeedlyOperation {
|
|||
self.operationQueue.add(finishOperation)
|
||||
}
|
||||
|
||||
@MainActor convenience init(account: Account, feedlyUserId: String, caller: FeedlyAPICaller, database: SyncDatabase, lastSuccessfulFetchStartDate: Date?, downloadProgress: DownloadProgress, log: OSLog) {
|
||||
self.init(account: account, feedlyUserId: feedlyUserId, lastSuccessfulFetchStartDate: lastSuccessfulFetchStartDate, markArticlesService: caller, getUnreadService: caller, getCollectionsService: caller, getStreamContentsService: caller, getStarredService: caller, getStreamIdsService: caller, getEntriesService: caller, database: database, downloadProgress: downloadProgress, log: log)
|
||||
@MainActor convenience init(account: Account, feedlyUserID: String, caller: FeedlyAPICaller, database: SyncDatabase, lastSuccessfulFetchStartDate: Date?, downloadProgress: DownloadProgress, log: OSLog) {
|
||||
self.init(account: account, feedlyUserID: feedlyUserID, lastSuccessfulFetchStartDate: lastSuccessfulFetchStartDate, markArticlesService: caller, getUnreadService: caller, getCollectionsService: caller, getStreamContentsService: caller, getStarredService: caller, getStreamIDsService: caller, getEntriesService: caller, database: database, downloadProgress: downloadProgress, log: log)
|
||||
}
|
||||
|
||||
override func run() {
|
||||
|
|
|
@ -16,7 +16,7 @@ import Core
|
|||
final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationDelegate, FeedlyGetStreamContentsOperationDelegate, FeedlyCheckpointOperationDelegate {
|
||||
|
||||
private let account: Account
|
||||
private let resource: FeedlyResourceId
|
||||
private let resource: FeedlyResourceID
|
||||
private let operationQueue = MainThreadOperationQueue()
|
||||
private let service: FeedlyGetStreamContentsService
|
||||
private let newerThan: Date?
|
||||
|
@ -24,7 +24,7 @@ final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationD
|
|||
private let log: OSLog
|
||||
private let finishOperation: FeedlyCheckpointOperation
|
||||
|
||||
@MainActor init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamContentsService, isPagingEnabled: Bool, newerThan: Date?, log: OSLog) {
|
||||
@MainActor init(account: Account, resource: FeedlyResourceID, service: FeedlyGetStreamContentsService, isPagingEnabled: Bool, newerThan: Date?, log: OSLog) {
|
||||
self.account = account
|
||||
self.resource = resource
|
||||
self.service = service
|
||||
|
@ -42,7 +42,7 @@ final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationD
|
|||
}
|
||||
|
||||
@MainActor convenience init(account: Account, credentials: Credentials, service: FeedlyGetStreamContentsService, newerThan: Date?, log: OSLog) {
|
||||
let all = FeedlyCategoryResourceId.Global.all(for: credentials.username)
|
||||
let all = FeedlyCategoryResourceID.Global.all(for: credentials.username)
|
||||
self.init(account: account, resource: all, service: service, isPagingEnabled: true, newerThan: newerThan, log: log)
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ final class FeedlyUpdateAccountFeedsWithItemsOperation: FeedlyOperation {
|
|||
|
||||
override func run() {
|
||||
|
||||
let feedIDsAndItems = organisedItemsProvider.parsedItemsKeyedByFeedId
|
||||
let feedIDsAndItems = organisedItemsProvider.parsedItemsKeyedByFeedID
|
||||
|
||||
Task { @MainActor in
|
||||
do {
|
||||
|
|
|
@ -9,5 +9,5 @@
|
|||
import Foundation
|
||||
|
||||
protocol FeedlyGetStreamContentsService: AnyObject {
|
||||
func getStreamContents(for resource: FeedlyResourceId, continuation: String?, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStream, Error>) -> ())
|
||||
func getStreamContents(for resource: FeedlyResourceID, continuation: String?, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStream, Error>) -> ())
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// FeedlyGetStreamIdsService.swift
|
||||
// FeedlyGetStreamIDsService.swift
|
||||
// Account
|
||||
//
|
||||
// Created by Kiel Gillard on 21/10/19.
|
||||
|
@ -8,6 +8,6 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
protocol FeedlyGetStreamIdsService: AnyObject {
|
||||
func getStreamIds(for resource: FeedlyResourceId, continuation: String?, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStreamIds, Error>) -> ())
|
||||
protocol FeedlyGetStreamIDsService: AnyObject {
|
||||
func getStreamIDs(for resource: FeedlyResourceID, continuation: String?, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStreamIDs, Error>) -> ())
|
||||
}
|
|
@ -31,5 +31,5 @@ enum FeedlyMarkAction: String {
|
|||
}
|
||||
|
||||
protocol FeedlyMarkArticlesService: AnyObject {
|
||||
func mark(_ articleIds: Set<String>, as action: FeedlyMarkAction, completion: @escaping (Result<Void, Error>) -> ())
|
||||
func mark(_ articleIDs: Set<String>, as action: FeedlyMarkAction, completion: @escaping (Result<Void, Error>) -> ())
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ public extension URLRequest {
|
|||
URLQueryItem(name: "password", value: credentials.secret),
|
||||
]
|
||||
httpBody = postData.enhancedPercentEncodedQuery?.data(using: .utf8)
|
||||
case .newsBlurSessionId:
|
||||
case .newsBlurSessionID:
|
||||
setValue("\(NewsBlurAPICaller.sessionIDCookieKey)=\(credentials.secret)", forHTTPHeaderField: "Cookie")
|
||||
httpShouldHandleCookies = true
|
||||
case .readerBasic:
|
||||
|
|
|
@ -64,7 +64,7 @@ class FeedlyCreateFeedsForCollectionFoldersOperationTests: XCTestCase {
|
|||
|
||||
waitForExpectations(timeout: 2)
|
||||
|
||||
let feedIds = Set([feedsForFolderOne, feedsForFolderTwo]
|
||||
let feedIDs = Set([feedsForFolderOne, feedsForFolderTwo]
|
||||
.flatMap { $0 }
|
||||
.map { $0.id })
|
||||
|
||||
|
@ -73,28 +73,28 @@ class FeedlyCreateFeedsForCollectionFoldersOperationTests: XCTestCase {
|
|||
.map { $0.title })
|
||||
|
||||
let accountFeeds = account.flattenedFeeds()
|
||||
let ingestedIds = Set(accountFeeds.map { $0.feedID })
|
||||
let ingestedIDs = Set(accountFeeds.map { $0.feedID })
|
||||
let ingestedTitles = Set(accountFeeds.map { $0.nameForDisplay })
|
||||
|
||||
let missingIds = feedIds.subtracting(ingestedIds)
|
||||
let missingIDs = feedIDs.subtracting(ingestedIDs)
|
||||
let missingTitles = feedTitles.subtracting(ingestedTitles)
|
||||
|
||||
XCTAssertTrue(missingIds.isEmpty, "Failed to ingest feeds with these ids.")
|
||||
XCTAssertTrue(missingIDs.isEmpty, "Failed to ingest feeds with these ids.")
|
||||
XCTAssertTrue(missingTitles.isEmpty, "Failed to ingest feeds with these titles.")
|
||||
|
||||
let expectedFolderAndFeedIds = namesAndFeeds
|
||||
let expectedFolderAndFeedIDs = namesAndFeeds
|
||||
.sorted { $0.0.id < $1.0.id }
|
||||
.map { folder, feeds -> [String: [String]] in
|
||||
return [folder.id: feeds.map { $0.id }.sorted(by: <)]
|
||||
}
|
||||
|
||||
let ingestedFolderAndFeedIds = (account.folders ?? Set())
|
||||
let ingestedFolderAndFeedIDs = (account.folders ?? Set())
|
||||
.sorted { $0.externalID! < $1.externalID! }
|
||||
.compactMap { folder -> [String: [String]]? in
|
||||
return [folder.externalID!: folder.topLevelFeeds.map { $0.feedID }.sorted(by: <)]
|
||||
}
|
||||
|
||||
XCTAssertEqual(expectedFolderAndFeedIds, ingestedFolderAndFeedIds, "Did not ingest feeds in their corresponding folders.")
|
||||
XCTAssertEqual(expectedFolderAndFeedIDs, ingestedFolderAndFeedIDs, "Did not ingest feeds in their corresponding folders.")
|
||||
}
|
||||
|
||||
func testRemoveFeeds() {
|
||||
|
@ -157,7 +157,7 @@ class FeedlyCreateFeedsForCollectionFoldersOperationTests: XCTestCase {
|
|||
|
||||
waitForExpectations(timeout: 2)
|
||||
|
||||
let feedIds = Set([feedsForFolderOne, feedsForFolderTwo]
|
||||
let feedIDs = Set([feedsForFolderOne, feedsForFolderTwo]
|
||||
.flatMap { $0 }
|
||||
.map { $0.id })
|
||||
|
||||
|
@ -166,30 +166,30 @@ class FeedlyCreateFeedsForCollectionFoldersOperationTests: XCTestCase {
|
|||
.map { $0.title })
|
||||
|
||||
let accountFeeds = account.flattenedFeeds()
|
||||
let ingestedIds = Set(accountFeeds.map { $0.feedID })
|
||||
let ingestedIDs = Set(accountFeeds.map { $0.feedID })
|
||||
let ingestedTitles = Set(accountFeeds.map { $0.nameForDisplay })
|
||||
|
||||
XCTAssertEqual(ingestedIds.count, feedIds.count)
|
||||
XCTAssertEqual(ingestedIDs.count, feedIDs.count)
|
||||
XCTAssertEqual(ingestedTitles.count, feedTitles.count)
|
||||
|
||||
let missingIds = feedIds.subtracting(ingestedIds)
|
||||
let missingIDs = feedIDs.subtracting(ingestedIDs)
|
||||
let missingTitles = feedTitles.subtracting(ingestedTitles)
|
||||
|
||||
XCTAssertTrue(missingIds.isEmpty, "Failed to ingest feeds with these ids.")
|
||||
XCTAssertTrue(missingIDs.isEmpty, "Failed to ingest feeds with these ids.")
|
||||
XCTAssertTrue(missingTitles.isEmpty, "Failed to ingest feeds with these titles.")
|
||||
|
||||
let expectedFolderAndFeedIds = namesAndFeeds
|
||||
let expectedFolderAndFeedIDs = namesAndFeeds
|
||||
.sorted { $0.0.id < $1.0.id }
|
||||
.map { folder, feeds -> [String: [String]] in
|
||||
return [folder.id: feeds.map { $0.id }.sorted(by: <)]
|
||||
}
|
||||
|
||||
let ingestedFolderAndFeedIds = (account.folders ?? Set())
|
||||
let ingestedFolderAndFeedIDs = (account.folders ?? Set())
|
||||
.sorted { $0.externalID! < $1.externalID! }
|
||||
.compactMap { folder -> [String: [String]]? in
|
||||
return [folder.externalID!: folder.topLevelFeeds.map { $0.feedID }.sorted(by: <)]
|
||||
}
|
||||
|
||||
XCTAssertEqual(expectedFolderAndFeedIds, ingestedFolderAndFeedIds, "Did not ingest feeds to their corresponding folders.")
|
||||
XCTAssertEqual(expectedFolderAndFeedIDs, ingestedFolderAndFeedIDs, "Did not ingest feeds to their corresponding folders.")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ class FeedlyEntryParserTests: XCTestCase {
|
|||
let parser = FeedlyEntryParser(entry: entry)
|
||||
|
||||
XCTAssertEqual(parser.id, entry.id)
|
||||
XCTAssertEqual(parser.feedUrl, origin.streamId)
|
||||
XCTAssertEqual(parser.feedUrl, origin.streamID)
|
||||
XCTAssertEqual(parser.externalUrl, canonicalLink.href)
|
||||
XCTAssertEqual(parser.title, entry.title)
|
||||
XCTAssertEqual(parser.contentHMTL, content.content)
|
||||
|
@ -56,7 +56,7 @@ class FeedlyEntryParserTests: XCTestCase {
|
|||
|
||||
// The following is not an error.
|
||||
// The feedURL must match the feedID for the article to be connected to its matching feed.
|
||||
XCTAssertEqual(item.feedURL, origin.streamId)
|
||||
XCTAssertEqual(item.feedURL, origin.streamID)
|
||||
XCTAssertEqual(item.title, entry.title)
|
||||
XCTAssertEqual(item.contentHTML, content.content)
|
||||
XCTAssertEqual(item.contentText, nil, "Is it now free of HTML characters?")
|
||||
|
|
|
@ -36,21 +36,21 @@ class FeedlyGetCollectionsOperationTests: XCTestCase {
|
|||
let ids = Set(getCollections.collections.map { $0.id })
|
||||
|
||||
let missingLabels = labelsInJSON.subtracting(labels)
|
||||
let missingIds = idsInJSON.subtracting(ids)
|
||||
let missingIDs = idsInJSON.subtracting(ids)
|
||||
|
||||
XCTAssertEqual(getCollections.collections.count, collections.count, "Mismatch between collections provided by operation and test JSON collections.")
|
||||
XCTAssertTrue(missingLabels.isEmpty, "Collections with these labels did not have a corresponding \(FeedlyCollection.self) value with the same name.")
|
||||
XCTAssertTrue(missingIds.isEmpty, "Collections with these ids did not have a corresponding \(FeedlyCollection.self) with the same id.")
|
||||
XCTAssertTrue(missingIDs.isEmpty, "Collections with these ids did not have a corresponding \(FeedlyCollection.self) with the same id.")
|
||||
|
||||
for collection in collections {
|
||||
let collectionId = collection["id"] as! String
|
||||
let collectionID = collection["id"] as! String
|
||||
let collectionFeeds = collection["feeds"] as! [[String: Any]]
|
||||
let collectionFeedIds = Set(collectionFeeds.map { $0["id"] as! String })
|
||||
let collectionFeedIDs = Set(collectionFeeds.map { $0["id"] as! String })
|
||||
|
||||
for operationCollection in getCollections.collections where operationCollection.id == collectionId {
|
||||
let feedIds = Set(operationCollection.feeds.map { $0.id })
|
||||
let missingIds = collectionFeedIds.subtracting(feedIds)
|
||||
XCTAssertTrue(missingIds.isEmpty, "Feeds with these ids were not found in the \"\(operationCollection.label)\" \(FeedlyCollection.self).")
|
||||
for operationCollection in getCollections.collections where operationCollection.id == collectionID {
|
||||
let feedIDs = Set(operationCollection.feeds.map { $0.id })
|
||||
let missingIDs = collectionFeedIDs.subtracting(feedIDs)
|
||||
XCTAssertTrue(missingIDs.isEmpty, "Feeds with these ids were not found in the \"\(operationCollection.label)\" \(FeedlyCollection.self).")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ class FeedlyGetStreamContentsOperationTests: XCTestCase {
|
|||
|
||||
func testGetStreamContentsFailure() {
|
||||
let service = TestGetStreamContentsService()
|
||||
let resource = FeedlyCategoryResourceId(id: "user/1234/category/5678")
|
||||
let resource = FeedlyCategoryResourceID(id: "user/1234/category/5678")
|
||||
|
||||
let getStreamContents = FeedlyGetStreamContentsOperation(account: account, resource: resource, service: service, continuation: nil, newerThan: nil, unreadOnly: nil, log: support.log)
|
||||
|
||||
|
@ -48,7 +48,7 @@ class FeedlyGetStreamContentsOperationTests: XCTestCase {
|
|||
|
||||
func testValuesPassingForGetStreamContents() {
|
||||
let service = TestGetStreamContentsService()
|
||||
let resource = FeedlyCategoryResourceId(id: "user/1234/category/5678")
|
||||
let resource = FeedlyCategoryResourceID(id: "user/1234/category/5678")
|
||||
|
||||
let continuation: String? = "abcdefg"
|
||||
let newerThan: Date? = Date(timeIntervalSinceReferenceDate: 86)
|
||||
|
@ -85,9 +85,9 @@ class FeedlyGetStreamContentsOperationTests: XCTestCase {
|
|||
XCTAssertEqual(stream.updated, mockStream.updated)
|
||||
XCTAssertEqual(stream.continuation, mockStream.continuation)
|
||||
|
||||
let streamIds = stream.items.map { $0.id }
|
||||
let mockStreamIds = mockStream.items.map { $0.id }
|
||||
XCTAssertEqual(streamIds, mockStreamIds)
|
||||
let streamIDs = stream.items.map { $0.id }
|
||||
let mockStreamIDs = mockStream.items.map { $0.id }
|
||||
XCTAssertEqual(streamIDs, mockStreamIDs)
|
||||
}
|
||||
|
||||
func testGetStreamContentsFromJSON() {
|
||||
|
@ -96,7 +96,7 @@ class FeedlyGetStreamContentsOperationTests: XCTestCase {
|
|||
let jsonName = "JSON/feedly_macintosh_initial"
|
||||
transport.testFiles["/v3/streams/contents"] = "\(jsonName).json"
|
||||
|
||||
let resource = FeedlyCategoryResourceId(id: "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/category/5ca4d61d-e55d-4999-a8d1-c3b9d8789815")
|
||||
let resource = FeedlyCategoryResourceID(id: "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/category/5ca4d61d-e55d-4999-a8d1-c3b9d8789815")
|
||||
let getStreamContents = FeedlyGetStreamContentsOperation(account: account, resource: resource, service: caller, continuation: nil, newerThan: nil, unreadOnly: nil, log: support.log)
|
||||
|
||||
let completionExpectation = expectation(description: "Did Finish")
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// FeedlyGetStreamIdsOperationTests.swift
|
||||
// FeedlyGetStreamIDsOperationTests.swift
|
||||
// AccountTests
|
||||
//
|
||||
// Created by Kiel Gillard on 23/10/19.
|
||||
|
@ -9,7 +9,7 @@
|
|||
import XCTest
|
||||
@testable import Account
|
||||
|
||||
class FeedlyGetStreamIdsOperationTests: XCTestCase {
|
||||
class FeedlyGetStreamIDsOperationTests: XCTestCase {
|
||||
|
||||
private var account: Account!
|
||||
private let support = FeedlyTestSupport()
|
||||
|
@ -26,39 +26,39 @@ class FeedlyGetStreamIdsOperationTests: XCTestCase {
|
|||
super.tearDown()
|
||||
}
|
||||
|
||||
func testGetStreamIdsFailure() {
|
||||
let service = TestGetStreamIdsService()
|
||||
let resource = FeedlyCategoryResourceId(id: "user/1234/category/5678")
|
||||
func testGetStreamIDsFailure() {
|
||||
let service = TestGetStreamIDsService()
|
||||
let resource = FeedlyCategoryResourceID(id: "user/1234/category/5678")
|
||||
|
||||
let getStreamIds = FeedlyGetStreamIdsOperation(account: account, resource: resource, service: service, continuation: nil, newerThan: nil, unreadOnly: nil, log: support.log)
|
||||
let getStreamIDs = FeedlyGetStreamIDsOperation(account: account, resource: resource, service: service, continuation: nil, newerThan: nil, unreadOnly: nil, log: support.log)
|
||||
|
||||
service.mockResult = .failure(URLError(.fileDoesNotExist))
|
||||
|
||||
let completionExpectation = expectation(description: "Did Finish")
|
||||
getStreamIds.completionBlock = { _ in
|
||||
getStreamIDs.completionBlock = { _ in
|
||||
completionExpectation.fulfill()
|
||||
}
|
||||
|
||||
MainThreadOperationQueue.shared.add(getStreamIds)
|
||||
MainThreadOperationQueue.shared.add(getStreamIDs)
|
||||
|
||||
waitForExpectations(timeout: 2)
|
||||
|
||||
XCTAssertNil(getStreamIds.streamIds)
|
||||
XCTAssertNil(getStreamIDs.streamIDs)
|
||||
}
|
||||
|
||||
func testValuesPassingForGetStreamIds() {
|
||||
let service = TestGetStreamIdsService()
|
||||
let resource = FeedlyCategoryResourceId(id: "user/1234/category/5678")
|
||||
func testValuesPassingForGetStreamIDs() {
|
||||
let service = TestGetStreamIDsService()
|
||||
let resource = FeedlyCategoryResourceID(id: "user/1234/category/5678")
|
||||
|
||||
let continuation: String? = "gfdsa"
|
||||
let newerThan: Date? = Date(timeIntervalSinceReferenceDate: 1000)
|
||||
let unreadOnly: Bool? = false
|
||||
|
||||
let getStreamIds = FeedlyGetStreamIdsOperation(account: account, resource: resource, service: service, continuation: continuation, newerThan: newerThan, unreadOnly: unreadOnly, log: support.log)
|
||||
let getStreamIDs = FeedlyGetStreamIDsOperation(account: account, resource: resource, service: service, continuation: continuation, newerThan: newerThan, unreadOnly: unreadOnly, log: support.log)
|
||||
|
||||
let mockStreamIds = FeedlyStreamIds(continuation: "1234", ids: ["item/1", "item/2", "item/3"])
|
||||
service.mockResult = .success(mockStreamIds)
|
||||
service.getStreamIdsExpectation = expectation(description: "Did Call Service")
|
||||
let mockStreamIDs = FeedlyStreamIDs(continuation: "1234", ids: ["item/1", "item/2", "item/3"])
|
||||
service.mockResult = .success(mockStreamIDs)
|
||||
service.getStreamIDsExpectation = expectation(description: "Did Call Service")
|
||||
service.parameterTester = { serviceResource, serviceContinuation, serviceNewerThan, serviceUnreadOnly in
|
||||
// Verify these values given to the operation are passed to the service.
|
||||
XCTAssertEqual(serviceResource.id, resource.id)
|
||||
|
@ -68,49 +68,49 @@ class FeedlyGetStreamIdsOperationTests: XCTestCase {
|
|||
}
|
||||
|
||||
let completionExpectation = expectation(description: "Did Finish")
|
||||
getStreamIds.completionBlock = { _ in
|
||||
getStreamIDs.completionBlock = { _ in
|
||||
completionExpectation.fulfill()
|
||||
}
|
||||
|
||||
MainThreadOperationQueue.shared.add(getStreamIds)
|
||||
MainThreadOperationQueue.shared.add(getStreamIDs)
|
||||
|
||||
waitForExpectations(timeout: 2)
|
||||
|
||||
guard let streamIds = getStreamIds.streamIds else {
|
||||
XCTFail("\(FeedlyGetStreamIdsOperation.self) did not store the stream.")
|
||||
guard let streamIDs = getStreamIDs.streamIDs else {
|
||||
XCTFail("\(FeedlyGetStreamIDsOperation.self) did not store the stream.")
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssertEqual(streamIds.continuation, mockStreamIds.continuation)
|
||||
XCTAssertEqual(streamIds.ids, mockStreamIds.ids)
|
||||
XCTAssertEqual(streamIDs.continuation, mockStreamIDs.continuation)
|
||||
XCTAssertEqual(streamIDs.ids, mockStreamIDs.ids)
|
||||
}
|
||||
|
||||
func testGetStreamIdsFromJSON() {
|
||||
func testGetStreamIDsFromJSON() {
|
||||
let support = FeedlyTestSupport()
|
||||
let (transport, caller) = support.makeMockNetworkStack()
|
||||
let jsonName = "JSON/feedly_unreads_1000"
|
||||
transport.testFiles["/v3/streams/ids"] = "\(jsonName).json"
|
||||
|
||||
let resource = FeedlyCategoryResourceId(id: "user/1234/category/5678")
|
||||
let getStreamIds = FeedlyGetStreamIdsOperation(account: account, resource: resource, service: caller, continuation: nil, newerThan: nil, unreadOnly: nil, log: support.log)
|
||||
let resource = FeedlyCategoryResourceID(id: "user/1234/category/5678")
|
||||
let getStreamIDs = FeedlyGetStreamIDsOperation(account: account, resource: resource, service: caller, continuation: nil, newerThan: nil, unreadOnly: nil, log: support.log)
|
||||
|
||||
let completionExpectation = expectation(description: "Did Finish")
|
||||
getStreamIds.completionBlock = { _ in
|
||||
getStreamIDs.completionBlock = { _ in
|
||||
completionExpectation.fulfill()
|
||||
}
|
||||
|
||||
MainThreadOperationQueue.shared.add(getStreamIds)
|
||||
MainThreadOperationQueue.shared.add(getStreamIDs)
|
||||
|
||||
waitForExpectations(timeout: 2)
|
||||
|
||||
guard let streamIds = getStreamIds.streamIds else {
|
||||
guard let streamIDs = getStreamIDs.streamIDs else {
|
||||
return XCTFail("Expected to have a stream of identifiers.")
|
||||
}
|
||||
|
||||
let streamIdsJSON = support.testJSON(named: jsonName) as! [String:Any]
|
||||
let streamIDsJSON = support.testJSON(named: jsonName) as! [String:Any]
|
||||
|
||||
let continuation = streamIdsJSON["continuation"] as! String
|
||||
XCTAssertEqual(streamIds.continuation, continuation)
|
||||
XCTAssertEqual(streamIds.ids, streamIdsJSON["ids"] as! [String])
|
||||
let continuation = streamIDsJSON["continuation"] as! String
|
||||
XCTAssertEqual(streamIDs.continuation, continuation)
|
||||
XCTAssertEqual(streamIDs.ids, streamIDsJSON["ids"] as! [String])
|
||||
}
|
||||
}
|
|
@ -47,16 +47,16 @@ class FeedlyMirrorCollectionsAsFoldersOperationTests: XCTestCase {
|
|||
|
||||
let folders = account.folders ?? Set()
|
||||
let folderNames = Set(folders.compactMap { $0.nameForDisplay })
|
||||
let folderExternalIds = Set(folders.compactMap { $0.externalID })
|
||||
let folderExternalIDs = Set(folders.compactMap { $0.externalID })
|
||||
|
||||
let collectionLabels = Set(provider.collections.map { $0.label })
|
||||
let collectionIds = Set(provider.collections.map { $0.id })
|
||||
let collectionIDs = Set(provider.collections.map { $0.id })
|
||||
|
||||
let missingNames = collectionLabels.subtracting(folderNames)
|
||||
let missingIds = collectionIds.subtracting(folderExternalIds)
|
||||
let missingIDs = collectionIDs.subtracting(folderExternalIDs)
|
||||
|
||||
XCTAssertTrue(missingNames.isEmpty, "Collections with these labels have no corresponding folder.")
|
||||
XCTAssertTrue(missingIds.isEmpty, "Collections with these ids have no corresponding folder.")
|
||||
XCTAssertTrue(missingIDs.isEmpty, "Collections with these ids have no corresponding folder.")
|
||||
// XCTAssertEqual(mirrorOperation.collectionsAndFolders.count, provider.collections.count, "Mismatch between collections and folders.")
|
||||
}
|
||||
|
||||
|
@ -90,16 +90,16 @@ class FeedlyMirrorCollectionsAsFoldersOperationTests: XCTestCase {
|
|||
|
||||
let folders = account.folders ?? Set()
|
||||
let folderNames = Set(folders.compactMap { $0.nameForDisplay })
|
||||
let folderExternalIds = Set(folders.compactMap { $0.externalID })
|
||||
let folderExternalIDs = Set(folders.compactMap { $0.externalID })
|
||||
|
||||
let collectionLabels = Set(provider.collections.map { $0.label })
|
||||
let collectionIds = Set(provider.collections.map { $0.id })
|
||||
let collectionIDs = Set(provider.collections.map { $0.id })
|
||||
|
||||
let remainingNames = folderNames.subtracting(collectionLabels)
|
||||
let remainingIds = folderExternalIds.subtracting(collectionIds)
|
||||
let remainingIDs = folderExternalIDs.subtracting(collectionIDs)
|
||||
|
||||
XCTAssertTrue(remainingNames.isEmpty, "Folders with these names remain with no corresponding collection.")
|
||||
XCTAssertTrue(remainingIds.isEmpty, "Folders with these ids remain with no corresponding collection.")
|
||||
XCTAssertTrue(remainingIDs.isEmpty, "Folders with these ids remain with no corresponding collection.")
|
||||
|
||||
XCTAssertTrue(removeFolders.feedsAndFolders.isEmpty)
|
||||
}
|
||||
|
@ -137,29 +137,29 @@ class FeedlyMirrorCollectionsAsFoldersOperationTests: XCTestCase {
|
|||
|
||||
let folders = account.folders ?? Set()
|
||||
let folderNames = Set(folders.compactMap { $0.nameForDisplay })
|
||||
let folderExternalIds = Set(folders.compactMap { $0.externalID })
|
||||
let folderExternalIDs = Set(folders.compactMap { $0.externalID })
|
||||
|
||||
let collectionLabels = Set(provider.collections.map { $0.label })
|
||||
let collectionIds = Set(provider.collections.map { $0.id })
|
||||
let collectionIDs = Set(provider.collections.map { $0.id })
|
||||
|
||||
let missingNames = collectionLabels.subtracting(folderNames)
|
||||
let missingIds = collectionIds.subtracting(folderExternalIds)
|
||||
let missingIDs = collectionIDs.subtracting(folderExternalIDs)
|
||||
|
||||
XCTAssertTrue(missingNames.isEmpty, "Collections with these labels have no corresponding folder.")
|
||||
XCTAssertTrue(missingIds.isEmpty, "Collections with these ids have no corresponding folder.")
|
||||
XCTAssertTrue(missingIDs.isEmpty, "Collections with these ids have no corresponding folder.")
|
||||
|
||||
let collectionIdsAndFeedIds = provider.collections.map { collection -> [String:[String]] in
|
||||
let collectionIDsAndFeedIDs = provider.collections.map { collection -> [String:[String]] in
|
||||
return [collection.id: collection.feeds.map { $0.id }.sorted(by: <)]
|
||||
}
|
||||
|
||||
let folderIdsAndFeedIds = mirrorOperation.feedsAndFolders.compactMap { feeds, folder -> [String:[String]]? in
|
||||
let folderIDsAndFeedIDs = mirrorOperation.feedsAndFolders.compactMap { feeds, folder -> [String:[String]]? in
|
||||
guard let id = folder.externalID else {
|
||||
return nil
|
||||
}
|
||||
return [id: feeds.map { $0.id }.sorted(by: <)]
|
||||
}
|
||||
|
||||
XCTAssertEqual(collectionIdsAndFeedIds, folderIdsAndFeedIds, "Did not map folders to feeds correctly.")
|
||||
XCTAssertEqual(collectionIDsAndFeedIDs, folderIDsAndFeedIDs, "Did not map folders to feeds correctly.")
|
||||
}
|
||||
|
||||
func testRemovingFolderRemovesFeeds() {
|
||||
|
|
|
@ -29,13 +29,13 @@ class FeedlyOrganiseParsedItemsByFeedOperationTests: XCTestCase {
|
|||
|
||||
struct TestParsedItemsProvider: FeedlyParsedItemProviding {
|
||||
let parsedItemProviderName = "TestParsedItemsProvider"
|
||||
var resource: FeedlyResourceId
|
||||
var resource: FeedlyResourceID
|
||||
var parsedEntries: Set<ParsedItem>
|
||||
}
|
||||
|
||||
func testNoEntries() {
|
||||
let entries = support.makeParsedItemTestDataFor(numberOfFeeds: 0, numberOfItemsInFeeds: 0)
|
||||
let resource = FeedlyCategoryResourceId(id: "user/12345/category/6789")
|
||||
let resource = FeedlyCategoryResourceID(id: "user/12345/category/6789")
|
||||
let parsedEntries = Set(entries.values.flatMap { $0 })
|
||||
let provider = TestParsedItemsProvider(resource: resource, parsedEntries: parsedEntries)
|
||||
|
||||
|
@ -50,13 +50,13 @@ class FeedlyOrganiseParsedItemsByFeedOperationTests: XCTestCase {
|
|||
|
||||
waitForExpectations(timeout: 2)
|
||||
|
||||
let itemsAndFeedIds = organise.parsedItemsKeyedByFeedId
|
||||
XCTAssertEqual(itemsAndFeedIds, entries)
|
||||
let itemsAndFeedIDs = organise.parsedItemsKeyedByFeedID
|
||||
XCTAssertEqual(itemsAndFeedIDs, entries)
|
||||
}
|
||||
|
||||
func testGroupsOneEntryByFeedId() {
|
||||
let entries = support.makeParsedItemTestDataFor(numberOfFeeds: 1, numberOfItemsInFeeds: 1)
|
||||
let resource = FeedlyCategoryResourceId(id: "user/12345/category/6789")
|
||||
let resource = FeedlyCategoryResourceID(id: "user/12345/category/6789")
|
||||
let parsedEntries = Set(entries.values.flatMap { $0 })
|
||||
let provider = TestParsedItemsProvider(resource: resource, parsedEntries: parsedEntries)
|
||||
|
||||
|
@ -71,13 +71,13 @@ class FeedlyOrganiseParsedItemsByFeedOperationTests: XCTestCase {
|
|||
|
||||
waitForExpectations(timeout: 2)
|
||||
|
||||
let itemsAndFeedIds = organise.parsedItemsKeyedByFeedId
|
||||
XCTAssertEqual(itemsAndFeedIds, entries)
|
||||
let itemsAndFeedIDs = organise.parsedItemsKeyedByFeedID
|
||||
XCTAssertEqual(itemsAndFeedIDs, entries)
|
||||
}
|
||||
|
||||
func testGroupsManyEntriesByFeedId() {
|
||||
let entries = support.makeParsedItemTestDataFor(numberOfFeeds: 100, numberOfItemsInFeeds: 100)
|
||||
let resource = FeedlyCategoryResourceId(id: "user/12345/category/6789")
|
||||
let resource = FeedlyCategoryResourceID(id: "user/12345/category/6789")
|
||||
let parsedEntries = Set(entries.values.flatMap { $0 })
|
||||
let provider = TestParsedItemsProvider(resource: resource, parsedEntries: parsedEntries)
|
||||
|
||||
|
@ -92,7 +92,7 @@ class FeedlyOrganiseParsedItemsByFeedOperationTests: XCTestCase {
|
|||
|
||||
waitForExpectations(timeout: 2)
|
||||
|
||||
let itemsAndFeedIds = organise.parsedItemsKeyedByFeedId
|
||||
XCTAssertEqual(itemsAndFeedIds, entries)
|
||||
let itemsAndFeedIDs = organise.parsedItemsKeyedByFeedID
|
||||
XCTAssertEqual(itemsAndFeedIDs, entries)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// FeedlyResourceIdTests.swift
|
||||
// FeedlyResourceIDTests.swift
|
||||
// AccountTests
|
||||
//
|
||||
// Created by Kiel Gillard on 3/10/19.
|
||||
|
@ -9,15 +9,15 @@
|
|||
import XCTest
|
||||
@testable import Account
|
||||
|
||||
class FeedlyResourceIdTests: XCTestCase {
|
||||
class FeedlyResourceIDTests: XCTestCase {
|
||||
|
||||
func testFeedResourceId() {
|
||||
func testFeedResourceID() {
|
||||
let expectedUrl = "http://ranchero.com/blog/atom.xml"
|
||||
|
||||
let feedResource = FeedlyFeedResourceId(id: "feed/\(expectedUrl)")
|
||||
let urlResource = FeedlyFeedResourceId(id: expectedUrl)
|
||||
let otherResource = FeedlyFeedResourceId(id: "whiskey/\(expectedUrl)")
|
||||
let invalidResource = FeedlyFeedResourceId(id: "")
|
||||
let feedResource = FeedlyFeedResourceID(id: "feed/\(expectedUrl)")
|
||||
let urlResource = FeedlyFeedResourceID(id: expectedUrl)
|
||||
let otherResource = FeedlyFeedResourceID(id: "whiskey/\(expectedUrl)")
|
||||
let invalidResource = FeedlyFeedResourceID(id: "")
|
||||
|
||||
XCTAssertEqual(feedResource.url, expectedUrl)
|
||||
XCTAssertEqual(urlResource.url, expectedUrl)
|
||||
|
|
|
@ -46,8 +46,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testSendUnreadSuccess() {
|
||||
let articleIds = Set((0..<100).map { "feed/0/article/\($0)" })
|
||||
let statuses = articleIds.map { SyncStatus(articleID: $0, key: .read, flag: false) }
|
||||
let articleIDs = Set((0..<100).map { "feed/0/article/\($0)" })
|
||||
let statuses = articleIDs.map { SyncStatus(articleID: $0, key: .read, flag: false) }
|
||||
|
||||
let insertExpectation = expectation(description: "Inserted Statuses")
|
||||
container.database.insertStatuses(statuses) { error in
|
||||
|
@ -59,8 +59,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
|
|||
|
||||
let service = TestMarkArticlesService()
|
||||
service.mockResult = .success(())
|
||||
service.parameterTester = { serviceArticleIds, action in
|
||||
XCTAssertEqual(serviceArticleIds, articleIds)
|
||||
service.parameterTester = { serviceArticleIDs, action in
|
||||
XCTAssertEqual(serviceArticleIDs, articleIDs)
|
||||
XCTAssertEqual(action, .unread)
|
||||
}
|
||||
|
||||
|
@ -89,8 +89,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testSendUnreadFailure() {
|
||||
let articleIds = Set((0..<100).map { "feed/0/article/\($0)" })
|
||||
let statuses = articleIds.map { SyncStatus(articleID: $0, key: .read, flag: false) }
|
||||
let articleIDs = Set((0..<100).map { "feed/0/article/\($0)" })
|
||||
let statuses = articleIDs.map { SyncStatus(articleID: $0, key: .read, flag: false) }
|
||||
|
||||
let insertExpectation = expectation(description: "Inserted Statuses")
|
||||
container.database.insertStatuses(statuses) { error in
|
||||
|
@ -102,8 +102,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
|
|||
|
||||
let service = TestMarkArticlesService()
|
||||
service.mockResult = .failure(URLError(.timedOut))
|
||||
service.parameterTester = { serviceArticleIds, action in
|
||||
XCTAssertEqual(serviceArticleIds, articleIds)
|
||||
service.parameterTester = { serviceArticleIDs, action in
|
||||
XCTAssertEqual(serviceArticleIDs, articleIDs)
|
||||
XCTAssertEqual(action, .unread)
|
||||
}
|
||||
|
||||
|
@ -132,8 +132,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testSendReadSuccess() {
|
||||
let articleIds = Set((0..<100).map { "feed/0/article/\($0)" })
|
||||
let statuses = articleIds.map { SyncStatus(articleID: $0, key: .read, flag: true) }
|
||||
let articleIDs = Set((0..<100).map { "feed/0/article/\($0)" })
|
||||
let statuses = articleIDs.map { SyncStatus(articleID: $0, key: .read, flag: true) }
|
||||
|
||||
let insertExpectation = expectation(description: "Inserted Statuses")
|
||||
container.database.insertStatuses(statuses) { error in
|
||||
|
@ -145,8 +145,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
|
|||
|
||||
let service = TestMarkArticlesService()
|
||||
service.mockResult = .success(())
|
||||
service.parameterTester = { serviceArticleIds, action in
|
||||
XCTAssertEqual(serviceArticleIds, articleIds)
|
||||
service.parameterTester = { serviceArticleIDs, action in
|
||||
XCTAssertEqual(serviceArticleIDs, articleIDs)
|
||||
XCTAssertEqual(action, .read)
|
||||
}
|
||||
|
||||
|
@ -175,8 +175,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testSendReadFailure() {
|
||||
let articleIds = Set((0..<100).map { "feed/0/article/\($0)" })
|
||||
let statuses = articleIds.map { SyncStatus(articleID: $0, key: .read, flag: true) }
|
||||
let articleIDs = Set((0..<100).map { "feed/0/article/\($0)" })
|
||||
let statuses = articleIDs.map { SyncStatus(articleID: $0, key: .read, flag: true) }
|
||||
|
||||
let insertExpectation = expectation(description: "Inserted Statuses")
|
||||
container.database.insertStatuses(statuses) { error in
|
||||
|
@ -188,8 +188,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
|
|||
|
||||
let service = TestMarkArticlesService()
|
||||
service.mockResult = .failure(URLError(.timedOut))
|
||||
service.parameterTester = { serviceArticleIds, action in
|
||||
XCTAssertEqual(serviceArticleIds, articleIds)
|
||||
service.parameterTester = { serviceArticleIDs, action in
|
||||
XCTAssertEqual(serviceArticleIDs, articleIDs)
|
||||
XCTAssertEqual(action, .read)
|
||||
}
|
||||
|
||||
|
@ -218,8 +218,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testSendStarredSuccess() {
|
||||
let articleIds = Set((0..<100).map { "feed/0/article/\($0)" })
|
||||
let statuses = articleIds.map { SyncStatus(articleID: $0, key: .starred, flag: true) }
|
||||
let articleIDs = Set((0..<100).map { "feed/0/article/\($0)" })
|
||||
let statuses = articleIDs.map { SyncStatus(articleID: $0, key: .starred, flag: true) }
|
||||
|
||||
let insertExpectation = expectation(description: "Inserted Statuses")
|
||||
container.database.insertStatuses(statuses) { error in
|
||||
|
@ -231,8 +231,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
|
|||
|
||||
let service = TestMarkArticlesService()
|
||||
service.mockResult = .success(())
|
||||
service.parameterTester = { serviceArticleIds, action in
|
||||
XCTAssertEqual(serviceArticleIds, articleIds)
|
||||
service.parameterTester = { serviceArticleIDs, action in
|
||||
XCTAssertEqual(serviceArticleIDs, articleIDs)
|
||||
XCTAssertEqual(action, .saved)
|
||||
}
|
||||
|
||||
|
@ -261,8 +261,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testSendStarredFailure() {
|
||||
let articleIds = Set((0..<100).map { "feed/0/article/\($0)" })
|
||||
let statuses = articleIds.map { SyncStatus(articleID: $0, key: .starred, flag: true) }
|
||||
let articleIDs = Set((0..<100).map { "feed/0/article/\($0)" })
|
||||
let statuses = articleIDs.map { SyncStatus(articleID: $0, key: .starred, flag: true) }
|
||||
|
||||
let insertExpectation = expectation(description: "Inserted Statuses")
|
||||
container.database.insertStatuses(statuses) { error in
|
||||
|
@ -274,8 +274,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
|
|||
|
||||
let service = TestMarkArticlesService()
|
||||
service.mockResult = .failure(URLError(.timedOut))
|
||||
service.parameterTester = { serviceArticleIds, action in
|
||||
XCTAssertEqual(serviceArticleIds, articleIds)
|
||||
service.parameterTester = { serviceArticleIDs, action in
|
||||
XCTAssertEqual(serviceArticleIDs, articleIDs)
|
||||
XCTAssertEqual(action, .saved)
|
||||
}
|
||||
|
||||
|
@ -304,8 +304,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testSendUnstarredSuccess() {
|
||||
let articleIds = Set((0..<100).map { "feed/0/article/\($0)" })
|
||||
let statuses = articleIds.map { SyncStatus(articleID: $0, key: .starred, flag: false) }
|
||||
let articleIDs = Set((0..<100).map { "feed/0/article/\($0)" })
|
||||
let statuses = articleIDs.map { SyncStatus(articleID: $0, key: .starred, flag: false) }
|
||||
|
||||
let insertExpectation = expectation(description: "Inserted Statuses")
|
||||
container.database.insertStatuses(statuses) { error in
|
||||
|
@ -317,8 +317,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
|
|||
|
||||
let service = TestMarkArticlesService()
|
||||
service.mockResult = .success(())
|
||||
service.parameterTester = { serviceArticleIds, action in
|
||||
XCTAssertEqual(serviceArticleIds, articleIds)
|
||||
service.parameterTester = { serviceArticleIDs, action in
|
||||
XCTAssertEqual(serviceArticleIDs, articleIDs)
|
||||
XCTAssertEqual(action, .unsaved)
|
||||
}
|
||||
|
||||
|
@ -347,8 +347,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testSendUnstarredFailure() {
|
||||
let articleIds = Set((0..<100).map { "feed/0/article/\($0)" })
|
||||
let statuses = articleIds.map { SyncStatus(articleID: $0, key: .starred, flag: false) }
|
||||
let articleIDs = Set((0..<100).map { "feed/0/article/\($0)" })
|
||||
let statuses = articleIDs.map { SyncStatus(articleID: $0, key: .starred, flag: false) }
|
||||
|
||||
let insertExpectation = expectation(description: "Inserted Statuses")
|
||||
container.database.insertStatuses(statuses) { error in
|
||||
|
@ -360,8 +360,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
|
|||
|
||||
let service = TestMarkArticlesService()
|
||||
service.mockResult = .failure(URLError(.timedOut))
|
||||
service.parameterTester = { serviceArticleIds, action in
|
||||
XCTAssertEqual(serviceArticleIds, articleIds)
|
||||
service.parameterTester = { serviceArticleIDs, action in
|
||||
XCTAssertEqual(serviceArticleIDs, articleIDs)
|
||||
XCTAssertEqual(action, .unsaved)
|
||||
}
|
||||
|
||||
|
@ -390,13 +390,13 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testSendAllSuccess() {
|
||||
let articleIds = Set((0..<100).map { "feed/0/article/\($0)" })
|
||||
let articleIDs = Set((0..<100).map { "feed/0/article/\($0)" })
|
||||
let keys = [SyncStatus.Key.read, .starred]
|
||||
let flags = [true, false]
|
||||
let statuses = articleIds.map { articleId -> SyncStatus in
|
||||
let statuses = articleIDs.map { articleID -> SyncStatus in
|
||||
let key = keys.randomElement()!
|
||||
let flag = flags.randomElement()!
|
||||
let status = SyncStatus(articleID: articleId, key: key, flag: flag)
|
||||
let status = SyncStatus(articleID: articleID, key: key, flag: flag)
|
||||
return status
|
||||
}
|
||||
|
||||
|
@ -410,7 +410,7 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
|
|||
|
||||
let service = TestMarkArticlesService()
|
||||
service.mockResult = .success(())
|
||||
service.parameterTester = { serviceArticleIds, action in
|
||||
service.parameterTester = { serviceArticleIDs, action in
|
||||
let syncStatuses: [SyncStatus]
|
||||
switch action {
|
||||
case .read:
|
||||
|
@ -422,8 +422,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
|
|||
case .unsaved:
|
||||
syncStatuses = statuses.filter { $0.key == .starred && $0.flag == false }
|
||||
}
|
||||
let expectedArticleIds = Set(syncStatuses.map { $0.articleID })
|
||||
XCTAssertEqual(serviceArticleIds, expectedArticleIds)
|
||||
let expectedArticleIDs = Set(syncStatuses.map { $0.articleID })
|
||||
XCTAssertEqual(serviceArticleIDs, expectedArticleIDs)
|
||||
}
|
||||
let send = FeedlySendArticleStatusesOperation(database: container.database, service: service, log: support.log)
|
||||
|
||||
|
@ -450,13 +450,13 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testSendAllFailure() {
|
||||
let articleIds = Set((0..<100).map { "feed/0/article/\($0)" })
|
||||
let articleIDs = Set((0..<100).map { "feed/0/article/\($0)" })
|
||||
let keys = [SyncStatus.Key.read, .starred]
|
||||
let flags = [true, false]
|
||||
let statuses = articleIds.map { articleId -> SyncStatus in
|
||||
let statuses = articleIDs.map { articleID -> SyncStatus in
|
||||
let key = keys.randomElement()!
|
||||
let flag = flags.randomElement()!
|
||||
let status = SyncStatus(articleID: articleId, key: key, flag: flag)
|
||||
let status = SyncStatus(articleID: articleID, key: key, flag: flag)
|
||||
return status
|
||||
}
|
||||
|
||||
|
@ -470,7 +470,7 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
|
|||
|
||||
let service = TestMarkArticlesService()
|
||||
service.mockResult = .failure(URLError(.timedOut))
|
||||
service.parameterTester = { serviceArticleIds, action in
|
||||
service.parameterTester = { serviceArticleIDs, action in
|
||||
let syncStatuses: [SyncStatus]
|
||||
switch action {
|
||||
case .read:
|
||||
|
@ -482,8 +482,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
|
|||
case .unsaved:
|
||||
syncStatuses = statuses.filter { $0.key == .starred && $0.flag == false }
|
||||
}
|
||||
let expectedArticleIds = Set(syncStatuses.map { $0.articleID })
|
||||
XCTAssertEqual(serviceArticleIds, expectedArticleIds)
|
||||
let expectedArticleIDs = Set(syncStatuses.map { $0.articleID })
|
||||
XCTAssertEqual(serviceArticleIDs, expectedArticleIDs)
|
||||
}
|
||||
|
||||
let send = FeedlySendArticleStatusesOperation(database: container.database, service: service, log: support.log)
|
||||
|
|
|
@ -28,7 +28,7 @@ class FeedlySyncStreamContentsOperationTests: XCTestCase {
|
|||
|
||||
func testIngestsOnePageSuccess() throws {
|
||||
let service = TestGetStreamContentsService()
|
||||
let resource = FeedlyCategoryResourceId(id: "user/1234/category/5678")
|
||||
let resource = FeedlyCategoryResourceID(id: "user/1234/category/5678")
|
||||
let newerThan: Date? = Date(timeIntervalSinceReferenceDate: 0)
|
||||
let items = service.makeMockFeedlyEntryItem()
|
||||
service.mockResult = .success(FeedlyStream(id: resource.id, updated: nil, continuation: nil, items: items))
|
||||
|
@ -55,14 +55,14 @@ class FeedlySyncStreamContentsOperationTests: XCTestCase {
|
|||
|
||||
waitForExpectations(timeout: 2)
|
||||
|
||||
let expectedArticleIds = Set(items.map { $0.id })
|
||||
let expectedArticles = try account.fetchArticles(.articleIDs(expectedArticleIds))
|
||||
XCTAssertEqual(expectedArticles.count, expectedArticleIds.count, "Did not fetch all the articles.")
|
||||
let expectedArticleIDs = Set(items.map { $0.id })
|
||||
let expectedArticles = try account.fetchArticles(.articleIDs(expectedArticleIDs))
|
||||
XCTAssertEqual(expectedArticles.count, expectedArticleIDs.count, "Did not fetch all the articles.")
|
||||
}
|
||||
|
||||
func testIngestsOnePageFailure() {
|
||||
let service = TestGetStreamContentsService()
|
||||
let resource = FeedlyCategoryResourceId(id: "user/1234/category/5678")
|
||||
let resource = FeedlyCategoryResourceID(id: "user/1234/category/5678")
|
||||
let newerThan: Date? = Date(timeIntervalSinceReferenceDate: 0)
|
||||
|
||||
service.mockResult = .failure(URLError(.timedOut))
|
||||
|
@ -92,7 +92,7 @@ class FeedlySyncStreamContentsOperationTests: XCTestCase {
|
|||
|
||||
func testIngestsManyPagesSuccess() throws {
|
||||
let service = TestGetPagedStreamContentsService()
|
||||
let resource = FeedlyCategoryResourceId(id: "user/1234/category/5678")
|
||||
let resource = FeedlyCategoryResourceID(id: "user/1234/category/5678")
|
||||
let newerThan: Date? = Date(timeIntervalSinceReferenceDate: 0)
|
||||
|
||||
let continuations = (1...10).map { "\($0)" }
|
||||
|
@ -131,8 +131,8 @@ class FeedlySyncStreamContentsOperationTests: XCTestCase {
|
|||
waitForExpectations(timeout: 30)
|
||||
|
||||
// Find articles inserted.
|
||||
let articleIds = Set(service.pages.values.map { $0.items }.flatMap { $0 }.map { $0.id })
|
||||
let articles = try account.fetchArticles(.articleIDs(articleIds))
|
||||
XCTAssertEqual(articleIds.count, articles.count)
|
||||
let articleIDs = Set(service.pages.values.map { $0.items }.flatMap { $0 }.map { $0.id })
|
||||
let articles = try account.fetchArticles(.articleIDs(articleIDs))
|
||||
XCTAssertEqual(articleIDs.count, articles.count)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,18 +99,18 @@ class FeedlyTestSupport {
|
|||
func checkFoldersAndFeeds(in account: Account, againstCollectionsAndFeedsInJSONNamed name: String, subdirectory: String? = nil) {
|
||||
let collections = testJSON(named: name, subdirectory: subdirectory) as! [[String:Any]]
|
||||
let collectionNames = Set(collections.map { $0["label"] as! String })
|
||||
let collectionIds = Set(collections.map { $0["id"] as! String })
|
||||
let collectionIDs = Set(collections.map { $0["id"] as! String })
|
||||
|
||||
let folders = account.folders ?? Set()
|
||||
let folderNames = Set(folders.compactMap { $0.name })
|
||||
let folderIds = Set(folders.compactMap { $0.externalID })
|
||||
let folderIDs = Set(folders.compactMap { $0.externalID })
|
||||
|
||||
let missingNames = collectionNames.subtracting(folderNames)
|
||||
let missingIds = collectionIds.subtracting(folderIds)
|
||||
let missingIDs = collectionIDs.subtracting(folderIDs)
|
||||
|
||||
XCTAssertEqual(folders.count, collections.count, "Mismatch between collections and folders.")
|
||||
XCTAssertTrue(missingNames.isEmpty, "Collections with these names did not have a corresponding folder with the same name.")
|
||||
XCTAssertTrue(missingIds.isEmpty, "Collections with these ids did not have a corresponding folder with the same id.")
|
||||
XCTAssertTrue(missingIDs.isEmpty, "Collections with these ids did not have a corresponding folder with the same id.")
|
||||
|
||||
for collection in collections {
|
||||
checkSingleFolderAndFeeds(in: account, againstOneCollectionAndFeedsInJSONPayload: collection)
|
||||
|
@ -134,11 +134,11 @@ class FeedlyTestSupport {
|
|||
|
||||
XCTAssertEqual(collectionFeeds.count, folderFeeds.count)
|
||||
|
||||
let collectionFeedIds = Set(collectionFeeds.map { $0["id"] as! String })
|
||||
let folderFeedIds = Set(folderFeeds.map { $0.feedID })
|
||||
let missingFeedIds = collectionFeedIds.subtracting(folderFeedIds)
|
||||
let collectionFeedIDs = Set(collectionFeeds.map { $0["id"] as! String })
|
||||
let folderFeedIDs = Set(folderFeeds.map { $0.feedID })
|
||||
let missingFeedIDs = collectionFeedIDs.subtracting(folderFeedIDs)
|
||||
|
||||
XCTAssertTrue(missingFeedIds.isEmpty, "Feeds with these ids were not found in the \"\(label)\" folder.")
|
||||
XCTAssertTrue(missingFeedIDs.isEmpty, "Feeds with these ids were not found in the \"\(label)\" folder.")
|
||||
}
|
||||
|
||||
func checkArticles(in account: Account, againstItemsInStreamInJSONNamed name: String, subdirectory: String? = nil) throws {
|
||||
|
@ -152,7 +152,7 @@ class FeedlyTestSupport {
|
|||
|
||||
private struct ArticleItem {
|
||||
var id: String
|
||||
var feedId: String
|
||||
var feedID: String
|
||||
var content: String
|
||||
var JSON: [String: Any]
|
||||
var unread: Bool
|
||||
|
@ -177,7 +177,7 @@ class FeedlyTestSupport {
|
|||
self.id = item["id"] as! String
|
||||
|
||||
let origin = item["origin"] as! [String: Any]
|
||||
self.feedId = origin["streamId"] as! String
|
||||
self.feedID = origin["streamId"] as! String
|
||||
|
||||
let content = item["content"] as? [String: Any]
|
||||
let summary = item["summary"] as? [String: Any]
|
||||
|
@ -192,12 +192,12 @@ class FeedlyTestSupport {
|
|||
|
||||
let items = stream["items"] as! [[String: Any]]
|
||||
let articleItems = items.map { ArticleItem(item: $0) }
|
||||
let itemIds = Set(articleItems.map { $0.id })
|
||||
let itemIDs = Set(articleItems.map { $0.id })
|
||||
|
||||
let articles = try testAccount.fetchArticles(.articleIDs(itemIds))
|
||||
let articleIds = Set(articles.map { $0.articleID })
|
||||
let articles = try testAccount.fetchArticles(.articleIDs(itemIDs))
|
||||
let articleIDs = Set(articles.map { $0.articleID })
|
||||
|
||||
let missing = itemIds.subtracting(articleIds)
|
||||
let missing = itemIDs.subtracting(articleIDs)
|
||||
|
||||
XCTAssertEqual(items.count, articles.count)
|
||||
XCTAssertTrue(missing.isEmpty, "Items with these ids did not have a corresponding article with the same id.")
|
||||
|
@ -212,61 +212,61 @@ class FeedlyTestSupport {
|
|||
}
|
||||
}
|
||||
|
||||
func checkUnreadStatuses(in account: Account, againstIdsInStreamInJSONNamed name: String, subdirectory: String? = nil, testCase: XCTestCase) {
|
||||
let streamIds = testJSON(named: name, subdirectory: subdirectory) as! [String:Any]
|
||||
checkUnreadStatuses(in: account, correspondToIdsInJSONPayload: streamIds, testCase: testCase)
|
||||
func checkUnreadStatuses(in account: Account, againstIDsInStreamInJSONNamed name: String, subdirectory: String? = nil, testCase: XCTestCase) {
|
||||
let streadIDs = testJSON(named: name, subdirectory: subdirectory) as! [String:Any]
|
||||
checkUnreadStatuses(in: account, correspondToIDsInJSONPayload: streadIDs, testCase: testCase)
|
||||
}
|
||||
|
||||
func checkUnreadStatuses(in testAccount: Account, correspondToIdsInJSONPayload streamIds: [String: Any], testCase: XCTestCase) {
|
||||
let ids = Set(streamIds["ids"] as! [String])
|
||||
let fetchIdsExpectation = testCase.expectation(description: "Fetch Article Ids")
|
||||
testAccount.fetchUnreadArticleIDs { articleIdsResult in
|
||||
func checkUnreadStatuses(in testAccount: Account, correspondToIDsInJSONPayload streadIDs: [String: Any], testCase: XCTestCase) {
|
||||
let ids = Set(streadIDs["ids"] as! [String])
|
||||
let fetchIDsExpectation = testCase.expectation(description: "Fetch Article IDs")
|
||||
testAccount.fetchUnreadArticleIDs { articleIDsResult in
|
||||
do {
|
||||
let articleIds = try articleIdsResult.get()
|
||||
let articleIDs = try articleIDsResult.get()
|
||||
// Unread statuses can be paged from Feedly.
|
||||
// Instead of joining test data, the best we can do is
|
||||
// make sure that these ids are marked as unread (a subset of the total).
|
||||
XCTAssertTrue(ids.isSubset(of: articleIds), "Some articles in `ids` are not marked as unread.")
|
||||
fetchIdsExpectation.fulfill()
|
||||
XCTAssertTrue(ids.isSubset(of: articleIDs), "Some articles in `ids` are not marked as unread.")
|
||||
fetchIDsExpectation.fulfill()
|
||||
} catch {
|
||||
XCTFail("Error unwrapping article IDs: \(error)")
|
||||
}
|
||||
}
|
||||
testCase.wait(for: [fetchIdsExpectation], timeout: 2)
|
||||
testCase.wait(for: [fetchIDsExpectation], timeout: 2)
|
||||
}
|
||||
|
||||
func checkStarredStatuses(in account: Account, againstItemsInStreamInJSONNamed name: String, subdirectory: String? = nil, testCase: XCTestCase) {
|
||||
let streamIds = testJSON(named: name, subdirectory: subdirectory) as! [String:Any]
|
||||
checkStarredStatuses(in: account, correspondToStreamItemsIn: streamIds, testCase: testCase)
|
||||
let streadIDs = testJSON(named: name, subdirectory: subdirectory) as! [String:Any]
|
||||
checkStarredStatuses(in: account, correspondToStreamItemsIn: streadIDs, testCase: testCase)
|
||||
}
|
||||
|
||||
func checkStarredStatuses(in testAccount: Account, correspondToStreamItemsIn stream: [String: Any], testCase: XCTestCase) {
|
||||
let items = stream["items"] as! [[String: Any]]
|
||||
let ids = Set(items.map { $0["id"] as! String })
|
||||
let fetchIdsExpectation = testCase.expectation(description: "Fetch Article Ids")
|
||||
testAccount.fetchStarredArticleIDs { articleIdsResult in
|
||||
let fetchIDsExpectation = testCase.expectation(description: "Fetch Article Ids")
|
||||
testAccount.fetchStarredArticleIDs { articleIDsResult in
|
||||
do {
|
||||
let articleIds = try articleIdsResult.get()
|
||||
let articleIDs = try articleIDsResult.get()
|
||||
// Starred articles can be paged from Feedly.
|
||||
// Instead of joining test data, the best we can do is
|
||||
// make sure that these articles are marked as starred (a subset of the total).
|
||||
XCTAssertTrue(ids.isSubset(of: articleIds), "Some articles in `ids` are not marked as starred.")
|
||||
fetchIdsExpectation.fulfill()
|
||||
XCTAssertTrue(ids.isSubset(of: articleIDs), "Some articles in `ids` are not marked as starred.")
|
||||
fetchIDsExpectation.fulfill()
|
||||
} catch {
|
||||
XCTFail("Error unwrapping article IDs: \(error)")
|
||||
}
|
||||
}
|
||||
testCase.wait(for: [fetchIdsExpectation], timeout: 2)
|
||||
testCase.wait(for: [fetchIDsExpectation], timeout: 2)
|
||||
}
|
||||
|
||||
func check(_ entries: [FeedlyEntry], correspondToStreamItemsIn stream: [String: Any]) {
|
||||
|
||||
let items = stream["items"] as! [[String: Any]]
|
||||
let itemIds = Set(items.map { $0["id"] as! String })
|
||||
let itemIDs = Set(items.map { $0["id"] as! String })
|
||||
|
||||
let articleIds = Set(entries.map { $0.id })
|
||||
let articleIDs = Set(entries.map { $0.id })
|
||||
|
||||
let missing = itemIds.subtracting(articleIds)
|
||||
let missing = itemIDs.subtracting(articleIDs)
|
||||
|
||||
XCTAssertEqual(items.count, entries.count)
|
||||
XCTAssertTrue(missing.isEmpty, "Failed to create \(FeedlyEntry.self) values from objects in the JSON with these ids.")
|
||||
|
@ -274,9 +274,9 @@ class FeedlyTestSupport {
|
|||
|
||||
func makeParsedItemTestDataFor(numberOfFeeds: Int, numberOfItemsInFeeds: Int) -> [String: Set<ParsedItem>] {
|
||||
let ids = (0..<numberOfFeeds).map { "feed/\($0)" }
|
||||
let feedIdsAndItemCounts = ids.map { ($0, numberOfItemsInFeeds) }
|
||||
let feedIDsAndItemCounts = ids.map { ($0, numberOfItemsInFeeds) }
|
||||
|
||||
let entries = feedIdsAndItemCounts.map { (feedId, count) -> (String, [Int]) in
|
||||
let entries = feedIDsAndItemCounts.map { (feedId, count) -> (String, [Int]) in
|
||||
return (feedId, (0..<count).map { $0 })
|
||||
|
||||
}.map { pair -> (String, Set<ParsedItem>) in
|
||||
|
@ -300,7 +300,7 @@ class FeedlyTestSupport {
|
|||
attachments: nil)
|
||||
}
|
||||
return (pair.0, Set(items))
|
||||
}.reduce([String: Set<ParsedItem>](minimumCapacity: feedIdsAndItemCounts.count)) { (dict, pair) in
|
||||
}.reduce([String: Set<ParsedItem>](minimumCapacity: feedIDsAndItemCounts.count)) { (dict, pair) in
|
||||
var mutant = dict
|
||||
mutant[pair.0] = pair.1
|
||||
return mutant
|
||||
|
|
|
@ -11,11 +11,11 @@ import XCTest
|
|||
|
||||
final class TestGetPagedStreamContentsService: FeedlyGetStreamContentsService {
|
||||
|
||||
var parameterTester: ((FeedlyResourceId, String?, Date?, Bool?) -> ())?
|
||||
var parameterTester: ((FeedlyResourceID, String?, Date?, Bool?) -> ())?
|
||||
var getStreamContentsExpectation: XCTestExpectation?
|
||||
var pages = [String: FeedlyStream]()
|
||||
|
||||
func addAtLeastOnePage(for resource: FeedlyResourceId, continuations: [String], numberOfEntriesPerPage count: Int) {
|
||||
func addAtLeastOnePage(for resource: FeedlyResourceID, continuations: [String], numberOfEntriesPerPage count: Int) {
|
||||
pages = [String: FeedlyStream](minimumCapacity: continuations.count + 1)
|
||||
|
||||
// A continuation is an identifier for the next page.
|
||||
|
@ -31,7 +31,7 @@ final class TestGetPagedStreamContentsService: FeedlyGetStreamContentsService {
|
|||
}
|
||||
}
|
||||
|
||||
private func makeStreamContents(for resource: FeedlyResourceId, continuation: String?, between range: Range<Int>) -> FeedlyStream {
|
||||
private func makeStreamContents(for resource: FeedlyResourceID, continuation: String?, between range: Range<Int>) -> FeedlyStream {
|
||||
let entries = range.map { index -> FeedlyEntry in
|
||||
let content = FeedlyEntry.Content(content: "Content \(index)",
|
||||
direction: .leftToRight)
|
||||
|
@ -61,11 +61,11 @@ final class TestGetPagedStreamContentsService: FeedlyGetStreamContentsService {
|
|||
return stream
|
||||
}
|
||||
|
||||
static func getPagingKey(for stream: FeedlyResourceId, continuation: String?) -> String {
|
||||
static func getPagingKey(for stream: FeedlyResourceID, continuation: String?) -> String {
|
||||
return "\(stream.id)@\(continuation ?? "")"
|
||||
}
|
||||
|
||||
func getStreamContents(for resource: FeedlyResourceId, continuation: String?, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStream, Error>) -> ()) {
|
||||
func getStreamContents(for resource: FeedlyResourceID, continuation: String?, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStream, Error>) -> ()) {
|
||||
let key = TestGetPagedStreamContentsService.getPagingKey(for: resource, continuation: continuation)
|
||||
guard let page = pages[key] else {
|
||||
XCTFail("Missing page for \(resource.id) and continuation \(String(describing: continuation)). Test may time out because the completion will not be called.")
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// TestGetPagedStreamIdsService.swift
|
||||
// TestGetPagedStreadIDsService.swift
|
||||
// AccountTests
|
||||
//
|
||||
// Created by Kiel Gillard on 29/10/19.
|
||||
|
@ -9,14 +9,14 @@
|
|||
import XCTest
|
||||
@testable import Account
|
||||
|
||||
final class TestGetPagedStreamIdsService: FeedlyGetStreamIdsService {
|
||||
final class TestGetPagedStreadIDsService: FeedlyGetStreamIDsService {
|
||||
|
||||
var parameterTester: ((FeedlyResourceId, String?, Date?, Bool?) -> ())?
|
||||
var getStreamIdsExpectation: XCTestExpectation?
|
||||
var pages = [String: FeedlyStreamIds]()
|
||||
var parameterTester: ((FeedlyResourceID, String?, Date?, Bool?) -> ())?
|
||||
var getStreadIDsExpectation: XCTestExpectation?
|
||||
var pages = [String: FeedlyStreamIDs]()
|
||||
|
||||
func addAtLeastOnePage(for resource: FeedlyResourceId, continuations: [String], numberOfEntriesPerPage count: Int) {
|
||||
pages = [String: FeedlyStreamIds](minimumCapacity: continuations.count + 1)
|
||||
func addAtLeastOnePage(for resource: FeedlyResourceID, continuations: [String], numberOfEntriesPerPage count: Int) {
|
||||
pages = [String: FeedlyStreamIDs](minimumCapacity: continuations.count + 1)
|
||||
|
||||
// A continuation is an identifier for the next page.
|
||||
// The first page has a nil identifier.
|
||||
|
@ -25,24 +25,24 @@ final class TestGetPagedStreamIdsService: FeedlyGetStreamIdsService {
|
|||
for index in -1..<continuations.count {
|
||||
let nextIndex = index + 1
|
||||
let continuation: String? = nextIndex < continuations.count ? continuations[nextIndex] : nil
|
||||
let page = makeStreamIds(for: resource, continuation: continuation, between: 0..<count)
|
||||
let key = TestGetPagedStreamIdsService.getPagingKey(for: resource, continuation: index < 0 ? nil : continuations[index])
|
||||
let page = makeStreadIDs(for: resource, continuation: continuation, between: 0..<count)
|
||||
let key = TestGetPagedStreadIDsService.getPagingKey(for: resource, continuation: index < 0 ? nil : continuations[index])
|
||||
pages[key] = page
|
||||
}
|
||||
}
|
||||
|
||||
private func makeStreamIds(for resource: FeedlyResourceId, continuation: String?, between range: Range<Int>) -> FeedlyStreamIds {
|
||||
let entryIds = range.map { _ in UUID().uuidString }
|
||||
let stream = FeedlyStreamIds(continuation: continuation, ids: entryIds)
|
||||
private func makeStreadIDs(for resource: FeedlyResourceID, continuation: String?, between range: Range<Int>) -> FeedlyStreamIDs {
|
||||
let entryIDs = range.map { _ in UUID().uuidString }
|
||||
let stream = FeedlyStreamIDs(continuation: continuation, ids: entryIDs)
|
||||
return stream
|
||||
}
|
||||
|
||||
static func getPagingKey(for stream: FeedlyResourceId, continuation: String?) -> String {
|
||||
static func getPagingKey(for stream: FeedlyResourceID, continuation: String?) -> String {
|
||||
return "\(stream.id)@\(continuation ?? "")"
|
||||
}
|
||||
|
||||
func getStreamIds(for resource: FeedlyResourceId, continuation: String?, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStreamIds, Error>) -> ()) {
|
||||
let key = TestGetPagedStreamIdsService.getPagingKey(for: resource, continuation: continuation)
|
||||
func getStreamIDs(for resource: FeedlyResourceID, continuation: String?, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStreamIDs, Error>) -> ()) {
|
||||
let key = TestGetPagedStreadIDsService.getPagingKey(for: resource, continuation: continuation)
|
||||
guard let page = pages[key] else {
|
||||
XCTFail("Missing page for \(resource.id) and continuation \(String(describing: continuation)). Test may time out because the completion will not be called.")
|
||||
return
|
||||
|
@ -50,7 +50,7 @@ final class TestGetPagedStreamIdsService: FeedlyGetStreamIdsService {
|
|||
parameterTester?(resource, continuation, newerThan, unreadOnly)
|
||||
DispatchQueue.main.async {
|
||||
completion(.success(page))
|
||||
self.getStreamIdsExpectation?.fulfill()
|
||||
self.getStreadIDsExpectation?.fulfill()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,10 +12,10 @@ import XCTest
|
|||
final class TestGetStreamContentsService: FeedlyGetStreamContentsService {
|
||||
|
||||
var mockResult: Result<FeedlyStream, Error>?
|
||||
var parameterTester: ((FeedlyResourceId, String?, Date?, Bool?) -> ())?
|
||||
var parameterTester: ((FeedlyResourceID, String?, Date?, Bool?) -> ())?
|
||||
var getStreamContentsExpectation: XCTestExpectation?
|
||||
|
||||
func getStreamContents(for resource: FeedlyResourceId, continuation: String?, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStream, Error>) -> ()) {
|
||||
func getStreamContents(for resource: FeedlyResourceID, continuation: String?, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStream, Error>) -> ()) {
|
||||
guard let result = mockResult else {
|
||||
XCTFail("Missing mock result. Test may time out because the completion will not be called.")
|
||||
return
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// TestGetStreamIdsService.swift
|
||||
// TestGetStreadIDsService.swift
|
||||
// AccountTests
|
||||
//
|
||||
// Created by Kiel Gillard on 29/10/19.
|
||||
|
@ -9,13 +9,13 @@
|
|||
import XCTest
|
||||
@testable import Account
|
||||
|
||||
final class TestGetStreamIdsService: FeedlyGetStreamIdsService {
|
||||
final class TestGetStreadIDsService: FeedlyGetStreamIDsService {
|
||||
|
||||
var mockResult: Result<FeedlyStreamIds, Error>?
|
||||
var parameterTester: ((FeedlyResourceId, String?, Date?, Bool?) -> ())?
|
||||
var getStreamIdsExpectation: XCTestExpectation?
|
||||
var mockResult: Result<FeedlyStreamIDs, Error>?
|
||||
var parameterTester: ((FeedlyResourceID, String?, Date?, Bool?) -> ())?
|
||||
var getStreadIDsExpectation: XCTestExpectation?
|
||||
|
||||
func getStreamIds(for resource: FeedlyResourceId, continuation: String?, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStreamIds, Error>) -> ()) {
|
||||
func getStreamIDs(for resource: FeedlyResourceID, continuation: String?, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStreamIDs, Error>) -> ()) {
|
||||
guard let result = mockResult else {
|
||||
XCTFail("Missing mock result. Test may time out because the completion will not be called.")
|
||||
return
|
||||
|
@ -23,7 +23,7 @@ final class TestGetStreamIdsService: FeedlyGetStreamIdsService {
|
|||
parameterTester?(resource, continuation, newerThan, unreadOnly)
|
||||
DispatchQueue.main.async {
|
||||
completion(result)
|
||||
self.getStreamIdsExpectation?.fulfill()
|
||||
self.getStreadIDsExpectation?.fulfill()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,10 +15,10 @@ class TestMarkArticlesService: FeedlyMarkArticlesService {
|
|||
var parameterTester: ((Set<String>, FeedlyMarkAction) -> ())?
|
||||
var mockResult: Result<Void, Error> = .success(())
|
||||
|
||||
func mark(_ articleIds: Set<String>, as action: FeedlyMarkAction, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
func mark(_ articleIDs: Set<String>, as action: FeedlyMarkAction, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.parameterTester?(articleIds, action)
|
||||
self.parameterTester?(articleIDs, action)
|
||||
completion(self.mockResult)
|
||||
self.didMarkExpectation?.fulfill()
|
||||
}
|
||||
|
|
|
@ -108,7 +108,7 @@ class AccountsNewsBlurWindowController: NSWindowController {
|
|||
|
||||
do {
|
||||
try self.account?.removeCredentials(type: .newsBlurBasic)
|
||||
try self.account?.removeCredentials(type: .newsBlurSessionId)
|
||||
try self.account?.removeCredentials(type: .newsBlurSessionID)
|
||||
try self.account?.storeCredentials(credentials)
|
||||
try self.account?.storeCredentials(validatedCredentials)
|
||||
|
||||
|
|
|
@ -122,10 +122,10 @@ import Core
|
|||
|
||||
@objc(valueInFoldersWithUniqueID:)
|
||||
func valueInFolders(withUniqueID id:NSNumber) -> ScriptableFolder? {
|
||||
let folderId = id.intValue
|
||||
let folderID = id.intValue
|
||||
let foldersSet = account.folders ?? Set<Folder>()
|
||||
let folders = Array(foldersSet)
|
||||
guard let folder = folders.first(where:{$0.folderID == folderId}) else { return nil }
|
||||
guard let folder = folders.first(where:{$0.folderID == folderID}) else { return nil }
|
||||
return ScriptableFolder(folder, container:self)
|
||||
}
|
||||
|
||||
|
|
|
@ -30,9 +30,9 @@ extension ScriptingObjectContainer {
|
|||
let containerClassDescription = self.scriptingClassDescription
|
||||
let containerScriptObjectSpecifier = self.objectSpecifier
|
||||
let scriptingKey = object.scriptingKey
|
||||
let uniqueId = object.scriptingUniqueId
|
||||
let uniqueID = object.scriptingUniqueId
|
||||
let specifier = NSUniqueIDSpecifier(containerClassDescription:containerClassDescription,
|
||||
containerSpecifier:containerScriptObjectSpecifier, key:scriptingKey, uniqueID: uniqueId)
|
||||
containerSpecifier:containerScriptObjectSpecifier, key:scriptingKey, uniqueID: uniqueID)
|
||||
return specifier
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ import Secrets
|
|||
|
||||
let cookies = HTTPCookie.cookies(withResponseHeaderFields: headerFields, for: url)
|
||||
for cookie in cookies where cookie.name == Self.sessionIDCookieKey {
|
||||
let credentials = Credentials(type: .newsBlurSessionId, username: username, secret: cookie.value)
|
||||
let credentials = Credentials(type: .newsBlurSessionID, username: username, secret: cookie.value)
|
||||
completion(.success(credentials))
|
||||
return
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ public extension URLRequest {
|
|||
}
|
||||
|
||||
let credentialsType = credentials.type
|
||||
precondition(credentialsType == .newsBlurBasic || credentialsType == .newsBlurSessionId)
|
||||
precondition(credentialsType == .newsBlurBasic || credentialsType == .newsBlurSessionID)
|
||||
|
||||
if credentialsType == .newsBlurBasic {
|
||||
|
||||
|
@ -34,7 +34,7 @@ public extension URLRequest {
|
|||
]
|
||||
httpBody = postData.enhancedPercentEncodedQuery?.data(using: .utf8)
|
||||
|
||||
} else if credentialsType == .newsBlurSessionId {
|
||||
} else if credentialsType == .newsBlurSessionID {
|
||||
|
||||
setValue("\(NewsBlurAPICaller.sessionIDCookieKey)=\(credentials.secret)", forHTTPHeaderField: "Cookie")
|
||||
httpShouldHandleCookies = true
|
||||
|
|
|
@ -64,7 +64,7 @@ public enum CreateReaderAPISubscriptionResult: Sendable {
|
|||
case subscriptionEdit = "/reader/api/0/subscription/edit"
|
||||
case subscriptionAdd = "/reader/api/0/subscription/quickadd"
|
||||
case contents = "/reader/api/0/stream/items/contents"
|
||||
case itemIds = "/reader/api/0/stream/items/ids"
|
||||
case itemIDs = "/reader/api/0/stream/items/ids"
|
||||
case editTag = "/reader/api/0/edit-tag"
|
||||
}
|
||||
|
||||
|
@ -452,7 +452,7 @@ public enum CreateReaderAPISubscriptionResult: Sendable {
|
|||
}
|
||||
|
||||
let url = baseURL
|
||||
.appendingPathComponent(ReaderAPIEndpoints.itemIds.rawValue)
|
||||
.appendingPathComponent(ReaderAPIEndpoints.itemIDs.rawValue)
|
||||
.appendingQueryItems(queryItems)
|
||||
|
||||
guard let callURL = url else {
|
||||
|
|
|
@ -16,7 +16,7 @@ public enum CredentialsError: Error, Sendable {
|
|||
public enum CredentialsType: String, Sendable {
|
||||
case basic = "password"
|
||||
case newsBlurBasic = "newsBlurBasic"
|
||||
case newsBlurSessionId = "newsBlurSessionId"
|
||||
case newsBlurSessionID = "newsBlurSessionId"
|
||||
case readerBasic = "readerBasic"
|
||||
case readerAPIKey = "readerAPIKey"
|
||||
case oauthAccessToken = "oauthAccessToken"
|
||||
|
|
|
@ -159,17 +159,17 @@ import CoreSpotlight
|
|||
#endif
|
||||
|
||||
@objc func feedIconDidBecomeAvailable(_ note: Notification) {
|
||||
guard let feed = note.userInfo?[UserInfoKey.feed] as? Feed, let activityFeedId = selectingActivity?.userInfo?[ArticlePathKey.feedID] as? String else {
|
||||
guard let feed = note.userInfo?[UserInfoKey.feed] as? Feed, let activityFeedID = selectingActivity?.userInfo?[ArticlePathKey.feedID] as? String else {
|
||||
return
|
||||
}
|
||||
|
||||
#if os(iOS)
|
||||
if let article = readingArticle, activityFeedId == article.feedID {
|
||||
if let article = readingArticle, activityFeedID == article.feedID {
|
||||
updateReadArticleSearchAttributes(with: article)
|
||||
}
|
||||
#endif
|
||||
|
||||
if activityFeedId == feed.feedID {
|
||||
if activityFeedID == feed.feedID {
|
||||
updateSelectingActivityFeedSearchAttributes(with: feed)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,11 +39,11 @@ class SharingTests: XCTestCase {
|
|||
}
|
||||
|
||||
private func article(titled title: String) -> Article {
|
||||
let articleId = randomId()
|
||||
return Article(accountID: randomId(),
|
||||
articleID: articleId,
|
||||
feedID: randomId(),
|
||||
uniqueID: randomId(),
|
||||
let articleID = randomID()
|
||||
return Article(accountID: randomID(),
|
||||
articleID: articleID,
|
||||
feedID: randomID(),
|
||||
uniqueID: randomID(),
|
||||
title: title,
|
||||
contentHTML: nil,
|
||||
contentText: nil,
|
||||
|
@ -54,11 +54,11 @@ class SharingTests: XCTestCase {
|
|||
datePublished: nil,
|
||||
dateModified: nil,
|
||||
authors: nil,
|
||||
status: ArticleStatus(articleID: articleId, read: true, dateArrived: Date())
|
||||
status: ArticleStatus(articleID: articleID, read: true, dateArrived: Date())
|
||||
)
|
||||
}
|
||||
|
||||
private func randomId() -> String {
|
||||
private func randomID() -> String {
|
||||
return UUID().uuidString
|
||||
}
|
||||
|
||||
|
|
|
@ -137,7 +137,7 @@ class NewsBlurAccountViewController: UITableViewController {
|
|||
do {
|
||||
|
||||
try self.account?.removeCredentials(type: .newsBlurBasic)
|
||||
try self.account?.removeCredentials(type: .newsBlurSessionId)
|
||||
try self.account?.removeCredentials(type: .newsBlurSessionID)
|
||||
try self.account?.storeCredentials(credentials)
|
||||
try self.account?.storeCredentials(validatedCredentials)
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ struct SidebarItemNode: Hashable {
|
|||
private var lastSearchScope: SearchScope? = nil
|
||||
private var isSearching: Bool = false
|
||||
private var savedSearchArticles: ArticleArray? = nil
|
||||
private var savedSearchArticleIds: Set<String>? = nil
|
||||
private var savedSearchArticleIDs: Set<String>? = nil
|
||||
|
||||
private(set) var sortDirection = AppDefaults.shared.timelineSortDirection {
|
||||
didSet {
|
||||
|
@ -869,7 +869,7 @@ struct SidebarItemNode: Hashable {
|
|||
isSearching = true
|
||||
preSearchTimelineFeed = timelineFeed
|
||||
savedSearchArticles = articles
|
||||
savedSearchArticleIds = Set(articles.map { $0.articleID })
|
||||
savedSearchArticleIDs = Set(articles.map { $0.articleID })
|
||||
setTimelineFeed(nil, animated: true)
|
||||
selectArticle(nil)
|
||||
}
|
||||
|
@ -887,7 +887,7 @@ struct SidebarItemNode: Hashable {
|
|||
lastSearchString = ""
|
||||
lastSearchScope = nil
|
||||
preSearchTimelineFeed = nil
|
||||
savedSearchArticleIds = nil
|
||||
savedSearchArticleIDs = nil
|
||||
savedSearchArticles = nil
|
||||
isSearching = false
|
||||
selectArticle(nil)
|
||||
|
@ -909,7 +909,7 @@ struct SidebarItemNode: Hashable {
|
|||
case .global:
|
||||
setTimelineFeed(SmartFeed(delegate: SearchFeedDelegate(searchString: searchString)), animated: true)
|
||||
case .timeline:
|
||||
setTimelineFeed(SmartFeed(delegate: SearchTimelineFeedDelegate(searchString: searchString, articleIDs: savedSearchArticleIds!)), animated: true)
|
||||
setTimelineFeed(SmartFeed(delegate: SearchTimelineFeedDelegate(searchString: searchString, articleIDs: savedSearchArticleIDs!)), animated: true)
|
||||
}
|
||||
|
||||
lastSearchString = searchString
|
||||
|
|
|
@ -34,9 +34,9 @@ extension UIStoryboard {
|
|||
|
||||
func instantiateController<T>(ofType type: T.Type = T.self) -> T where T: UIViewController {
|
||||
|
||||
let storyboardId = String(describing: type)
|
||||
guard let viewController = instantiateViewController(withIdentifier: storyboardId) as? T else {
|
||||
print("Unable to load view with Scene Identifier: \(storyboardId)")
|
||||
let storyboardID = String(describing: type)
|
||||
guard let viewController = instantiateViewController(withIdentifier: storyboardID) as? T else {
|
||||
print("Unable to load view with Scene Identifier: \(storyboardID)")
|
||||
fatalError()
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue