mirror of
https://github.com/Ranchero-Software/NetNewsWire
synced 2025-08-12 06:26:36 +00:00
Create SidebarViewController, a UICollectionViewController subclass, to replace the UITableViewController subclass previously in use. This will get us the modern sidebar appearance.
This commit is contained in:
@@ -136,6 +136,7 @@ extension AppImage {
|
||||
extension AppImage {
|
||||
|
||||
#if os(iOS)
|
||||
static var allUnread = systemImage("largecircle.fill.circle")
|
||||
static var articleExtractorOffSF = systemImage("doc.plaintext")
|
||||
static var articleExtractorOnSF = appImage("articleExtractorOnSF")
|
||||
static var articleExtractorOffTinted = articleExtractorOff.tinted(color: AppColor.accent)!
|
||||
@@ -158,7 +159,9 @@ extension AppImage {
|
||||
static var previousArticle = systemImage("chevron.up")
|
||||
static var safari = systemImage("safari")
|
||||
static var settings = systemImage("gear")
|
||||
static var starred = systemImage("star.fill")
|
||||
static var timelineStar = systemImage("star.fill").withTintColor(AppColor.star, renderingMode: .alwaysOriginal)
|
||||
static var today = systemImage("sun.max.fill")
|
||||
static var trash = systemImage("trash")
|
||||
|
||||
// IconImages
|
||||
@@ -167,20 +170,9 @@ extension AppImage {
|
||||
|
||||
// TODO: handle color palette change
|
||||
|
||||
static var starredFeed: IconImage = {
|
||||
let image = systemImage("star.fill")
|
||||
return IconImage(image, isSymbol: true, isBackgroundSuppressed: true, preferredColor: AppColor.star.cgColor)
|
||||
}()
|
||||
|
||||
static var todayFeed: IconImage = {
|
||||
let image = systemImage("sun.max.fill")
|
||||
return IconImage(image, isSymbol: true, isBackgroundSuppressed: true, preferredColor: UIColor.systemOrange.cgColor)
|
||||
}()
|
||||
|
||||
static var unreadFeed: IconImage = {
|
||||
let image = systemImage("largecircle.fill.circle")
|
||||
return IconImage(image, isSymbol: true, isBackgroundSuppressed: true, preferredColor: AppColor.secondaryAccent.cgColor)
|
||||
}()
|
||||
static var starredFeed = IconImage(starred, isSymbol: true, isBackgroundSuppressed: true, preferredColor: AppColor.star.cgColor)
|
||||
static var todayFeed = IconImage(today, isSymbol: true, isBackgroundSuppressed: true, preferredColor: UIColor.systemOrange.cgColor)
|
||||
static var unreadFeed = IconImage(allUnread, isSymbol: true, isBackgroundSuppressed: true, preferredColor: AppColor.secondaryAccent.cgColor)
|
||||
|
||||
static var folder: IconImage = {
|
||||
let image = systemImage("folder.fill")
|
||||
|
||||
@@ -14,7 +14,7 @@ final class MainWindowController {
|
||||
let window: UIWindow
|
||||
|
||||
let rootSplitViewController: RootSplitViewController
|
||||
let sidebarViewController = MainFeedViewController()
|
||||
let sidebarViewController = SidebarViewController()
|
||||
let timelineViewController = TimelineViewController()
|
||||
let articleViewController = ArticleViewController()
|
||||
|
||||
|
||||
@@ -13,17 +13,17 @@ final class RootSplitViewController: UISplitViewController {
|
||||
|
||||
var coordinator: SceneCoordinator! {
|
||||
didSet {
|
||||
sidebarViewController.coordinator = coordinator
|
||||
// sidebarViewController.coordinator = coordinator
|
||||
timelineViewController.coordinator = coordinator
|
||||
articleViewController.coordinator = coordinator
|
||||
}
|
||||
}
|
||||
|
||||
private let sidebarViewController: MainFeedViewController
|
||||
private let sidebarViewController: SidebarViewController
|
||||
private let timelineViewController: TimelineViewController
|
||||
private let articleViewController: ArticleViewController
|
||||
|
||||
init(sidebarViewController: MainFeedViewController,
|
||||
init(sidebarViewController: SidebarViewController,
|
||||
timelineViewController: TimelineViewController,
|
||||
articleViewController: ArticleViewController) {
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ final class SceneCoordinator: NSObject, UndoableCommandRunner {
|
||||
|
||||
private var rootSplitViewController: RootSplitViewController!
|
||||
|
||||
private var mainFeedViewController: MainFeedViewController!
|
||||
private var mainFeedViewController: MainFeedViewController?
|
||||
private var mainTimelineViewController: TimelineViewController?
|
||||
private var articleViewController: ArticleViewController?
|
||||
|
||||
@@ -279,7 +279,7 @@ final class SceneCoordinator: NSObject, UndoableCommandRunner {
|
||||
super.init()
|
||||
|
||||
self.mainFeedViewController = rootSplitViewController.viewController(for: .primary) as? MainFeedViewController
|
||||
self.mainFeedViewController.coordinator = self
|
||||
self.mainFeedViewController?.coordinator = self
|
||||
self.mainFeedViewController?.navigationController?.delegate = self
|
||||
|
||||
self.mainTimelineViewController = rootSplitViewController.viewController(for: .supplementary) as? TimelineViewController
|
||||
@@ -741,7 +741,7 @@ final class SceneCoordinator: NSObject, UndoableCommandRunner {
|
||||
}
|
||||
|
||||
currentFeedIndexPath = indexPath
|
||||
mainFeedViewController.updateFeedSelection(animations: animations)
|
||||
mainFeedViewController?.updateFeedSelection(animations: animations)
|
||||
|
||||
if deselectArticle {
|
||||
selectArticle(nil)
|
||||
@@ -1168,14 +1168,14 @@ final class SceneCoordinator: NSObject, UndoableCommandRunner {
|
||||
|
||||
addNavViewController.modalPresentationStyle = .formSheet
|
||||
addNavViewController.preferredContentSize = AddFeedViewController.preferredContentSizeForFormSheetDisplay
|
||||
mainFeedViewController.present(addNavViewController, animated: true)
|
||||
mainFeedViewController?.present(addNavViewController, animated: true)
|
||||
}
|
||||
|
||||
func showAddFolder() {
|
||||
let addNavViewController = UIStoryboard.add.instantiateViewController(withIdentifier: "AddFolderViewControllerNav") as! UINavigationController
|
||||
addNavViewController.modalPresentationStyle = .formSheet
|
||||
addNavViewController.preferredContentSize = AddFolderViewController.preferredContentSizeForFormSheetDisplay
|
||||
mainFeedViewController.present(addNavViewController, animated: true)
|
||||
mainFeedViewController?.present(addNavViewController, animated: true)
|
||||
}
|
||||
|
||||
func showFullScreenImage(image: UIImage, imageTitle: String?, transitioningDelegate: UIViewControllerTransitioningDelegate) {
|
||||
@@ -1223,7 +1223,7 @@ final class SceneCoordinator: NSObject, UndoableCommandRunner {
|
||||
if currentArticle != nil {
|
||||
articleViewController?.openInAppBrowser()
|
||||
} else {
|
||||
mainFeedViewController.openInAppBrowser()
|
||||
mainFeedViewController?.openInAppBrowser()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1270,7 +1270,7 @@ final class SceneCoordinator: NSObject, UndoableCommandRunner {
|
||||
/// `SFSafariViewController` or `SettingsViewController`,
|
||||
/// otherwise, this function does nothing.
|
||||
func dismissIfLaunchingFromExternalAction() {
|
||||
guard let presentedController = mainFeedViewController.presentedViewController else { return }
|
||||
guard let presentedController = mainFeedViewController?.presentedViewController else { return }
|
||||
|
||||
if presentedController.isKind(of: SFSafariViewController.self) {
|
||||
presentedController.dismiss(animated: true, completion: nil)
|
||||
@@ -1462,7 +1462,7 @@ private extension SceneCoordinator {
|
||||
|
||||
updateExpandedNodes?()
|
||||
let changes = rebuildShadowTable()
|
||||
mainFeedViewController.reloadFeeds(initialLoad: initialLoad, changes: changes, completion: completion)
|
||||
mainFeedViewController?.reloadFeeds(initialLoad: initialLoad, changes: changes, completion: completion)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2072,7 +2072,7 @@ private extension SceneCoordinator {
|
||||
self.treeControllerDelegate.resetFilterExceptions()
|
||||
if let indexPath = self.indexPathFor(smartFeed) {
|
||||
self.selectFeed(indexPath: indexPath) {
|
||||
self.mainFeedViewController.focus()
|
||||
self.mainFeedViewController?.focus()
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -2093,7 +2093,7 @@ private extension SceneCoordinator {
|
||||
|
||||
if let folderNode = self.findFolderNode(folderName: folderName, beginningAt: accountNode), let indexPath = self.indexPathFor(folderNode) {
|
||||
self.selectFeed(indexPath: indexPath) {
|
||||
self.mainFeedViewController.focus()
|
||||
self.mainFeedViewController?.focus()
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -2106,7 +2106,7 @@ private extension SceneCoordinator {
|
||||
}
|
||||
|
||||
self.discloseFeed(feed, initialLoad: true) {
|
||||
self.mainFeedViewController.focus()
|
||||
self.mainFeedViewController?.focus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
77
iOS/MainWindow/Sidebar/SidebarViewController.swift
Normal file
77
iOS/MainWindow/Sidebar/SidebarViewController.swift
Normal file
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// SidebarViewController.swift
|
||||
// NetNewsWire-iOS
|
||||
//
|
||||
// Created by Brent Simmons on 2/2/25.
|
||||
// Copyright © 2025 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
final class SidebarViewController: UICollectionViewController {
|
||||
|
||||
enum Section {
|
||||
case smartFeeds
|
||||
}
|
||||
|
||||
struct SidebarItem: Hashable, Identifiable {
|
||||
let id: UUID = UUID()
|
||||
let title: String
|
||||
let icon: UIImage?
|
||||
}
|
||||
|
||||
typealias DataSource = UICollectionViewDiffableDataSource<Section, SidebarViewController.SidebarItem>
|
||||
private lazy var dataSource = createDataSource()
|
||||
|
||||
init() {
|
||||
super.init(collectionViewLayout: Self.createSidebarLayout())
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
|
||||
super.viewDidLoad()
|
||||
|
||||
applySnapshot()
|
||||
}
|
||||
}
|
||||
|
||||
private extension SidebarViewController {
|
||||
|
||||
static func createSidebarLayout() -> UICollectionViewLayout {
|
||||
let configuration = UICollectionLayoutListConfiguration(appearance: .sidebar)
|
||||
return UICollectionViewCompositionalLayout.list(using: configuration)
|
||||
}
|
||||
|
||||
private func createDataSource() -> DataSource {
|
||||
let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, SidebarItem> { (cell, indexPath, item) in
|
||||
var content = UIListContentConfiguration.cell()
|
||||
content.text = item.title
|
||||
content.image = item.icon
|
||||
cell.contentConfiguration = content
|
||||
}
|
||||
|
||||
dataSource = UICollectionViewDiffableDataSource<Section, SidebarItem>(collectionView: collectionView) { (collectionView, indexPath, item) in
|
||||
return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: item)
|
||||
}
|
||||
|
||||
return dataSource
|
||||
}
|
||||
|
||||
private func applySnapshot() {
|
||||
var snapshot = NSDiffableDataSourceSnapshot<Section, SidebarItem>()
|
||||
|
||||
snapshot.appendSections([.smartFeeds])
|
||||
snapshot.appendItems([
|
||||
SidebarItem(title: "Today", icon: AppImage.today),
|
||||
SidebarItem(title: "All Unread", icon: AppImage.allUnread),
|
||||
SidebarItem(title: "Starred", icon: AppImage.starred)
|
||||
])
|
||||
|
||||
dataSource.apply(snapshot, animatingDifferences: true)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user