Compare commits

...

20 Commits

Author SHA1 Message Date
Brent Simmons 69c908c891 Convert UserAgent functions to variables and make them non-optional. 2024-05-07 19:50:53 -07:00
Brent Simmons ae2c21f5f0 Move NonIntrinsic* views to UIKitExtras. 2024-05-06 22:26:11 -07:00
Brent Simmons 482ff49a64 Move UIFont extension to the file where it’s used. 2024-05-06 22:21:37 -07:00
Brent Simmons 03eff6a0da Move UIPageViewController extension to the file where it’s used. 2024-05-06 22:18:09 -07:00
Brent Simmons 51a893ed98 Move Animations and UITableView extensions to UIKitExtras. 2024-05-06 22:16:05 -07:00
Brent Simmons 043b7841d8 Move RoundedProgressView to UIKitExtras. 2024-05-06 22:12:57 -07:00
Brent Simmons e84d8ad1d7 Move TickMarkSlider to UIKitExtras. 2024-05-06 22:11:28 -07:00
Brent Simmons 314da23321 Move some String extensions to UIKitExtras. 2024-05-06 22:07:20 -07:00
Brent Simmons 7308cb6b04 Move Bundle extension to the place where it’s used. 2024-05-06 21:37:24 -07:00
Brent Simmons a80acbacf1 Add missing import. 2024-05-06 21:37:09 -07:00
Brent Simmons 18acf5919c Move maxY extension method to FoundationExtras. 2024-05-06 21:31:30 -07:00
Brent Simmons bfa7ad55bb Make SceneDelegate final. 2024-05-05 22:43:52 -07:00
Brent Simmons b4c8a6920f Convert method to async. 2024-05-05 22:35:18 -07:00
Brent Simmons c46494de13 Use async await in runSheetOnWindow. 2024-05-05 22:01:26 -07:00
Brent Simmons 3d91a6b38d Convert some functions to async instead of completion-based. 2024-05-05 18:02:46 -07:00
Brent Simmons cd7f4f7052 Convert runSheetOnWindow to async. 2024-05-05 17:23:54 -07:00
Brent Simmons fba8c52b67 Convert several methods to async await. 2024-05-05 17:08:30 -07:00
Brent Simmons 399703c2fe Rename completion to callback, since it wasn’t a completion handler. 2024-05-05 16:51:43 -07:00
Brent Simmons c96a3c7e5c Rename completion to callback, since it wasn’t a completion handler. 2024-05-05 16:51:09 -07:00
Brent Simmons 4b381daa92 Convert restoreWindow to async await. 2024-05-05 16:49:49 -07:00
49 changed files with 213 additions and 299 deletions

View File

@ -63,11 +63,8 @@ public enum FeedbinAccountDelegateError: String, Error {
sessionConfiguration.httpMaximumConnectionsPerHost = 1
sessionConfiguration.httpCookieStorage = nil
sessionConfiguration.urlCache = nil
if let userAgentHeaders = UserAgent.headers() {
sessionConfiguration.httpAdditionalHeaders = userAgentHeaders
}
sessionConfiguration.httpAdditionalHeaders = UserAgent.headers
caller = FeedbinAPICaller(transport: URLSession(configuration: sessionConfiguration))
}

View File

@ -93,10 +93,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
sessionConfiguration.httpMaximumConnectionsPerHost = 1
sessionConfiguration.httpCookieStorage = nil
sessionConfiguration.urlCache = nil
if let userAgentHeaders = UserAgent.headers() {
sessionConfiguration.httpAdditionalHeaders = userAgentHeaders
}
sessionConfiguration.httpAdditionalHeaders = UserAgent.headers
let session = URLSession(configuration: sessionConfiguration)
self.caller = FeedlyAPICaller(transport: session, api: api, secretsProvider: secretsProvider)

View File

@ -47,10 +47,7 @@ final class NewsBlurAccountDelegate: AccountDelegate {
sessionConfiguration.httpMaximumConnectionsPerHost = 1
sessionConfiguration.httpCookieStorage = nil
sessionConfiguration.urlCache = nil
if let userAgentHeaders = UserAgent.headers() {
sessionConfiguration.httpAdditionalHeaders = userAgentHeaders
}
sessionConfiguration.httpAdditionalHeaders = UserAgent.headers
let session = URLSession(configuration: sessionConfiguration)
caller = NewsBlurAPICaller(transport: session)

View File

@ -71,11 +71,8 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
sessionConfiguration.httpMaximumConnectionsPerHost = 1
sessionConfiguration.httpCookieStorage = nil
sessionConfiguration.urlCache = nil
if let userAgentHeaders = UserAgent.headers() {
sessionConfiguration.httpAdditionalHeaders = userAgentHeaders
}
sessionConfiguration.httpAdditionalHeaders = UserAgent.headers
self.caller = ReaderAPICaller(transport: URLSession(configuration: sessionConfiguration), secretsProvider: secretsProvider)
}

View File

@ -7,6 +7,7 @@
//
import Foundation
import CoreGraphics
public extension Array {
@ -15,7 +16,6 @@ public extension Array {
Array(self[$0 ..< Swift.min($0 + size, count)])
}
}
}
public extension Array where Element: Equatable {
@ -24,5 +24,16 @@ public extension Array where Element: Equatable {
guard let index = firstIndex(of: object) else {return}
remove(at: index)
}
}
public extension Array where Element == CGRect {
func maxY() -> CGFloat {
var y: CGFloat = 0.0
for r in self {
y = Swift.max(y, r.maxY)
}
return y
}
}

View File

@ -980,14 +980,14 @@ extension AppDelegate : ScriptingAppDelegate {
extension AppDelegate: NSWindowRestoration {
@objc static func restoreWindow(withIdentifier identifier: NSUserInterfaceItemIdentifier, state: NSCoder, completionHandler: @escaping (NSWindow?, Error?) -> Void) {
@objc static func restoreWindow(withIdentifier identifier: NSUserInterfaceItemIdentifier, state: NSCoder) async throws -> NSWindow {
var mainWindow: NSWindow? = nil
if identifier.rawValue == WindowRestorationIdentifiers.mainWindow {
mainWindow = appDelegate.createAndShowMainWindow().window
}
completionHandler(mainWindow, nil)
return mainWindow!
}
}
// Handle Notification Actions

View File

@ -54,8 +54,7 @@ class AddFeedWindowController : NSWindowController {
}
func runSheetOnWindow(_ hostWindow: NSWindow) {
hostWindow.beginSheet(window!) { (returnCode: NSApplication.ModalResponse) -> Void in
}
hostWindow.beginSheet(window!, completionHandler: nil)
}
override func windowDidLoad() {

View File

@ -10,8 +10,8 @@ import AppKit
import Articles
import Account
class AddFolderWindowController : NSWindowController {
final class AddFolderWindowController : NSWindowController {
@IBOutlet var folderNameTextField: NSTextField!
@IBOutlet var accountPopupButton: NSPopUpButton!
@IBOutlet var addFolderButton: NSButton!
@ -25,9 +25,10 @@ class AddFolderWindowController : NSWindowController {
func runSheetOnWindow(_ w: NSWindow) {
hostWindow = w
hostWindow!.beginSheet(window!) { (returnCode: NSApplication.ModalResponse) -> Void in
if returnCode == NSApplication.ModalResponse.OK {
Task { @MainActor in
let returnCode = await hostWindow!.beginSheet(window!)
if returnCode == .OK {
self.addFolderIfNeeded()
}
}

View File

@ -83,12 +83,12 @@ final class DetailViewController: NSViewController, WKUIDelegate {
currentWebViewController.stopMediaPlayback()
}
func canScrollDown(_ callback: @escaping (Bool) -> Void) {
currentWebViewController.canScrollDown(callback)
func canScrollDown() async -> Bool {
await currentWebViewController.canScrollDown()
}
func canScrollUp(_ callback: @escaping (Bool) -> Void) {
currentWebViewController.canScrollUp(callback)
func canScrollUp() async -> Bool {
await currentWebViewController.canScrollUp()
}
override func scrollPageDown(_ sender: Any?) {

View File

@ -126,7 +126,7 @@ final class DetailWebViewController: NSViewController {
webView.navigationDelegate = self
webView.keyboardDelegate = keyboardDelegate
webView.translatesAutoresizingMaskIntoConstraints = false
if let userAgent = UserAgent.fromInfoPlist() {
if let userAgent = UserAgent.fromInfoPlist {
webView.customUserAgent = userAgent
}
@ -166,14 +166,21 @@ final class DetailWebViewController: NSViewController {
}
@objc func userDefaultsDidChange(_ note: Notification) {
if articleTextSize != AppDefaults.shared.articleTextSize {
articleTextSize = AppDefaults.shared.articleTextSize
reloadHTMLMaintainingScrollPosition()
Task { @MainActor in
await reloadHTMLMaintainingScrollPosition()
}
}
}
@objc func currentArticleThemeDidChangeNotification(_ note: Notification) {
reloadHTMLMaintainingScrollPosition()
Task { @MainActor in
await reloadHTMLMaintainingScrollPosition()
}
}
// MARK: Media Functions
@ -184,16 +191,14 @@ final class DetailWebViewController: NSViewController {
// MARK: Scrolling
func canScrollDown(_ completion: @escaping (Bool) -> Void) {
fetchScrollInfo { (scrollInfo) in
completion(scrollInfo?.canScrollDown ?? false)
}
func canScrollDown() async -> Bool {
let scrollInfo = await fetchScrollInfo()
return scrollInfo?.canScrollDown ?? false
}
func canScrollUp(_ completion: @escaping (Bool) -> Void) {
fetchScrollInfo { (scrollInfo) in
completion(scrollInfo?.canScrollUp ?? false)
}
func canScrollUp() async -> Bool {
let scrollInfo = await fetchScrollInfo()
return scrollInfo?.canScrollUp ?? false
}
override func scrollPageDown(_ sender: Any?) {
@ -326,11 +331,10 @@ private extension DetailWebViewController {
}
}
func reloadHTMLMaintainingScrollPosition() {
fetchScrollInfo() { scrollInfo in
self.windowScrollY = scrollInfo?.offsetY
self.reloadHTML()
}
func reloadHTMLMaintainingScrollPosition() async {
let scrollInfo = await fetchScrollInfo()
windowScrollY = scrollInfo?.offsetY
self.reloadHTML()
}
func reloadHTML() {
@ -380,23 +384,22 @@ private extension DetailWebViewController {
webView.loadHTMLString(html, baseURL: baseURL)
}
func fetchScrollInfo(_ completion: @escaping (ScrollInfo?) -> Void) {
func fetchScrollInfo() async -> ScrollInfo? {
let javascriptString = "var x = {contentHeight: document.body.scrollHeight, offsetY: window.pageYOffset}; x"
webView.evaluateJavaScript(javascriptString) { (info, error) in
guard let info = info as? [String: Any] else {
completion(nil)
return
}
guard let contentHeight = info["contentHeight"] as? CGFloat, let offsetY = info["offsetY"] as? CGFloat else {
completion(nil)
return
}
let scrollInfo = ScrollInfo(contentHeight: contentHeight, viewHeight: self.webView.frame.height, offsetY: offsetY)
completion(scrollInfo)
guard let info = try? await webView.evaluateJavaScript(javascriptString) else {
return nil
}
guard let info = info as? [String: Any] else {
return nil
}
guard let contentHeight = info["contentHeight"] as? CGFloat, let offsetY = info["offsetY"] as? CGFloat else {
return nil
}
let scrollInfo = ScrollInfo(contentHeight: contentHeight, viewHeight: self.webView.frame.height, offsetY: offsetY)
return scrollInfo
}
#if !MAC_APP_STORE

View File

@ -288,26 +288,36 @@ final class MainWindowController : NSWindowController, NSUserInterfaceValidation
// MARK: - Actions
@IBAction func scrollOrGoToNextUnread(_ sender: Any?) {
guard let detailViewController = detailViewController else {
guard let detailViewController else {
return
}
detailViewController.canScrollDown { (canScroll) in
Task { @MainActor in
let canScroll = await detailViewController.canScrollDown()
NSCursor.setHiddenUntilMouseMoves(true)
canScroll ? detailViewController.scrollPageDown(sender) : self.nextUnread(sender)
if canScroll {
detailViewController.scrollPageDown(sender)
} else {
self.nextUnread(sender)
}
}
}
@IBAction func scrollUp(_ sender: Any?) {
guard let detailViewController = detailViewController else {
guard let detailViewController else {
return
}
detailViewController.canScrollUp { (canScroll) in
if (canScroll) {
Task { @MainActor in
let canScroll = await detailViewController.canScrollUp()
if canScroll {
NSCursor.setHiddenUntilMouseMoves(true)
detailViewController.scrollPageUp(sender)
}
}
}
@IBAction func copyArticleURL(_ sender: Any?) {

View File

@ -841,19 +841,19 @@ private extension SidebarViewController {
return rowView.view(atColumn: 0) as? SidebarCell
}
func applyToAvailableCells(_ completion: (SidebarCell, Node) -> Void) {
func applyToAvailableCells(_ callback: (SidebarCell, Node) -> Void) {
outlineView.enumerateAvailableRowViews { (rowView: NSTableRowView, row: Int) -> Void in
guard let cell = cellForRowView(rowView), let node = nodeForRow(row) else {
return
}
completion(cell, node)
callback(cell, node)
}
}
func applyToCellsForRepresentedObject(_ representedObject: AnyObject, _ completion: (SidebarCell, Node) -> Void) {
func applyToCellsForRepresentedObject(_ representedObject: AnyObject, _ callback: (SidebarCell, Node) -> Void) {
applyToAvailableCells { (cell, node) in
if node.representsSidebarObject(representedObject) {
completion(cell, node)
callback(cell, node)
}
}
}

View File

@ -17,7 +17,7 @@ enum AccountsAddCloudKitWindowControllerError: LocalizedError {
}
}
class AccountsAddCloudKitWindowController: NSWindowController {
final class AccountsAddCloudKitWindowController: NSWindowController {
private weak var hostWindow: NSWindow?
@ -31,9 +31,9 @@ class AccountsAddCloudKitWindowController: NSWindowController {
// MARK: API
func runSheetOnWindow(_ hostWindow: NSWindow, completion: ((NSApplication.ModalResponse) -> Void)? = nil) {
func runSheetOnWindow(_ hostWindow: NSWindow) async -> NSApplication.ModalResponse {
self.hostWindow = hostWindow
hostWindow.beginSheet(window!, completionHandler: completion)
return await hostWindow.beginSheet(window!)
}
// MARK: Actions
@ -51,5 +51,4 @@ class AccountsAddCloudKitWindowController: NSWindowController {
let _ = AccountManager.shared.createAccount(type: .cloudKit)
hostWindow!.endSheet(window!, returnCode: NSApplication.ModalResponse.OK)
}
}

View File

@ -64,14 +64,16 @@ final class AccountsDetailViewController: NSViewController, NSTextFieldDelegate
@IBAction func credentials(_ sender: Any) {
guard let account = account else { return }
guard let account else { return }
switch account.type {
case .feedbin:
let accountsFeedbinWindowController = AccountsFeedbinWindowController()
accountsFeedbinWindowController.account = account
accountsFeedbinWindowController.runSheetOnWindow(self.view.window!)
accountsWindowController = accountsFeedbinWindowController
case .inoreader, .bazQux, .theOldReader, .freshRSS:
let accountsReaderAPIWindowController = AccountsReaderAPIWindowController()
accountsReaderAPIWindowController.accountType = account.type
@ -79,15 +81,15 @@ final class AccountsDetailViewController: NSViewController, NSTextFieldDelegate
accountsReaderAPIWindowController.runSheetOnWindow(self.view.window!)
accountsWindowController = accountsReaderAPIWindowController
break
case .newsBlur:
let accountsNewsBlurWindowController = AccountsNewsBlurWindowController()
accountsNewsBlurWindowController.account = account
accountsNewsBlurWindowController.runSheetOnWindow(self.view.window!)
accountsWindowController = accountsNewsBlurWindowController
default:
break
}
}
}

View File

@ -11,7 +11,7 @@ import Account
import Web
import Secrets
class AccountsFeedbinWindowController: NSWindowController {
final class AccountsFeedbinWindowController: NSWindowController {
@IBOutlet weak var signInTextField: NSTextField!
@IBOutlet weak var noAccountTextField: NSTextField!
@ -49,9 +49,11 @@ class AccountsFeedbinWindowController: NSWindowController {
// MARK: API
func runSheetOnWindow(_ hostWindow: NSWindow, completion: ((NSApplication.ModalResponse) -> Void)? = nil) {
func runSheetOnWindow(_ hostWindow: NSWindow) {
self.hostWindow = hostWindow
hostWindow.beginSheet(window!, completionHandler: completion)
Task { @MainActor in
await hostWindow.beginSheet(window!)
}
}
// MARK: Actions

View File

@ -47,9 +47,11 @@ class AccountsNewsBlurWindowController: NSWindowController {
// MARK: API
func runSheetOnWindow(_ hostWindow: NSWindow, completion: ((NSApplication.ModalResponse) -> Void)? = nil) {
func runSheetOnWindow(_ hostWindow: NSWindow) {
self.hostWindow = hostWindow
hostWindow.beginSheet(window!, completionHandler: completion)
Task { @MainActor in
await hostWindow.beginSheet(window!)
}
}
// MARK: Actions

View File

@ -151,42 +151,53 @@ extension AccountsPreferencesViewController: NSTableViewDelegate {
}
extension AccountsPreferencesViewController: AccountsPreferencesAddAccountDelegate {
func presentSheetForAccount(_ accountType: AccountType) {
switch accountType {
case .onMyMac:
let accountsAddLocalWindowController = AccountsAddLocalWindowController()
accountsAddLocalWindowController.runSheetOnWindow(self.view.window!)
addAccountWindowController = accountsAddLocalWindowController
case .cloudKit:
let accountsAddCloudKitWindowController = AccountsAddCloudKitWindowController()
accountsAddCloudKitWindowController.runSheetOnWindow(self.view.window!) { response in
Task { @MainActor in
let response = await accountsAddCloudKitWindowController.runSheetOnWindow(self.view.window!)
if response == NSApplication.ModalResponse.OK {
self.tableView.reloadData()
}
}
addAccountWindowController = accountsAddCloudKitWindowController
case .feedbin:
let accountsFeedbinWindowController = AccountsFeedbinWindowController()
accountsFeedbinWindowController.runSheetOnWindow(self.view.window!)
addAccountWindowController = accountsFeedbinWindowController
case .freshRSS, .inoreader, .bazQux, .theOldReader:
let accountsReaderAPIWindowController = AccountsReaderAPIWindowController()
accountsReaderAPIWindowController.accountType = accountType
accountsReaderAPIWindowController.runSheetOnWindow(self.view.window!)
addAccountWindowController = accountsReaderAPIWindowController
case .feedly:
let addAccount = FeedlyOAuthAccountAuthorizationOperation(accountType: .feedly, secretsProvider: Secrets())
addAccount.delegate = self
addAccount.presentationAnchor = self.view.window!
runAwaitingFeedlyLoginAlertModal(forLifetimeOf: addAccount)
MainThreadOperationQueue.shared.add(addAccount)
case .newsBlur:
let accountsNewsBlurWindowController = AccountsNewsBlurWindowController()
accountsNewsBlurWindowController.runSheetOnWindow(self.view.window!)
addAccountWindowController = accountsNewsBlurWindowController
}
}
private func runAwaitingFeedlyLoginAlertModal(forLifetimeOf operation: FeedlyOAuthAccountAuthorizationOperation) {
let alert = NSAlert()
alert.alertStyle = .informational

View File

@ -79,9 +79,11 @@ class AccountsReaderAPIWindowController: NSWindowController {
// MARK: API
func runSheetOnWindow(_ hostWindow: NSWindow, completion: ((NSApplication.ModalResponse) -> Void)? = nil) {
func runSheetOnWindow(_ hostWindow: NSWindow) {
self.hostWindow = hostWindow
hostWindow.beginSheet(window!, completionHandler: completion)
Task { @MainActor in
await hostWindow.beginSheet(window!)
}
}
// MARK: Actions

View File

@ -74,7 +74,6 @@
5108F6B72375E612001ABC45 /* CacheCleaner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5108F6B52375E612001ABC45 /* CacheCleaner.swift */; };
5108F6D22375EED2001ABC45 /* TimelineCustomizerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5108F6D12375EED2001ABC45 /* TimelineCustomizerViewController.swift */; };
5108F6D42375EEEF001ABC45 /* TimelinePreviewTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5108F6D32375EEEF001ABC45 /* TimelinePreviewTableViewController.swift */; };
5108F6D823763094001ABC45 /* TickMarkSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5108F6D723763094001ABC45 /* TickMarkSlider.swift */; };
510C416124E5CDE3008226FD /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 510C416024E5CDE3008226FD /* ShareViewController.swift */; };
510C416424E5CDE3008226FD /* ShareViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 510C416224E5CDE3008226FD /* ShareViewController.xib */; };
510C416924E5CDE3008226FD /* NetNewsWire Share Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 510C415C24E5CDE3008226FD /* NetNewsWire Share Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
@ -107,7 +106,6 @@
511D43D2231FA62C00FB1562 /* GlobalKeyboardShortcuts.plist in Resources */ = {isa = PBXBuildFile; fileRef = 844B5B641FEA11F200C7C76A /* GlobalKeyboardShortcuts.plist */; };
511D43EF231FBDE900FB1562 /* LaunchScreenPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 511D43ED231FBDE800FB1562 /* LaunchScreenPad.storyboard */; };
511D4419231FC02D00FB1562 /* KeyboardManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 511D4410231FC02D00FB1562 /* KeyboardManager.swift */; };
51236339236915B100951F16 /* RoundedProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 512363372369155100951F16 /* RoundedProgressView.swift */; };
5126EE97226CB48A00C22AFC /* SceneCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5126EE96226CB48A00C22AFC /* SceneCoordinator.swift */; };
5127B238222B4849006D641D /* DetailKeyboardDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5127B236222B4849006D641D /* DetailKeyboardDelegate.swift */; };
5127B23A222B4849006D641D /* DetailKeyboardShortcuts.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5127B237222B4849006D641D /* DetailKeyboardShortcuts.plist */; };
@ -184,9 +182,6 @@
51707439232AA97100A461A3 /* ShareFolderPickerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51707438232AA97100A461A3 /* ShareFolderPickerController.swift */; };
517630042336215100E15FFF /* main.js in Resources */ = {isa = PBXBuildFile; fileRef = 517630032336215100E15FFF /* main.js */; };
517630052336215100E15FFF /* main.js in Resources */ = {isa = PBXBuildFile; fileRef = 517630032336215100E15FFF /* main.js */; };
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 */; };
5183CCE6226F4E110010922C /* RefreshInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCE4226F4DFA0010922C /* RefreshInterval.swift */; };
5183CCE8226F68D90010922C /* AccountRefreshTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCE7226F68D90010922C /* AccountRefreshTimer.swift */; };
@ -253,7 +248,6 @@
51C45258226508CF00C03939 /* AppAssets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C45254226507D200C03939 /* AppAssets.swift */; };
51C45259226508D300C03939 /* AppDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C45255226507D200C03939 /* AppDefaults.swift */; };
51C4525A226508D600C03939 /* UIStoryboard-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C4524E226506F400C03939 /* UIStoryboard-Extensions.swift */; };
51C4525C226508DF00C03939 /* String-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C45250226506F400C03939 /* String-Extensions.swift */; };
51C45268226508F600C03939 /* FeedUnreadCountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C45261226508F600C03939 /* FeedUnreadCountView.swift */; };
51C45269226508F600C03939 /* FeedTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C45262226508F600C03939 /* FeedTableViewCell.swift */; };
51C4526A226508F600C03939 /* FeedTableViewCellLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C45263226508F600C03939 /* FeedTableViewCellLayout.swift */; };
@ -321,7 +315,6 @@
51E4DAED2425F6940091EB5B /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51E4DAEC2425F6940091EB5B /* CloudKit.framework */; };
51E595A5228CC36500FCC42B /* ArticleStatusSyncTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E595A4228CC36500FCC42B /* ArticleStatusSyncTimer.swift */; };
51E595A6228CC36500FCC42B /* ArticleStatusSyncTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E595A4228CC36500FCC42B /* ArticleStatusSyncTimer.swift */; };
51EAED96231363EF00A9EEE3 /* NonIntrinsicButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EAED95231363EF00A9EEE3 /* NonIntrinsicButton.swift */; };
51EC114C2149FE3300B296E3 /* FolderTreeMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EC114B2149FE3300B296E3 /* FolderTreeMenu.swift */; };
51EF0F7E2277A57D0050506E /* TimelineAccessibilityCellLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F7D2277A57D0050506E /* TimelineAccessibilityCellLayout.swift */; };
51EF0F802277A8330050506E /* TimelineCellLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F7F2277A8330050506E /* TimelineCellLayout.swift */; };
@ -330,14 +323,9 @@
51F85BEF2272520B00C787DC /* Thanks.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 51F85BEE2272520B00C787DC /* Thanks.rtf */; };
51F85BF12272524100C787DC /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 51F85BF02272524100C787DC /* Credits.rtf */; };
51F85BF32272531500C787DC /* Dedication.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 51F85BF22272531500C787DC /* Dedication.rtf */; };
51F85BF52273625800C787DC /* Bundle-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F85BF42273625800C787DC /* Bundle-Extensions.swift */; };
51F85BF722749FA100C787DC /* UIFont-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F85BF622749FA100C787DC /* UIFont-Extensions.swift */; };
51F85BF92274AA7B00C787DC /* UIBarButtonItem-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F85BF82274AA7B00C787DC /* UIBarButtonItem-Extensions.swift */; };
51F85BFB2275D85000C787DC /* Array-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F85BFA2275D85000C787DC /* Array-Extensions.swift */; };
51F85BFD2275DCA800C787DC /* SingleLineUILabelSizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F85BFC2275DCA800C787DC /* SingleLineUILabelSizer.swift */; };
51F9F3F723DF6DB200A314FD /* ArticleIconSchemeHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F9F3F623DF6DB200A314FD /* ArticleIconSchemeHandler.swift */; };
51F9F3F923DFB16300A314FD /* UITableView-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F9F3F823DFB16300A314FD /* UITableView-Extensions.swift */; };
51F9F3FB23DFB25700A314FD /* Animations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F9F3FA23DFB25700A314FD /* Animations.swift */; };
51FA73B72332D5F70090D516 /* LegacyArticleExtractorButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51FA73B62332D5F70090D516 /* LegacyArticleExtractorButton.swift */; };
51FD413B2342BD0500880194 /* TimelineUnreadCountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51FD413A2342BD0500880194 /* TimelineUnreadCountView.swift */; };
51FE10032345529D0056195D /* UserNotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51FE10022345529D0056195D /* UserNotificationManager.swift */; };
@ -1051,7 +1039,6 @@
5108F6B52375E612001ABC45 /* CacheCleaner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheCleaner.swift; sourceTree = "<group>"; };
5108F6D12375EED2001ABC45 /* TimelineCustomizerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineCustomizerViewController.swift; sourceTree = "<group>"; };
5108F6D32375EEEF001ABC45 /* TimelinePreviewTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelinePreviewTableViewController.swift; sourceTree = "<group>"; };
5108F6D723763094001ABC45 /* TickMarkSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TickMarkSlider.swift; sourceTree = "<group>"; };
510C415C24E5CDE3008226FD /* NetNewsWire Share Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "NetNewsWire Share Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
510C416024E5CDE3008226FD /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = "<group>"; };
510C416324E5CDE3008226FD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ShareViewController.xib; sourceTree = "<group>"; };
@ -1066,7 +1053,6 @@
511B9805237DCAC90028BCAA /* UserInfoKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInfoKey.swift; sourceTree = "<group>"; };
511D43EE231FBDE800FB1562 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreenPad.storyboard; sourceTree = "<group>"; };
511D4410231FC02D00FB1562 /* KeyboardManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardManager.swift; sourceTree = "<group>"; };
512363372369155100951F16 /* RoundedProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundedProgressView.swift; sourceTree = "<group>"; };
5126EE96226CB48A00C22AFC /* SceneCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneCoordinator.swift; sourceTree = "<group>"; };
5127B236222B4849006D641D /* DetailKeyboardDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailKeyboardDelegate.swift; sourceTree = "<group>"; };
5127B237222B4849006D641D /* DetailKeyboardShortcuts.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = DetailKeyboardShortcuts.plist; sourceTree = "<group>"; };
@ -1122,9 +1108,6 @@
516AE9B22371C372007DEEAA /* FeedTableViewSectionHeaderLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedTableViewSectionHeaderLayout.swift; sourceTree = "<group>"; };
51707438232AA97100A461A3 /* ShareFolderPickerController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareFolderPickerController.swift; sourceTree = "<group>"; };
517630032336215100E15FFF /* main.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = main.js; sourceTree = "<group>"; };
517A745A2443665000B553B9 /* UIPageViewController-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIPageViewController-Extensions.swift"; sourceTree = "<group>"; };
5183CCCF226E1E880010922C /* NonIntrinsicLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonIntrinsicLabel.swift; sourceTree = "<group>"; };
5183CCD9226E31A50010922C /* NonIntrinsicImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonIntrinsicImageView.swift; sourceTree = "<group>"; };
5183CCE4226F4DFA0010922C /* RefreshInterval.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshInterval.swift; sourceTree = "<group>"; };
5183CCE7226F68D90010922C /* AccountRefreshTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountRefreshTimer.swift; sourceTree = "<group>"; };
518651AB23555EB20078E021 /* NNW3Document.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NNW3Document.swift; sourceTree = "<group>"; };
@ -1167,7 +1150,6 @@
51C03080257D815A00609262 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Mac/Base.lproj/UnifiedWindow.storyboard; sourceTree = SOURCE_ROOT; };
51C266E9238C334800F53014 /* ContextMenuPreviewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextMenuPreviewViewController.swift; sourceTree = "<group>"; };
51C4524E226506F400C03939 /* UIStoryboard-Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIStoryboard-Extensions.swift"; sourceTree = "<group>"; };
51C45250226506F400C03939 /* String-Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String-Extensions.swift"; sourceTree = "<group>"; };
51C45254226507D200C03939 /* AppAssets.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppAssets.swift; sourceTree = "<group>"; };
51C45255226507D200C03939 /* AppDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDefaults.swift; sourceTree = "<group>"; };
51C45261226508F600C03939 /* FeedUnreadCountView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedUnreadCountView.swift; sourceTree = "<group>"; };
@ -1208,7 +1190,6 @@
51E498B224A806AA00B667CB /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; };
51E4DAEC2425F6940091EB5B /* CloudKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CloudKit.framework; path = System/Library/Frameworks/CloudKit.framework; sourceTree = SDKROOT; };
51E595A4228CC36500FCC42B /* ArticleStatusSyncTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleStatusSyncTimer.swift; sourceTree = "<group>"; };
51EAED95231363EF00A9EEE3 /* NonIntrinsicButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonIntrinsicButton.swift; sourceTree = "<group>"; };
51EC114B2149FE3300B296E3 /* FolderTreeMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = FolderTreeMenu.swift; path = AddFeed/FolderTreeMenu.swift; sourceTree = "<group>"; };
51EF0F7D2277A57D0050506E /* TimelineAccessibilityCellLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineAccessibilityCellLayout.swift; sourceTree = "<group>"; };
51EF0F7F2277A8330050506E /* TimelineCellLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineCellLayout.swift; sourceTree = "<group>"; };
@ -1218,14 +1199,9 @@
51F85BEE2272520B00C787DC /* Thanks.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = Thanks.rtf; sourceTree = "<group>"; };
51F85BF02272524100C787DC /* Credits.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = Credits.rtf; sourceTree = "<group>"; };
51F85BF22272531500C787DC /* Dedication.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = Dedication.rtf; sourceTree = "<group>"; };
51F85BF42273625800C787DC /* Bundle-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle-Extensions.swift"; sourceTree = "<group>"; };
51F85BF622749FA100C787DC /* UIFont-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIFont-Extensions.swift"; sourceTree = "<group>"; };
51F85BF82274AA7B00C787DC /* UIBarButtonItem-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIBarButtonItem-Extensions.swift"; sourceTree = "<group>"; };
51F85BFA2275D85000C787DC /* Array-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array-Extensions.swift"; sourceTree = "<group>"; };
51F85BFC2275DCA800C787DC /* SingleLineUILabelSizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleLineUILabelSizer.swift; sourceTree = "<group>"; };
51F9F3F623DF6DB200A314FD /* ArticleIconSchemeHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleIconSchemeHandler.swift; sourceTree = "<group>"; };
51F9F3F823DFB16300A314FD /* UITableView-Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UITableView-Extensions.swift"; sourceTree = "<group>"; };
51F9F3FA23DFB25700A314FD /* Animations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Animations.swift; sourceTree = "<group>"; };
51FA73B62332D5F70090D516 /* LegacyArticleExtractorButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyArticleExtractorButton.swift; sourceTree = "<group>"; };
51FD413A2342BD0500880194 /* TimelineUnreadCountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineUnreadCountView.swift; sourceTree = "<group>"; };
51FE10022345529D0056195D /* UserNotificationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserNotificationManager.swift; sourceTree = "<group>"; };
@ -1860,27 +1836,15 @@
51C45245226506C800C03939 /* UIKit Extensions */ = {
isa = PBXGroup;
children = (
51F9F3FA23DFB25700A314FD /* Animations.swift */,
51F85BFA2275D85000C787DC /* Array-Extensions.swift */,
51F85BF42273625800C787DC /* Bundle-Extensions.swift */,
51627A92238A3836007B3B4B /* CroppingPreviewParameters.swift */,
512AF9C1236ED52C0066F8BE /* ImageHeaderView.swift */,
512AF9DC236F05230066F8BE /* InteractiveLabel.swift */,
51934CC1230F5963006127BE /* InteractiveNavigationController.swift */,
51A9A5F42380F6A60033AADF /* ModalNavigationController.swift */,
51EAED95231363EF00A9EEE3 /* NonIntrinsicButton.swift */,
5183CCD9226E31A50010922C /* NonIntrinsicImageView.swift */,
5183CCCF226E1E880010922C /* NonIntrinsicLabel.swift */,
51A9A6092382FD240033AADF /* PoppableGestureRecognizerDelegate.swift */,
512363372369155100951F16 /* RoundedProgressView.swift */,
51C45250226506F400C03939 /* String-Extensions.swift */,
5108F6D723763094001ABC45 /* TickMarkSlider.swift */,
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 */,
@ -3826,16 +3790,12 @@
51E36E71239D6610006F47A5 /* AddFeedSelectFolderTableViewCell.swift in Sources */,
512DD4C92430086400C17B1F /* CloudKitAccountViewController.swift in Sources */,
840D617F2029031C009BC708 /* AppDelegate.swift in Sources */,
51236339236915B100951F16 /* RoundedProgressView.swift in Sources */,
512E08E72268801200BDCFDD /* FeedTreeControllerDelegate.swift in Sources */,
51C452A422650A2D00C03939 /* ArticleUtilities.swift in Sources */,
51F9F3FB23DFB25700A314FD /* Animations.swift in Sources */,
5195C1DA2720205F00888867 /* ShadowTableChanges.swift in Sources */,
5183CCDA226E31A50010922C /* NonIntrinsicImageView.swift in Sources */,
B2B80778239C4C7000F191E0 /* RSImage-AppIcons.swift in Sources */,
518ED21D23D0F26000E0A862 /* UIViewController-Extensions.swift in Sources */,
51A9A5F52380F6A60033AADF /* ModalNavigationController.swift in Sources */,
51EAED96231363EF00A9EEE3 /* NonIntrinsicButton.swift in Sources */,
51C4527B2265091600C03939 /* UnreadIndicatorView.swift in Sources */,
5186A635235EF3A800C97195 /* VibrantLabel.swift in Sources */,
51F85BF92274AA7B00C787DC /* UIBarButtonItem-Extensions.swift in Sources */,
@ -3865,17 +3825,13 @@
514B7C8323205EFB00BAC947 /* RootSplitViewController.swift in Sources */,
51314704235C41FC00387FDC /* Intents.intentdefinition in Sources */,
FF3ABF162325AF5D0074C542 /* ArticleSorter.swift in Sources */,
51C4525C226508DF00C03939 /* String-Extensions.swift in Sources */,
51F9F3F923DFB16300A314FD /* UITableView-Extensions.swift in Sources */,
51C452792265091600C03939 /* TimelineTableViewCell.swift in Sources */,
51C4526B226508F600C03939 /* SidebarViewController.swift in Sources */,
5126EE97226CB48A00C22AFC /* SceneCoordinator.swift in Sources */,
84CAFCB022BC8C35007694F0 /* FetchRequestOperation.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 */,
177A0C2D25454AAB00D7EAF6 /* ReaderAPIAccountViewController.swift in Sources */,
51C452A622650A3500C03939 /* Node-Extensions.swift in Sources */,
51C45294226509C800C03939 /* SearchFeedDelegate.swift in Sources */,
@ -3906,7 +3862,6 @@
51DC079A2552083500A3F79F /* ArticleTextSize.swift in Sources */,
51C4529922650A0000C03939 /* ArticleThemesManager.swift in Sources */,
51EF0F802277A8330050506E /* TimelineCellLayout.swift in Sources */,
51F85BF722749FA100C787DC /* UIFont-Extensions.swift in Sources */,
51C452AF2265108300C03939 /* ArticleArray.swift in Sources */,
51C4528E2265099C00C03939 /* SmartFeedsController.swift in Sources */,
51C9DE5823EA2EF4003D5A6D /* WrapperScriptMessageHandler.swift in Sources */,
@ -3927,7 +3882,6 @@
845122742B8CEA9100480DB0 /* SidebarItem.swift in Sources */,
512E094D2268B8AB00BDCFDD /* DeleteCommand.swift in Sources */,
5110C37D2373A8D100A9C04F /* InspectorIconHeaderView.swift in Sources */,
51F85BFB2275D85000C787DC /* Array-Extensions.swift in Sources */,
51C452AC22650FD200C03939 /* AppNotifications.swift in Sources */,
51EF0F7E2277A57D0050506E /* TimelineAccessibilityCellLayout.swift in Sources */,
51A1699B235E10D700EB091F /* AccountInspectorViewController.swift in Sources */,
@ -3935,7 +3889,6 @@
512D554423C804DE0023FFFA /* OpenInSafariActivity.swift in Sources */,
51C452762265091600C03939 /* TimelineViewController.swift in Sources */,
5195C1DC2720BD3000888867 /* FeedRowIdentifier.swift in Sources */,
5108F6D823763094001ABC45 /* TickMarkSlider.swift in Sources */,
51C452882265093600C03939 /* AddFeedViewController.swift in Sources */,
51B5C8C023F3866C00032075 /* ExtensionFeedAddRequestFile.swift in Sources */,
51A169A0235E10D700EB091F /* FeedbinAccountViewController.swift in Sources */,
@ -3958,7 +3911,6 @@
512E09012268907400BDCFDD /* FeedTableViewSectionHeader.swift in Sources */,
51C45268226508F600C03939 /* FeedUnreadCountView.swift in Sources */,
D3A39865246505DF00F9A366 /* FindInArticleActivity.swift in Sources */,
5183CCD0226E1E880010922C /* NonIntrinsicLabel.swift in Sources */,
5137C2EA26F63AE6009EFEDB /* ArticleThemeImporter.swift in Sources */,
5108F6D22375EED2001ABC45 /* TimelineCustomizerViewController.swift in Sources */,
519E743D22C663F900A78E47 /* SceneDelegate.swift in Sources */,

View File

@ -1,13 +1,13 @@
{
"originHash" : "b43137d843d357a97b0dc7bc5a49f46d93502bbf01a89e1655ce67d2ca07dc5f",
"originHash" : "59328e75653678265f96b3e73fe970261384ed8254eaf879de4d37bf88c50409",
"pins" : [
{
"identity" : "plcrashreporter",
"kind" : "remoteSourceControl",
"location" : "https://github.com/microsoft/plcrashreporter.git",
"state" : {
"revision" : "1aed8f7dc79ce8e674c61e430ef51ca3db18cea9",
"version" : "1.11.1"
"revision" : "6752f71de206f6a53fa6a758c3660fd9a7fe7527",
"version" : "1.11.2"
}
},
{

View File

@ -10,10 +10,10 @@ import Foundation
import UIKit
class NonIntrinsicButton: UIButton {
public final class NonIntrinsicButton: UIButton {
// Prevent autolayout from messing around with our frame settings
override var intrinsicContentSize: CGSize {
public override var intrinsicContentSize: CGSize {
return CGSize(width: UIView.noIntrinsicMetric, height: UIView.noIntrinsicMetric)
}

View File

@ -8,10 +8,10 @@
import UIKit
class NonIntrinsicImageView: UIImageView {
public final class NonIntrinsicImageView: UIImageView {
// Prevent autolayout from messing around with our frame settings
override var intrinsicContentSize: CGSize {
public override var intrinsicContentSize: CGSize {
return CGSize(width: UIView.noIntrinsicMetric, height: UIView.noIntrinsicMetric)
}

View File

@ -8,10 +8,10 @@
import UIKit
class NonIntrinsicLabel: UILabel {
public final class NonIntrinsicLabel: UILabel {
// Prevent autolayout from messing around with our frame settings
override var intrinsicContentSize: CGSize {
public override var intrinsicContentSize: CGSize {
return CGSize(width: UIView.noIntrinsicMetric, height: UIView.noIntrinsicMetric)
}

View File

@ -8,9 +8,9 @@
import UIKit
class RoundedProgressView: UIProgressView {
public final class RoundedProgressView: UIProgressView {
override func layoutSubviews() {
public override func layoutSubviews() {
super.layoutSubviews()
for subview in subviews {
subview.layer.masksToBounds = true

View File

@ -1,5 +1,5 @@
//
// String-Extensions.swift
// String+Extensions.swift
// NetNewsWire
//
// Created by Maurice Parker on 4/8/19.
@ -8,8 +8,8 @@
import UIKit
extension String {
public extension String {
func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
let boundingBox = self.boundingRect(with: constraintRect, options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: [NSAttributedString.Key.font: font], context: nil)
@ -21,5 +21,4 @@ extension String {
let boundingBox = self.boundingRect(with: constraintRect, options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: [NSAttributedString.Key.font: font], context: nil)
return ceil(boundingBox.width)
}
}

View File

@ -8,13 +8,13 @@
import UIKit
class TickMarkSlider: UISlider {
public final class TickMarkSlider: UISlider {
private var enableFeedback = false
private let feedbackGenerator = UISelectionFeedbackGenerator()
private var roundedValue: Float?
override var value: Float {
public override var value: Float {
didSet {
let testValue = value.rounded()
if testValue != roundedValue && enableFeedback && value.truncatingRemainder(dividingBy: 1) == 0 {
@ -24,7 +24,7 @@ class TickMarkSlider: UISlider {
}
}
func addTickMarks() {
public func addTickMarks(color: UIColor) {
enableFeedback = true
@ -36,7 +36,7 @@ class TickMarkSlider: UISlider {
let tick = UIView()
tick.translatesAutoresizingMaskIntoConstraints = false
tick.backgroundColor = AppAssets.tickMarkColor
tick.backgroundColor = backgroundColor
insertSubview(tick, at: 0)
tick.widthAnchor.constraint(equalToConstant: 3).isActive = true
@ -59,7 +59,6 @@ class TickMarkSlider: UISlider {
} else {
tick.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
}
}
if let firstGapLayoutGuild = gapLayoutGuides.first {
@ -67,17 +66,15 @@ class TickMarkSlider: UISlider {
gapLayoutGuides[i].widthAnchor.constraint(equalTo: firstGapLayoutGuild.widthAnchor).isActive = true
}
}
}
override func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
public override func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
let result = super.continueTracking(touch, with: event)
value = value.rounded()
return result
}
override func endTracking(_ touch: UITouch?, with event: UIEvent?) {
public override func endTracking(_ touch: UITouch?, with event: UIEvent?) {
value = value.rounded()
}
}

View File

@ -48,10 +48,7 @@ public protocol DownloadSessionDelegate {
sessionConfiguration.httpMaximumConnectionsPerHost = 2
sessionConfiguration.httpCookieStorage = nil
sessionConfiguration.urlCache = nil
if let userAgentHeaders = UserAgent.headers() {
sessionConfiguration.httpAdditionalHeaders = userAgentHeaders
}
sessionConfiguration.httpAdditionalHeaders = UserAgent.headers
urlSession = URLSession(configuration: sessionConfiguration, delegate: self, delegateQueue: OperationQueue.main)
}

View File

@ -27,10 +27,7 @@ public typealias OneShotDownloadCallback = @Sendable (Data?, URLResponse?, Error
sessionConfiguration.httpCookieStorage = nil
sessionConfiguration.urlCache = nil
sessionConfiguration.timeoutIntervalForRequest = 30
if let userAgentHeaders = UserAgent.headers() {
sessionConfiguration.httpAdditionalHeaders = userAgentHeaders
}
sessionConfiguration.httpAdditionalHeaders = UserAgent.headers
urlSession = URLSession(configuration: sessionConfiguration)
}

View File

@ -10,17 +10,14 @@ import Foundation
public struct UserAgent {
public static func fromInfoPlist() -> String? {
public static let fromInfoPlist: String = {
return Bundle.main.object(forInfoDictionaryKey: "UserAgent") as? String
}
Bundle.main.object(forInfoDictionaryKey: "UserAgent") as! String
}()
public static func headers() -> [AnyHashable: String]? {
guard let userAgent = fromInfoPlist() else {
return nil
}
public static let headers: [String: String] = {
let userAgent = fromInfoPlist
return [HTTPRequestHeader.userAgent: userAgent]
}
}()
}

View File

@ -281,11 +281,8 @@ extension URLSession: Transport {
sessionConfiguration.httpMaximumConnectionsPerHost = 2
sessionConfiguration.httpCookieStorage = nil
sessionConfiguration.urlCache = nil
if let userAgentHeaders = UserAgent.headers() {
sessionConfiguration.httpAdditionalHeaders = userAgentHeaders
}
sessionConfiguration.httpAdditionalHeaders = UserAgent.headers
return URLSession(configuration: sessionConfiguration)
}
}

View File

@ -13,7 +13,7 @@ import Articles
import SafariServices
import ArticleExtractor
class ArticleViewController: UIViewController {
final class ArticleViewController: UIViewController {
typealias State = (extractedArticle: ExtractedArticle?,
isShowingExtractedArticle: Bool,
@ -509,3 +509,16 @@ private extension ArticleViewController {
}
}
private extension UIPageViewController {
var scrollViewInsidePageControl: UIScrollView? {
for view in view.subviews {
if let scrollView = view as? UIScrollView {
return scrollView
}
}
return nil
}
}

View File

@ -7,6 +7,7 @@
//
import UIKit
import UIKitExtras
import Account
import Tree
import Images

View File

@ -121,3 +121,17 @@ class FeedUnreadCountView : UIView {
}
private extension UIFont {
func withTraits(traits:UIFontDescriptor.SymbolicTraits) -> UIFont {
if let descriptor = fontDescriptor.withSymbolicTraits(traits) {
return UIFont(descriptor: descriptor, size: 0) //size 0 means keep the size as it is
} else {
return self
}
}
func bold() -> UIFont {
return withTraits(traits: .traitBold)
}
}

View File

@ -7,6 +7,7 @@
//
import UIKit
import UIKitExtras
import Account
import Articles
import Tree

View File

@ -7,6 +7,7 @@
//
import UIKit
import UIKitExtras
import Images
final class IconView: UIView {

View File

@ -7,6 +7,7 @@
//
import UIKit
import UIKitExtras
import UserNotifications
import Account
import Articles

View File

@ -10,7 +10,7 @@ import UIKit
import UserNotifications
import Account
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
final class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
var coordinator: SceneCoordinator!
@ -52,10 +52,10 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
}
}
func windowScene(_ windowScene: UIWindowScene, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
func windowScene(_ windowScene: UIWindowScene, performActionFor shortcutItem: UIApplicationShortcutItem) async -> Bool {
appDelegate.resumeDatabaseProcessingIfNecessary()
handleShortcutItem(shortcutItem)
completionHandler(true)
return true
}
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {

View File

@ -7,8 +7,9 @@
//
import UIKit
import UIKitExtras
class AboutViewController: UITableViewController {
final class AboutViewController: UITableViewController {
@IBOutlet weak var aboutTextView: UITextView!
@IBOutlet weak var creditsTextView: UITextView!

View File

@ -7,13 +7,14 @@
//
import UIKit
import UIKitExtras
import Account
import CoreServices
import SafariServices
import SwiftUI
import UniformTypeIdentifiers
class SettingsViewController: UITableViewController {
final class SettingsViewController: UITableViewController {
private weak var opmlAccount: Account?
@ -480,6 +481,19 @@ private extension SettingsViewController {
vc.modalPresentationStyle = .pageSheet
present(vc, animated: true)
}
}
extension Bundle {
var appName: String {
return infoDictionary?["CFBundleName"] as! String
}
var versionNumber: String {
return infoDictionary?["CFBundleShortVersionString"] as! String
}
var buildNumber: String {
return infoDictionary?["CFBundleVersion"] as! String
}
}

View File

@ -8,8 +8,9 @@
import UIKit
import Images
import UIKitExtras
class TimelineCustomizerViewController: UIViewController {
final class TimelineCustomizerViewController: UIViewController {
@IBOutlet weak var iconSizeSliderContainerView: UIView!
@IBOutlet weak var iconSizeSlider: TickMarkSlider!
@ -29,11 +30,11 @@ class TimelineCustomizerViewController: UIViewController {
iconSizeSliderContainerView.layer.cornerRadius = 10
iconSizeSlider.value = Float(AppDefaults.shared.timelineIconSize.rawValue)
iconSizeSlider.addTickMarks()
iconSizeSlider.addTickMarks(color: AppAssets.tickMarkColor)
numberOfLinesSliderContainerView.layer.cornerRadius = 10
numberOfLinesSlider.value = Float(AppDefaults.shared.timelineNumberOfLines)
numberOfLinesSlider.addTickMarks()
numberOfLinesSlider.addTickMarks(color: AppAssets.tickMarkColor)
}
override func viewWillAppear(_ animated: Bool) {
@ -57,7 +58,6 @@ class TimelineCustomizerViewController: UIViewController {
AppDefaults.shared.timelineNumberOfLines = Int(numberOfLinesSlider.value.rounded())
updatePreview()
}
}
// MARK: Private
@ -87,5 +87,4 @@ private extension TimelineCustomizerViewController {
previewContainerView.layer.borderWidth = 0
}
}
}

View File

@ -7,6 +7,7 @@
//
import UIKit
import UIKitExtras
import Images
class TimelineTableViewCell: VibrantTableViewCell {

View File

@ -8,7 +8,7 @@
import UIKit
class TimelineUnreadCountView: FeedUnreadCountView {
final class TimelineUnreadCountView: FeedUnreadCountView {
override var padding: UIEdgeInsets {
return UIEdgeInsets(top: 2.0, left: 9.0, bottom: 2.0, right: 9.0)
@ -33,7 +33,5 @@ class TimelineUnreadCountView: FeedUnreadCountView {
if unreadCount > 0 {
unreadCountString.draw(at: textRect().origin, withAttributes: textAttributes)
}
}
}

View File

@ -7,6 +7,7 @@
//
import UIKit
import UIKitExtras
import Account
import Articles
import Core

View File

@ -1,21 +0,0 @@
//
// Array-Extensions.swift
// NetNewsWire-iOS
//
// Created by Maurice Parker on 4/28/19.
// Copyright © 2019 Ranchero Software. All rights reserved.
//
import UIKit
extension Array where Element == CGRect {
func maxY() -> CGFloat {
var y: CGFloat = 0.0
for r in self {
y = Swift.max(y, r.maxY)
}
return y
}
}

View File

@ -1,25 +0,0 @@
//
// Bundle-Extensions.swift
// NetNewsWire-iOS
//
// Created by Maurice Parker on 4/26/19.
// Copyright © 2019 Ranchero Software. All rights reserved.
//
import Foundation
extension Bundle {
var appName: String {
return infoDictionary?["CFBundleName"] as! String
}
var versionNumber: String {
return infoDictionary?["CFBundleShortVersionString"] as! String
}
var buildNumber: String {
return infoDictionary?["CFBundleVersion"] as! String
}
}

View File

@ -1,29 +0,0 @@
//
// UIFont-Extensions.swift
// NetNewsWire-iOS
//
// Created by Maurice Parker on 4/27/19.
// Copyright © 2019 Ranchero Software. All rights reserved.
//
import UIKit
extension UIFont {
func withTraits(traits:UIFontDescriptor.SymbolicTraits) -> UIFont {
if let descriptor = fontDescriptor.withSymbolicTraits(traits) {
return UIFont(descriptor: descriptor, size: 0) //size 0 means keep the size as it is
} else {
return self
}
}
func bold() -> UIFont {
return withTraits(traits: .traitBold)
}
func italic() -> UIFont {
return withTraits(traits: .traitItalic)
}
}

View File

@ -1,22 +0,0 @@
//
// 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
}
}