Bring in code from previous iOS release.

This commit is contained in:
Brent Simmons
2024-12-04 17:52:46 -08:00
parent 4aaabacd24
commit d5dd6131b1
36 changed files with 130 additions and 129 deletions

View File

@@ -79,6 +79,9 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
// Configure the table
tableView.dataSource = dataSource
if #available(iOS 15.0, *) {
tableView.isPrefetchingEnabled = false
}
numberOfTextLines = AppDefaults.shared.timelineNumberOfLines
iconSize = AppDefaults.shared.timelineIconSize
resetEstimatedRowHeight()
@@ -525,14 +528,10 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
}
@objc private func reloadAllVisibleCells() {
if #available(iOS 15, *) {
reconfigureCells(coordinator.articles)
} else {
let visibleArticles = tableView.indexPathsForVisibleRows!.compactMap { return dataSource.itemIdentifier(for: $0) }
reloadCells(visibleArticles)
}
let visibleArticles = tableView.indexPathsForVisibleRows!.compactMap { return dataSource.itemIdentifier(for: $0) }
reloadCells(visibleArticles)
}
private func reloadCells(_ articles: [Article]) {
var snapshot = dataSource.snapshot()
snapshot.reloadItems(articles)
@@ -540,15 +539,6 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
self?.restoreSelectionIfNecessary(adjustScroll: false)
}
}
private func reconfigureCells(_ articles: [Article]) {
guard #available(iOS 15, *) else { return }
var snapshot = dataSource.snapshot()
snapshot.reconfigureItems(articles)
dataSource.apply(snapshot, animatingDifferences: false) { [weak self] in
self?.restoreSelectionIfNecessary(adjustScroll: false)
}
}
// MARK: Cell Configuring

View File

@@ -1,23 +0,0 @@
{
"images" : [
{
"filename" : "onepassword-navbar.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "onepassword-navbar@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "onepassword-navbar@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 770 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -1,116 +1,116 @@
{
"images" : [
{
"size" : "20x20",
"filename" : "Icon_20x20@2x.png",
"idiom" : "iphone",
"filename" : "icon-41.png",
"scale" : "2x"
"scale" : "2x",
"size" : "20x20"
},
{
"size" : "20x20",
"filename" : "Icon_20x20@3x.png",
"idiom" : "iphone",
"filename" : "icon-60.png",
"scale" : "3x"
"scale" : "3x",
"size" : "20x20"
},
{
"size" : "29x29",
"filename" : "Icon_29x29@2x.png",
"idiom" : "iphone",
"filename" : "icon-58.png",
"scale" : "2x"
"scale" : "2x",
"size" : "29x29"
},
{
"size" : "29x29",
"filename" : "Icon_29x29@3x.png",
"idiom" : "iphone",
"filename" : "icon-87.png",
"scale" : "3x"
"scale" : "3x",
"size" : "29x29"
},
{
"size" : "40x40",
"filename" : "Icon_40x40@2x.png",
"idiom" : "iphone",
"filename" : "icon-80.png",
"scale" : "2x"
"scale" : "2x",
"size" : "40x40"
},
{
"size" : "40x40",
"filename" : "Icon_40x40@3x.png",
"idiom" : "iphone",
"filename" : "icon-121.png",
"scale" : "3x"
"scale" : "3x",
"size" : "40x40"
},
{
"size" : "60x60",
"filename" : "Icon_60x60@2x.png",
"idiom" : "iphone",
"filename" : "icon-120.png",
"scale" : "2x"
"scale" : "2x",
"size" : "60x60"
},
{
"size" : "60x60",
"filename" : "Icon_60x60@3x.png",
"idiom" : "iphone",
"filename" : "icon-180.png",
"scale" : "3x"
"scale" : "3x",
"size" : "60x60"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "icon-20.png",
"scale" : "1x"
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
},
{
"size" : "20x20",
"filename" : "Icon_20x20@2x 1.png",
"idiom" : "ipad",
"filename" : "icon-42.png",
"scale" : "2x"
"scale" : "2x",
"size" : "20x20"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "icon-29.png",
"scale" : "1x"
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
},
{
"size" : "29x29",
"filename" : "Icon_29x29@2x 1.png",
"idiom" : "ipad",
"filename" : "icon-59.png",
"scale" : "2x"
"scale" : "2x",
"size" : "29x29"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "icon-40.png",
"scale" : "1x"
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
},
{
"size" : "40x40",
"filename" : "Icon_40x40@2x 1.png",
"idiom" : "ipad",
"filename" : "icon-81.png",
"scale" : "2x"
"scale" : "2x",
"size" : "40x40"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "icon-76.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "icon-152.png",
"scale" : "2x"
"scale" : "1x",
"size" : "76x76"
},
{
"size" : "83.5x83.5",
"filename" : "Icon_76x76@2x.png",
"idiom" : "ipad",
"filename" : "icon-167.png",
"scale" : "2x"
"scale" : "2x",
"size" : "76x76"
},
{
"size" : "1024x1024",
"filename" : "Icon_83.5x83.5@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
},
{
"filename" : "Icon_1024x1024.png",
"idiom" : "ios-marketing",
"filename" : "icon-1024.png",
"scale" : "1x"
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
"author" : "xcode",
"version" : 1
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 969 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 689 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

View File

@@ -204,6 +204,8 @@
</array>
<key>CFBundleTypeName</key>
<string>NetNewsWire Theme</string>
<key>LSHandlerRank</key>
<string>Owner</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>

View File

@@ -86,11 +86,19 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
private let rebuildBackingStoresQueue = CoalescingQueue(name: "Rebuild The Backing Stores", interval: 0.5)
private var fetchSerialNumber = 0
private let fetchRequestQueue = FetchRequestQueue()
// Which Containers are expanded
private var expandedTable = Set<ContainerIdentifier>()
// Which Containers used to be expanded. Reset by rebuilding the Shadow Table.
private var lastExpandedTable = Set<ContainerIdentifier>()
// 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?
private var lastSearchString = ""
private var lastSearchScope: SearchScope? = nil
@@ -649,12 +657,15 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
}
func nodeFor(_ indexPath: IndexPath) -> Node? {
guard indexPath.section < shadowTable.count && indexPath.row < shadowTable[indexPath.section].feedNodes.count else {
guard indexPath.section > -1 &&
indexPath.row > -1 &&
indexPath.section < shadowTable.count &&
indexPath.row < shadowTable[indexPath.section].feedNodes.count else {
return nil
}
return shadowTable[indexPath.section].feedNodes[indexPath.row].node
}
func indexPathFor(_ node: Node) -> IndexPath? {
for i in 0..<shadowTable.count {
if let row = shadowTable[i].feedNodes.firstIndex(of: FeedNode(node)) {
@@ -718,12 +729,15 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
markExpanded(containerID)
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)
}
func expandAllSectionsAndFolders() {
for sectionNode in treeController.rootNode.childNodes {
markExpanded(sectionNode)
@@ -742,11 +756,14 @@ 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)
}
func collapseAllFolders() {
for sectionNode in treeController.rootNode.childNodes {
for topLevelNode in sectionNode.childNodes {
@@ -1111,23 +1128,23 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
return timelineFeed == feed
}
func discloseWebFeed(_ webFeed: WebFeed, animations: Animations = [], completion: (() -> Void)? = nil) {
func discloseWebFeed(_ webFeed: WebFeed, initialLoad: Bool = false, animations: Animations = [], completion: (() -> Void)? = nil) {
if isSearching {
masterTimelineViewController?.hideSearch()
}
guard let account = webFeed.account else {
completion?()
return
}
let parentFolder = account.sortedFolders?.first(where: { $0.objectIsChild(webFeed) })
markExpanded(account)
if let parentFolder = parentFolder {
markExpanded(parentFolder)
}
if let webFeedFeedID = webFeed.feedID {
self.treeControllerDelegate.addFilterException(webFeedFeedID)
}
@@ -1135,13 +1152,14 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
self.treeControllerDelegate.addFilterException(parentFolderFeedID)
}
rebuildBackingStores(completion: {
rebuildBackingStores(initialLoad: initialLoad, completion: {
self.treeControllerDelegate.resetFilterExceptions()
self.selectFeed(webFeed, animations: animations, completion: completion)
self.selectFeed(nil) {
self.selectFeed(webFeed, animations: animations, completion: completion)
}
})
}
func showStatusBar() {
prefersStatusBarHidden = false
UIView.animate(withDuration: 0.15) {
@@ -1510,10 +1528,10 @@ private extension SceneCoordinator {
var newShadowTable = [(sectionID: String, feedNodes: [FeedNode])]()
for i in 0..<treeController.rootNode.numberOfChildNodes {
var feedNodes = [FeedNode]()
let sectionNode = treeController.rootNode.childAtIndex(i)!
if isExpanded(sectionNode) {
for node in sectionNode.childNodes {
feedNodes.append(FeedNode(node))
@@ -1524,26 +1542,27 @@ private extension SceneCoordinator {
}
}
}
let sectionID = (sectionNode.representedObject as? Account)?.accountID ?? ""
newShadowTable.append((sectionID: sectionID, feedNodes: feedNodes))
}
// If we have a current Feed IndexPath it is no longer valid and needs reset.
if currentFeedIndexPath != nil {
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<ShadowTableChanges.Move>()
var inserts = Set<Int>()
var deletes = Set<Int>()
let oldFeedNodes = shadowTable.first(where: { $0.sectionID == newSectionRows.sectionID })?.feedNodes ?? [FeedNode]()
let diff = newSectionRows.feedNodes.difference(from: oldFeedNodes).inferringMoves()
for change in diff {
switch change {
@@ -1561,15 +1580,28 @@ 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<Int>()
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<ShadowTableChanges.Move>()
var inserts = Set<Int>()
var deletes = Set<Int>()
let oldSections = shadowTable.map { $0.sectionID }
let newSections = newShadowTable.map { $0.sectionID }
let diff = newSections.difference(from: oldSections).inferringMoves()
@@ -1591,10 +1623,10 @@ private extension SceneCoordinator {
}
shadowTable = newShadowTable
return ShadowTableChanges(deletes: deletes, inserts: inserts, moves: moves, rowChanges: changes)
}
func shadowTableContains(_ feed: Feed) -> Bool {
for section in shadowTable {
for feedNode in section.feedNodes {
@@ -2258,7 +2290,7 @@ private extension SceneCoordinator {
return
}
self.discloseWebFeed(webFeed) {
self.discloseWebFeed(webFeed, initialLoad: true) {
self.masterFeedViewController.focus()
}
}