diff --git a/Appcasts/netnewswire-beta.xml b/Appcasts/netnewswire-beta.xml
index d098b9293..4f7b01376 100755
--- a/Appcasts/netnewswire-beta.xml
+++ b/Appcasts/netnewswire-beta.xml
@@ -6,7 +6,17 @@
Most recent NetNewsWire changes with links to updates.
en
- -
+
-
+ NetNewsWire 6.1b4
+ Fixed a few font and sizing issues.
+ ]]>
+ Sun, 27 Feb 2022 21:50:00 -0800
+
+ 10.15.0
+
+
+ -
NetNewsWire 6.1b3
Two new themes: Hyperlegible and NewsFax
diff --git a/iOS/AppDelegate.swift b/iOS/AppDelegate.swift
index f30a509a7..2a29531c4 100644
--- a/iOS/AppDelegate.swift
+++ b/iOS/AppDelegate.swift
@@ -408,11 +408,11 @@ private extension AppDelegate {
// set expiration handler
task.expirationHandler = { [weak task] in
- DispatchQueue.main.sync {
- self.suspendApplication()
- }
os_log("Accounts refresh processing terminated for running too long.", log: self.log, type: .info)
- task?.setTaskCompleted(success: false)
+ DispatchQueue.main.async {
+ self.suspendApplication()
+ task?.setTaskCompleted(success: false)
+ }
}
}
diff --git a/iOS/MasterFeed/MasterFeedViewController.swift b/iOS/MasterFeed/MasterFeedViewController.swift
index 3b8faf264..91d0a2341 100644
--- a/iOS/MasterFeed/MasterFeedViewController.swift
+++ b/iOS/MasterFeed/MasterFeedViewController.swift
@@ -563,6 +563,14 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner, Ma
}
}
+ 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 2180a11ea..f1b68d654 100644
--- a/iOS/SceneCoordinator.swift
+++ b/iOS/SceneCoordinator.swift
@@ -73,8 +73,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?
@@ -675,8 +683,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)
}
@@ -698,8 +709,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)
}
@@ -1080,7 +1094,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)
+ }
})
}
@@ -1512,9 +1528,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()
@@ -1540,9 +1557,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()