diff --git a/Mac/AppAssets.swift b/Mac/AppAssets.swift
index 13244e996..cefbe0423 100644
--- a/Mac/AppAssets.swift
+++ b/Mac/AppAssets.swift
@@ -50,7 +50,7 @@ struct AppAssets {
static let nnwFeedIcon = RSImage(named: "nnwFeedIcon")!
- @available(macOS 11.0, *)
+
static var addNewSidebarItemImage: RSImage = {
return NSImage(systemSymbolName: "plus", accessibilityDescription: nil)!
}()
@@ -67,14 +67,22 @@ struct AppAssets {
return RSImage(named: "articleExtractorOn")!
}()
- @available(macOS 11.0, *)
+
static var articleTheme: RSImage = {
return NSImage(systemSymbolName: "doc.richtext", accessibilityDescription: nil)!
}()
- @available(macOS 11.0, *)
+
static var cleanUpImage: RSImage = {
- return NSImage(systemSymbolName: "wind", accessibilityDescription: nil)!
+ return NSImage(systemSymbolName: "bubbles.and.sparkles", accessibilityDescription: nil)!
+ }()
+
+ static var copyImage: RSImage = {
+ return NSImage(systemSymbolName: "document.on.document", accessibilityDescription: nil)!
+ }()
+
+ static var deleteImage: RSImage = {
+ return NSImage(systemSymbolName: "xmark.bin", accessibilityDescription: nil)!
}()
static var marsEditIcon: RSImage = {
@@ -90,19 +98,11 @@ struct AppAssets {
}()
static var filterActive: RSImage = {
- if #available(macOS 11.0, *) {
- return NSImage(systemSymbolName: "line.horizontal.3.decrease.circle.fill", accessibilityDescription: nil)!
- } else {
- return RSImage(named: "filterActive")!
- }
+ return NSImage(systemSymbolName: "line.horizontal.3.decrease.circle.fill", accessibilityDescription: nil)!
}()
static var filterInactive: RSImage = {
- if #available(macOS 11.0, *) {
- return NSImage(systemSymbolName: "line.horizontal.3.decrease.circle", accessibilityDescription: nil)!
- } else {
- return RSImage(named: "filterInactive")!
- }
+ return NSImage(systemSymbolName: "line.horizontal.3.decrease.circle", accessibilityDescription: nil)!
}()
static var iconLightBackgroundColor: NSColor = {
@@ -146,100 +146,94 @@ struct AppAssets {
}()
static var mainFolderImage: IconImage {
- if #available(macOS 11.0, *) {
- let image = NSImage(systemSymbolName: "folder", accessibilityDescription: nil)!
- let preferredColor = NSColor(named: "AccentColor")!
- return IconImage(image, isSymbol: true, isBackgroundSuppressed: true, preferredColor: preferredColor.cgColor)
- } else {
- return IconImage(RSImage(named: NSImage.folderName)!)
- }
+ let image = NSImage(systemSymbolName: "folder", accessibilityDescription: nil)!
+ let preferredColor = NSColor(named: "AccentColor")!
+ return IconImage(image, isSymbol: true, isBackgroundSuppressed: true, preferredColor: preferredColor.cgColor)
}
+
+ static var markAllAsReadMenuImage: RSImage = {
+ let image = RSImage(named: "markAllAsRead")
+ return image!
+ }()
+
static var markAllAsReadImage: RSImage = {
- return RSImage(named: "markAllAsRead")!
+ let image = RSImage(named: "markAllAsRead")
+ return image!
}()
- @available(macOS 11.0, *)
+
static var nextUnreadImage: RSImage = {
return NSImage(systemSymbolName: "chevron.down.circle", accessibilityDescription: nil)!
}()
- @available(macOS 11.0, *)
+ static var notificationImage: RSImage = {
+ return NSImage(systemSymbolName: "bell.badge", accessibilityDescription: nil)!
+ }()
+
static var openInBrowserImage: RSImage = {
return NSImage(systemSymbolName: "safari", accessibilityDescription: nil)!
}()
static var preferencesToolbarAccountsImage: RSImage = {
- if #available(macOS 11.0, *) {
- return NSImage(systemSymbolName: "at", accessibilityDescription: nil)!
- } else {
- return NSImage(named: NSImage.userAccountsName)!
- }
+ return NSImage(systemSymbolName: "at", accessibilityDescription: nil)!
}()
static var preferencesToolbarGeneralImage: RSImage = {
- if #available(macOS 11.0, *) {
- return NSImage(systemSymbolName: "gearshape", accessibilityDescription: nil)!
- } else {
- return NSImage(named: NSImage.preferencesGeneralName)!
- }
+ return NSImage(systemSymbolName: "gearshape", accessibilityDescription: nil)!
}()
static var preferencesToolbarAdvancedImage: RSImage = {
- if #available(macOS 11.0, *) {
- return NSImage(systemSymbolName: "gearshape.2", accessibilityDescription: nil)!
- } else {
- return NSImage(named: NSImage.advancedName)!
- }
+ return NSImage(systemSymbolName: "gearshape.2", accessibilityDescription: nil)!
}()
- @available(macOS 11.0, *)
+
static var readClosedImage: RSImage = {
return NSImage(systemSymbolName: "largecircle.fill.circle", accessibilityDescription: nil)!
}()
- @available(macOS 11.0, *)
+
static var readOpenImage: RSImage = {
return NSImage(systemSymbolName: "circle", accessibilityDescription: nil)!
}()
- @available(macOS 11.0, *)
+
static var refreshImage: RSImage = {
return NSImage(systemSymbolName: "arrow.clockwise", accessibilityDescription: nil)!
}()
+ static var renameImage: RSImage = {
+ return NSImage(systemSymbolName: "pencil", accessibilityDescription: nil)!
+ }()
+
static var searchFeedImage: IconImage = {
return IconImage(RSImage(named: NSImage.smartBadgeTemplateName)!, isSymbol: true, isBackgroundSuppressed: true)
}()
- @available(macOS 11.0, *)
+
static var shareImage: RSImage = {
return NSImage(systemSymbolName: "square.and.arrow.up", accessibilityDescription: nil)!
}()
- @available(macOS 11.0, *)
+
static var sidebarToggleImage: RSImage = {
return NSImage(systemSymbolName: "sidebar.left", accessibilityDescription: nil)!
}()
- @available(macOS 11.0, *)
+
static var starClosedImage: RSImage = {
return NSImage(systemSymbolName: "star.fill", accessibilityDescription: nil)!
}()
- @available(macOS 11.0, *)
+
static var starOpenImage: RSImage = {
return NSImage(systemSymbolName: "star", accessibilityDescription: nil)!
}()
static var starredFeedImage: IconImage = {
- if #available(macOS 11.0, *) {
- let image = NSImage(systemSymbolName: "star.fill", accessibilityDescription: nil)!
- let preferredColor = NSColor(named: "StarColor")!
- return IconImage(image, isSymbol: true, isBackgroundSuppressed: true, preferredColor: preferredColor.cgColor)
- } else {
- return IconImage(RSImage(named: NSImage.smartBadgeTemplateName)!, isBackgroundSuppressed: true)
- }
+ let image = NSImage(systemSymbolName: "star.fill", accessibilityDescription: nil)!
+ let preferredColor = NSColor(named: "StarColor")!
+ return IconImage(image, isSymbol: true, isBackgroundSuppressed: true, preferredColor: preferredColor.cgColor)
}()
static var timelineSeparatorColor: NSColor = {
@@ -255,61 +249,31 @@ struct AppAssets {
}()
static var todayFeedImage: IconImage = {
- if #available(macOS 11.0, *) {
- let image = NSImage(systemSymbolName: "sun.max.fill", accessibilityDescription: nil)!
- let preferredColor = NSColor.orange
- return IconImage(image, isSymbol: true, isBackgroundSuppressed: true, preferredColor: preferredColor.cgColor)
- } else {
- return IconImage(RSImage(named: NSImage.smartBadgeTemplateName)!, isBackgroundSuppressed: true)
- }
+ let image = NSImage(systemSymbolName: "sun.max.fill", accessibilityDescription: nil)!
+ let preferredColor = NSColor.orange
+ return IconImage(image, isSymbol: true, isBackgroundSuppressed: true, preferredColor: preferredColor.cgColor)
}()
static var unreadFeedImage: IconImage = {
- if #available(macOS 11.0, *) {
- let image = NSImage(systemSymbolName: "largecircle.fill.circle", accessibilityDescription: nil)!
- let preferredColor = NSColor(named: "AccentColor")!
- return IconImage(image, isSymbol: true, isBackgroundSuppressed: true, preferredColor: preferredColor.cgColor)
- } else {
- return IconImage(RSImage(named: NSImage.smartBadgeTemplateName)!, isBackgroundSuppressed: true)
- }
+ let image = NSImage(systemSymbolName: "largecircle.fill.circle", accessibilityDescription: nil)!
+ let preferredColor = NSColor(named: "AccentColor")!
+ return IconImage(image, isSymbol: true, isBackgroundSuppressed: true, preferredColor: preferredColor.cgColor)
}()
static var swipeMarkReadImage: RSImage = {
- if #available(OSX 11.0, *) {
- return RSImage(systemSymbolName: "circle", accessibilityDescription: "Mark Read")!
- .withSymbolConfiguration(.init(scale: .large))!
- } else {
- // TODO: remove swipeMarkRead asset when dropping support for macOS 10.15
- return RSImage(named: "swipeMarkRead")!
- }
+ return RSImage(systemSymbolName: "circle", accessibilityDescription: "Mark Read")!
}()
static var swipeMarkUnreadImage: RSImage = {
- if #available(OSX 11.0, *) {
- return RSImage(systemSymbolName: "largecircle.fill.circle", accessibilityDescription: "Mark Unread")!
- .withSymbolConfiguration(.init(scale: .large))!
- } else {
- // TODO: remove swipeMarkUnread asset when dropping support for macOS 10.15
- return RSImage(named: "swipeMarkUnread")!
- }
+ return RSImage(systemSymbolName: "largecircle.fill.circle", accessibilityDescription: "Mark Unread")!
}()
static var swipeMarkStarredImage: RSImage = {
- if #available(OSX 11.0, *) {
- return RSImage(systemSymbolName: "star.fill", accessibilityDescription: "Star")!
- .withSymbolConfiguration(.init(scale: .large))!
- } else {
- return RSImage(named: "swipeMarkStarred")!
- }
+ return RSImage(systemSymbolName: "star.fill", accessibilityDescription: "Star")!
}()
static var swipeMarkUnstarredImage: RSImage = {
- if #available(OSX 11.0, *) {
- return RSImage(systemSymbolName: "star", accessibilityDescription: "Unstar")!
- .withSymbolConfiguration(.init(scale: .large))!
- } else {
- return RSImage(named: "swipeMarkUnstarred")!
- }
+ return RSImage(systemSymbolName: "star", accessibilityDescription: "Unstar")!
}()
static var starColor: NSColor = {
diff --git a/Mac/AppDelegate.swift b/Mac/AppDelegate.swift
index 79a53d955..adf91c8a5 100644
--- a/Mac/AppDelegate.swift
+++ b/Mac/AppDelegate.swift
@@ -798,30 +798,20 @@ internal extension AppDelegate {
attrs[.font] = NSFont.systemFont(ofSize: NSFont.smallSystemFontSize)
attrs[.foregroundColor] = NSColor.textColor
- if #available(macOS 11.0, *) {
- let titleParagraphStyle = NSMutableParagraphStyle()
- titleParagraphStyle.alignment = .center
- attrs[.paragraphStyle] = titleParagraphStyle
- }
-
+ let titleParagraphStyle = NSMutableParagraphStyle()
+ titleParagraphStyle.alignment = .center
+ attrs[.paragraphStyle] = titleParagraphStyle
+
let websiteText = NSMutableAttributedString()
websiteText.append(NSAttributedString(string: NSLocalizedString("Author‘s website:", comment: "Author's Website"), attributes: attrs))
- if #available(macOS 11.0, *) {
- websiteText.append(NSAttributedString(string: "\n"))
- } else {
- websiteText.append(NSAttributedString(string: " "))
- }
+ websiteText.append(NSAttributedString(string: "\n"))
attrs[.link] = theme.creatorHomePage
websiteText.append(NSAttributedString(string: theme.creatorHomePage, attributes: attrs))
let textViewWidth: CGFloat
- if #available(macOS 11.0, *) {
- textViewWidth = 200
- } else {
- textViewWidth = 400
- }
+ textViewWidth = 200
let textView = NSTextView(frame: CGRect(x: 0, y: 0, width: textViewWidth, height: 15))
textView.isEditable = false
diff --git a/Mac/Inspector/BuiltinSmartFeedInspectorViewController.swift b/Mac/Inspector/BuiltinSmartFeedInspectorViewController.swift
index bbd1a928d..3c6c7b908 100644
--- a/Mac/Inspector/BuiltinSmartFeedInspectorViewController.swift
+++ b/Mac/Inspector/BuiltinSmartFeedInspectorViewController.swift
@@ -64,8 +64,6 @@ private extension BuiltinSmartFeedInspectorViewController {
func updateUI() {
nameTextField?.stringValue = smartFeed?.nameForDisplay ?? ""
windowTitle = smartFeed?.nameForDisplay ?? NSLocalizedString("Smart Feed Inspector", comment: "Smart Feed Inspector window title")
- if #available(macOS 11.0, *) {
- smartFeedImageView?.image = smartFeed?.smallIcon?.image
- }
+ smartFeedImageView?.image = smartFeed?.smallIcon?.image
}
}
diff --git a/Mac/Inspector/FolderInspectorViewController.swift b/Mac/Inspector/FolderInspectorViewController.swift
index d67dfca80..63f76b0d7 100644
--- a/Mac/Inspector/FolderInspectorViewController.swift
+++ b/Mac/Inspector/FolderInspectorViewController.swift
@@ -47,11 +47,9 @@ final class FolderInspectorViewController: NSViewController, Inspector {
override func viewDidLoad() {
updateUI()
- if #available(macOS 11.0, *) {
- let image = NSImage(systemSymbolName: "folder", accessibilityDescription: nil)!
- folderImageView.image = image
- folderImageView.contentTintColor = NSColor.controlAccentColor
- }
+ let image = NSImage(systemSymbolName: "folder", accessibilityDescription: nil)!
+ folderImageView.image = image
+ folderImageView.contentTintColor = NSColor.controlAccentColor
NotificationCenter.default.addObserver(self, selector: #selector(displayNameDidChange(_:)), name: .DisplayNameDidChange, object: nil)
}
diff --git a/Mac/MainWindow/Detail/DetailWebViewController.swift b/Mac/MainWindow/Detail/DetailWebViewController.swift
index 2f82fed78..b026fbc7d 100644
--- a/Mac/MainWindow/Detail/DetailWebViewController.swift
+++ b/Mac/MainWindow/Detail/DetailWebViewController.swift
@@ -120,19 +120,6 @@ final class DetailWebViewController: NSViewController {
view = webView
- // Use the safe area layout guides if they are available.
- if #available(OSX 11.0, *) {
- // These constraints have been removed as they were unsatisfiable after removing NSBox.
- } else {
- let constraints = [
- webView.topAnchor.constraint(equalTo: view.topAnchor),
- webView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- ]
- NSLayoutConstraint.activate(constraints)
- }
-
// Hide the web view until the first reload (navigation) is complete (plus some delay) to avoid the awful white flash that happens on the initial display in dark mode.
// See bug #901.
webView.isHidden = true
@@ -346,9 +333,6 @@ private extension DetailWebViewController {
func fetchScrollInfo(_ completion: @escaping (ScrollInfo?) -> Void) {
var javascriptString = "var x = {contentHeight: document.body.scrollHeight, offsetY: document.body.scrollTop}; x"
- if #available(macOS 10.15, *) {
- 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 {
diff --git a/Mac/MainWindow/MainWindowController.swift b/Mac/MainWindow/MainWindowController.swift
index a0b9932c5..0f90b85b1 100644
--- a/Mac/MainWindow/MainWindowController.swift
+++ b/Mac/MainWindow/MainWindowController.swift
@@ -854,11 +854,11 @@ extension MainWindowController: NSToolbarDelegate {
func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
[
+ NSToolbarItem.Identifier.toggleSidebar,
.flexibleSpace,
.refresh,
.newSidebarItemMenu,
.sidebarTrackingSeparator,
- NSToolbarItem.Identifier.toggleSidebar,
.markAllAsRead,
.toggleReadArticlesFilter,
.timelineTrackingSeparator,
diff --git a/Mac/MainWindow/Sidebar/Cell/SidebarCell.swift b/Mac/MainWindow/Sidebar/Cell/SidebarCell.swift
index d3154e2c8..190e48321 100644
--- a/Mac/MainWindow/Sidebar/Cell/SidebarCell.swift
+++ b/Mac/MainWindow/Sidebar/Cell/SidebarCell.swift
@@ -78,6 +78,7 @@ class SidebarCell : NSTableCellView {
override var backgroundStyle: NSView.BackgroundStyle {
didSet {
updateFaviconImage()
+ unreadCountView.isSelected = (backgroundStyle != .normal)
}
}
@@ -164,4 +165,3 @@ private extension SidebarCell {
}
}
-
diff --git a/Mac/MainWindow/Sidebar/Cell/SidebarCellAppearance.swift b/Mac/MainWindow/Sidebar/Cell/SidebarCellAppearance.swift
index 7a082b434..c13996732 100644
--- a/Mac/MainWindow/Sidebar/Cell/SidebarCellAppearance.swift
+++ b/Mac/MainWindow/Sidebar/Cell/SidebarCellAppearance.swift
@@ -23,11 +23,7 @@ struct SidebarCellAppearance: Equatable {
textFieldFontSize = 11
case .large:
imageSize = CGSize(width: 22, height: 22)
- if #available(macOS 11.0, *) {
- textFieldFontSize = 15
- } else {
- textFieldFontSize = 13
- }
+ textFieldFontSize = 15
default:
imageSize = CGSize(width: 19, height: 19)
textFieldFontSize = 13
diff --git a/Mac/MainWindow/Sidebar/SidebarViewController+ContextualMenus.swift b/Mac/MainWindow/Sidebar/SidebarViewController+ContextualMenus.swift
index 3944c1bfd..4bff3aca6 100644
--- a/Mac/MainWindow/Sidebar/SidebarViewController+ContextualMenus.swift
+++ b/Mac/MainWindow/Sidebar/SidebarViewController+ContextualMenus.swift
@@ -216,23 +216,23 @@ private extension SidebarViewController {
}
if let homePageURL = webFeed.homePageURL, let _ = URL(string: homePageURL) {
- let item = menuItem(NSLocalizedString("Open Home Page", comment: "Command"), #selector(openHomePageFromContextualMenu(_:)), homePageURL)
+ let item = menuItem(NSLocalizedString("Open Home Page", comment: "Command"), #selector(openHomePageFromContextualMenu(_:)), homePageURL, image: AppAssets.openInBrowserImage)
menu.addItem(item)
menu.addItem(NSMenuItem.separator())
}
- let copyFeedURLItem = menuItem(NSLocalizedString("Copy Feed URL", comment: "Command"), #selector(copyURLFromContextualMenu(_:)), webFeed.url)
+ let copyFeedURLItem = menuItem(NSLocalizedString("Copy Feed URL", comment: "Command"), #selector(copyURLFromContextualMenu(_:)), webFeed.url, image: AppAssets.copyImage)
menu.addItem(copyFeedURLItem)
if let homePageURL = webFeed.homePageURL {
- let item = menuItem(NSLocalizedString("Copy Home Page URL", comment: "Command"), #selector(copyURLFromContextualMenu(_:)), homePageURL)
+ let item = menuItem(NSLocalizedString("Copy Home Page URL", comment: "Command"), #selector(copyURLFromContextualMenu(_:)), homePageURL, image: AppAssets.copyImage)
menu.addItem(item)
}
menu.addItem(NSMenuItem.separator())
let notificationText = webFeed.notificationDisplayName.capitalized
- let notificationMenuItem = menuItem(notificationText, #selector(toggleNotificationsFromContextMenu(_:)), webFeed)
+ let notificationMenuItem = menuItem(notificationText, #selector(toggleNotificationsFromContextMenu(_:)), webFeed, image: AppAssets.notificationImage)
if webFeed.isNotifyAboutNewArticles == nil || webFeed.isNotifyAboutNewArticles! == false {
notificationMenuItem.state = .off
} else {
@@ -241,7 +241,7 @@ private extension SidebarViewController {
menu.addItem(notificationMenuItem)
let articleExtractorText = NSLocalizedString("Always Use Reader View", comment: "Always Use Reader View")
- let articleExtractorMenuItem = menuItem(articleExtractorText, #selector(toggleArticleExtractorFromContextMenu(_:)), webFeed)
+ let articleExtractorMenuItem = menuItem(articleExtractorText, #selector(toggleArticleExtractorFromContextMenu(_:)), webFeed, image: AppAssets.articleExtractorOff)
if webFeed.isArticleExtractorAlwaysOn == nil || webFeed.isArticleExtractorAlwaysOn! == false {
articleExtractorMenuItem.state = .off
@@ -301,17 +301,17 @@ private extension SidebarViewController {
func markAllReadMenuItem(_ objects: [Any]) -> NSMenuItem {
- return menuItem(NSLocalizedString("Mark All as Read", comment: "Command"), #selector(markObjectsReadFromContextualMenu(_:)), objects)
+ return menuItem(NSLocalizedString("Mark All as Read", comment: "Command"), #selector(markObjectsReadFromContextualMenu(_:)), objects, image: AppAssets.markAllAsReadMenuImage)
}
func deleteMenuItem(_ objects: [Any]) -> NSMenuItem {
- return menuItem(NSLocalizedString("Delete", comment: "Command"), #selector(deleteFromContextualMenu(_:)), objects)
+ return menuItem(NSLocalizedString("Delete", comment: "Command"), #selector(deleteFromContextualMenu(_:)), objects, image: AppAssets.deleteImage)
}
func renameMenuItem(_ object: Any) -> NSMenuItem {
- return menuItem(NSLocalizedString("Rename", comment: "Command"), #selector(renameFromContextualMenu(_:)), object)
+ return menuItem(NSLocalizedString("Rename", comment: "Command"), #selector(renameFromContextualMenu(_:)), object, image: AppAssets.renameImage)
}
func anyObjectInArrayHasNonZeroUnreadCount(_ objects: [Any]) -> Bool {
@@ -341,11 +341,14 @@ private extension SidebarViewController {
return object is WebFeed || object is Folder
}
- func menuItem(_ title: String, _ action: Selector, _ representedObject: Any) -> NSMenuItem {
+ func menuItem(_ title: String, _ action: Selector, _ representedObject: Any, image: RSImage?) -> NSMenuItem {
let item = NSMenuItem(title: title, action: action, keyEquivalent: "")
item.representedObject = representedObject
item.target = self
+ if let image {
+ item.image = image
+ }
return item
}
diff --git a/Mac/MainWindow/Sidebar/UnreadCountView.swift b/Mac/MainWindow/Sidebar/UnreadCountView.swift
index 25ee1c2a4..75ab94e6b 100644
--- a/Mac/MainWindow/Sidebar/UnreadCountView.swift
+++ b/Mac/MainWindow/Sidebar/UnreadCountView.swift
@@ -13,11 +13,9 @@ class UnreadCountView : NSView {
struct Appearance {
static let padding = NSEdgeInsets(top: 1.0, left: 7.0, bottom: 1.0, right: 7.0)
static let cornerRadius: CGFloat = 8.0
- static let backgroundColor = NSColor(named: "SidebarUnreadCountBackground")!
- static let textColor = NSColor(named: "SidebarUnreadCountText")!
- static let textSize: CGFloat = 11.0
- static let textFont = NSFont.systemFont(ofSize: textSize, weight: NSFont.Weight.semibold)
- static let textAttributes: [NSAttributedString.Key: AnyObject] = [NSAttributedString.Key.foregroundColor: textColor, NSAttributedString.Key.font: textFont, NSAttributedString.Key.kern: NSNull()]
+ static let backgroundColor = NSColor.clear
+ static let textSize: CGFloat = 13.0
+ static let textFont = NSFont.systemFont(ofSize: textSize, weight: NSFont.Weight.regular)
}
var unreadCount = 0 {
@@ -30,6 +28,24 @@ class UnreadCountView : NSView {
return unreadCount < 1 ? "" : "\(unreadCount)"
}
+ var isSelected: Bool = false {
+ didSet {
+ needsDisplay = true
+ }
+ }
+
+ private var currentTextColor: NSColor {
+ return isSelected ? NSColor.white : NSColor.tertiaryLabelColor
+ }
+
+ private var textAttributes: [NSAttributedString.Key: AnyObject] {
+ return [
+ .foregroundColor: currentTextColor,
+ .font: Appearance.textFont,
+ .kern: NSNull()
+ ]
+ }
+
private var intrinsicContentSizeIsValid = false
private var _intrinsicContentSize = NSZeroSize
@@ -66,7 +82,7 @@ class UnreadCountView : NSView {
return cachedSize
}
- var size = unreadCountString.size(withAttributes: Appearance.textAttributes)
+ var size = unreadCountString.size(withAttributes: textAttributes)
size.height = ceil(size.height)
size.width = ceil(size.width)
@@ -89,7 +105,7 @@ class UnreadCountView : NSView {
path.fill()
if unreadCount > 0 {
- unreadCountString.draw(at: textRect().origin, withAttributes: Appearance.textAttributes)
+ unreadCountString.draw(at: textRect().origin, withAttributes: textAttributes)
}
}
}
diff --git a/Mac/MainWindow/Timeline/Cell/TimelineCellAppearance.swift b/Mac/MainWindow/Timeline/Cell/TimelineCellAppearance.swift
index dbfdf045b..83e5a81c5 100644
--- a/Mac/MainWindow/Timeline/Cell/TimelineCellAppearance.swift
+++ b/Mac/MainWindow/Timeline/Cell/TimelineCellAppearance.swift
@@ -56,11 +56,7 @@ struct TimelineCellAppearance: Equatable {
self.showIcon = showIcon
- if #available(macOS 11.0, *) {
- cellPadding = NSEdgeInsets(top: 8.0, left: 4.0, bottom: 10.0, right: 4.0)
- } else {
- cellPadding = NSEdgeInsets(top: 8.0, left: 18.0, bottom: 10.0, right: 18.0)
- }
+ cellPadding = NSEdgeInsets(top: 8.0, left: 4.0, bottom: 10.0, right: 4.0)
let margin = self.cellPadding.left + self.unreadCircleDimension + self.unreadCircleMarginRight
self.boxLeftMargin = margin
diff --git a/Mac/MainWindow/Timeline/TimelineTableRowView.swift b/Mac/MainWindow/Timeline/TimelineTableRowView.swift
index bf42f4edd..54d87479c 100644
--- a/Mac/MainWindow/Timeline/TimelineTableRowView.swift
+++ b/Mac/MainWindow/Timeline/TimelineTableRowView.swift
@@ -59,21 +59,12 @@ class TimelineTableRowView : NSTableRowView {
separator!.wantsLayer = true
separator!.layer?.backgroundColor = AppAssets.timelineSeparatorColor.cgColor
addSubview(separator!)
- if #available(macOS 11.0, *) {
- NSLayoutConstraint.activate([
- separator!.leadingAnchor.constraint(equalTo: cellView.leadingAnchor, constant: 20),
- separator!.trailingAnchor.constraint(equalTo: cellView.trailingAnchor, constant: -4),
- separator!.heightAnchor.constraint(equalToConstant: 1),
- separator!.bottomAnchor.constraint(equalTo: bottomAnchor, constant: 0)
- ])
- } else {
- NSLayoutConstraint.activate([
- separator!.leadingAnchor.constraint(equalTo: cellView.leadingAnchor, constant: 34),
- separator!.trailingAnchor.constraint(equalTo: cellView.trailingAnchor, constant: -28),
- separator!.heightAnchor.constraint(equalToConstant: 1),
- separator!.bottomAnchor.constraint(equalTo: bottomAnchor, constant: 0)
- ])
- }
+ NSLayoutConstraint.activate([
+ separator!.leadingAnchor.constraint(equalTo: cellView.leadingAnchor, constant: 20),
+ separator!.trailingAnchor.constraint(equalTo: cellView.trailingAnchor, constant: -4),
+ separator!.heightAnchor.constraint(equalToConstant: 1),
+ separator!.bottomAnchor.constraint(equalTo: bottomAnchor, constant: 0)
+ ])
}
}
diff --git a/Mac/MainWindow/Timeline/TimelineViewController+ContextualMenus.swift b/Mac/MainWindow/Timeline/TimelineViewController+ContextualMenus.swift
index 1cc5d6e3e..32ce32ac0 100644
--- a/Mac/MainWindow/Timeline/TimelineViewController+ContextualMenus.swift
+++ b/Mac/MainWindow/Timeline/TimelineViewController+ContextualMenus.swift
@@ -222,36 +222,36 @@ private extension TimelineViewController {
func markReadMenuItem(_ articles: [Article]) -> NSMenuItem {
- return menuItem(NSLocalizedString("Mark as Read", comment: "Command"), #selector(markArticlesReadFromContextualMenu(_:)), articles)
+ return menuItem(NSLocalizedString("Mark as Read", comment: "Command"), #selector(markArticlesReadFromContextualMenu(_:)), articles, image: AppAssets.swipeMarkReadImage)
}
func markUnreadMenuItem(_ articles: [Article]) -> NSMenuItem {
- return menuItem(NSLocalizedString("Mark as Unread", comment: "Command"), #selector(markArticlesUnreadFromContextualMenu(_:)), articles)
+ return menuItem(NSLocalizedString("Mark as Unread", comment: "Command"), #selector(markArticlesUnreadFromContextualMenu(_:)), articles, image: AppAssets.swipeMarkUnreadImage)
}
func markStarredMenuItem(_ articles: [Article]) -> NSMenuItem {
- return menuItem(NSLocalizedString("Mark as Starred", comment: "Command"), #selector(markArticlesStarredFromContextualMenu(_:)), articles)
+ return menuItem(NSLocalizedString("Mark as Starred", comment: "Command"), #selector(markArticlesStarredFromContextualMenu(_:)), articles, image: AppAssets.swipeMarkStarredImage)
}
func markUnstarredMenuItem(_ articles: [Article]) -> NSMenuItem {
- return menuItem(NSLocalizedString("Mark as Unstarred", comment: "Command"), #selector(markArticlesUnstarredFromContextualMenu(_:)), articles)
+ return menuItem(NSLocalizedString("Mark as Unstarred", comment: "Command"), #selector(markArticlesUnstarredFromContextualMenu(_:)), articles, image: AppAssets.swipeMarkUnstarredImage)
}
func markAboveReadMenuItem(_ articles: [Article]) -> NSMenuItem {
- return menuItem(NSLocalizedString("Mark Above as Read", comment: "Command"), #selector(markAboveArticlesReadFromContextualMenu(_:)), articles)
+ return menuItem(NSLocalizedString("Mark Above as Read", comment: "Command"), #selector(markAboveArticlesReadFromContextualMenu(_:)), articles, image: nil)
}
func markBelowReadMenuItem(_ articles: [Article]) -> NSMenuItem {
- return menuItem(NSLocalizedString("Mark Below as Read", comment: "Command"), #selector(markBelowArticlesReadFromContextualMenu(_:)), articles)
+ return menuItem(NSLocalizedString("Mark Below as Read", comment: "Command"), #selector(markBelowArticlesReadFromContextualMenu(_:)), articles, image: nil)
}
func selectFeedInSidebarMenuItem(_ feed: WebFeed) -> NSMenuItem {
let localizedMenuText = NSLocalizedString("Select “%@” in Sidebar", comment: "Command")
let formattedMenuText = NSString.localizedStringWithFormat(localizedMenuText as NSString, feed.nameForDisplay)
- return menuItem(formattedMenuText as String, #selector(selectFeedInSidebarFromContextualMenu(_:)), feed)
+ return menuItem(formattedMenuText as String, #selector(selectFeedInSidebarFromContextualMenu(_:)), feed, image: nil)
}
func markAllAsReadMenuItem(_ feed: WebFeed) -> NSMenuItem? {
@@ -266,28 +266,31 @@ private extension TimelineViewController {
let localizedMenuText = NSLocalizedString("Mark All as Read in “%@”", comment: "Command")
let menuText = NSString.localizedStringWithFormat(localizedMenuText as NSString, feed.nameForDisplay) as String
- return menuItem(menuText, #selector(markAllInFeedAsRead(_:)), articles)
+ return menuItem(menuText, #selector(markAllInFeedAsRead(_:)), articles, image: AppAssets.markAllAsReadImage)
}
func openInBrowserMenuItem(_ urlString: String) -> NSMenuItem {
- return menuItem(NSLocalizedString("Open in Browser", comment: "Command"), #selector(openInBrowserFromContextualMenu(_:)), urlString)
+ return menuItem(NSLocalizedString("Open in Browser", comment: "Command"), #selector(openInBrowserFromContextualMenu(_:)), urlString, image: AppAssets.openInBrowserImage)
}
func copyArticleURLMenuItem(_ urlString: String) -> NSMenuItem {
- return menuItem(NSLocalizedString("Copy Article URL", comment: "Command"), #selector(copyURLFromContextualMenu(_:)), urlString)
+ return menuItem(NSLocalizedString("Copy Article URL", comment: "Command"), #selector(copyURLFromContextualMenu(_:)), urlString, image: AppAssets.copyImage)
}
func copyExternalURLMenuItem(_ urlString: String) -> NSMenuItem {
- return menuItem(NSLocalizedString("Copy External URL", comment: "Command"), #selector(copyURLFromContextualMenu(_:)), urlString)
+ return menuItem(NSLocalizedString("Copy External URL", comment: "Command"), #selector(copyURLFromContextualMenu(_:)), urlString, image: AppAssets.copyImage)
}
- func menuItem(_ title: String, _ action: Selector, _ representedObject: Any) -> NSMenuItem {
+ func menuItem(_ title: String, _ action: Selector, _ representedObject: Any, image: RSImage?) -> NSMenuItem {
let item = NSMenuItem(title: title, action: action, keyEquivalent: "")
item.representedObject = representedObject
item.target = self
+ if let image {
+ item.image = image
+ }
return item
}
}
diff --git a/Mac/MainWindow/Timeline/TimelineViewController.swift b/Mac/MainWindow/Timeline/TimelineViewController.swift
index f19276b9f..bf9e886b1 100644
--- a/Mac/MainWindow/Timeline/TimelineViewController.swift
+++ b/Mac/MainWindow/Timeline/TimelineViewController.swift
@@ -208,9 +208,7 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
tableView.setDraggingSourceOperationMask(.copy, forLocal: false)
tableView.keyboardDelegate = keyboardDelegate
- if #available(macOS 11.0, *) {
- tableView.style = .inset
- }
+ tableView.style = .inset
if !didRegisterForNotifications {
NotificationCenter.default.addObserver(self, selector: #selector(statusesDidChange(_:)), name: .StatusesDidChange, object: nil)
diff --git a/Mac/Preferences/Accounts/AccountsFeedbinWindowController.swift b/Mac/Preferences/Accounts/AccountsFeedbinWindowController.swift
index 444e152d0..3a4112ca4 100644
--- a/Mac/Preferences/Accounts/AccountsFeedbinWindowController.swift
+++ b/Mac/Preferences/Accounts/AccountsFeedbinWindowController.swift
@@ -133,10 +133,8 @@ class AccountsFeedbinWindowController: NSWindowController {
// MARK: Autofill
func enableAutofill() {
- if #available(macOS 11, *) {
- usernameTextField.contentType = .username
- passwordTextField.contentType = .password
- }
+ usernameTextField.contentType = .username
+ passwordTextField.contentType = .password
}
}
diff --git a/Mac/Preferences/Accounts/AccountsNewsBlurWindowController.swift b/Mac/Preferences/Accounts/AccountsNewsBlurWindowController.swift
index 00f47778e..9c70fceb5 100644
--- a/Mac/Preferences/Accounts/AccountsNewsBlurWindowController.swift
+++ b/Mac/Preferences/Accounts/AccountsNewsBlurWindowController.swift
@@ -129,10 +129,8 @@ class AccountsNewsBlurWindowController: NSWindowController {
// MARK: Autofill
func enableAutofill() {
- if #available(macOS 11, *) {
- usernameTextField.contentType = .username
- passwordTextField.contentType = .password
- }
+ usernameTextField.contentType = .username
+ passwordTextField.contentType = .password
}
}
diff --git a/Mac/Preferences/Accounts/AccountsReaderAPIWindowController.swift b/Mac/Preferences/Accounts/AccountsReaderAPIWindowController.swift
index a9e831afd..846c4f9a4 100644
--- a/Mac/Preferences/Accounts/AccountsReaderAPIWindowController.swift
+++ b/Mac/Preferences/Accounts/AccountsReaderAPIWindowController.swift
@@ -197,10 +197,8 @@ class AccountsReaderAPIWindowController: NSWindowController {
// MARK: Autofill
func enableAutofill() {
- if #available(macOS 11, *) {
- usernameTextField.contentType = .username
- passwordTextField.contentType = .password
- }
+ usernameTextField.contentType = .username
+ passwordTextField.contentType = .password
}
}
diff --git a/Mac/Preferences/Accounts/AddAccountsView.swift b/Mac/Preferences/Accounts/AddAccountsView.swift
index c8a496ad2..e43463125 100644
--- a/Mac/Preferences/Accounts/AddAccountsView.swift
+++ b/Mac/Preferences/Accounts/AddAccountsView.swift
@@ -102,45 +102,23 @@ struct AddAccountsView: View {
HStack(spacing: 12) {
Spacer()
- if #available(OSX 11.0, *) {
- Button(action: {
- parent?.dismiss(nil)
- }, label: {
- Text("Cancel")
- .frame(width: 76)
- })
- .help("Cancel")
- .keyboardShortcut(.cancelAction)
-
- } else {
- Button(action: {
- parent?.dismiss(nil)
- }, label: {
- Text("Cancel")
- .frame(width: 76)
- })
- .accessibility(label: Text("Add Account"))
- }
- if #available(OSX 11.0, *) {
- Button(action: {
- addAccountDelegate?.presentSheetForAccount(selectedAccount)
- parent?.dismiss(nil)
- }, label: {
- Text("Continue")
- .frame(width: 76)
- })
- .help("Add Account")
- .keyboardShortcut(.defaultAction)
-
- } else {
- Button(action: {
- addAccountDelegate?.presentSheetForAccount(selectedAccount)
- parent?.dismiss(nil)
- }, label: {
- Text("Continue")
- .frame(width: 76)
- })
- }
+ Button(action: {
+ parent?.dismiss(nil)
+ }, label: {
+ Text("Cancel")
+ .frame(width: 76)
+ })
+ .help("Cancel")
+ .keyboardShortcut(.cancelAction)
+ Button(action: {
+ addAccountDelegate?.presentSheetForAccount(selectedAccount)
+ parent?.dismiss(nil)
+ }, label: {
+ Text("Continue")
+ .frame(width: 76)
+ })
+ .help("Add Account")
+ .keyboardShortcut(.defaultAction)
}
.padding(.top, 12)
.padding(.bottom, 4)
diff --git a/Mac/Resources/Assets.xcassets/articleExtractorOff.imageset/ArticleExtractorOff.pdf b/Mac/Resources/Assets.xcassets/articleExtractorOff.imageset/ArticleExtractorOff.pdf
deleted file mode 100644
index d1a8f11c8..000000000
Binary files a/Mac/Resources/Assets.xcassets/articleExtractorOff.imageset/ArticleExtractorOff.pdf and /dev/null differ
diff --git a/Mac/Resources/Assets.xcassets/articleExtractorOff.imageset/Contents.json b/Mac/Resources/Assets.xcassets/articleExtractorOff.imageset/Contents.json
deleted file mode 100644
index a0b6f11cb..000000000
--- a/Mac/Resources/Assets.xcassets/articleExtractorOff.imageset/Contents.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "images" : [
- {
- "filename" : "ArticleExtractorOff.pdf",
- "idiom" : "universal"
- }
- ],
- "info" : {
- "author" : "xcode",
- "version" : 1
- },
- "properties" : {
- "preserves-vector-representation" : true,
- "template-rendering-intent" : "template"
- }
-}
diff --git a/Mac/Resources/Assets.xcassets/articleExtractorOff.symbolset/Article Extractor Off.svg b/Mac/Resources/Assets.xcassets/articleExtractorOff.symbolset/Article Extractor Off.svg
new file mode 100644
index 000000000..95c2b0801
--- /dev/null
+++ b/Mac/Resources/Assets.xcassets/articleExtractorOff.symbolset/Article Extractor Off.svg
@@ -0,0 +1,158 @@
+
+
\ No newline at end of file
diff --git a/Mac/Resources/Assets.xcassets/articleExtractorOff.symbolset/Contents.json b/Mac/Resources/Assets.xcassets/articleExtractorOff.symbolset/Contents.json
new file mode 100644
index 000000000..255ead96d
--- /dev/null
+++ b/Mac/Resources/Assets.xcassets/articleExtractorOff.symbolset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "symbols" : [
+ {
+ "filename" : "Article Extractor Off.svg",
+ "idiom" : "universal"
+ }
+ ]
+}
diff --git a/Mac/Resources/Assets.xcassets/articleExtractorOn.imageset/ArticleExtractorOn.pdf b/Mac/Resources/Assets.xcassets/articleExtractorOn.imageset/ArticleExtractorOn.pdf
deleted file mode 100644
index 59cf13d37..000000000
Binary files a/Mac/Resources/Assets.xcassets/articleExtractorOn.imageset/ArticleExtractorOn.pdf and /dev/null differ
diff --git a/Mac/Resources/Assets.xcassets/articleExtractorOn.imageset/Contents.json b/Mac/Resources/Assets.xcassets/articleExtractorOn.imageset/Contents.json
deleted file mode 100644
index ba8f780d4..000000000
--- a/Mac/Resources/Assets.xcassets/articleExtractorOn.imageset/Contents.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "images" : [
- {
- "filename" : "ArticleExtractorOn.pdf",
- "idiom" : "universal"
- }
- ],
- "info" : {
- "author" : "xcode",
- "version" : 1
- },
- "properties" : {
- "preserves-vector-representation" : true,
- "template-rendering-intent" : "template"
- }
-}
diff --git a/Mac/Resources/Assets.xcassets/articleExtractorOn.symbolset/Article Extractor On.svg b/Mac/Resources/Assets.xcassets/articleExtractorOn.symbolset/Article Extractor On.svg
new file mode 100644
index 000000000..de5808f1f
--- /dev/null
+++ b/Mac/Resources/Assets.xcassets/articleExtractorOn.symbolset/Article Extractor On.svg
@@ -0,0 +1,158 @@
+
+
\ No newline at end of file
diff --git a/Mac/Resources/Assets.xcassets/articleExtractorOn.symbolset/Contents.json b/Mac/Resources/Assets.xcassets/articleExtractorOn.symbolset/Contents.json
new file mode 100644
index 000000000..14e45223b
--- /dev/null
+++ b/Mac/Resources/Assets.xcassets/articleExtractorOn.symbolset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "symbols" : [
+ {
+ "filename" : "Article Extractor On.svg",
+ "idiom" : "universal"
+ }
+ ]
+}
diff --git a/Mac/Resources/Assets.xcassets/markAllAsRead.imageset/Contents.json b/Mac/Resources/Assets.xcassets/markAllAsRead.imageset/Contents.json
deleted file mode 100644
index 9937c57c5..000000000
--- a/Mac/Resources/Assets.xcassets/markAllAsRead.imageset/Contents.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "images" : [
- {
- "filename" : "markAllAsRead.pdf",
- "idiom" : "universal"
- }
- ],
- "info" : {
- "author" : "xcode",
- "version" : 1
- },
- "properties" : {
- "preserves-vector-representation" : true,
- "template-rendering-intent" : "template"
- }
-}
diff --git a/Mac/Resources/Assets.xcassets/markAllAsRead.imageset/markAllAsRead.pdf b/Mac/Resources/Assets.xcassets/markAllAsRead.imageset/markAllAsRead.pdf
deleted file mode 100644
index 420f9d49c..000000000
Binary files a/Mac/Resources/Assets.xcassets/markAllAsRead.imageset/markAllAsRead.pdf and /dev/null differ
diff --git a/Mac/Resources/Assets.xcassets/markAllAsRead.symbolset/Contents.json b/Mac/Resources/Assets.xcassets/markAllAsRead.symbolset/Contents.json
new file mode 100644
index 000000000..5a1bb0402
--- /dev/null
+++ b/Mac/Resources/Assets.xcassets/markAllAsRead.symbolset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "symbols" : [
+ {
+ "filename" : "markAsRead3.svg",
+ "idiom" : "universal"
+ }
+ ]
+}
diff --git a/Mac/Resources/Assets.xcassets/markAllAsRead.symbolset/markAsRead3.svg b/Mac/Resources/Assets.xcassets/markAllAsRead.symbolset/markAsRead3.svg
new file mode 100644
index 000000000..070af7a07
--- /dev/null
+++ b/Mac/Resources/Assets.xcassets/markAllAsRead.symbolset/markAsRead3.svg
@@ -0,0 +1,150 @@
+
+
\ No newline at end of file
diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj
index 75c4065b9..41dd76ac5 100644
--- a/NetNewsWire.xcodeproj/project.pbxproj
+++ b/NetNewsWire.xcodeproj/project.pbxproj
@@ -1464,11 +1464,6 @@
baseConfigurationReferenceAnchor = 84719F372DB9C60400EEF332 /* xcconfig */;
baseConfigurationReferenceRelativePath = NetNewsWire_iOSapp_target.xcconfig;
buildSettings = {
- SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
- SUPPORTS_MACCATALYST = NO;
- SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
- SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
- TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
@@ -1477,11 +1472,6 @@
baseConfigurationReferenceAnchor = 84719F372DB9C60400EEF332 /* xcconfig */;
baseConfigurationReferenceRelativePath = NetNewsWire_iOSapp_target.xcconfig;
buildSettings = {
- SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
- SUPPORTS_MACCATALYST = NO;
- SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
- SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
- TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
diff --git a/Shared/Extensions/NSView-Extensions.swift b/Shared/Extensions/NSView-Extensions.swift
index e9449208e..2c5aff1d0 100644
--- a/Shared/Extensions/NSView-Extensions.swift
+++ b/Shared/Extensions/NSView-Extensions.swift
@@ -11,20 +11,10 @@ import AppKit
extension NSView {
func constraintsToMakeSubViewFullSize(_ subview: NSView) -> [NSLayoutConstraint] {
-
- if #available(macOS 11, *) {
- let leadingConstraint = NSLayoutConstraint(item: subview, attribute: .leading, relatedBy: .equal, toItem: self.safeAreaLayoutGuide, attribute: .leading, multiplier: 1.0, constant: 0.0)
- let trailingConstraint = NSLayoutConstraint(item: subview, attribute: .trailing, relatedBy: .equal, toItem: self.safeAreaLayoutGuide, attribute: .trailing, multiplier: 1.0, constant: 0.0)
- let topConstraint = NSLayoutConstraint(item: subview, attribute: .top, relatedBy: .equal, toItem: self.safeAreaLayoutGuide, attribute: .top, multiplier: 1.0, constant: 0.0)
- let bottomConstraint = NSLayoutConstraint(item: subview, attribute: .bottom, relatedBy: .equal, toItem: self.safeAreaLayoutGuide, attribute: .bottom, multiplier: 1.0, constant: 0.0)
- return [leadingConstraint, trailingConstraint, topConstraint, bottomConstraint]
- } else {
- let leadingConstraint = NSLayoutConstraint(item: subview, attribute: .leading, relatedBy: .equal, toItem: self, attribute: .leading, multiplier: 1.0, constant: 0.0)
- let trailingConstraint = NSLayoutConstraint(item: subview, attribute: .trailing, relatedBy: .equal, toItem: self, attribute: .trailing, multiplier: 1.0, constant: 0.0)
- let topConstraint = NSLayoutConstraint(item: subview, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1.0, constant: 0.0)
- let bottomConstraint = NSLayoutConstraint(item: subview, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1.0, constant: 0.0)
- return [leadingConstraint, trailingConstraint, topConstraint, bottomConstraint]
- }
-
+ let leadingConstraint = NSLayoutConstraint(item: subview, attribute: .leading, relatedBy: .equal, toItem: self, attribute: .leading, multiplier: 1.0, constant: 0.0)
+ let trailingConstraint = NSLayoutConstraint(item: subview, attribute: .trailing, relatedBy: .equal, toItem: self, attribute: .trailing, multiplier: 1.0, constant: 0.0)
+ let topConstraint = NSLayoutConstraint(item: subview, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1.0, constant: 0.0)
+ let bottomConstraint = NSLayoutConstraint(item: subview, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1.0, constant: 0.0)
+ return [leadingConstraint, trailingConstraint, topConstraint, bottomConstraint]
}
}
diff --git a/iOS/MainFeed/MainFeedViewController.swift b/iOS/MainFeed/MainFeedViewController.swift
index 829a91265..eead0a72e 100644
--- a/iOS/MainFeed/MainFeedViewController.swift
+++ b/iOS/MainFeed/MainFeedViewController.swift
@@ -18,7 +18,6 @@ import SafariServices
class MainFeedViewController: UITableViewController, UndoableCommandRunner {
@IBOutlet weak var filterButton: UIBarButtonItem!
- private var refreshProgressView: RefreshProgressView?
@IBOutlet weak var addNewItemButton: UIBarButtonItem! {
didSet {
if #available(iOS 14, *) {
@@ -72,7 +71,6 @@ class MainFeedViewController: UITableViewController, UndoableCommandRunner {
NotificationCenter.default.addObserver(self, selector: #selector(contentSizeCategoryDidChange), name: UIContentSizeCategory.didChangeNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground(_:)), name: UIApplication.willEnterForegroundNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(displayNameDidChange(_:)), name: .DisplayNameDidChange, object: nil)
- NotificationCenter.default.addObserver(self, selector: #selector(progressDidChange(_:)), name: .combinedRefreshProgressDidChange, object: nil)
registerForTraitChanges([UITraitPreferredContentSizeCategory.self], target: self, action: #selector(preferredContentSizeCategoryDidChange))
@@ -81,7 +79,7 @@ class MainFeedViewController: UITableViewController, UndoableCommandRunner {
}
override func viewWillAppear(_ animated: Bool) {
- navigationController?.isToolbarHidden = false
+ navigationController?.isToolbarHidden = false
updateUI()
super.viewWillAppear(animated)
@@ -180,10 +178,6 @@ class MainFeedViewController: UITableViewController, UndoableCommandRunner {
updateUI()
}
- @objc func progressDidChange(_ note: Notification) {
- updateNavigationBarSubtitle()
- }
-
// MARK: Table View
override func numberOfSections(in tableView: UITableView) -> Int {
@@ -661,11 +655,9 @@ class MainFeedViewController: UITableViewController, UndoableCommandRunner {
} else {
setFilterButtonToInactive()
}
- refreshProgressView?.update()
addNewItemButton?.isEnabled = !AccountManager.shared.activeAccounts.isEmpty
configureContextMenu()
- updateNavigationBarSubtitle()
}
@objc
@@ -699,37 +691,7 @@ class MainFeedViewController: UITableViewController, UndoableCommandRunner {
}
}
- func updateNavigationBarSubtitle() {
- let progress = AccountManager.shared.combinedRefreshProgress
-
- if progress.isComplete {
- if let accountLastArticleFetchEndTime = AccountManager.shared.lastArticleFetchEndTime {
- if Date() > accountLastArticleFetchEndTime.addingTimeInterval(60) {
- let relativeDateTimeFormatter = RelativeDateTimeFormatter()
- relativeDateTimeFormatter.dateTimeStyle = .named
- let refreshed = relativeDateTimeFormatter.localizedString(for: accountLastArticleFetchEndTime, relativeTo: Date())
- let localizedRefreshText = NSLocalizedString("Updated %@", comment: "Updated")
- let refreshText = NSString.localizedStringWithFormat(localizedRefreshText as NSString, refreshed) as String
- navigationController?.navigationBar.topItem?.subtitle = refreshText
- } else {
- navigationController?.navigationBar.topItem?.subtitle = NSLocalizedString("Updated Just Now", comment: "Updated Just Now")
- }
- } else {
- navigationController?.navigationBar.topItem?.subtitle = ""
- }
-
- } else {
- navigationController?.navigationBar.topItem?.subtitle = NSLocalizedString("Updating...", comment: "Updating...")
- }
-
- scheduleNavigationBarSubtitleUpdate()
- }
- func scheduleNavigationBarSubtitleUpdate() {
- DispatchQueue.main.asyncAfter(deadline: .now() + 60) { [weak self] in
- self?.updateNavigationBarSubtitle()
- }
- }
func focus() {
becomeFirstResponder()
diff --git a/iOS/MainTimeline/MainTimelineTitleView.swift b/iOS/MainTimeline/MainTimelineTitleView.swift
index 7a68a4493..3c4ca49df 100644
--- a/iOS/MainTimeline/MainTimelineTitleView.swift
+++ b/iOS/MainTimeline/MainTimelineTitleView.swift
@@ -33,7 +33,7 @@ class MainTimelineTitleView: UIView {
}
func buttonize() {
- heightAnchor.constraint(equalToConstant: 40.0).isActive = true
+ heightAnchor.constraint(equalToConstant: 25.0).isActive = true
accessibilityTraits = .button
if #available(iOS 13.4, *) {
addInteraction(pointerInteraction)
@@ -41,7 +41,7 @@ class MainTimelineTitleView: UIView {
}
func debuttonize() {
- heightAnchor.constraint(equalToConstant: 40.0).isActive = true
+ heightAnchor.constraint(equalToConstant: 25.0).isActive = true
accessibilityTraits.remove(.button)
if #available(iOS 13.4, *) {
removeInteraction(pointerInteraction)
diff --git a/iOS/MainTimeline/MainTimelineTitleView.xib b/iOS/MainTimeline/MainTimelineTitleView.xib
index 9ea9ed250..2c75c4244 100644
--- a/iOS/MainTimeline/MainTimelineTitleView.xib
+++ b/iOS/MainTimeline/MainTimelineTitleView.xib
@@ -1,9 +1,8 @@
-
+
-
-
+
@@ -11,38 +10,43 @@
-
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
@@ -50,7 +54,6 @@
-
diff --git a/iOS/MainTimeline/MainTimelineViewController.swift b/iOS/MainTimeline/MainTimelineViewController.swift
index a78866f4a..42c90e8f8 100644
--- a/iOS/MainTimeline/MainTimelineViewController.swift
+++ b/iOS/MainTimeline/MainTimelineViewController.swift
@@ -195,14 +195,13 @@ class MainTimelineViewController: UITableViewController, UndoableCommandRunner {
if navigationController?.navigationBar.isHidden ?? false {
navigationController?.navigationBar.alpha = 0
}
- navigationController?.navigationBar.topItem?.subtitle = nil
+
super.viewWillAppear(animated)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
isTimelineViewControllerPending = false
-
if navigationController?.navigationBar.alpha == 0 {
UIView.animate(withDuration: 0.5) {
self.navigationController?.navigationBar.alpha = 1
diff --git a/iOS/SceneCoordinator.swift b/iOS/SceneCoordinator.swift
index 5475255ed..71c9e5efd 100644
--- a/iOS/SceneCoordinator.swift
+++ b/iOS/SceneCoordinator.swift
@@ -39,6 +39,7 @@ struct FeedNode: Hashable {
}
}
+
class SceneCoordinator: NSObject, UndoableCommandRunner {
var undoableCommands = [UndoableCommand]()
@@ -83,6 +84,9 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
var isTimelineViewControllerPending = false
var isArticleViewControllerPending = false
+ /// `Bool` to track whether a refresh is scheduled.
+ private var isRefreshScheduled: Bool = false
+
private(set) var sortDirection = AppDefaults.shared.timelineSortDirection {
didSet {
if sortDirection != oldValue {
@@ -272,7 +276,11 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
return appDelegate.unreadCount > 0
}
- var timelineUnreadCount: Int = 0
+ var timelineUnreadCount: Int = 0 {
+ didSet {
+ updateNavigationBarSubtitles(nil)
+ }
+ }
init(rootSplitViewController: RootSplitViewController) {
self.rootSplitViewController = rootSplitViewController
@@ -312,6 +320,8 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground(_:)), name: UIApplication.willEnterForegroundNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(importDownloadedTheme(_:)), name: .didEndDownloadingTheme, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(themeDownloadDidFail(_:)), name: .didFailToImportThemeWithError, object: nil)
+ NotificationCenter.default.addObserver(self, selector: #selector(updateNavigationBarSubtitles(_:)), name: .combinedRefreshProgressDidChange, object: nil)
+
}
func restoreWindowState(_ activity: NSUserActivity?) {
@@ -539,6 +549,94 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
self.rootSplitViewController.presentError(error, dismiss: nil)
}
}
+
+
+ /// Updates navigation bar subtitles in response to feed selection, unread count changes,
+ /// `combinedRefreshProgressDidChange` notifications, and a timed refresh every
+ /// 60s.
+ ///
+ /// Subtitles are handled differently on iPhone and iPad.
+ ///
+ /// `MainFeedViewController`
+ /// - When refreshing: Feeds will display "Updating..." on both iPhone and iPad.
+ /// - When refreshed: Feeds will display "Updated <#relative_time#>" on both iPhone and iPad.
+ ///
+ /// `MainTimelineViewController`
+ /// - Where the unread count for the timeline is > 0, this is displayed on both iPhone and iPad.
+ /// - If the timeline count is 0, the iPhone follows the same logic as `MainFeedViewController`
+ /// - Specific to iPad, if the unread count is 0, the iPad will not display a subtitle. The refresh text
+ /// will generally be visible in the sidebar and there's no need to display it twice.
+ ///
+ /// - Parameter note: Optional `Notification`
+ @objc func updateNavigationBarSubtitles(_ note: Notification?) {
+ let progress = AccountManager.shared.combinedRefreshProgress
+
+ if progress.isComplete {
+ if let accountLastArticleFetchEndTime = AccountManager.shared.lastArticleFetchEndTime {
+ if Date.now > accountLastArticleFetchEndTime.addingTimeInterval(60) {
+ let relativeDateTimeFormatter = RelativeDateTimeFormatter()
+ relativeDateTimeFormatter.dateTimeStyle = .named
+ let refreshed = relativeDateTimeFormatter.localizedString(for: accountLastArticleFetchEndTime, relativeTo: Date())
+ let localizedRefreshText = NSLocalizedString("Updated %@", comment: "Updated")
+ let refreshText = NSString.localizedStringWithFormat(localizedRefreshText as NSString, refreshed) as String
+
+ // Update Feeds with Updated text
+ self.mainFeedViewController?.navigationItem.subtitle = refreshText
+
+ // If unread count > 0, add unread string to timeline
+ if let _ = timelineFeed, timelineUnreadCount > 0 {
+ let localizedUnreadCount = NSLocalizedString("%i Unread", comment: "14 Unread")
+ let unreadCount = NSString.localizedStringWithFormat(localizedUnreadCount as NSString, timelineUnreadCount) as String
+ self.mainTimelineViewController?.navigationItem.subtitle = unreadCount
+ } else {
+ // When unread count == 0, iPhone timeline displays Updated Just Now; iPad is blank
+ if UIDevice.current.userInterfaceIdiom == .phone {
+ self.mainTimelineViewController?.navigationItem.subtitle = refreshText
+ } else {
+ self.mainTimelineViewController?.navigationItem.subtitle = ""
+ }
+ }
+ } else {
+ // Use 'Updated Just Now' while <60s have passed since refresh.
+ self.mainFeedViewController?.navigationItem.subtitle = NSLocalizedString("Updated Just Now", comment: "Updated Just Now")
+
+ // If unread count > 0, add unread string to timeline
+ if let _ = timelineFeed, timelineUnreadCount > 0 {
+ let localizedUnreadCount = NSLocalizedString("%i Unread", comment: "14 Unread")
+ let refreshTextWithUnreadCount = NSString.localizedStringWithFormat(localizedUnreadCount as NSString, timelineUnreadCount) as String
+ self.mainTimelineViewController?.navigationItem.subtitle = refreshTextWithUnreadCount
+ } else {
+ // When unread count == 0, iPhone timeline displays Updated Just Now; iPad is blank
+ if UIDevice.current.userInterfaceIdiom == .phone {
+ self.mainTimelineViewController?.navigationItem.subtitle = NSLocalizedString("Updated Just Now", comment: "Updated Just Now")
+ } else {
+ self.mainTimelineViewController?.navigationItem.subtitle = ""
+ }
+ }
+ }
+ } else {
+ self.mainFeedViewController?.navigationItem.subtitle = ""
+ self.mainTimelineViewController?.navigationItem.subtitle = ""
+ }
+ } else {
+ // Updating in progress, apply to both iPhone and iPad Feeds.
+ self.mainFeedViewController?.navigationItem.subtitle = NSLocalizedString("Updating...", comment: "Updating...")
+ }
+
+ scheduleNavigationBarSubtitleUpdate()
+
+ }
+
+ func scheduleNavigationBarSubtitleUpdate() {
+ if isRefreshScheduled {
+ return
+ }
+ isRefreshScheduled = true
+ DispatchQueue.main.asyncAfter(deadline: .now() + 60) { [weak self] in
+ self?.isRefreshScheduled = false
+ self?.updateNavigationBarSubtitles(nil)
+ }
+ }
// MARK: API
@@ -735,6 +833,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
}
}()
selectFeed(indexPath: indexPath, animations: animations, deselectArticle: deselectArticle, completion: completion)
+ updateNavigationBarSubtitles(nil)
}
func selectFeed(indexPath: IndexPath?, animations: Animations = [], deselectArticle: Bool = true, completion: (() -> Void)? = nil) {
@@ -773,6 +872,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
}
}
+ updateNavigationBarSubtitles(nil)
}
@@ -2212,4 +2312,5 @@ private extension SceneCoordinator {
return true
}
+
}
diff --git a/xcconfig/NetNewsWire_iOSapp_target.xcconfig b/xcconfig/NetNewsWire_iOSapp_target.xcconfig
index 3c5f63c71..cd5380c77 100644
--- a/xcconfig/NetNewsWire_iOSapp_target.xcconfig
+++ b/xcconfig/NetNewsWire_iOSapp_target.xcconfig
@@ -44,3 +44,8 @@ PRODUCT_NAME = NetNewsWire
CLANG_ENABLE_MODULES = YES
SWIFT_OBJC_BRIDGING_HEADER = iOS/Resources/NetNewsWire-iOS-Bridging-Header.h
SWIFT_VERSION = 5.7
+SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+SUPPORTS_MACCATALYST = NO;
+SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
+SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
+TARGETED_DEVICE_FAMILY = "1,2";
diff --git a/xcconfig/NetNewsWire_macapp_target.xcconfig b/xcconfig/NetNewsWire_macapp_target.xcconfig
index 600a8a2a1..13d4b1a36 100644
--- a/xcconfig/NetNewsWire_macapp_target.xcconfig
+++ b/xcconfig/NetNewsWire_macapp_target.xcconfig
@@ -37,3 +37,4 @@ DEVELOPER_ENTITLEMENTS =
CODE_SIGN_ENTITLEMENTS = Mac/Resources/NetNewsWire$(DEVELOPER_ENTITLEMENTS).entitlements
PRODUCT_BUNDLE_IDENTIFIER = $(ORGANIZATION_IDENTIFIER).NetNewsWire-Evergreen
+MACOSX_DEPLOYMENT_TARGET = 26.0