From 5ffdad9b64e46d4ce66a0939c95c92b18c8353ff Mon Sep 17 00:00:00 2001 From: Stuart Breckenridge Date: Mon, 28 Feb 2022 07:56:58 +0800 Subject: [PATCH 01/15] Changes when appearance menu is configured Fixes #3483 --- iOS/Article/ArticleViewController.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iOS/Article/ArticleViewController.swift b/iOS/Article/ArticleViewController.swift index 1da544502..4fae590ae 100644 --- a/iOS/Article/ArticleViewController.swift +++ b/iOS/Article/ArticleViewController.swift @@ -162,7 +162,6 @@ class ArticleViewController: UIViewController, MainControllerIdentifiable { searchBar.delegate = self view.bringSubviewToFront(searchBar) - configureAppearanceMenu() updateUI() } @@ -234,6 +233,8 @@ class ArticleViewController: UIViewController, MainControllerIdentifiable { starBarButtonItem.accLabelText = NSLocalizedString("Star Article", comment: "Star Article") } + configureAppearanceMenu() + } override func contentScrollView(for edge: NSDirectionalRectEdge) -> UIScrollView? { From 477062c75672a612ee46f82301c74060c2cb8a47 Mon Sep 17 00:00:00 2001 From: Matt Meissner Date: Sun, 13 Feb 2022 22:10:36 -0600 Subject: [PATCH 02/15] Attempt #2: Update `gyb` to latest version and use python3 --- Shared/Secrets.swift.gyb | 6 ++-- Vendor/gyb | 2 +- Vendor/gyb.py | 62 +++++++++++++++++++++------------------- 3 files changed, 37 insertions(+), 33 deletions(-) diff --git a/Shared/Secrets.swift.gyb b/Shared/Secrets.swift.gyb index e51700f4a..5b9602b8a 100644 --- a/Shared/Secrets.swift.gyb +++ b/Shared/Secrets.swift.gyb @@ -8,14 +8,14 @@ def chunks(seq, size): return (seq[i:(i + size)] for i in range(0, len(seq), size)) def encode(string, salt): - bytes = string.encode("UTF-8") - return [ord(bytes[i]) ^ salt[i % len(salt)] for i in range(0, len(bytes))] + bytes_ = string.encode("UTF-8") + return [bytes_[i] ^ salt[i % len(salt)] for i in range(0, len(bytes_))] def snake_to_camel(snake_str): components = snake_str.split('_') return components[0].lower() + ''.join(x.title() for x in components[1:]) -salt = [ord(byte) for byte in os.urandom(64)] +salt = [byte for byte in os.urandom(64)] }% import Secrets diff --git a/Vendor/gyb b/Vendor/gyb index dece788e5..8206bd8a0 100755 --- a/Vendor/gyb +++ b/Vendor/gyb @@ -1,3 +1,3 @@ -#!/usr/bin/env python2.7 +#!/usr/bin/env python3 import gyb gyb.main() diff --git a/Vendor/gyb.py b/Vendor/gyb.py index d9ce0e7b3..a1ff11ee4 100644 --- a/Vendor/gyb.py +++ b/Vendor/gyb.py @@ -4,17 +4,21 @@ from __future__ import print_function +import io import os import re import sys -try: - from cStringIO import StringIO -except ImportError: - from io import StringIO import textwrap import tokenize from bisect import bisect + +try: + from StringIO import StringIO +except ImportError: + from io import StringIO + + try: basestring except NameError: @@ -48,7 +52,7 @@ def split_lines(s): If the lines are later concatenated, the result is s, possibly with a single appended newline. """ - return [l + '\n' for l in s.split('\n')] + return [line + '\n' for line in s.split('\n')] # text on a line up to the first '$$', '${', or '%%' @@ -396,9 +400,9 @@ class ParseContext(object): def __init__(self, filename, template=None): self.filename = os.path.abspath(filename) if sys.platform == 'win32': - self.filename = self.filename.replace('\\', '/') + self.filename = '/'.join(self.filename.split(os.sep)) if template is None: - with open(filename) as f: + with io.open(os.path.normpath(filename), encoding='utf-8') as f: self.template = f.read() else: self.template = template @@ -733,8 +737,10 @@ class Code(ASTNode): result_string = None if isinstance(result, Number) and not isinstance(result, Integral): result_string = repr(result) - else: + elif isinstance(result, Integral) or isinstance(result, list): result_string = str(result) + else: + result_string = StringIO(result).read() context.append_text( result_string, self.filename, self.start_line_number) @@ -745,7 +751,7 @@ class Code(ASTNode): s = indent + 'Code: {' + source_lines[0] + '}' else: s = indent + 'Code:\n' + indent + '{\n' + '\n'.join( - indent + 4 * ' ' + l for l in source_lines + indent + 4 * ' ' + line for line in source_lines ) + '\n' + indent + '}' return s + self.format_children(indent) @@ -760,8 +766,8 @@ def expand(filename, line_directive=_default_line_directive, **local_bindings): >>> # manually handle closing and deleting this file to allow us to open >>> # the file by its name across all platforms. >>> f = NamedTemporaryFile(delete=False) - >>> f.write( - ... r'''--- + >>> _ = f.write( + ... br'''--- ... % for i in range(int(x)): ... a pox on ${i} for epoxy ... % end @@ -800,7 +806,7 @@ def expand(filename, line_directive=_default_line_directive, **local_bindings): >>> f.close() >>> os.remove(f.name) """ - with open(filename) as f: + with io.open(filename, encoding='utf-8') as f: t = parse_template(filename, f.read()) d = os.getcwd() os.chdir(os.path.dirname(os.path.abspath(filename))) @@ -1133,16 +1139,6 @@ def execute_template( def main(): - """ - Lint this file. - >>> import sys - >>> gyb_path = os.path.realpath(__file__).replace('.pyc', '.py') - >>> sys.path.append(os.path.dirname(gyb_path)) - >>> import python_lint - >>> python_lint.lint([gyb_path], verbose=False) - 0 - """ - import argparse import sys @@ -1215,12 +1211,12 @@ def main(): help='''Bindings to be set in the template's execution context''') parser.add_argument( - 'file', type=argparse.FileType(), + 'file', type=str, help='Path to GYB template file (defaults to stdin)', nargs='?', - default=sys.stdin) + default='-') parser.add_argument( - '-o', dest='target', type=argparse.FileType('w'), - help='Output file (defaults to stdout)', default=sys.stdout) + '-o', dest='target', type=str, + help='Output file (defaults to stdout)', default='-') parser.add_argument( '--test', action='store_true', default=False, help='Run a self-test') @@ -1252,15 +1248,23 @@ def main(): sys.exit(1) bindings = dict(x.split('=', 1) for x in args.defines) - ast = parse_template(args.file.name, args.file.read()) + if args.file == '-': + ast = parse_template('stdin', sys.stdin.read()) + else: + with io.open(os.path.normpath(args.file), 'r', encoding='utf-8') as f: + ast = parse_template(args.file, f.read()) if args.dump: print(ast) # Allow the template to open files and import .py files relative to its own # directory - os.chdir(os.path.dirname(os.path.abspath(args.file.name))) + os.chdir(os.path.dirname(os.path.abspath(args.file))) sys.path = ['.'] + sys.path - args.target.write(execute_template(ast, args.line_directive, **bindings)) + if args.target == '-': + sys.stdout.write(execute_template(ast, args.line_directive, **bindings)) + else: + with io.open(args.target, 'w', encoding='utf-8', newline='\n') as f: + f.write(execute_template(ast, args.line_directive, **bindings)) if __name__ == '__main__': From 2ff8fee3080e1b62a9b623c0b65db78e5e110d62 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Tue, 1 Mar 2022 11:14:41 -0600 Subject: [PATCH 03/15] Reload any Container rows that have change disclosure state since the last rebuild of the Shadow Table. Fixes #3484 --- iOS/MasterFeed/MasterFeedViewController.swift | 8 +++++ iOS/MasterFeed/ShadowTableChanges.swift | 9 ++++- iOS/SceneCoordinator.swift | 34 +++++++++++++++++-- 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/iOS/MasterFeed/MasterFeedViewController.swift b/iOS/MasterFeed/MasterFeedViewController.swift index 6e2964c2d..4e71c23ae 100644 --- a/iOS/MasterFeed/MasterFeedViewController.swift +++ b/iOS/MasterFeed/MasterFeedViewController.swift @@ -627,6 +627,14 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner { } } + if let rowChanges = changes.rowChanges { + for rowChange in rowChanges { + if let reloads = rowChange.reloadIndexPaths, !reloads.isEmpty { + tableView.reloadRows(at: reloads, with: .none) + } + } + } + completion?() } diff --git a/iOS/MasterFeed/ShadowTableChanges.swift b/iOS/MasterFeed/ShadowTableChanges.swift index dd8a12801..49c4a9f9f 100644 --- a/iOS/MasterFeed/ShadowTableChanges.swift +++ b/iOS/MasterFeed/ShadowTableChanges.swift @@ -25,6 +25,7 @@ struct ShadowTableChanges { var section: Int var deletes: Set? var inserts: Set? + var reloads: Set? var moves: Set? var isEmpty: Bool { @@ -41,15 +42,21 @@ struct ShadowTableChanges { return inserts.map { IndexPath(row: $0, section: section) } } + var reloadIndexPaths: [IndexPath]? { + guard let reloads = reloads else { return nil } + return reloads.map { IndexPath(row: $0, section: section) } + } + var moveIndexPaths: [(IndexPath, IndexPath)]? { guard let moves = moves else { return nil } return moves.map { (IndexPath(row: $0.from, section: section), IndexPath(row: $0.to, section: section)) } } - init(section: Int, deletes: Set?, inserts: Set?, moves: Set?) { + init(section: Int, deletes: Set?, inserts: Set?, reloads: Set?, moves: Set?) { self.section = section self.deletes = deletes self.inserts = inserts + self.reloads = reloads self.moves = moves } diff --git a/iOS/SceneCoordinator.swift b/iOS/SceneCoordinator.swift index bed102e59..278e0ba9f 100644 --- a/iOS/SceneCoordinator.swift +++ b/iOS/SceneCoordinator.swift @@ -87,8 +87,16 @@ class SceneCoordinator: NSObject, UndoableCommandRunner { private var fetchSerialNumber = 0 private let fetchRequestQueue = FetchRequestQueue() + // Which Containers are expanded private var expandedTable = Set() + + // Which Containers used to be expanded. Reset by rebuilding the Shadow Table. + private var lastExpandedTable = Set() + + // Which Feeds have the Read Articles Filter enabled private var readFilterEnabledTable = [FeedIdentifier: Bool]() + + // Flattened tree structure for the Sidebar private var shadowTable = [(sectionID: String, feedNodes: [FeedNode])]() private(set) var preSearchTimelineFeed: Feed? @@ -719,8 +727,11 @@ class SceneCoordinator: NSObject, UndoableCommandRunner { rebuildBackingStores() } + /// This is a special function that expects the caller to change the disclosure arrow state outside this function. + /// Failure to do so will get the Sidebar into an invalid state. func expand(_ node: Node) { guard let containerID = (node.representedObject as? ContainerIdentifiable)?.containerID else { return } + lastExpandedTable.insert(containerID) expand(containerID) } @@ -742,8 +753,11 @@ class SceneCoordinator: NSObject, UndoableCommandRunner { clearTimelineIfNoLongerAvailable() } + /// This is a special function that expects the caller to change the disclosure arrow state outside this function. + /// Failure to do so will get the Sidebar into an invalid state. func collapse(_ node: Node) { guard let containerID = (node.representedObject as? ContainerIdentifiable)?.containerID else { return } + lastExpandedTable.remove(containerID) collapse(containerID) } @@ -1548,9 +1562,10 @@ private extension SceneCoordinator { currentFeedIndexPath = indexPathFor(timelineFeed as AnyObject) } - // Compute the differences in the shadow table rows + // Compute the differences in the shadow table rows and the expanded table entries var changes = [ShadowTableChanges.RowChanges]() - + let expandedTableDifference = lastExpandedTable.symmetricDifference(expandedTable) + for (section, newSectionRows) in newShadowTable.enumerated() { var moves = Set() var inserts = Set() @@ -1576,9 +1591,22 @@ private extension SceneCoordinator { } } - changes.append(ShadowTableChanges.RowChanges(section: section, deletes: deletes, inserts: inserts, moves: moves)) + // We need to reload the difference in expanded rows to get the disclosure arrows correct when programmatically changing their state + var reloads = Set() + + for (index, newFeedNode) in newSectionRows.feedNodes.enumerated() { + if let newFeedNodeContainerID = (newFeedNode.node.representedObject as? Container)?.containerID { + if expandedTableDifference.contains(newFeedNodeContainerID) { + reloads.insert(index) + } + } + } + + changes.append(ShadowTableChanges.RowChanges(section: section, deletes: deletes, inserts: inserts, reloads: reloads, moves: moves)) } + lastExpandedTable = expandedTable + // Compute the difference in the shadow table sections var moves = Set() var inserts = Set() From 0719e5883b3c23f38a3aacdcbbdefdd0ef5389d3 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Tue, 1 Mar 2022 14:12:43 -0600 Subject: [PATCH 04/15] Clear the timeline when disclosing a web feed so that the previously loaded timeline articles aren't merged. Fixes #3485 --- iOS/SceneCoordinator.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iOS/SceneCoordinator.swift b/iOS/SceneCoordinator.swift index 278e0ba9f..2b63e3199 100644 --- a/iOS/SceneCoordinator.swift +++ b/iOS/SceneCoordinator.swift @@ -1151,7 +1151,9 @@ class SceneCoordinator: NSObject, UndoableCommandRunner { rebuildBackingStores(initialLoad: initialLoad, completion: { self.treeControllerDelegate.resetFilterExceptions() - self.selectFeed(webFeed, animations: animations, completion: completion) + self.selectFeed(nil) { + self.selectFeed(webFeed, animations: animations, completion: completion) + } }) } From f22239db361817efb837817a1bc65c1381dc189b Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Tue, 1 Mar 2022 14:43:54 -0600 Subject: [PATCH 05/15] Change task completion notification so that it blocks until NNW has completed suspending. Fixes #3200 --- iOS/AppDelegate.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iOS/AppDelegate.swift b/iOS/AppDelegate.swift index f7cbe5b84..aeb74260e 100644 --- a/iOS/AppDelegate.swift +++ b/iOS/AppDelegate.swift @@ -410,11 +410,11 @@ private extension AppDelegate { // set expiration handler task.expirationHandler = { [weak task] in + os_log("Accounts refresh processing terminated for running too long.", log: self.log, type: .info) DispatchQueue.main.sync { self.suspendApplication() + task?.setTaskCompleted(success: false) } - os_log("Accounts refresh processing terminated for running too long.", log: self.log, type: .info) - task?.setTaskCompleted(success: false) } } From 27dd920cce355a976fa68ca7bf3f4e25b0095196 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Tue, 1 Mar 2022 14:53:43 -0600 Subject: [PATCH 06/15] Change sync to async --- iOS/AppDelegate.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iOS/AppDelegate.swift b/iOS/AppDelegate.swift index 283dbf7ea..2a29531c4 100644 --- a/iOS/AppDelegate.swift +++ b/iOS/AppDelegate.swift @@ -409,7 +409,7 @@ private extension AppDelegate { // set expiration handler task.expirationHandler = { [weak task] in os_log("Accounts refresh processing terminated for running too long.", log: self.log, type: .info) - DispatchQueue.main.sync { + DispatchQueue.main.async { self.suspendApplication() task?.setTaskCompleted(success: false) } From cca1929837caf6ab0125511ba12eac28c65c5b99 Mon Sep 17 00:00:00 2001 From: Stuart Breckenridge Date: Mon, 28 Feb 2022 07:56:58 +0800 Subject: [PATCH 07/15] Changes when appearance menu is configured Fixes #3483 --- iOS/Article/ArticleViewController.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iOS/Article/ArticleViewController.swift b/iOS/Article/ArticleViewController.swift index 1da544502..4fae590ae 100644 --- a/iOS/Article/ArticleViewController.swift +++ b/iOS/Article/ArticleViewController.swift @@ -162,7 +162,6 @@ class ArticleViewController: UIViewController, MainControllerIdentifiable { searchBar.delegate = self view.bringSubviewToFront(searchBar) - configureAppearanceMenu() updateUI() } @@ -234,6 +233,8 @@ class ArticleViewController: UIViewController, MainControllerIdentifiable { starBarButtonItem.accLabelText = NSLocalizedString("Star Article", comment: "Star Article") } + configureAppearanceMenu() + } override func contentScrollView(for edge: NSDirectionalRectEdge) -> UIScrollView? { From e2242a79281831df14251aa0f0d1ff2268054a05 Mon Sep 17 00:00:00 2001 From: Stuart Breckenridge Date: Thu, 3 Mar 2022 08:33:53 +0800 Subject: [PATCH 08/15] Appearance menu changes: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - On iPad—theme selector only, with theme selector image. - On iPhone—theme selector and full size toggle; Aa is the image used. Reader view and notifications options have been removed. --- iOS/AppAssets.swift | 4 ++ iOS/Article/ArticleViewController.swift | 52 +++++++------------------ 2 files changed, 17 insertions(+), 39 deletions(-) diff --git a/iOS/AppAssets.swift b/iOS/AppAssets.swift index d5808dcc5..4cf2dca03 100644 --- a/iOS/AppAssets.swift +++ b/iOS/AppAssets.swift @@ -58,6 +58,10 @@ struct AppAssets { static var appBadgeImage: UIImage = { return UIImage(systemName: "app.badge")! }() + + static var articleAppearanceImage: UIImage = { + return UIImage(systemName: "textformat.size")! + }() static var articleExtractorError: UIImage = { return UIImage(named: "articleExtractorError")! diff --git a/iOS/Article/ArticleViewController.swift b/iOS/Article/ArticleViewController.swift index 4fae590ae..df9db6f21 100644 --- a/iOS/Article/ArticleViewController.swift +++ b/iOS/Article/ArticleViewController.swift @@ -241,6 +241,11 @@ class ArticleViewController: UIViewController, MainControllerIdentifiable { return currentWebViewController?.webView?.scrollView } + + /// The appearance menu is different on iPhone and iPad. + /// On iPad, it's only the theme selector. On iPhone, the appearance menu + /// contains the the theme selector and full screen options. + /// - Parameter sender: `Any?` @objc func configureAppearanceMenu(_ sender: Any? = nil) { @@ -267,6 +272,12 @@ class ArticleViewController: UIViewController, MainControllerIdentifiable { let themeMenu = UIMenu(title: "Theme", image: AppAssets.themeImage, identifier: nil, options: .singleSelection, children: [ defaultThemeMenu, customThemeMenu]) + if UIDevice.current.userInterfaceIdiom == .pad { + appearanceBarButtonItem.image = AppAssets.themeImage + appearanceBarButtonItem.menu = themeMenu + return + } + var appearanceChildren: [UIMenuElement] = [themeMenu] if let currentWebViewController = currentWebViewController { @@ -292,49 +303,12 @@ class ArticleViewController: UIViewController, MainControllerIdentifiable { } } - var feedManagementChildren = [UIMenuElement]() - - if let feed = article?.webFeed { - let extractorOn = feed.isArticleExtractorAlwaysOn ?? false - let readerAction = UIAction(title: NSLocalizedString("Always Use Reader View", comment: "Always Use Reader View"), - image: AppAssets.articleExtractorOffSF, - identifier: nil, - discoverabilityTitle: nil, - attributes: [], - state: extractorOn ? .on : .off) { [weak self] _ in - if feed.isArticleExtractorAlwaysOn == nil { - feed.isArticleExtractorAlwaysOn = true - } else { - feed.isArticleExtractorAlwaysOn?.toggle() - } - self?.configureAppearanceMenu() - } - feedManagementChildren.append(readerAction) - - let notifyOn = feed.isNotifyAboutNewArticles ?? false - let notifyAction = UIAction(title: NSLocalizedString("Notify About New Articles", comment: "Notify About New Articles"), - image: AppAssets.appBadgeImage, - identifier: nil, - discoverabilityTitle: nil, - attributes: [], - state: notifyOn ? .on : .off) { [weak self] _ in - if feed.isNotifyAboutNewArticles == nil { - feed.isNotifyAboutNewArticles = true - } else { - feed.isNotifyAboutNewArticles?.toggle() - } - self?.configureAppearanceMenu() - } - feedManagementChildren.append(notifyAction) - } - let appearanceMenu = UIMenu(title: NSLocalizedString("Article Appearance", comment: "Appearance"), image: nil, identifier: nil, options: .displayInline, children: appearanceChildren) - let feedMgmtMenu = UIMenu(title: NSLocalizedString("Feed Management", comment: "Feed Management"), image: nil , identifier: nil, options: .displayInline, children: feedManagementChildren) - let menu = UIMenu(title: "", image: nil, identifier: nil, options: .displayInline, children: [appearanceMenu, feedMgmtMenu]) + let menu = UIMenu(title: "", image: nil, identifier: nil, options: .displayInline, children: [appearanceMenu]) + appearanceBarButtonItem.image = AppAssets.articleAppearanceImage appearanceBarButtonItem.menu = menu - } From fc323c40722535114c561d39415978bcfd22db17 Mon Sep 17 00:00:00 2001 From: Stuart Breckenridge Date: Thu, 3 Mar 2022 08:50:55 +0800 Subject: [PATCH 09/15] Adds long press menu to article extractor button --- iOS/Article/ArticleViewController.swift | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/iOS/Article/ArticleViewController.swift b/iOS/Article/ArticleViewController.swift index df9db6f21..dd89e9006 100644 --- a/iOS/Article/ArticleViewController.swift +++ b/iOS/Article/ArticleViewController.swift @@ -234,6 +234,7 @@ class ArticleViewController: UIViewController, MainControllerIdentifiable { } configureAppearanceMenu() + configureArticleExtractorMenu() } @@ -311,6 +312,29 @@ class ArticleViewController: UIViewController, MainControllerIdentifiable { appearanceBarButtonItem.menu = menu } + private func configureArticleExtractorMenu() { + if let feed = article?.webFeed { + let extractorOn = feed.isArticleExtractorAlwaysOn ?? false + let readerAction = UIAction(title: NSLocalizedString("Always Use Reader View", comment: "Always Use Reader View"), + image: AppAssets.articleExtractorOffSF, + identifier: nil, + discoverabilityTitle: nil, + attributes: [], + state: extractorOn ? .on : .off) { [weak self] _ in + if feed.isArticleExtractorAlwaysOn == nil { + feed.isArticleExtractorAlwaysOn = true + self?.currentWebViewController?.toggleArticleExtractor() + } else { + feed.isArticleExtractorAlwaysOn?.toggle() + } + self?.configureArticleExtractorMenu() + } + let menu = UIMenu(title: feed.nameForDisplay, image: AppAssets.articleExtractorOffSF, identifier: nil, options: .displayInline, children: [readerAction]) + articleExtractorButton.menu = menu + articleExtractorButton.showsMenuAsPrimaryAction = false + } + } + @objc func reloadDueToThemeChange(_ notification: Notification) { From 115fa702caa8aa57152d8f39c9334cce5d55393e Mon Sep 17 00:00:00 2001 From: Stuart Breckenridge Date: Thu, 3 Mar 2022 09:01:51 +0800 Subject: [PATCH 10/15] rebuild menu after toggle --- iOS/Article/ArticleViewController.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/iOS/Article/ArticleViewController.swift b/iOS/Article/ArticleViewController.swift index dd89e9006..9a989cb14 100644 --- a/iOS/Article/ArticleViewController.swift +++ b/iOS/Article/ArticleViewController.swift @@ -415,6 +415,7 @@ class ArticleViewController: UIViewController, MainControllerIdentifiable { @IBAction func toggleArticleExtractor(_ sender: Any) { currentWebViewController?.toggleArticleExtractor() + configureArticleExtractorMenu() } @IBAction func nextUnread(_ sender: Any) { From b9ae38cfb31875268bd12e996974927785995749 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Fri, 25 Mar 2022 13:27:50 -0500 Subject: [PATCH 11/15] Updated to latest package versions --- .../xcshareddata/swiftpm/Package.resolved | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/NetNewsWire.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/NetNewsWire.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index dc8075713..f107850d7 100644 --- a/NetNewsWire.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/NetNewsWire.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -51,8 +51,8 @@ "repositoryURL": "https://github.com/microsoft/plcrashreporter.git", "state": { "branch": null, - "revision": "d747ab5de269cd44022bbe96ff9609d8626694ab", - "version": "1.9.0" + "revision": "6b27393cad517c067dceea85fadf050e70c4ceaa", + "version": "1.10.1" } }, { @@ -105,8 +105,8 @@ "repositoryURL": "https://github.com/Ranchero-Software/Sparkle-Binary.git", "state": { "branch": null, - "revision": "67cd26321bdf4e77954cf6de7d9e6a20544f2030", - "version": "2.0.0" + "revision": "d1a8b3c98d96c601453f2e4230f1dd65b60d0581", + "version": "2.0.1" } }, { From 02dce80f8d068a583e106a7a6db2532399fa0d11 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Fri, 25 Mar 2022 16:22:04 -0500 Subject: [PATCH 12/15] Fix toolbar flashing back and forth to clear --- iOS/SceneCoordinator.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/iOS/SceneCoordinator.swift b/iOS/SceneCoordinator.swift index f1b68d654..da737f550 100644 --- a/iOS/SceneCoordinator.swift +++ b/iOS/SceneCoordinator.swift @@ -1399,6 +1399,7 @@ private extension SceneCoordinator { let toolbarAppearance = UIToolbarAppearance() navController.toolbar.standardAppearance = toolbarAppearance navController.toolbar.compactAppearance = toolbarAppearance + navController.toolbar.scrollEdgeAppearance = toolbarAppearance navController.toolbar.tintColor = AppAssets.primaryAccentColor } From 0f402d429c5b88f7842cd83eb840e1060c7b75bb Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Sat, 26 Mar 2022 13:32:52 -0500 Subject: [PATCH 13/15] Add a commit to make sure the database has uncommitted data for the following query. --- SyncDatabase/Sources/SyncDatabase/SyncStatusTable.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SyncDatabase/Sources/SyncDatabase/SyncStatusTable.swift b/SyncDatabase/Sources/SyncDatabase/SyncStatusTable.swift index 0ab0d80cb..286b50b11 100644 --- a/SyncDatabase/Sources/SyncDatabase/SyncStatusTable.swift +++ b/SyncDatabase/Sources/SyncDatabase/SyncStatusTable.swift @@ -30,6 +30,8 @@ struct SyncStatusTable: DatabaseTable { let updateSQL = "update syncStatus set selected = true" database.executeUpdate(updateSQL, withArgumentsIn: nil) + database.commit() + var selectSQL = "select * from syncStatus where selected == true" if let limit = limit { selectSQL = "\(selectSQL) limit \(limit)" From e1a6455af50af2f7d75d82746a5cbbd832c2b30f Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Sat, 26 Mar 2022 16:15:43 -0500 Subject: [PATCH 14/15] Back out unnecessary commit statement. --- SyncDatabase/Sources/SyncDatabase/SyncStatusTable.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/SyncDatabase/Sources/SyncDatabase/SyncStatusTable.swift b/SyncDatabase/Sources/SyncDatabase/SyncStatusTable.swift index 286b50b11..0ab0d80cb 100644 --- a/SyncDatabase/Sources/SyncDatabase/SyncStatusTable.swift +++ b/SyncDatabase/Sources/SyncDatabase/SyncStatusTable.swift @@ -30,8 +30,6 @@ struct SyncStatusTable: DatabaseTable { let updateSQL = "update syncStatus set selected = true" database.executeUpdate(updateSQL, withArgumentsIn: nil) - database.commit() - var selectSQL = "select * from syncStatus where selected == true" if let limit = limit { selectSQL = "\(selectSQL) limit \(limit)" From 5e2fe5f610b677ac07bf716a040445519c62506c Mon Sep 17 00:00:00 2001 From: Ethan Wong Date: Mon, 4 Apr 2022 13:51:53 +0800 Subject: [PATCH 15/15] Add proper OSLog argument for os_log calls. --- .../Feedly/Operations/FeedlyLogoutOperation.swift | 4 ++-- Mac/AppDelegate.swift | 12 +++++++----- Mac/MainWindow/Timeline/TimelineViewController.swift | 2 +- iOS/AppDelegate.swift | 8 ++++---- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/Account/Sources/Account/Feedly/Operations/FeedlyLogoutOperation.swift b/Account/Sources/Account/Feedly/Operations/FeedlyLogoutOperation.swift index 29fb7eed6..6f412eafe 100644 --- a/Account/Sources/Account/Feedly/Operations/FeedlyLogoutOperation.swift +++ b/Account/Sources/Account/Feedly/Operations/FeedlyLogoutOperation.swift @@ -34,7 +34,7 @@ final class FeedlyLogoutOperation: FeedlyOperation { assert(Thread.isMainThread) switch result { case .success: - os_log("Logged out of %{public}@ account.", "\(account.type)") + os_log("Logged out of %{public}@ account.", log: log, "\(account.type)") do { try account.removeCredentials(type: .oauthAccessToken) try account.removeCredentials(type: .oauthRefreshToken) @@ -44,7 +44,7 @@ final class FeedlyLogoutOperation: FeedlyOperation { didFinish() case .failure(let error): - os_log("Logout failed because %{public}@.", error as NSError) + os_log("Logout failed because %{public}@.", log: log, error as NSError) didFinish(with: error) } } diff --git a/Mac/AppDelegate.swift b/Mac/AppDelegate.swift index 2d28c3bb7..44c877446 100644 --- a/Mac/AppDelegate.swift +++ b/Mac/AppDelegate.swift @@ -37,6 +37,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, static let mainWindow = "mainWindow" } + var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "Application") + var userNotificationManager: UserNotificationManager! var faviconDownloader: FaviconDownloader! var imageDownloader: ImageDownloader! @@ -199,7 +201,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, AppDefaults.shared.registerDefaults() let isFirstRun = AppDefaults.shared.isFirstRun if isFirstRun { - os_log(.debug, "Is first run.") + os_log(.debug, log: log, "Is first run.") } let localAccount = AccountManager.shared.defaultAccount @@ -1010,12 +1012,12 @@ private extension AppDelegate { let account = AccountManager.shared.existingAccount(with: accountID) guard account != nil else { - os_log(.debug, "No account found from notification.") + os_log(.debug, log: log, "No account found from notification.") return } let article = try? account!.fetchArticles(.articleIDs([articleID])) guard article != nil else { - os_log(.debug, "No article found from search using %@", articleID) + os_log(.debug, log: log, "No article found from search using %@", articleID) return } account!.markArticles(article!, statusKey: .read, flag: true) { _ in } @@ -1029,12 +1031,12 @@ private extension AppDelegate { } let account = AccountManager.shared.existingAccount(with: accountID) guard account != nil else { - os_log(.debug, "No account found from notification.") + os_log(.debug, log: log, "No account found from notification.") return } let article = try? account!.fetchArticles(.articleIDs([articleID])) guard article != nil else { - os_log(.debug, "No article found from search using %@", articleID) + os_log(.debug, log: log, "No article found from search using %@", articleID) return } account!.markArticles(article!, statusKey: .starred, flag: true) { _ in } diff --git a/Mac/MainWindow/Timeline/TimelineViewController.swift b/Mac/MainWindow/Timeline/TimelineViewController.swift index e3fdc0895..294918613 100644 --- a/Mac/MainWindow/Timeline/TimelineViewController.swift +++ b/Mac/MainWindow/Timeline/TimelineViewController.swift @@ -940,7 +940,7 @@ extension TimelineViewController: NSTableViewDelegate { return [action] @unknown default: - os_log(.error, "Unknown table row edge: %ld", edge.rawValue) + print("Unknown table row edge: \(edge.rawValue)") } return [] diff --git a/iOS/AppDelegate.swift b/iOS/AppDelegate.swift index 2a29531c4..298faba77 100644 --- a/iOS/AppDelegate.swift +++ b/iOS/AppDelegate.swift @@ -431,12 +431,12 @@ private extension AppDelegate { resumeDatabaseProcessingIfNecessary() let account = AccountManager.shared.existingAccount(with: accountID) guard account != nil else { - os_log(.debug, "No account found from notification.") + os_log(.debug, log: self.log, "No account found from notification.") return } let article = try? account!.fetchArticles(.articleIDs([articleID])) guard article != nil else { - os_log(.debug, "No article found from search using %@", articleID) + os_log(.debug, log: self.log, "No article found from search using %@", articleID) return } account!.markArticles(article!, statusKey: .read, flag: true) { _ in } @@ -459,12 +459,12 @@ private extension AppDelegate { resumeDatabaseProcessingIfNecessary() let account = AccountManager.shared.existingAccount(with: accountID) guard account != nil else { - os_log(.debug, "No account found from notification.") + os_log(.debug, log: self.log, "No account found from notification.") return } let article = try? account!.fetchArticles(.articleIDs([articleID])) guard article != nil else { - os_log(.debug, "No article found from search using %@", articleID) + os_log(.debug, log: self.log, "No article found from search using %@", articleID) return } account!.markArticles(article!, statusKey: .starred, flag: true) { _ in }