diff --git a/Frameworks/Account/CloudKit/CloudKitAccountDelegate.swift b/Frameworks/Account/CloudKit/CloudKitAccountDelegate.swift index ca7ce0c0c..276ac113d 100644 --- a/Frameworks/Account/CloudKit/CloudKitAccountDelegate.swift +++ b/Frameworks/Account/CloudKit/CloudKitAccountDelegate.swift @@ -8,6 +8,7 @@ import Foundation import CloudKit +import SystemConfiguration import os.log import SyncDatabase import RSCore @@ -84,7 +85,14 @@ final class CloudKitAccountDelegate: AccountDelegate { return } - refreshAll(for: account, downloadFeeds: true, completion: completion) + let reachability = SCNetworkReachabilityCreateWithName(nil, "apple.com") + var flags = SCNetworkReachabilityFlags() + guard SCNetworkReachabilityGetFlags(reachability!, &flags), flags.contains(.reachable) else { + completion(.success(())) + return + } + + standardRefreshAll(for: account, completion: completion) } func sendArticleStatus(for account: Account, completion: @escaping ((Result) -> Void)) { @@ -194,25 +202,10 @@ final class CloudKitAccountDelegate: AccountDelegate { let normalizedItems = OPMLNormalizer.normalize(opmlItems) - // Combine all existing web feed URLs with all the new ones - - var webFeedURLs = account.flattenedWebFeedURLs - for opmlItem in normalizedItems { - if let webFeedURL = opmlItem.feedSpecifier?.feedURL { - webFeedURLs.insert(webFeedURL) - } else { - if let childItems = opmlItem.children { - for childItem in childItems { - if let webFeedURL = childItem.feedSpecifier?.feedURL { - webFeedURLs.insert(webFeedURL) - } - } - } - } - } + // TODO: remove duplicates created by import self.accountZone.importOPML(rootExternalID: rootExternalID, items: normalizedItems) { _ in - self.refreshAll(for: account, downloadFeeds: false, completion: completion) + self.initialRefreshAll(for: account, completion: completion) } } @@ -490,7 +483,7 @@ final class CloudKitAccountDelegate: AccountDelegate { switch result { case .success(let externalID): account.externalID = externalID - self.refreshAll(for: account, downloadFeeds: false) { _ in } + self.initialRefreshAll(for: account) { _ in } case .failure(let error): os_log(.error, log: self.log, "Error adding account container: %@", error.localizedDescription) } @@ -530,9 +523,49 @@ final class CloudKitAccountDelegate: AccountDelegate { private extension CloudKitAccountDelegate { - func refreshAll(for account: Account, downloadFeeds: Bool, completion: @escaping (Result) -> Void) { + func initialRefreshAll(for account: Account, completion: @escaping (Result) -> Void) { - let intialWebFeedsCount = downloadFeeds ? account.flattenedWebFeeds().count : 0 + func fail(_ error: Error) { + self.processAccountError(account, error) + self.refreshProgress.clear() + completion(.failure(error)) + } + + refreshProgress.addToNumberOfTasksAndRemaining(3) + refreshArticleStatus(for: account) { result in + switch result { + case .success: + + self.refreshProgress.completeTask() + self.accountZone.fetchChangesInZone() { result in + switch result { + case .success: + + self.refreshProgress.completeTask() + self.sendArticleStatus(for: account) { result in + switch result { + case .success: + self.refreshProgress.completeTask() + completion(.success(())) + case .failure(let error): + fail(error) + } + } + + case .failure(let error): + fail(error) + } + } + case .failure(let error): + fail(error) + } + } + + } + + func standardRefreshAll(for account: Account, completion: @escaping (Result) -> Void) { + + let intialWebFeedsCount = account.flattenedWebFeeds().count refreshProgress.addToNumberOfTasksAndRemaining(3 + intialWebFeedsCount) func fail(_ error: Error) { @@ -541,16 +574,12 @@ private extension CloudKitAccountDelegate { completion(.failure(error)) } - BatchUpdate.shared.start() accountZone.fetchChangesInZone() { result in - BatchUpdate.shared.end() switch result { case .success: let webFeeds = account.flattenedWebFeeds() - if downloadFeeds { - self.refreshProgress.addToNumberOfTasksAndRemaining(webFeeds.count - intialWebFeedsCount) - } + self.refreshProgress.addToNumberOfTasksAndRemaining(webFeeds.count - intialWebFeedsCount) self.refreshProgress.completeTask() self.sendArticleStatus(for: account) { result in @@ -564,11 +593,6 @@ private extension CloudKitAccountDelegate { self.refreshProgress.completeTask() - guard downloadFeeds else { - completion(.success(())) - return - } - self.refresher.refreshFeeds(webFeeds) { account.metadata.lastArticleFetchEndTime = Date() diff --git a/Frameworks/Account/CloudKit/CloudKitAccountZone.swift b/Frameworks/Account/CloudKit/CloudKitAccountZone.swift index e9d73bcff..69ff6bef2 100644 --- a/Frameworks/Account/CloudKit/CloudKitAccountZone.swift +++ b/Frameworks/Account/CloudKit/CloudKitAccountZone.swift @@ -247,24 +247,10 @@ final class CloudKitAccountZone: CloudKitZone { } } default: - DispatchQueue.main.async { - completion(.failure(CloudKitError(error!))) - } - } - } - - query(ckQuery) { result in - switch result { - case .success(let records): - if records.count > 0 { - completion(.success(records[0].externalID)) - } else { - self.createContainer(name: "Account", isAccount: true, completion: completion) - } - case .failure: self.createContainer(name: "Account", isAccount: true, completion: completion) } } + } func createFolder(name: String, completion: @escaping (Result) -> Void) { diff --git a/Frameworks/Account/CloudKit/CloudKitAccountZoneDelegate.swift b/Frameworks/Account/CloudKit/CloudKitAccountZoneDelegate.swift index 6ab4004fa..8415bd5d0 100644 --- a/Frameworks/Account/CloudKit/CloudKitAccountZoneDelegate.swift +++ b/Frameworks/Account/CloudKit/CloudKitAccountZoneDelegate.swift @@ -26,54 +26,77 @@ class CloudKitAcountZoneDelegate: CloudKitZoneDelegate { self.refreshProgress = refreshProgress } - func cloudKitDidChange(record: CKRecord) { - switch record.recordType { - case CloudKitAccountZone.CloudKitWebFeed.recordType: - addOrUpdateWebFeed(record) - case CloudKitAccountZone.CloudKitContainer.recordType: - addOrUpdateContainer(record) - default: - assertionFailure("Unknown record type: \(record.recordType)") - } - } - - func cloudKitDidDelete(recordKey: CloudKitRecordKey) { - switch recordKey.recordType { - case CloudKitAccountZone.CloudKitWebFeed.recordType: - removeWebFeed(recordKey.recordID.externalID) - case CloudKitAccountZone.CloudKitContainer.recordType: - removeContainer(recordKey.recordID.externalID) - default: - assertionFailure("Unknown record type: \(recordKey.recordType)") - } - } - func cloudKitDidModify(changed: [CKRecord], deleted: [CloudKitRecordKey], completion: @escaping (Result) -> Void) { - completion(.success(())) + for deletedRecordKey in deleted { + switch deletedRecordKey.recordType { + case CloudKitAccountZone.CloudKitWebFeed.recordType: + removeWebFeed(deletedRecordKey.recordID.externalID) + case CloudKitAccountZone.CloudKitContainer.recordType: + removeContainer(deletedRecordKey.recordID.externalID) + default: + assertionFailure("Unknown record type: \(deletedRecordKey.recordType)") + } + } + + let group = DispatchGroup() + + for changedRecord in changed { + switch changedRecord.recordType { + case CloudKitAccountZone.CloudKitWebFeed.recordType: + group.enter() + addOrUpdateWebFeed(changedRecord) { + group.leave() + } + case CloudKitAccountZone.CloudKitContainer.recordType: + group.enter() + addOrUpdateContainer(changedRecord) { + group.leave() + } + default: + assertionFailure("Unknown record type: \(changedRecord.recordType)") + } + } + + group.notify(queue: DispatchQueue.main) { + completion(.success(())) + } } - func addOrUpdateWebFeed(_ record: CKRecord) { + func addOrUpdateWebFeed(_ record: CKRecord, completion: @escaping () -> Void) { guard let account = account, let urlString = record[CloudKitAccountZone.CloudKitWebFeed.Fields.url] as? String, let containerExternalIDs = record[CloudKitAccountZone.CloudKitWebFeed.Fields.containerExternalIDs] as? [String], - let url = URL(string: urlString) else { return } + let url = URL(string: urlString) else { + completion() + return + } let editedName = record[CloudKitAccountZone.CloudKitWebFeed.Fields.editedName] as? String if let webFeed = account.existingWebFeed(withExternalID: record.externalID) { + updateWebFeed(webFeed, editedName: editedName, containerExternalIDs: containerExternalIDs) + completion() + } else { - var webFeed: WebFeed? = nil + + let group = DispatchGroup() for containerExternalID in containerExternalIDs { + group.enter() if let container = account.existingContainer(withExternalID: containerExternalID) { - if webFeed == nil { - webFeed = createWebFeed(url: url, editedName: editedName, webFeedExternalID: record.externalID) + createWebFeedIfNecessary(url: url, editedName: editedName, webFeedExternalID: record.externalID, container: container) { webFeed in + group.leave() } - container.addWebFeed(webFeed!) } else { addUnclaimedWebFeed(url: url, editedName: editedName, webFeedExternalID: record.externalID, containerExternalID: containerExternalID) + group.leave() } } + + group.notify(queue: DispatchQueue.main) { + completion() + } + } } @@ -83,11 +106,14 @@ class CloudKitAcountZoneDelegate: CloudKitZoneDelegate { } } - func addOrUpdateContainer(_ record: CKRecord) { + func addOrUpdateContainer(_ record: CKRecord, completion: @escaping () -> Void) { guard let account = account, let name = record[CloudKitAccountZone.CloudKitContainer.Fields.name] as? String, let isAccount = record[CloudKitAccountZone.CloudKitContainer.Fields.isAccount] as? String, - isAccount != "1" else { return } + isAccount != "1" else { + completion() + return + } var folder = account.existingFolder(withExternalID: record.externalID) folder?.name = name @@ -98,16 +124,25 @@ class CloudKitAcountZoneDelegate: CloudKitZoneDelegate { } if let folder = folder, let containerExternalID = folder.externalID, let unclaimedWebFeeds = unclaimedWebFeeds[containerExternalID] { + + let group = DispatchGroup() + for unclaimedWebFeed in unclaimedWebFeeds { - var webFeed = account.existingWebFeed(withExternalID: unclaimedWebFeed.webFeedExternalID) - if webFeed == nil { - webFeed = createWebFeed(url: unclaimedWebFeed.url, editedName: unclaimedWebFeed.editedName, webFeedExternalID: unclaimedWebFeed.webFeedExternalID) - } - if let webFeed = webFeed { - folder.addWebFeed(webFeed) + group.enter() + createWebFeedIfNecessary(url: unclaimedWebFeed.url, editedName: unclaimedWebFeed.editedName, webFeedExternalID: unclaimedWebFeed.webFeedExternalID, container: folder) { webFeed in + group.leave() } } - self.unclaimedWebFeeds.removeValue(forKey: containerExternalID) + + group.notify(queue: DispatchQueue.main) { + self.unclaimedWebFeeds.removeValue(forKey: containerExternalID) + completion() + } + + } else { + + completion() + } } @@ -144,22 +179,31 @@ private extension CloudKitAcountZoneDelegate { } } - func createWebFeed(url: URL, editedName: String?, webFeedExternalID: String) -> WebFeed? { - guard let account = account else { return nil } + func createWebFeedIfNecessary(url: URL, editedName: String?, webFeedExternalID: String, container: Container, completion: @escaping (WebFeed) -> Void) { + guard let account = account else { return } + + if let webFeed = account.existingWebFeed(withExternalID: webFeedExternalID) { + completion(webFeed) + return + } let webFeed = account.createWebFeed(with: editedName, url: url.absoluteString, webFeedID: url.absoluteString, homePageURL: nil) webFeed.editedName = editedName webFeed.externalID = webFeedExternalID + container.addWebFeed(webFeed) refreshProgress?.addToNumberOfTasksAndRemaining(1) InitialFeedDownloader.download(url) { parsedFeed in self.refreshProgress?.completeTask() if let parsedFeed = parsedFeed { - account.update(webFeed, with: parsedFeed, {_ in }) + account.update(webFeed, with: parsedFeed, { _ in + completion(webFeed) + }) + } else { + completion(webFeed) } } - return webFeed } func addUnclaimedWebFeed(url: URL, editedName: String?, webFeedExternalID: String, containerExternalID: String) { diff --git a/Frameworks/Account/CloudKit/CloudKitArticlesZoneDelegate.swift b/Frameworks/Account/CloudKit/CloudKitArticlesZoneDelegate.swift index 1e1ed466c..a5c1baf3e 100644 --- a/Frameworks/Account/CloudKit/CloudKitArticlesZoneDelegate.swift +++ b/Frameworks/Account/CloudKit/CloudKitArticlesZoneDelegate.swift @@ -37,14 +37,6 @@ class CloudKitArticlesZoneDelegate: CloudKitZoneDelegate { self.refreshProgress = refreshProgress } - func cloudKitDidChange(record: CKRecord) { - - } - - func cloudKitDidDelete(recordKey: CloudKitRecordKey) { - // Article downloads clean up old articles and statuses - } - func cloudKitDidModify(changed: [CKRecord], deleted: [CloudKitRecordKey], completion: @escaping (Result) -> Void) { database.selectPendingReadStatusArticleIDs() { result in @@ -118,8 +110,13 @@ private extension CloudKitArticlesZoneDelegate { webFeeds.forEach { $0.dropConditionalGetInfo() } self.refreshProgress?.addToNumberOfTasksAndRemaining(webFeeds.count) - self.refresher.refreshFeeds(webFeeds) { + + if webFeeds.isEmpty { group.leave() + } else { + self.refresher.refreshFeeds(webFeeds) { + group.leave() + } } } diff --git a/Frameworks/Account/CloudKit/CloudKitZone.swift b/Frameworks/Account/CloudKit/CloudKitZone.swift index ee3f45474..c87a676ac 100644 --- a/Frameworks/Account/CloudKit/CloudKitZone.swift +++ b/Frameworks/Account/CloudKit/CloudKitZone.swift @@ -25,8 +25,6 @@ enum CloudKitZoneError: LocalizedError { } protocol CloudKitZoneDelegate: class { - func cloudKitDidChange(record: CKRecord); - func cloudKitDidDelete(recordKey: CloudKitRecordKey) func cloudKitDidModify(changed: [CKRecord], deleted: [CloudKitRecordKey], completion: @escaping (Result) -> Void); } @@ -492,24 +490,13 @@ extension CloudKitZone { } } - op.recordChangedBlock = { [weak self] record in - guard let self = self else { return } - + op.recordChangedBlock = { record in changedRecords.append(record) - DispatchQueue.main.async { - self.delegate?.cloudKitDidChange(record: record) - } } - op.recordWithIDWasDeletedBlock = { [weak self] recordID, recordType in - guard let self = self else { return } - + op.recordWithIDWasDeletedBlock = { recordID, recordType in let recordKey = CloudKitRecordKey(recordType: recordType, recordID: recordID) deletedRecordKeys.append(recordKey) - - DispatchQueue.main.async { - self.delegate?.cloudKitDidDelete(recordKey: recordKey) - } } op.recordZoneFetchCompletionBlock = { [weak self] zoneID ,token, _, _, error in diff --git a/Frameworks/Account/FeedIdentifier.swift b/Frameworks/Account/FeedIdentifier.swift index eed0a7555..842963e74 100644 --- a/Frameworks/Account/FeedIdentifier.swift +++ b/Frameworks/Account/FeedIdentifier.swift @@ -85,12 +85,16 @@ public enum FeedIdentifier: CustomStringConvertible, Hashable { public func hash(into hasher: inout Hasher) { switch self { case .smartFeed(let id): + hasher.combine("smartFeed") hasher.combine(id) case .script(let id): + hasher.combine("smartFeed") hasher.combine(id) case .webFeed(_, let webFeedID): + hasher.combine("webFeed") hasher.combine(webFeedID) case .folder(_, let folderName): + hasher.combine("folder") hasher.combine(folderName) } } diff --git a/Frameworks/Account/OPMLNormalizer.swift b/Frameworks/Account/OPMLNormalizer.swift index dee350ee3..77f6ee54b 100644 --- a/Frameworks/Account/OPMLNormalizer.swift +++ b/Frameworks/Account/OPMLNormalizer.swift @@ -25,7 +25,7 @@ final class OPMLNormalizer { items.forEach { (item) in if let _ = item.feedSpecifier { - if !feedsToAdd.contains(where: { $0.feedSpecifier?.feedURL == item.feedSpecifier?.feedURL } ) { + if !feedsToAdd.contains(where: { $0.feedSpecifier?.feedURL == item.feedSpecifier?.feedURL }) { feedsToAdd.append(item) } return @@ -39,15 +39,21 @@ final class OPMLNormalizer { return } - normalizedOPMLItems.append(item) + feedsToAdd.append(item) if let itemChildren = item.children { - normalize(itemChildren, parentFolder: item) + if let parentFolder = parentFolder { + normalize(itemChildren, parentFolder: parentFolder) + } else { + normalize(itemChildren, parentFolder: item) + } } } if let parentFolder = parentFolder { for feed in feedsToAdd { - parentFolder.addChild(feed) + if !(parentFolder.children?.contains(where: { $0.feedSpecifier?.feedURL == feed.feedSpecifier?.feedURL}) ?? false) { + parentFolder.addChild(feed) + } } } else { for feed in feedsToAdd { diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index cfe77b8a8..1ffab33cd 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -122,6 +122,7 @@ 517630042336215100E15FFF /* main.js in Resources */ = {isa = PBXBuildFile; fileRef = 517630032336215100E15FFF /* main.js */; }; 517630052336215100E15FFF /* main.js in Resources */ = {isa = PBXBuildFile; fileRef = 517630032336215100E15FFF /* main.js */; }; 517630232336657E00E15FFF /* WebViewProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 517630222336657E00E15FFF /* WebViewProvider.swift */; }; + 517A745B2443665000B553B9 /* UIPageViewController-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 517A745A2443665000B553B9 /* UIPageViewController-Extensions.swift */; }; 5183CCD0226E1E880010922C /* NonIntrinsicLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCCF226E1E880010922C /* NonIntrinsicLabel.swift */; }; 5183CCDA226E31A50010922C /* NonIntrinsicImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCD9226E31A50010922C /* NonIntrinsicImageView.swift */; }; 5183CCE5226F4DFA0010922C /* RefreshInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCE4226F4DFA0010922C /* RefreshInterval.swift */; }; @@ -1339,6 +1340,7 @@ 51707438232AA97100A461A3 /* ShareFolderPickerController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareFolderPickerController.swift; sourceTree = ""; }; 517630032336215100E15FFF /* main.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = main.js; sourceTree = ""; }; 517630222336657E00E15FFF /* WebViewProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewProvider.swift; sourceTree = ""; }; + 517A745A2443665000B553B9 /* UIPageViewController-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIPageViewController-Extensions.swift"; sourceTree = ""; }; 5183CCCF226E1E880010922C /* NonIntrinsicLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonIntrinsicLabel.swift; sourceTree = ""; }; 5183CCD9226E31A50010922C /* NonIntrinsicImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonIntrinsicImageView.swift; sourceTree = ""; }; 5183CCE4226F4DFA0010922C /* RefreshInterval.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshInterval.swift; sourceTree = ""; }; @@ -1952,6 +1954,7 @@ 51C45245226506C800C03939 /* UIKit Extensions */ = { isa = PBXGroup; children = ( + 51F9F3FA23DFB25700A314FD /* Animations.swift */, 51F85BFA2275D85000C787DC /* Array-Extensions.swift */, 51F85BF42273625800C787DC /* Bundle-Extensions.swift */, 51627A92238A3836007B3B4B /* CroppingPreviewParameters.swift */, @@ -1969,13 +1972,13 @@ C5A6ED6C23C9B0C800AB6BE2 /* UIActivityViewController-Extensions.swift */, 51F85BF82274AA7B00C787DC /* UIBarButtonItem-Extensions.swift */, 51F85BF622749FA100C787DC /* UIFont-Extensions.swift */, + 517A745A2443665000B553B9 /* UIPageViewController-Extensions.swift */, 51C4524E226506F400C03939 /* UIStoryboard-Extensions.swift */, 51F9F3F823DFB16300A314FD /* UITableView-Extensions.swift */, 518ED21C23D0F26000E0A862 /* UIViewController-Extensions.swift */, 51FFF0C3235EE8E5002762AA /* VibrantButton.swift */, 5186A634235EF3A800C97195 /* VibrantLabel.swift */, 5F323808231DF9F000706F6B /* VibrantTableViewCell.swift */, - 51F9F3FA23DFB25700A314FD /* Animations.swift */, ); path = "UIKit Extensions"; sourceTree = ""; @@ -3989,6 +3992,7 @@ 51EF0F77227716200050506E /* FaviconGenerator.swift in Sources */, 51938DF3231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift in Sources */, 51C4525A226508D600C03939 /* UIStoryboard-Extensions.swift in Sources */, + 517A745B2443665000B553B9 /* UIPageViewController-Extensions.swift in Sources */, 51BB7C272335A8E5008E8144 /* ArticleActivityItemSource.swift in Sources */, 51F85BF52273625800C787DC /* Bundle-Extensions.swift in Sources */, 51C452A622650A3500C03939 /* Node-Extensions.swift in Sources */, diff --git a/README.md b/README.md index f53c59995..790ab2f33 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ PROVISIONING_PROFILE_SPECIFIER = ``` Set `DEVELOPMENT_TEAM` to your Apple supplied development team. You can use Keychain -Acceass to [find your development team ID](/Technotes/FindingYourDevelopmentTeamID.md). +Access to [find your development team ID](/Technotes/FindingYourDevelopmentTeamID.md). Set `ORGANIZATION_IDENTIFIER` to a reversed domain name that you control or have made up. Note that `PROVISIONING_PROFILE_SPECIFIER` should not have a value associated with it. diff --git a/Shared/Importers/DefaultFeeds.opml b/Shared/Importers/DefaultFeeds.opml index 67fd725e3..90bfa495c 100644 --- a/Shared/Importers/DefaultFeeds.opml +++ b/Shared/Importers/DefaultFeeds.opml @@ -6,19 +6,19 @@ - + - + - - + + diff --git a/iOS/Article/ArticleViewController.swift b/iOS/Article/ArticleViewController.swift index d6227ccab..31f132ea3 100644 --- a/iOS/Article/ArticleViewController.swift +++ b/iOS/Article/ArticleViewController.swift @@ -92,8 +92,15 @@ class ArticleViewController: UIViewController { pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: [:]) pageViewController.delegate = self pageViewController.dataSource = self + + // This code is to disallow paging if we scroll from the left edge. If this code is removed + // PoppableGestureRecognizerDelegate will allow us to both navigate back and page back at the + // same time. That is really weird when it happens. + let panGestureRecognizer = UIPanGestureRecognizer() + panGestureRecognizer.delegate = self + pageViewController.scrollViewInsidePageControl?.addGestureRecognizer(panGestureRecognizer) + pageViewController.view.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(pageViewController.view) addChild(pageViewController!) NSLayoutConstraint.activate([ @@ -329,6 +336,24 @@ extension ArticleViewController: UIPageViewControllerDelegate { } +// MARK: UIGestureRecognizerDelegate + +extension ArticleViewController: UIGestureRecognizerDelegate { + + func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { + return true + } + + func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { + let point = gestureRecognizer.location(in: nil) + if point.x > 40 { + return true + } + return false + } + +} + // MARK: Private private extension ArticleViewController { diff --git a/iOS/Article/ImageScrollView.swift b/iOS/Article/ImageScrollView.swift index 49233085c..d00224d00 100644 --- a/iOS/Article/ImageScrollView.swift +++ b/iOS/Article/ImageScrollView.swift @@ -191,6 +191,7 @@ open class ImageScrollView: UIScrollView { zoomView!.addGestureRecognizer(upSwipeGesture) configureImageForSize(image.size) + adjustFrameToCenter() } private func configureImageForSize(_ size: CGSize) { diff --git a/iOS/Resources/main_ios.js b/iOS/Resources/main_ios.js index 4f7b0f8ee..8411a57ac 100644 --- a/iOS/Resources/main_ios.js +++ b/iOS/Resources/main_ios.js @@ -36,7 +36,7 @@ class ImageViewer { var canvas = document.createElement("canvas"); canvas.width = this.img.naturalWidth; canvas.height = this.img.naturalHeight; - canvas.getContext("2d").drawImage(this.img, 0, 0); + canvas.getContext("2d").drawImage(this.img, 0, 0, canvas.width, canvas.height); const rect = this.img.getBoundingClientRect(); const message = { diff --git a/iOS/UIKit Extensions/UIPageViewController-Extensions.swift b/iOS/UIKit Extensions/UIPageViewController-Extensions.swift new file mode 100644 index 000000000..8db0ce553 --- /dev/null +++ b/iOS/UIKit Extensions/UIPageViewController-Extensions.swift @@ -0,0 +1,22 @@ +// +// UIPageViewController-Extensions.swift +// NetNewsWire-iOS +// +// Created by Maurice Parker on 4/12/20. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import UIKit + +extension UIPageViewController { + + var scrollViewInsidePageControl: UIScrollView? { + for view in view.subviews { + if let scrollView = view as? UIScrollView { + return scrollView + } + } + return nil + } + +} diff --git a/submodules/RSWeb b/submodules/RSWeb index c524ce914..05388e4f7 160000 --- a/submodules/RSWeb +++ b/submodules/RSWeb @@ -1 +1 @@ -Subproject commit c524ce9145dfe093500325b1c758ea83f82cc090 +Subproject commit 05388e4f7073b014f786cfce18782c3d61f8e378