Merge pull request #2775 from stuartbreckenridge/context-menu

Adds Context Menus for Add Item and Mark All as Read
This commit is contained in:
Maurice Parker 2021-01-31 18:57:23 -06:00 committed by GitHub
commit 56f1969715
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 168 additions and 52 deletions

View File

@ -157,6 +157,10 @@ struct AppAssets {
return IconImage(UIImage(systemName: "folder.fill")!, isSymbol: true, isBackgroundSupressed: true, preferredColor: AppAssets.secondaryAccentColor.cgColor) return IconImage(UIImage(systemName: "folder.fill")!, isSymbol: true, isBackgroundSupressed: true, preferredColor: AppAssets.secondaryAccentColor.cgColor)
}() }()
static var masterFolderImageNonIcon: UIImage = {
return UIImage(systemName: "folder.fill")!.withRenderingMode(.alwaysOriginal).withTintColor(.secondaryLabel)
}()
static var moreImage: UIImage = { static var moreImage: UIImage = {
return UIImage(systemName: "ellipsis.circle")! return UIImage(systemName: "ellipsis.circle")!
}() }()
@ -181,6 +185,10 @@ struct AppAssets {
return UIColor(named: "primaryAccentColor")! return UIColor(named: "primaryAccentColor")!
} }
static var redditOriginal: UIImage = {
return UIImage(named: "redditWhite")!.withRenderingMode(.alwaysOriginal).withTintColor(.secondaryLabel)
}()
static var safariImage: UIImage = { static var safariImage: UIImage = {
return UIImage(systemName: "safari")! return UIImage(systemName: "safari")!
}() }()
@ -240,6 +248,10 @@ struct AppAssets {
return UIImage(systemName: "trash")! return UIImage(systemName: "trash")!
}() }()
static var twitterOriginal: UIImage = {
return UIImage(named: "twitterWhite")!.withRenderingMode(.alwaysOriginal).withTintColor(.secondaryLabel)
}()
static var unreadFeedImage: IconImage { static var unreadFeedImage: IconImage {
let image = UIImage(systemName: "largecircle.fill.circle")! let image = UIImage(systemName: "largecircle.fill.circle")!
return IconImage(image, isSymbol: true, isBackgroundSupressed: true, preferredColor: AppAssets.secondaryAccentColor.cgColor) return IconImage(image, isSymbol: true, isBackgroundSupressed: true, preferredColor: AppAssets.secondaryAccentColor.cgColor)
@ -253,6 +265,7 @@ struct AppAssets {
return UIColor(named: "controlBackgroundColor")! return UIColor(named: "controlBackgroundColor")!
}() }()
static func image(for accountType: AccountType) -> UIImage? { static func image(for accountType: AccountType) -> UIImage? {
switch accountType { switch accountType {
case .onMyMac: case .onMyMac:

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17506" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/> <device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies> <dependencies>
<deployment identifier="iOS"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17505"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
<capability name="Named colors" minToolsVersion="9.0"/> <capability name="Named colors" minToolsVersion="9.0"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/> <capability name="System colors in document resources" minToolsVersion="11.0"/>
@ -138,9 +138,6 @@
<userDefinedRuntimeAttributes> <userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="accLabelText" value="Mark All as Read"/> <userDefinedRuntimeAttribute type="string" keyPath="accLabelText" value="Mark All as Read"/>
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
<connections>
<action selector="markAllAsRead:" destination="Kyk-vK-QRX" id="4nd-Gg-APm"/>
</connections>
</barButtonItem> </barButtonItem>
<barButtonItem style="plain" systemItem="flexibleSpace" id="53V-wq-bat"/> <barButtonItem style="plain" systemItem="flexibleSpace" id="53V-wq-bat"/>
<barButtonItem style="plain" systemItem="flexibleSpace" id="93y-8j-WBh"/> <barButtonItem style="plain" systemItem="flexibleSpace" id="93y-8j-WBh"/>
@ -196,9 +193,6 @@
<userDefinedRuntimeAttributes> <userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="accLabelText" value="Add Item"/> <userDefinedRuntimeAttribute type="string" keyPath="accLabelText" value="Add Item"/>
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
<connections>
<action selector="add:" destination="7bK-jq-Zjz" id="d1n-0d-2gR"/>
</connections>
</barButtonItem> </barButtonItem>
</toolbarItems> </toolbarItems>
<navigationItem key="navigationItem" title="Feeds" id="Zdf-7t-Un8"> <navigationItem key="navigationItem" title="Feeds" id="Zdf-7t-Un8">
@ -332,7 +326,7 @@
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Article Title" textAlignment="natural" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iFp-rn-HhQ"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Article Title" textAlignment="natural" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iFp-rn-HhQ">
<rect key="frame" x="20" y="74.5" width="136" height="33.5"/> <rect key="frame" x="20" y="74.5" width="135.5" height="33.5"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleTitle1"/> <fontDescription key="fontDescription" style="UICTFontTextStyleTitle1"/>
<nil key="textColor"/> <nil key="textColor"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>

View File

@ -17,7 +17,15 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner {
@IBOutlet weak var filterButton: UIBarButtonItem! @IBOutlet weak var filterButton: UIBarButtonItem!
private var refreshProgressView: RefreshProgressView? private var refreshProgressView: RefreshProgressView?
@IBOutlet weak var addNewItemButton: UIBarButtonItem! @IBOutlet weak var addNewItemButton: UIBarButtonItem! {
didSet {
if #available(iOS 14, *) {
addNewItemButton.primaryAction = nil
} else {
addNewItemButton.action = #selector(MasterFeedViewController.add(_:))
}
}
}
private let operationQueue = MainThreadOperationQueue() private let operationQueue = MainThreadOperationQueue()
lazy var dataSource = makeDataSource() lazy var dataSource = makeDataSource()
@ -62,6 +70,7 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner {
NotificationCenter.default.addObserver(self, selector: #selector(webFeedSettingDidChange(_:)), name: .WebFeedSettingDidChange, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(webFeedSettingDidChange(_:)), name: .WebFeedSettingDidChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(contentSizeCategoryDidChange), name: UIContentSizeCategory.didChangeNotification, object: nil) 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(willEnterForeground(_:)), name: UIApplication.willEnterForegroundNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(configureContextMenu(_:)), name: .ActiveExtensionPointsDidChange, object: nil)
refreshControl = UIRefreshControl() refreshControl = UIRefreshControl()
refreshControl!.addTarget(self, action: #selector(refreshAccounts(_:)), for: .valueChanged) refreshControl!.addTarget(self, action: #selector(refreshAccounts(_:)), for: .valueChanged)
@ -394,6 +403,10 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner {
} }
@IBAction func add(_ sender: UIBarButtonItem) { @IBAction func add(_ sender: UIBarButtonItem) {
if #available(iOS 14, *) {
} else {
let title = NSLocalizedString("Add Item", comment: "Add Item") let title = NSLocalizedString("Add Item", comment: "Add Item")
let alertController = UIAlertController(title: title, message: nil, preferredStyle: .actionSheet) let alertController = UIAlertController(title: title, message: nil, preferredStyle: .actionSheet)
@ -439,6 +452,9 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner {
present(alertController, animated: true) present(alertController, animated: true)
} }
}
@objc func toggleSectionHeader(_ sender: UITapGestureRecognizer) { @objc func toggleSectionHeader(_ sender: UITapGestureRecognizer) {
guard let headerView = sender.view as? MasterFeedTableViewSectionHeader else { guard let headerView = sender.view as? MasterFeedTableViewSectionHeader else {
return return
@ -566,6 +582,48 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner {
} }
refreshProgressView?.update() refreshProgressView?.update()
addNewItemButton?.isEnabled = !AccountManager.shared.activeAccounts.isEmpty addNewItemButton?.isEnabled = !AccountManager.shared.activeAccounts.isEmpty
configureContextMenu()
}
@objc
func configureContextMenu(_: Any? = nil) {
if #available(iOS 14.0, *) {
let addWebFeedActionTitle = NSLocalizedString("Add Web Feed", comment: "Add Web Feed")
let addWebFeedAction = UIAction(title: addWebFeedActionTitle, image: AppAssets.faviconTemplateImage.withRenderingMode(.alwaysOriginal).withTintColor(.secondaryLabel)) { _ in
self.coordinator.showAddWebFeed()
}
let addRedditFeedActionTitle = NSLocalizedString("Add Reddit Feed", comment: "Add Reddit Feed")
let addRedditFeedAction = UIAction(title: addRedditFeedActionTitle, image: AppAssets.redditOriginal) { _ in
self.coordinator.showAddRedditFeed()
}
let addTwitterFeedActionTitle = NSLocalizedString("Add Twitter Feed", comment: "Add Twitter Feed")
let addTwitterFeedAction = UIAction(title: addTwitterFeedActionTitle, image: AppAssets.twitterOriginal) { _ in
self.coordinator.showAddTwitterFeed()
}
let addWebFolderdActionTitle = NSLocalizedString("Add Folder", comment: "Add Folder")
let addWebFolderAction = UIAction(title: addWebFolderdActionTitle, image: AppAssets.masterFolderImageNonIcon) { _ in
self.coordinator.showAddFolder()
}
var children = [addWebFolderAction, addWebFeedAction]
if AccountManager.shared.activeAccounts.contains(where: { $0.type == .onMyMac || $0.type == .cloudKit }) {
if ExtensionPointManager.shared.isRedditEnabled {
children.insert(addRedditFeedAction, at: 0)
}
if ExtensionPointManager.shared.isTwitterEnabled {
children.insert(addTwitterFeedAction, at: 0)
}
}
let menu = UIMenu(title: "Add Item", image: nil, identifier: nil, options: [], children: children)
self.addNewItemButton.menu = menu
}
} }
func focus() { func focus() {

View File

@ -47,8 +47,8 @@ struct MarkAsReadAlertController {
let title = NSLocalizedString("Mark As Read", comment: "Mark As Read") let title = NSLocalizedString("Mark As Read", comment: "Mark As Read")
let message = NSLocalizedString("You can turn this confirmation off in settings.", let message = NSLocalizedString("You can turn this confirmation off in Settings.",
comment: "You can turn this confirmation off in settings.") comment: "You can turn this confirmation off in Settings.")
let cancelTitle = NSLocalizedString("Cancel", comment: "Cancel") let cancelTitle = NSLocalizedString("Cancel", comment: "Cancel")
let settingsTitle = NSLocalizedString("Open Settings", comment: "Open Settings") let settingsTitle = NSLocalizedString("Open Settings", comment: "Open Settings")

View File

@ -19,7 +19,15 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
private var refreshProgressView: RefreshProgressView? private var refreshProgressView: RefreshProgressView?
@IBOutlet weak var markAllAsReadButton: UIBarButtonItem! @IBOutlet weak var markAllAsReadButton: UIBarButtonItem! {
didSet {
if #available(iOS 14, *) {
markAllAsReadButton.primaryAction = nil
} else {
markAllAsReadButton.action = #selector(MasterTimelineViewController.markAllAsRead(_:))
}
}
}
private var filterButton: UIBarButtonItem! private var filterButton: UIBarButtonItem!
private var firstUnreadButton: UIBarButtonItem! private var firstUnreadButton: UIBarButtonItem!
@ -655,6 +663,25 @@ private extension MasterTimelineViewController {
setToolbarItems(items, animated: false) setToolbarItems(items, animated: false)
} }
} }
if #available(iOS 14, *) {
let title = NSLocalizedString("Mark All as Read", comment: "Mark All as Read")
var markAsReadAction: UIAction!
if AppDefaults.shared.confirmMarkAllAsRead {
markAsReadAction = UIAction(title: title, image: AppAssets.markAllAsReadImage, discoverabilityTitle: "in \(self.title!)") { [weak self] action in
self?.coordinator.markAllAsReadInTimeline()
}
let settingsAction = UIAction(title: NSLocalizedString("Settings", comment: "Settings"), image: UIImage(systemName: "gear")!, discoverabilityTitle: NSLocalizedString("You can turn this confirmation off in Settings.", comment: "You can turn this confirmation off in Settings.")) { [weak self] action in
self?.coordinator.showSettings(scrollToArticlesSection: true)
}
markAllAsReadButton.menu = UIMenu(title: NSLocalizedString(title, comment: title), image: nil, identifier: nil, children: [settingsAction, markAsReadAction])
} else {
markAllAsReadButton.action = #selector(MasterTimelineViewController.markAllAsRead(_:))
}
}
} }
func updateTitleUnreadCount() { func updateTitleUnreadCount() {

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "redditWhite.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "twitter_white.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB