diff --git a/NetNewsWire/MainWindow/Timeline/TimelineViewController+ContextualMenus.swift b/NetNewsWire/MainWindow/Timeline/TimelineViewController+ContextualMenus.swift index 56b6f0be4..1dcae135a 100644 --- a/NetNewsWire/MainWindow/Timeline/TimelineViewController+ContextualMenus.swift +++ b/NetNewsWire/MainWindow/Timeline/TimelineViewController+ContextualMenus.swift @@ -70,6 +70,13 @@ extension TimelineViewController { } Browser.open(urlString, inBackground: false) } + + @objc func performShareServiceFromContextualMenu(_ sender: Any?) { + guard let menuItem = sender as? NSMenuItem, let sharingCommandInfo = menuItem.representedObject as? SharingCommandInfo else { + return + } + sharingCommandInfo.perform() + } } @@ -121,24 +128,50 @@ private extension TimelineViewController { if articles.anyArticleIsRead() { menu.addItem(markUnreadMenuItem(articles)) } - if menu.items.count > 0 { - menu.addItem(NSMenuItem.separator()) - } - if articles.anyArticleIsUnstarred() { menu.addItem(markStarredMenuItem(articles)) } if articles.anyArticleIsStarred() { menu.addItem(markUnstarredMenuItem(articles)) } - if menu.items.count > 0 && !menu.items.last!.isSeparatorItem { - menu.addItem(NSMenuItem.separator()) - } + menu.addSeparatorIfNeeded() if articles.count == 1, let link = articles.first!.preferredLink { menu.addItem(openInBrowserMenuItem(link)) } + if let sharingMenu = shareMenu(for: articles) { + menu.addSeparatorIfNeeded() + let menuItem = NSMenuItem(title: sharingMenu.title, action: nil, keyEquivalent: "") + menuItem.submenu = sharingMenu + menu.addItem(menuItem) + } + + return menu + } + + func shareMenu(for articles: [Article]) -> NSMenu? { + if articles.isEmpty { + return nil + } + + let items = articles.map { ArticlePasteboardWriter(article: $0) } + let standardServices = NSSharingService.sharingServices(forItems: items) + let customServices = SharingServicePickerDelegate.customSharingServices(for: items) + let services = standardServices + customServices + if services.isEmpty { + return nil + } + + let menu = NSMenu(title: NSLocalizedString("Share", comment: "Share menu name")) + services.forEach { (service) in + let menuItem = NSMenuItem(title: service.menuItemTitle, action: #selector(performShareServiceFromContextualMenu(_:)), keyEquivalent: "") + menuItem.image = service.image + let sharingCommandInfo = SharingCommandInfo(service: service, items: items) + menuItem.representedObject = sharingCommandInfo + menu.addItem(menuItem) + } + return menu } @@ -175,3 +208,18 @@ private extension TimelineViewController { return item } } + +private final class SharingCommandInfo { + + let service: NSSharingService + let items: [Any] + + init(service: NSSharingService, items: [Any]) { + self.service = service + self.items = items + } + + func perform() { + service.perform(withItems: items) + } +}