From cdf2dd5d6404d7331126d849cb28c24a33f6f576 Mon Sep 17 00:00:00 2001 From: Nate Weaver Date: Mon, 10 Oct 2022 16:43:36 -0500 Subject: [PATCH] Alert the user the first time they try to copy URLs from articles where some have no URLs --- Mac/AppDefaults.swift | 10 +++++++ Mac/MainWindow/MainWindowController.swift | 12 ++++++--- ...melineViewController+ContextualMenus.swift | 16 ++++++----- .../URLPasteboardWriter+NetNewsWire.swift | 27 +++++++++++++++++++ NetNewsWire.xcodeproj/project.pbxproj | 6 +++++ 5 files changed, 60 insertions(+), 11 deletions(-) create mode 100644 Mac/MainWindow/URLPasteboardWriter+NetNewsWire.swift diff --git a/Mac/AppDefaults.swift b/Mac/AppDefaults.swift index df9b7c618..685d6fd44 100644 --- a/Mac/AppDefaults.swift +++ b/Mac/AppDefaults.swift @@ -42,6 +42,7 @@ final class AppDefaults { static let exportOPMLAccountID = "exportOPMLAccountID" static let defaultBrowserID = "defaultBrowserID" static let currentThemeName = "currentThemeName" + static let hasSeenNotAllArticlesHaveURLsAlert = "hasSeenNotAllArticlesHaveURLsAlert" // Hidden prefs static let showDebugMenu = "ShowDebugMenu" @@ -220,6 +221,15 @@ final class AppDefaults { AppDefaults.setString(for: Key.currentThemeName, newValue) } } + + var hasSeenNotAllArticlesHaveURLsAlert: Bool { + get { + return UserDefaults.standard.bool(forKey: Key.hasSeenNotAllArticlesHaveURLsAlert) + } + set { + UserDefaults.standard.set(newValue, forKey: Key.hasSeenNotAllArticlesHaveURLsAlert) + } + } var showTitleOnMainWindow: Bool { return AppDefaults.bool(for: Key.showTitleOnMainWindow) diff --git a/Mac/MainWindow/MainWindowController.swift b/Mac/MainWindow/MainWindowController.swift index 8455b8d1a..496b0d6ba 100644 --- a/Mac/MainWindow/MainWindowController.swift +++ b/Mac/MainWindow/MainWindowController.swift @@ -330,7 +330,7 @@ class MainWindowController : NSWindowController, NSUserInterfaceValidations { @IBAction func copyArticleURL(_ sender: Any?) { if let currentLinks { - URLPasteboardWriter.write(urlStrings: currentLinks, to: .general) + URLPasteboardWriter.write(urlStrings: currentLinks, alertingInWindow: window) } } @@ -1071,8 +1071,8 @@ private extension MainWindowController { return selectedArticles?.first { $0.preferredLink != nil }?.preferredLink } - var currentLinks: [String]? { - return selectedArticles?.compactMap { $0.preferredLink } + var currentLinks: [String?]? { + return selectedArticles?.map { $0.preferredLink } } // MARK: - State Restoration @@ -1110,7 +1110,11 @@ private extension MainWindowController { // MARK: - Command Validation func canCopyArticleURL() -> Bool { - return currentLinks != nil + if let currentLinks, currentLinks.count != 0 { + return true + } + + return false } func canCopyExternalURL() -> Bool { diff --git a/Mac/MainWindow/Timeline/TimelineViewController+ContextualMenus.swift b/Mac/MainWindow/Timeline/TimelineViewController+ContextualMenus.swift index 716e8555e..a2e5d29b7 100644 --- a/Mac/MainWindow/Timeline/TimelineViewController+ContextualMenus.swift +++ b/Mac/MainWindow/Timeline/TimelineViewController+ContextualMenus.swift @@ -97,10 +97,11 @@ extension TimelineViewController { } @objc func copyURLFromContextualMenu(_ sender: Any?) { - guard let menuItem = sender as? NSMenuItem, let urlStrings = menuItem.representedObject as? [String] else { + guard let menuItem = sender as? NSMenuItem, let urlStrings = menuItem.representedObject as? [String?] else { return } - URLPasteboardWriter.write(urlStrings: urlStrings, to: .general) + + URLPasteboardWriter.write(urlStrings: urlStrings, alertingInWindow: self.view.window) } @objc func performShareServiceFromContextualMenu(_ sender: Any?) { @@ -177,12 +178,13 @@ private extension TimelineViewController { } } - let links = articles.compactMap { $0.preferredLink } + let links = articles.map { $0.preferredLink } + let compactLinks = links.compactMap { $0 } - if links.count > 0 { + if compactLinks.count > 0 { menu.addSeparatorIfNeeded() - menu.addItem(openInBrowserMenuItem(links)) - menu.addItem(openInBrowserReversedMenuItem(links)) + menu.addItem(openInBrowserMenuItem(compactLinks)) + menu.addItem(openInBrowserReversedMenuItem(compactLinks)) menu.addSeparatorIfNeeded() menu.addItem(copyArticleURLsMenuItem(links)) @@ -289,7 +291,7 @@ private extension TimelineViewController { return item; } - func copyArticleURLsMenuItem(_ urlStrings: [String]) -> NSMenuItem { + func copyArticleURLsMenuItem(_ urlStrings: [String?]) -> NSMenuItem { let format = NSLocalizedString("Copy Article URL", comment: "Command") let title = String.localizedStringWithFormat(format, urlStrings.count) return menuItem(title, #selector(copyURLFromContextualMenu(_:)), urlStrings) diff --git a/Mac/MainWindow/URLPasteboardWriter+NetNewsWire.swift b/Mac/MainWindow/URLPasteboardWriter+NetNewsWire.swift new file mode 100644 index 000000000..679cd1602 --- /dev/null +++ b/Mac/MainWindow/URLPasteboardWriter+NetNewsWire.swift @@ -0,0 +1,27 @@ +// +// URLPasteboardWriter+NetNewsWire.swift +// NetNewsWire +// +// Created by Nate Weaver on 2022-10-10. +// Copyright © 2022 Ranchero Software. All rights reserved. +// + +import RSCore + +extension URLPasteboardWriter { + + static func write(urlStrings: [String?], to pasteboard: NSPasteboard = .general, alertingInWindow window: NSWindow?) { + URLPasteboardWriter.write(urlStrings: urlStrings.compactMap { $0 }, to: pasteboard) + + if urlStrings.contains(nil), !AppDefaults.shared.hasSeenNotAllArticlesHaveURLsAlert, let window { + let alert = NSAlert() + alert.messageText = NSLocalizedString("Some articles don’t have links, so they weren't copied.", comment: "") + alert.informativeText = NSLocalizedString("You won't see this message again.", comment: "") + + alert.beginSheetModal(for: window) + + AppDefaults.shared.hasSeenNotAllArticlesHaveURLsAlert = true + } + } + +} diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index f3bcf0fc3..9fafa10ba 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -828,6 +828,8 @@ B2B8075E239C49D300F191E0 /* RSImage-AppIcons.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2B8075D239C49D300F191E0 /* RSImage-AppIcons.swift */; }; B2B80778239C4C7000F191E0 /* RSImage-AppIcons.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2B8075D239C49D300F191E0 /* RSImage-AppIcons.swift */; }; B2B80779239C4C7300F191E0 /* RSImage-AppIcons.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2B8075D239C49D300F191E0 /* RSImage-AppIcons.swift */; }; + B2C12C6628F4C46800373730 /* URLPasteboardWriter+NetNewsWire.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2C12C6528F4C46800373730 /* URLPasteboardWriter+NetNewsWire.swift */; }; + B2C12C6728F4C46800373730 /* URLPasteboardWriter+NetNewsWire.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2C12C6528F4C46800373730 /* URLPasteboardWriter+NetNewsWire.swift */; }; B528F81E23333C7E00E735DD /* page.html in Resources */ = {isa = PBXBuildFile; fileRef = B528F81D23333C7E00E735DD /* page.html */; }; BDCB516724282C8A00102A80 /* AccountsNewsBlur.xib in Resources */ = {isa = PBXBuildFile; fileRef = BDCB514D24282C8A00102A80 /* AccountsNewsBlur.xib */; }; BDCB516824282C8A00102A80 /* AccountsNewsBlur.xib in Resources */ = {isa = PBXBuildFile; fileRef = BDCB514D24282C8A00102A80 /* AccountsNewsBlur.xib */; }; @@ -1572,6 +1574,7 @@ B24EFD5923310109006C6242 /* WKPreferencesPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WKPreferencesPrivate.h; sourceTree = ""; }; B27EEBDF244D15F2000932E6 /* stylesheet.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = stylesheet.css; sourceTree = ""; }; B2B8075D239C49D300F191E0 /* RSImage-AppIcons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RSImage-AppIcons.swift"; sourceTree = ""; }; + B2C12C6528F4C46800373730 /* URLPasteboardWriter+NetNewsWire.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URLPasteboardWriter+NetNewsWire.swift"; sourceTree = ""; }; B528F81D23333C7E00E735DD /* page.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = page.html; sourceTree = ""; }; BDCB514D24282C8A00102A80 /* AccountsNewsBlur.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AccountsNewsBlur.xib; sourceTree = ""; }; C5A6ED5123C9AF4300AB6BE2 /* TitleActivityItemSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleActivityItemSource.swift; sourceTree = ""; }; @@ -2270,6 +2273,7 @@ 5117715424E1EA0F00A2A836 /* ArticleExtractorButton.swift */, 51FA73B62332D5F70090D516 /* LegacyArticleExtractorButton.swift */, 847CD6C9232F4CBF00FAC46D /* IconView.swift */, + B2C12C6528F4C46800373730 /* URLPasteboardWriter+NetNewsWire.swift */, 844B5B6B1FEA224B00C7C76A /* Keyboard */, 849A975F1ED9EB95007D329B /* Sidebar */, 849A97681ED9EBC8007D329B /* Timeline */, @@ -3873,6 +3877,7 @@ 65ED3FD0235DEF6C0081F399 /* Author+Scriptability.swift in Sources */, 65ED3FD1235DEF6C0081F399 /* PseudoFeed.swift in Sources */, 65ED3FD3235DEF6C0081F399 /* NSScriptCommand+NetNewsWire.swift in Sources */, + B2C12C6728F4C46800373730 /* URLPasteboardWriter+NetNewsWire.swift in Sources */, 65ED3FD4235DEF6C0081F399 /* Article+Scriptability.swift in Sources */, 515A5172243E802B0089E588 /* ExtensionPointDetailViewController.swift in Sources */, 65ED3FD5235DEF6C0081F399 /* SmartFeed.swift in Sources */, @@ -4223,6 +4228,7 @@ 848B937221C8C5540038DC0D /* CrashReporter.swift in Sources */, 515A5171243E802B0089E588 /* ExtensionPointDetailViewController.swift in Sources */, 847CD6CA232F4CBF00FAC46D /* IconView.swift in Sources */, + B2C12C6628F4C46800373730 /* URLPasteboardWriter+NetNewsWire.swift in Sources */, 84BBB12E20142A4700F054F5 /* InspectorWindowController.swift in Sources */, 51EF0F7A22771B890050506E /* ColorHash.swift in Sources */, 84E46C7D1F75EF7B005ECFB3 /* AppDefaults.swift in Sources */,