From ea0171cb2715a896fecf6dda6353a6d8ed1c05ed Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Sat, 17 Oct 2020 18:33:45 -0700 Subject: [PATCH 01/35] Bump version to 5.1.2b1. --- xcconfig/common/NetNewsWire_mac_target_common.xcconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xcconfig/common/NetNewsWire_mac_target_common.xcconfig b/xcconfig/common/NetNewsWire_mac_target_common.xcconfig index aaaab96b3..14aaab69a 100644 --- a/xcconfig/common/NetNewsWire_mac_target_common.xcconfig +++ b/xcconfig/common/NetNewsWire_mac_target_common.xcconfig @@ -1,6 +1,6 @@ // High Level Settings common to both the Mac application and any extensions we bundle with it -MARKETING_VERSION = 5.1.1 -CURRENT_PROJECT_VERSION = 3012 +MARKETING_VERSION = 5.1.2b1 +CURRENT_PROJECT_VERSION = 3013 ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon From 065236ada398da8862715ab201298625ac34b741 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Sun, 18 Oct 2020 18:27:36 -0500 Subject: [PATCH 02/35] Fix row background color. Issue #2503 --- Mac/MainWindow/Timeline/TimelineTableRowView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mac/MainWindow/Timeline/TimelineTableRowView.swift b/Mac/MainWindow/Timeline/TimelineTableRowView.swift index e7a78d6a2..44a4203ec 100644 --- a/Mac/MainWindow/Timeline/TimelineTableRowView.swift +++ b/Mac/MainWindow/Timeline/TimelineTableRowView.swift @@ -35,7 +35,7 @@ class TimelineTableRowView : NSTableRowView { } override func drawBackground(in dirtyRect: NSRect) { - NSColor.controlBackgroundColor.setFill() + NSColor.alternatingContentBackgroundColors[0].setFill() dirtyRect.fill() } From d504a4b1a8d707fca995231d3bb8047414d8cf3d Mon Sep 17 00:00:00 2001 From: Nate Weaver Date: Tue, 20 Oct 2020 12:02:27 -0500 Subject: [PATCH 03/35] Replace force-unwraps Fix for #2513. --- .../General/GeneralPrefencesViewController.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Mac/Preferences/General/GeneralPrefencesViewController.swift b/Mac/Preferences/General/GeneralPrefencesViewController.swift index 1ecfb3ff3..9d4b0c20b 100644 --- a/Mac/Preferences/General/GeneralPrefencesViewController.swift +++ b/Mac/Preferences/General/GeneralPrefencesViewController.swift @@ -202,10 +202,12 @@ private extension GeneralPreferencesViewController { menu.addItem(NSMenuItem.separator()) for browser in allBrowsers { - let item = NSMenuItem(title: browser.name!, action: nil, keyEquivalent: "") + guard let name = browser.name else { continue } + + let item = NSMenuItem(title: name, action: nil, keyEquivalent: "") item.representedObject = browser.bundleIdentifier - let icon = browser.icon! + let icon = browser.icon ?? NSWorkspace.shared.icon(forFileType: kUTTypeApplicationBundle as String) icon.size = NSSize(width: 16.0, height: 16.0) item.image = browser.icon menu.addItem(item) From 6588a141c2b8fc4ab95693be176aaefbfb4b1dd4 Mon Sep 17 00:00:00 2001 From: Nate Weaver Date: Tue, 20 Oct 2020 12:05:40 -0500 Subject: [PATCH 04/35] Make sure range.location isn't out-of-bounds Fix for #2512. --- Shared/Extensions/NSAttributedString+NetNewsWire.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Shared/Extensions/NSAttributedString+NetNewsWire.swift b/Shared/Extensions/NSAttributedString+NetNewsWire.swift index f778dfb75..98fb694b7 100644 --- a/Shared/Extensions/NSAttributedString+NetNewsWire.swift +++ b/Shared/Extensions/NSAttributedString+NetNewsWire.swift @@ -191,6 +191,8 @@ extension NSAttributedString { result.addAttribute(.font, value: baseFont, range: NSRange(location: 0, length: result.length)) for (range, styles) in attributeRanges { + if range.location >= result.length { continue } + let currentFont = result.attribute(.font, at: range.location, effectiveRange: nil) as! Font let currentDescriptor = currentFont.fontDescriptor var descriptor = currentDescriptor.copy() as! FontDescriptor From ef8709ed5c3bcde60b48697be52b881a30690c95 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Tue, 20 Oct 2020 15:02:27 -0500 Subject: [PATCH 05/35] Don't create the feed if it can't be downloaded. --- .../Account/LocalAccount/LocalAccountDelegate.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Frameworks/Account/LocalAccount/LocalAccountDelegate.swift b/Frameworks/Account/LocalAccount/LocalAccountDelegate.swift index 8b69cfe46..1980939fe 100644 --- a/Frameworks/Account/LocalAccount/LocalAccountDelegate.swift +++ b/Frameworks/Account/LocalAccount/LocalAccountDelegate.swift @@ -312,14 +312,14 @@ private extension LocalAccountDelegate { return } - let feed = account.createWebFeed(with: nil, url: url.absoluteString, webFeedID: url.absoluteString, homePageURL: nil) - feed.editedName = editedName - container.addWebFeed(feed) - InitialFeedDownloader.download(url) { parsedFeed in self.refreshProgress.completeTask() if let parsedFeed = parsedFeed { + let feed = account.createWebFeed(with: nil, url: url.absoluteString, webFeedID: url.absoluteString, homePageURL: nil) + feed.editedName = editedName + container.addWebFeed(feed) + account.update(feed, with: parsedFeed, {_ in BatchUpdate.shared.end() completion(.success(feed)) From 70194dd411fc6dea262ce908b5f9a620456588bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kiel=20Gillard=20=F0=9F=A4=AA?= Date: Mon, 26 Oct 2020 10:27:36 +1100 Subject: [PATCH 06/35] macOS: Ingest a change of feed name on Feedly into NNW. #2520 --- ...yCreateFeedsForCollectionFoldersOperation.swift | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Frameworks/Account/Feedly/Operations/FeedlyCreateFeedsForCollectionFoldersOperation.swift b/Frameworks/Account/Feedly/Operations/FeedlyCreateFeedsForCollectionFoldersOperation.swift index 264c046a1..b166d1e48 100644 --- a/Frameworks/Account/Feedly/Operations/FeedlyCreateFeedsForCollectionFoldersOperation.swift +++ b/Frameworks/Account/Feedly/Operations/FeedlyCreateFeedsForCollectionFoldersOperation.swift @@ -59,6 +59,20 @@ final class FeedlyCreateFeedsForCollectionFoldersOperation: FeedlyOperation { // find an existing feed previously added to the account if let feed = account.existingWebFeed(withWebFeedID: collectionFeed.id) { + + // If the feed was renamed on Feedly, ensure we ingest the new name. + if feed.nameForDisplay != collectionFeed.title { + feed.name = collectionFeed.title + + // Let the rest of the app (e.g.: the sidebar) know the feed name changed + // `editedName` would post this if its value is changing. + // Setting the `name` property has no side effects like this. + if feed.editedName != nil { + feed.editedName = nil + } else { + feed.postDisplayNameDidChangeNotification() + } + } return (feed, folder) } else { // find an existing feed we created below in an earlier value From 8846f145b9489407c41f27912a30f5ce52f2420c Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Mon, 26 Oct 2020 20:31:58 -0700 Subject: [PATCH 07/35] Bump version to 5.1.2b2. --- xcconfig/common/NetNewsWire_mac_target_common.xcconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xcconfig/common/NetNewsWire_mac_target_common.xcconfig b/xcconfig/common/NetNewsWire_mac_target_common.xcconfig index 14aaab69a..6d48f57c5 100644 --- a/xcconfig/common/NetNewsWire_mac_target_common.xcconfig +++ b/xcconfig/common/NetNewsWire_mac_target_common.xcconfig @@ -1,6 +1,6 @@ // High Level Settings common to both the Mac application and any extensions we bundle with it -MARKETING_VERSION = 5.1.2b1 -CURRENT_PROJECT_VERSION = 3013 +MARKETING_VERSION = 5.1.2b2 +CURRENT_PROJECT_VERSION = 3014 ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon From 092d5efb3c9e10f342b532b44c5101a26cbf803c Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Thu, 29 Oct 2020 11:55:49 -0500 Subject: [PATCH 08/35] Allow the credentials to be updated for Feedbin. Fixes #2532 --- Mac/Preferences/Accounts/AccountsFeedbinWindowController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mac/Preferences/Accounts/AccountsFeedbinWindowController.swift b/Mac/Preferences/Accounts/AccountsFeedbinWindowController.swift index e6598cd5a..b022e75b5 100644 --- a/Mac/Preferences/Accounts/AccountsFeedbinWindowController.swift +++ b/Mac/Preferences/Accounts/AccountsFeedbinWindowController.swift @@ -58,7 +58,7 @@ class AccountsFeedbinWindowController: NSWindowController { return } - guard !AccountManager.shared.duplicateServiceAccount(type: .feedbin, username: usernameTextField.stringValue) else { + guard account != nil || !AccountManager.shared.duplicateServiceAccount(type: .feedbin, username: usernameTextField.stringValue) else { self.errorMessageLabel.stringValue = NSLocalizedString("There is already a Feedbin account with that username created.", comment: "Duplicate Error") return } From 1f4c0c45e249f0652c8570bc3f57130977e5a6b2 Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Thu, 29 Oct 2020 17:49:08 -0700 Subject: [PATCH 09/35] Bump version to 5.1.2b3. --- xcconfig/common/NetNewsWire_mac_target_common.xcconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xcconfig/common/NetNewsWire_mac_target_common.xcconfig b/xcconfig/common/NetNewsWire_mac_target_common.xcconfig index 6d48f57c5..26714b81a 100644 --- a/xcconfig/common/NetNewsWire_mac_target_common.xcconfig +++ b/xcconfig/common/NetNewsWire_mac_target_common.xcconfig @@ -1,6 +1,6 @@ // High Level Settings common to both the Mac application and any extensions we bundle with it -MARKETING_VERSION = 5.1.2b2 -CURRENT_PROJECT_VERSION = 3014 +MARKETING_VERSION = 5.1.2b3 +CURRENT_PROJECT_VERSION = 3015 ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon From 24dbe7c310a5bad0397cc857397954ff9db9a0fa Mon Sep 17 00:00:00 2001 From: Stuart Breckenridge Date: Fri, 30 Oct 2020 09:30:11 +0800 Subject: [PATCH 10/35] Fixes #2534 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit • Minor tweaks to the iCloud icon • Consistent footers on add account sheet • Old functionality removed when the accounts tableview has no selection --- .../AccountsPreferencesViewController.swift | 24 ++++++-- .../Accounts/AddAccountsView.swift | 55 ++++++++++-------- .../accountCloudKit.imageset/icloud-any.pdf | Bin 5871 -> 6041 bytes .../accountCloudKit.imageset/icloud-dark.pdf | Bin 5870 -> 6041 bytes 4 files changed, 48 insertions(+), 31 deletions(-) diff --git a/Mac/Preferences/Accounts/AccountsPreferencesViewController.swift b/Mac/Preferences/Accounts/AccountsPreferencesViewController.swift index 50ef70f42..c33b1ea85 100644 --- a/Mac/Preferences/Accounts/AccountsPreferencesViewController.swift +++ b/Mac/Preferences/Accounts/AccountsPreferencesViewController.swift @@ -11,7 +11,12 @@ import Account import SwiftUI import RSCore +// MARK: - AccountsPreferencesAddAccountDelegate +protocol AccountsPreferencesAddAccountDelegate { + func presentSheetForAccount(_ accountType: AccountType) +} +// MARK: - AccountsPreferencesViewController final class AccountsPreferencesViewController: NSViewController { @IBOutlet weak var tableView: NSTableView! @@ -39,6 +44,11 @@ final class AccountsPreferencesViewController: NSViewController { var rTable = tableView.frame rTable.size.width = tableView.superview!.frame.size.width tableView.frame = rTable + + // Set initial row selection + if sortedAccounts.count > 0 { + tableView.selectRow(0) + } } @IBAction func addAccount(_ sender: Any) { @@ -119,7 +129,7 @@ extension AccountsPreferencesViewController: NSTableViewDelegate { let selectedRow = tableView.selectedRow if tableView.selectedRow == -1 { deleteButton.isEnabled = false - showController(AccountsAddViewController()) + hideController() return } else { deleteButton.isEnabled = true @@ -137,11 +147,6 @@ extension AccountsPreferencesViewController: NSTableViewDelegate { } -// MARK: - AccountsPreferencesAddAccountDelegate -protocol AccountsPreferencesAddAccountDelegate { - func presentSheetForAccount(_ accountType: AccountType) -} - extension AccountsPreferencesViewController: AccountsPreferencesAddAccountDelegate { func presentSheetForAccount(_ accountType: AccountType) { switch accountType { @@ -241,6 +246,13 @@ private extension AccountsPreferencesViewController { } + func hideController() { + if let controller = children.first { + children.removeAll() + controller.view.removeFromSuperview() + } + } + } extension AccountsPreferencesViewController: OAuthAccountAuthorizationOperationDelegate { diff --git a/Mac/Preferences/Accounts/AddAccountsView.swift b/Mac/Preferences/Accounts/AddAccountsView.swift index 4a6acdc24..cdfc56cf1 100644 --- a/Mac/Preferences/Accounts/AddAccountsView.swift +++ b/Mac/Preferences/Accounts/AddAccountsView.swift @@ -31,7 +31,7 @@ private enum AddAccountSections: Int, CaseIterable { var sectionFooter: String { switch self { case .local: - return NSLocalizedString("This account does not sync subscriptions across devices.", comment: "Local Account") + return NSLocalizedString("Local accounts do not sync subscriptions across devices.", comment: "Local Account") case .icloud: return NSLocalizedString("Use your iCloud account to sync your subscriptions across your iOS and macOS devices.", comment: "iCloud Account") case .web: @@ -130,6 +130,7 @@ struct AddAccountsView: View { Text("Local") .font(.headline) .padding(.horizontal) + Picker(selection: $selectedAccount, label: Text(""), content: { ForEach(AddAccountSections.local.sectionContent, id: \.self, content: { account in HStack(alignment: .top) { @@ -137,21 +138,22 @@ struct AddAccountsView: View { .resizable() .aspectRatio(contentMode: .fit) .frame(width: 25, height: 25, alignment: .center) - .offset(CGSize(width: 0, height: -2.5)) + .offset(CGSize(width: 0, height: -3.5)) .padding(.leading, 4) - VStack(alignment: .leading, spacing: 4) { - Text(account.localizedAccountName()) - Text(AddAccountSections.local.sectionFooter).foregroundColor(.gray) - .font(.caption) - } + Text(account.localizedAccountName()) } .tag(account) }) }) .pickerStyle(RadioGroupPickerStyle()) .offset(x: 7.5, y: 0) + + Text(AddAccountSections.local.sectionFooter).foregroundColor(.gray) + .font(.caption) + .padding(.horizontal) + } } @@ -161,6 +163,8 @@ struct AddAccountsView: View { Text("iCloud") .font(.headline) .padding(.horizontal) + .padding(.top, 8) + Picker(selection: $selectedAccount, label: Text(""), content: { ForEach(AddAccountSections.icloud.sectionContent, id: \.self, content: { account in HStack(alignment: .top) { @@ -168,20 +172,20 @@ struct AddAccountsView: View { .resizable() .aspectRatio(contentMode: .fit) .frame(width: 25, height: 25, alignment: .center) - .offset(CGSize(width: 0, height: -5)) + .offset(CGSize(width: 0, height: -3.5)) .padding(.leading, 4) - VStack(alignment: .leading, spacing: 4) { - Text(account.localizedAccountName()) - Text(AddAccountSections.icloud.sectionFooter).foregroundColor(.gray) - .font(.caption) - } + Text(account.localizedAccountName()) } .tag(account) }) }) .offset(x: 7.5, y: 0) .disabled(isCloudInUse()) + + Text(AddAccountSections.icloud.sectionFooter).foregroundColor(.gray) + .font(.caption) + .padding(.horizontal) } } @@ -190,6 +194,8 @@ struct AddAccountsView: View { Text("Web") .font(.headline) .padding(.horizontal) + .padding(.top, 8) + Picker(selection: $selectedAccount, label: Text(""), content: { ForEach(AddAccountSections.web.sectionContent.filter({ isRestricted($0) != true }), id: \.self, content: { account in @@ -200,15 +206,17 @@ struct AddAccountsView: View { .frame(width: 25, height: 25, alignment: .center) .padding(.leading, 4) - VStack(alignment: .leading) { - Text(account.localizedAccountName()) - } + Text(account.localizedAccountName()) } .tag(account) }) }) .offset(x: 7.5, y: 0) + + Text(AddAccountSections.web.sectionFooter).foregroundColor(.gray) + .font(.caption) + .padding(.horizontal) } } @@ -218,6 +226,7 @@ struct AddAccountsView: View { .font(.headline) .padding(.horizontal) .padding(.top, 8) + Picker(selection: $selectedAccount, label: Text(""), content: { ForEach(AddAccountSections.selfhosted.sectionContent, id: \.self, content: { account in HStack(alignment: .top) { @@ -227,20 +236,16 @@ struct AddAccountsView: View { .frame(width: 25, height: 25, alignment: .center) .offset(CGSize(width: 0, height: -4)) .padding(.leading, 4) - - - VStack(alignment: .leading, spacing: 4) { - Text(account.localizedAccountName()) - Text("Web and self-hosted accounts sync across all signed-in devices.") - .font(.caption) - .foregroundColor(.gray) - } + + Text(account.localizedAccountName()) }.tag(account) }) }) .offset(x: 7.5, y: 0) - + Text(AddAccountSections.selfhosted.sectionFooter).foregroundColor(.gray) + .font(.caption) + .padding(.horizontal) } } diff --git a/Mac/Resources/Assets.xcassets/accountCloudKit.imageset/icloud-any.pdf b/Mac/Resources/Assets.xcassets/accountCloudKit.imageset/icloud-any.pdf index 552cab54c068dea7dad3ee824e75174b42cb72d4..79ba7e3eb1efdc43ee2b55b7a4d675fef0592414 100644 GIT binary patch delta 1271 zcmaE_J5zsxUA?)niGrOSS8+*EYGN)|1!L+I>oQey9+%H?tjX*qA5~}mwwQl{JK&K+ z^8B0ikGRWT_Z~Yn>nclthRBb_wb}NwBK+sC^bPxNy0|u9sP?T-y`$0ZD`#>h**=Tg z{nusB>eMG+zj2!_TP@>q#Umv}#*F*qQa`3s$7ZdbyCZ&McXUAgO_d9J3#%T@FS`4&%Jq=+&Rz0I7V+vPcTR8p1GH!yXC5* zpVZdn-%EY9=-AKv+7R1ghA->=ZrAQByMAZd)jP$_ZWCN47tiARG}Xh->7+#TG)29j zbB#Ol_1{z_UOe6=`h2gg`5qm^*0~c;oKes!=$p%!5iYN(P~A55PE@I?{)DHy)%cCC ztE%_S;n`up|2eCS$Nrzj;ww4(6nGeT9+}2f8C-D{Ue^82qO7I2)rfh1VkiHDdR~u` zg3hh`d6n3^r)?vYB(in_Cz0Db>(7~#Rn&xa@6sAvd$ohF>6IYGy{o1yO zz0B#h^QG(GZ#}=Sxwk^#XtzXQq><5_%g^7g-~Zv_)YnQTDF%fSCO3h1wrgk7}av#%kPD2GF1tT*BBjd^S%whEw zDEYznv?1Ri10J`BbA$JACnQ;y9y-HmRoKwA%7b;~lYc@foj2_4|Ju#4^hn8Z;-1f5 zeouvSUQFKEh^YNtZP6vJE5zTgGOgshbtuwxecZCiGhNvAb&hQPXL0M_^&`de-#!+V z&P-1I$MoQ~LNwH2n}b>2@-rEkPIeMGt8HvxU|?clXcA>$pbkWu3i`hJDK3d6sR|k{ zRz?O!28ISOC6ld0EyOI0EEIrR3=9J@4$;>3lJTW!JG&RM@(#+h< v!ZO(;(a_w$JkdPODAA6~hM*FKSV$Zu7L`;KrKWM2ni&~$sj9mAyKw;ks9g$F delta 1065 zcmbQK|6X^3UA?K9iGrOSS8+*EYGN)|1!HcA;LQx8|FoNM)#Q{d}eX1U9$bl#6=PMw%bL{MpZpOA658JVq49FjSTS?$Le*ZA#rQzhHhP08CjP5V_hZ{psExrZbJ**9LUjLNO=30vv*W_RL}tL!q} zT>hu$3Ywg#k9w}d&U<3QU9U9v13&G5Oe=~wo!;f(z@~n8)-xrGSyS(J&(n%>v~^>( z*3fcnZz`LedjDFrme~aU_Z|_t{TKP_%w~%gYOHa}K6T&ePSS;h?N=Agb(tVpQNK|} z)Tep+L!H>%(kCqa>B5h4>P?sBJrL15?Pag1JgwLD#57Ny@|mAsIy~Cp)yec;KSFSh z0+Xg==n9?-LdJKGS=e3VCmM|U-ruAsGOc5azD7n;aQ;Q&n`tYaHn zF7O`w`E=R4m)|F+emYiQE0B?q{yS|~s31>j*d7NZ;l-1hlspdysW257S=jJQU9EEX z&cjyCzPX=D4tN+ZylFT=V1dT1+?4Qv99v3?ci_R0={`GbAugUxV*YtmRoL}{u{hR84;mKOe zU%8AFbPW}Z%oU6bCTp;S)tjTFE7xvEu4V%f*6;I@^e&j#ci!Lejx(l`Auwt~)3bj8 z_F+$RpYfjYI^K0(JWFMB?-!kl)^#pGXN4)MvU#ukoQey9+%H?tjX*qA5~}mwwQl{JK&K+ z^8B0ikGRWT_Z~Yn>nclthRBb_wb}NwBK+sC^bPxNy0|u9sP?T-y`$0ZD`#>h**=Tg z{nusB>eMG+zj2!_TP@>q#Umv}#*F*qQa`3s$7ZdbyCZ&McXUAgO_d9J3#%T@FS`4&%Jq=+&Rz0I7V+vPcTR8p1GH!yXC5* zpVZdn-%EY9=-AKv+7R1ghA->=ZrAQByMAZd)jP$_ZWCN47tiARG}Xh->7+#TG)29j zbB#Ol_1{z_UOe6=`h2gg`5qm^*0~c;oKes!=$p%!5iYN(P~A55PE@I?{)DHy)%cCC ztE%_S;n`up|2eCS$Nrzj;ww4(6nGeT9+}2f8C-D{Ue^82qO7I2)rfh1VkiHDdR~u` zg3hh`d6n3^r)?vYB(in_Cz0Db>(7~#Rn&xa@6sAvd$ohF>6IYGy{o1yO zz0B#h^QG(GZ#}=Sxwk^#XtzXQq><5_%g^7g-~Zv_)YnQTDF%fSCO3h1wrgk7}av#%kPD2GF1tT*BBjd^S%whEw zDEYznv@h2o1A(@OdzV+}KbUdmN%>vjlBbMb-AEn`R4@(Pb-THbJ~z$zcXv;>a_XZ3v^@l{>ZY73sEio;52!LzPkJE|Fa@qY_8q2 zNZIzrjQx+EC?rB1wmFF9EkBcy>10Qdv)aZ61_mY;h9*%42I@ehsi5zhpW>2OlB%HL zVr67tWMF6jQ!?37)I!|C$U*_A#lS!zPk{@}FfcVXG@9HYs#N?J-q6Sb zL!FT+7ITfv%`o&Dn_`F=nVNy^P(gK+C5FYOCZ^_-1H|m(4HJ`0%#)3iEP6m#V6(zZ(|-AWaIy delta 1067 zcmbQK|4w&;UA?K9iGrOSS8+*EYGN)|1!HcA;LQx8|FoNM)#Q{d}eX1U9$bl#6=PMw%bL{MpZpOA658JVq49FjSTS?$Le*ZA#rQzhHhP08CjP5V_hZ{psExrZbJ**9LUjLNO=30vv*W_RL}tL!q} zT>hu$3Ywg#k9w}d&U<3QU9U9v13&G5Oe=~wo!;f(z@~n8)-xrGSyS(J&(n%>v~^>( z*3fcnZz`LedjDFrme~aU_Z|_t{TKP_%w~%gYOHa}K6T&ePSS;h?N=Agb(tVpQNK|} z)Tep+L!H>%(kCqa>B5h4>P?sBJrL15?Pag1JgwLD#57Ny@|mAsIy~Cp)yec;KSFSh z0+Xg==n9?-LdJKGS=e3VCmM|U-ruAsGOc5azD7n;aQ;Q&n`tYaHn zF7O`w`E=R4m)|F+emYiQE0B?q{yS|~s31>j*d7NZ;l-1hlspdysW257S=jJQU9EEX z&cjyCzPX=D4tN+ZylFT=V1dT1+?4Qv99v3?ci_R0={`GbAugUxV*YtmRoL}{u{hR84;mKOe zU%8AFbPW}Z%oU6bCTp;S)tjNDE7xvsu4V%Xw(s+j^cI|b+^?4H|KJoe%Tm_p4Lj{; z2*}sW{>he>p5*>ivi;j1@wB=X>z*IZ_Gz2(X>;5Wt7uQw*W9g+{Ba%=!^#~yceu54 z)foQm+N5LBWN3yH79qLPZD)HE(r6H_BDRaIAiH!c9G*`yl) From 5b1df3631e584473a4db5af1b0bd5f86ff5b0967 Mon Sep 17 00:00:00 2001 From: Stuart Breckenridge Date: Fri, 30 Oct 2020 09:44:44 +0800 Subject: [PATCH 11/35] Alignment consistency --- .../Accounts/AddAccountsView.swift | 13 ++++++------- .../accountFreshRSS.imageset/Contents.json | 2 +- .../{freshrss-any.pdf => FreshRSS.pdf} | Bin 3974 -> 3974 bytes 3 files changed, 7 insertions(+), 8 deletions(-) rename Mac/Resources/Assets.xcassets/accountFreshRSS.imageset/{freshrss-any.pdf => FreshRSS.pdf} (95%) diff --git a/Mac/Preferences/Accounts/AddAccountsView.swift b/Mac/Preferences/Accounts/AddAccountsView.swift index cdfc56cf1..61ccaf3f1 100644 --- a/Mac/Preferences/Accounts/AddAccountsView.swift +++ b/Mac/Preferences/Accounts/AddAccountsView.swift @@ -117,7 +117,9 @@ struct AddAccountsView: View { .frame(width: 80) }) } - }.padding(.vertical, 8) + } + .padding(.top, 12) + .padding(.bottom, 4) } .pickerStyle(RadioGroupPickerStyle()) .fixedSize(horizontal: false, vertical: true) @@ -133,12 +135,11 @@ struct AddAccountsView: View { Picker(selection: $selectedAccount, label: Text(""), content: { ForEach(AddAccountSections.local.sectionContent, id: \.self, content: { account in - HStack(alignment: .top) { + HStack(alignment: .center) { account.image() .resizable() .aspectRatio(contentMode: .fit) .frame(width: 25, height: 25, alignment: .center) - .offset(CGSize(width: 0, height: -3.5)) .padding(.leading, 4) @@ -167,12 +168,11 @@ struct AddAccountsView: View { Picker(selection: $selectedAccount, label: Text(""), content: { ForEach(AddAccountSections.icloud.sectionContent, id: \.self, content: { account in - HStack(alignment: .top) { + HStack(alignment: .center) { account.image() .resizable() .aspectRatio(contentMode: .fit) .frame(width: 25, height: 25, alignment: .center) - .offset(CGSize(width: 0, height: -3.5)) .padding(.leading, 4) Text(account.localizedAccountName()) @@ -229,12 +229,11 @@ struct AddAccountsView: View { Picker(selection: $selectedAccount, label: Text(""), content: { ForEach(AddAccountSections.selfhosted.sectionContent, id: \.self, content: { account in - HStack(alignment: .top) { + HStack(alignment: .center) { account.image() .resizable() .aspectRatio(contentMode: .fit) .frame(width: 25, height: 25, alignment: .center) - .offset(CGSize(width: 0, height: -4)) .padding(.leading, 4) Text(account.localizedAccountName()) diff --git a/Mac/Resources/Assets.xcassets/accountFreshRSS.imageset/Contents.json b/Mac/Resources/Assets.xcassets/accountFreshRSS.imageset/Contents.json index 974a47751..99d210221 100644 --- a/Mac/Resources/Assets.xcassets/accountFreshRSS.imageset/Contents.json +++ b/Mac/Resources/Assets.xcassets/accountFreshRSS.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "freshrss-any.pdf", + "filename" : "FreshRSS.pdf", "idiom" : "universal" } ], diff --git a/Mac/Resources/Assets.xcassets/accountFreshRSS.imageset/freshrss-any.pdf b/Mac/Resources/Assets.xcassets/accountFreshRSS.imageset/FreshRSS.pdf similarity index 95% rename from Mac/Resources/Assets.xcassets/accountFreshRSS.imageset/freshrss-any.pdf rename to Mac/Resources/Assets.xcassets/accountFreshRSS.imageset/FreshRSS.pdf index 066de5aa370c429a1f93dcdf60a8d3b205a81e81..d9ba3f3ead38ccbe005d084d0f21445e2babde77 100644 GIT binary patch delta 127 zcmZpZZT9_J`7^j&f8(E~K*m2nqP%=4_UlsruO(1aq From d9df9e53d340f7f15679334eed37f39398bb38ed Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Fri, 30 Oct 2020 04:18:11 -0500 Subject: [PATCH 12/35] Remove obsolete Add Account code --- Mac/Preferences/Accounts/AccountsAdd.xib | 123 --------- .../Accounts/AccountsAddTableCellView.swift | 29 -- .../Accounts/AccountsAddViewController.swift | 260 ------------------ NetNewsWire.xcodeproj/project.pbxproj | 18 -- 4 files changed, 430 deletions(-) delete mode 100644 Mac/Preferences/Accounts/AccountsAdd.xib delete mode 100644 Mac/Preferences/Accounts/AccountsAddTableCellView.swift delete mode 100644 Mac/Preferences/Accounts/AccountsAddViewController.swift diff --git a/Mac/Preferences/Accounts/AccountsAdd.xib b/Mac/Preferences/Accounts/AccountsAdd.xib deleted file mode 100644 index 1fb72c35e..000000000 --- a/Mac/Preferences/Accounts/AccountsAdd.xib +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Mac/Preferences/Accounts/AccountsAddTableCellView.swift b/Mac/Preferences/Accounts/AccountsAddTableCellView.swift deleted file mode 100644 index fca762320..000000000 --- a/Mac/Preferences/Accounts/AccountsAddTableCellView.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// AccountsAddTableCellView.swift -// NetNewsWire -// -// Created by Maurice Parker on 5/1/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import AppKit -import Account - -protocol AccountsAddTableCellViewDelegate: class { - func addAccount(_ accountType: AccountType) -} - -class AccountsAddTableCellView: NSTableCellView { - - weak var delegate: AccountsAddTableCellViewDelegate? - var accountType: AccountType? - - @IBOutlet weak var accountImageView: NSImageView? - @IBOutlet weak var accountNameLabel: NSTextField? - - @IBAction func pressed(_ sender: Any) { - guard let accountType = accountType else { return } - delegate?.addAccount(accountType) - } - -} diff --git a/Mac/Preferences/Accounts/AccountsAddViewController.swift b/Mac/Preferences/Accounts/AccountsAddViewController.swift deleted file mode 100644 index 2b78d7532..000000000 --- a/Mac/Preferences/Accounts/AccountsAddViewController.swift +++ /dev/null @@ -1,260 +0,0 @@ -// -// AccountsAddViewController.swift -// NetNewsWire -// -// Created by Maurice Parker on 5/1/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import AppKit -import Account -import RSCore - -class AccountsAddViewController: NSViewController { - - @IBOutlet weak var tableView: NSTableView! - - private var accountsAddWindowController: NSWindowController? - - #if DEBUG - private var addableAccountTypes: [AccountType] = [.onMyMac, .cloudKit, .bazQux, .feedbin, .feedly, .feedWrangler, .inoreader, .newsBlur, .theOldReader, .freshRSS] - #else - private var addableAccountTypes: [AccountType] = [.onMyMac, .cloudKit, .bazQux, .feedbin, .feedly, .feedWrangler, .inoreader, .newsBlur, .theOldReader, .freshRSS] - #endif - - init() { - super.init(nibName: "AccountsAdd", bundle: nil) - } - - public required init?(coder: NSCoder) { - super.init(coder: coder) - } - - override func viewDidLoad() { - super.viewDidLoad() - tableView.dataSource = self - tableView.delegate = self - restrictAccounts() - } - -} - -// MARK: - NSTableViewDataSource - -extension AccountsAddViewController: NSTableViewDataSource { - - func numberOfRows(in tableView: NSTableView) -> Int { - return addableAccountTypes.count - } - - func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? { - return nil - } -} - -// MARK: - NSTableViewDelegate - -extension AccountsAddViewController: NSTableViewDelegate { - - private static let cellIdentifier = NSUserInterfaceItemIdentifier(rawValue: "AccountCell") - - func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { - - if let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "Cell"), owner: nil) as? AccountsAddTableCellView { - - cell.accountType = addableAccountTypes[row] - cell.delegate = self - - switch addableAccountTypes[row] { - case .onMyMac: - cell.accountNameLabel?.stringValue = Account.defaultLocalAccountName - cell.accountImageView?.image = AppAssets.accountLocal - case .cloudKit: - cell.accountNameLabel?.stringValue = NSLocalizedString("iCloud", comment: "iCloud") - cell.accountImageView?.image = AppAssets.accountCloudKit - case .feedbin: - cell.accountNameLabel?.stringValue = NSLocalizedString("Feedbin", comment: "Feedbin") - cell.accountImageView?.image = AppAssets.accountFeedbin - case .feedWrangler: - cell.accountNameLabel?.stringValue = NSLocalizedString("Feed Wrangler", comment: "Feed Wrangler") - cell.accountImageView?.image = AppAssets.accountFeedWrangler - case .freshRSS: - cell.accountNameLabel?.stringValue = NSLocalizedString("FreshRSS", comment: "FreshRSS") - cell.accountImageView?.image = AppAssets.accountFreshRSS - case .feedly: - cell.accountNameLabel?.stringValue = NSLocalizedString("Feedly", comment: "Feedly") - cell.accountImageView?.image = AppAssets.accountFeedly - case .newsBlur: - cell.accountNameLabel?.stringValue = NSLocalizedString("NewsBlur", comment: "NewsBlur") - cell.accountImageView?.image = AppAssets.accountNewsBlur - case .inoreader: - cell.accountNameLabel?.stringValue = NSLocalizedString("Inoreader", comment: "Inoreader") - cell.accountImageView?.image = AppAssets.accountInoreader - case .bazQux: - cell.accountNameLabel?.stringValue = NSLocalizedString("Bazqux", comment: "Bazqux") - cell.accountImageView?.image = AppAssets.accountBazQux - case .theOldReader: - cell.accountNameLabel?.stringValue = NSLocalizedString("The Old Reader", comment: "The Old Reader") - cell.accountImageView?.image = AppAssets.accountTheOldReader - } - return cell - } - return nil - } - -} - -// MARK: AccountsAddTableCellViewDelegate - -extension AccountsAddViewController: AccountsAddTableCellViewDelegate { - - func addAccount(_ accountType: AccountType) { - - switch accountType { - case .onMyMac: - let accountsAddLocalWindowController = AccountsAddLocalWindowController() - accountsAddLocalWindowController.runSheetOnWindow(self.view.window!) - accountsAddWindowController = accountsAddLocalWindowController - - case .cloudKit: - let accountsAddCloudKitWindowController = AccountsAddCloudKitWindowController() - accountsAddCloudKitWindowController.runSheetOnWindow(self.view.window!) { response in - if response == NSApplication.ModalResponse.OK { - self.restrictAccounts() - self.tableView.reloadData() - } - } - accountsAddWindowController = accountsAddCloudKitWindowController - - case .feedbin: - let accountsFeedbinWindowController = AccountsFeedbinWindowController() - accountsFeedbinWindowController.runSheetOnWindow(self.view.window!) - accountsAddWindowController = accountsFeedbinWindowController - - case .feedWrangler: - let accountsFeedWranglerWindowController = AccountsFeedWranglerWindowController() - accountsFeedWranglerWindowController.runSheetOnWindow(self.view.window!) - accountsAddWindowController = accountsFeedWranglerWindowController - - case .freshRSS: - let accountsReaderAPIWindowController = AccountsReaderAPIWindowController() - accountsReaderAPIWindowController.accountType = .freshRSS - accountsReaderAPIWindowController.runSheetOnWindow(self.view.window!) - accountsAddWindowController = accountsReaderAPIWindowController - - case .feedly: - let addAccount = OAuthAccountAuthorizationOperation(accountType: .feedly) - 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!) - accountsAddWindowController = accountsNewsBlurWindowController - - case .inoreader: - let accountsReaderAPIWindowController = AccountsReaderAPIWindowController() - accountsReaderAPIWindowController.accountType = .inoreader - accountsReaderAPIWindowController.runSheetOnWindow(self.view.window!) - accountsAddWindowController = accountsReaderAPIWindowController - - case .bazQux: - let accountsReaderAPIWindowController = AccountsReaderAPIWindowController() - accountsReaderAPIWindowController.accountType = .bazQux - accountsReaderAPIWindowController.runSheetOnWindow(self.view.window!) - accountsAddWindowController = accountsReaderAPIWindowController - - case .theOldReader: - let accountsReaderAPIWindowController = AccountsReaderAPIWindowController() - accountsReaderAPIWindowController.accountType = .theOldReader - accountsReaderAPIWindowController.runSheetOnWindow(self.view.window!) - accountsAddWindowController = accountsReaderAPIWindowController - } - - } - - private func runAwaitingFeedlyLoginAlertModal(forLifetimeOf operation: OAuthAccountAuthorizationOperation) { - let alert = NSAlert() - alert.alertStyle = .informational - alert.messageText = NSLocalizedString("Waiting for access to Feedly", - comment: "Alert title when adding a Feedly account and waiting for authorization from the user.") - - alert.informativeText = NSLocalizedString("Your default web browser will open the Feedly login for you to authorize access.", - comment: "Alert informative text when adding a Feedly account and waiting for authorization from the user.") - - alert.addButton(withTitle: NSLocalizedString("Cancel", comment: "Cancel")) - - let attachedWindow = self.view.window! - - alert.beginSheetModal(for: attachedWindow) { response in - if response == .alertFirstButtonReturn { - operation.cancel() - } - } - - operation.completionBlock = { _ in - guard alert.window.isVisible else { - return - } - attachedWindow.endSheet(alert.window) - } - } -} - -// MARK: OAuthAccountAuthorizationOperationDelegate - -extension AccountsAddViewController: OAuthAccountAuthorizationOperationDelegate { - - func oauthAccountAuthorizationOperation(_ operation: OAuthAccountAuthorizationOperation, didCreate account: Account) { - // `OAuthAccountAuthorizationOperation` is using `ASWebAuthenticationSession` which bounces the user - // to their browser on macOS for authorizing NetNewsWire to access the user's Feedly account. - // When this authorization is granted, the browser remains the foreground app which is unfortunate - // because the user probably wants to see the result of authorizing NetNewsWire to act on their behalf. - NSApp.activate(ignoringOtherApps: true) - - account.refreshAll { [weak self] result in - switch result { - case .success: - break - case .failure(let error): - self?.presentError(error) - } - } - } - - func oauthAccountAuthorizationOperation(_ operation: OAuthAccountAuthorizationOperation, didFailWith error: Error) { - // `OAuthAccountAuthorizationOperation` is using `ASWebAuthenticationSession` which bounces the user - // to their browser on macOS for authorizing NetNewsWire to access the user's Feedly account. - NSApp.activate(ignoringOtherApps: true) - - view.window?.presentError(error) - } -} - -// MARK: Private - -private extension AccountsAddViewController { - - func restrictAccounts() { - func removeAccountType(_ accountType: AccountType) { - if let index = addableAccountTypes.firstIndex(of: accountType) { - addableAccountTypes.remove(at: index) - } - } - - if AppDefaults.shared.isDeveloperBuild { - removeAccountType(.cloudKit) - removeAccountType(.feedly) - removeAccountType(.feedWrangler) - removeAccountType(.inoreader) - return - } - - if AccountManager.shared.accounts.firstIndex(where: { $0.type == .cloudKit }) != nil { - removeAccountType(.cloudKit) - } - } - -} diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 2d8fcc1a4..6dfaabae5 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -662,9 +662,6 @@ 51EF0F7A22771B890050506E /* ColorHash.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F78227716380050506E /* ColorHash.swift */; }; 51EF0F7E2277A57D0050506E /* MasterTimelineAccessibilityCellLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F7D2277A57D0050506E /* MasterTimelineAccessibilityCellLayout.swift */; }; 51EF0F802277A8330050506E /* MasterTimelineCellLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F7F2277A8330050506E /* MasterTimelineCellLayout.swift */; }; - 51EF0F8E2279C9260050506E /* AccountsAdd.xib in Resources */ = {isa = PBXBuildFile; fileRef = 51EF0F8D2279C9260050506E /* AccountsAdd.xib */; }; - 51EF0F902279C9500050506E /* AccountsAddViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F8F2279C9500050506E /* AccountsAddViewController.swift */; }; - 51EF0F922279CA620050506E /* AccountsAddTableCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F912279CA620050506E /* AccountsAddTableCellView.swift */; }; 51EFDA1A24E6159C0085C3D6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 849C64671ED37A5D003D8FC0 /* Assets.xcassets */; }; 51EFDA1B24E6D16A0085C3D6 /* SafariExt.js in Resources */ = {isa = PBXBuildFile; fileRef = 515D4FCB2325815A00EE1167 /* SafariExt.js */; }; 51EFDA1D24E6E27E0085C3D6 /* icon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 51EFDA1C24E6E27E0085C3D6 /* icon.icns */; }; @@ -737,7 +734,6 @@ 65ED3FCF235DEF6C0081F399 /* TimelineContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8405DD9822153B6B008CE1BF /* TimelineContainerView.swift */; }; 65ED3FD0235DEF6C0081F399 /* Author+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A2678B20130ECF00A8D3C0 /* Author+Scriptability.swift */; }; 65ED3FD1235DEF6C0081F399 /* PseudoFeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2D5351FC22FCB00998D64 /* PseudoFeed.swift */; }; - 65ED3FD2235DEF6C0081F399 /* AccountsAddViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F8F2279C9500050506E /* AccountsAddViewController.swift */; }; 65ED3FD3235DEF6C0081F399 /* NSScriptCommand+NetNewsWire.swift in Sources */ = {isa = PBXBuildFile; fileRef = D57BE6DF204CD35F00D11AAC /* NSScriptCommand+NetNewsWire.swift */; }; 65ED3FD4235DEF6C0081F399 /* Article+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D553737C20186C1F006D8857 /* Article+Scriptability.swift */; }; 65ED3FD5235DEF6C0081F399 /* SmartFeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845EE7C01FC2488C00854A1F /* SmartFeed.swift */; }; @@ -798,7 +794,6 @@ 65ED400D235DEF6C0081F399 /* SmartFeedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DEE56422C32CA4005FC42C /* SmartFeedDelegate.swift */; }; 65ED400E235DEF6C0081F399 /* ImageDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845213221FCA5B10003B6E93 /* ImageDownloader.swift */; }; 65ED400F235DEF6C0081F399 /* LegacyArticleExtractorButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51FA73B62332D5F70090D516 /* LegacyArticleExtractorButton.swift */; }; - 65ED4010235DEF6C0081F399 /* AccountsAddTableCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F912279CA620050506E /* AccountsAddTableCellView.swift */; }; 65ED4011235DEF6C0081F399 /* AddFolderWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97421ED9EAA9007D329B /* AddFolderWindowController.swift */; }; 65ED4012235DEF6C0081F399 /* TimelineContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8405DDA422168C62008CE1BF /* TimelineContainerViewController.swift */; }; 65ED4013235DEF6C0081F399 /* MainWIndowKeyboardHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844B5B661FEA18E300C7C76A /* MainWIndowKeyboardHandler.swift */; }; @@ -853,7 +848,6 @@ 65ED4051235DEF6C0081F399 /* TimelineKeyboardShortcuts.plist in Resources */ = {isa = PBXBuildFile; fileRef = 845479871FEB77C000AD8B59 /* TimelineKeyboardShortcuts.plist */; }; 65ED4052235DEF6C0081F399 /* template.html in Resources */ = {isa = PBXBuildFile; fileRef = 848362FE2262A30E00DA1D35 /* template.html */; }; 65ED4054235DEF6C0081F399 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 848363062262A3DD00DA1D35 /* Main.storyboard */; }; - 65ED4055235DEF6C0081F399 /* AccountsAdd.xib in Resources */ = {isa = PBXBuildFile; fileRef = 51EF0F8D2279C9260050506E /* AccountsAdd.xib */; }; 65ED4056235DEF6C0081F399 /* NetNewsWire.sdef in Resources */ = {isa = PBXBuildFile; fileRef = 84C9FC8A22629E8F00D921D6 /* NetNewsWire.sdef */; }; 65ED4057235DEF6C0081F399 /* AccountsDetail.xib in Resources */ = {isa = PBXBuildFile; fileRef = 84C9FC7422629E1200D921D6 /* AccountsDetail.xib */; }; 65ED4058235DEF6C0081F399 /* main.js in Resources */ = {isa = PBXBuildFile; fileRef = 517630032336215100E15FFF /* main.js */; }; @@ -1774,9 +1768,6 @@ 51EF0F78227716380050506E /* ColorHash.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorHash.swift; sourceTree = ""; }; 51EF0F7D2277A57D0050506E /* MasterTimelineAccessibilityCellLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MasterTimelineAccessibilityCellLayout.swift; sourceTree = ""; }; 51EF0F7F2277A8330050506E /* MasterTimelineCellLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MasterTimelineCellLayout.swift; sourceTree = ""; }; - 51EF0F8D2279C9260050506E /* AccountsAdd.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AccountsAdd.xib; sourceTree = ""; }; - 51EF0F8F2279C9500050506E /* AccountsAddViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsAddViewController.swift; sourceTree = ""; }; - 51EF0F912279CA620050506E /* AccountsAddTableCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsAddTableCellView.swift; sourceTree = ""; }; 51EFDA1C24E6E27E0085C3D6 /* icon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = icon.icns; sourceTree = ""; }; 51F805D32428499E0022C792 /* NetNewsWire-dev.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "NetNewsWire-dev.entitlements"; sourceTree = ""; }; 51F805ED24284C1C0022C792 /* NetNewsWire-dev.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "NetNewsWire-dev.entitlements"; sourceTree = ""; }; @@ -3350,9 +3341,6 @@ children = ( 178A9F9C2549449F00AB7E9D /* AddAccountsView.swift */, 84C9FC7222629E1200D921D6 /* AccountsPreferencesViewController.swift */, - 51EF0F8D2279C9260050506E /* AccountsAdd.xib */, - 51EF0F8F2279C9500050506E /* AccountsAddViewController.swift */, - 51EF0F912279CA620050506E /* AccountsAddTableCellView.swift */, 84C9FC7422629E1200D921D6 /* AccountsDetail.xib */, 5144EA2E2279FAB600D19003 /* AccountsDetailViewController.swift */, 5144EA50227B8E4500D19003 /* AccountsFeedbin.xib */, @@ -4193,7 +4181,6 @@ 65ED4052235DEF6C0081F399 /* template.html in Resources */, 65ED4054235DEF6C0081F399 /* Main.storyboard in Resources */, 510C43EE243C0973009F70C3 /* ExtensionPointAdd.xib in Resources */, - 65ED4055235DEF6C0081F399 /* AccountsAdd.xib in Resources */, 65ED4056235DEF6C0081F399 /* NetNewsWire.sdef in Resources */, 65ED4057235DEF6C0081F399 /* AccountsDetail.xib in Resources */, 65ED4058235DEF6C0081F399 /* main.js in Resources */, @@ -4290,7 +4277,6 @@ 845479881FEB77C000AD8B59 /* TimelineKeyboardShortcuts.plist in Resources */, 848362FF2262A30E00DA1D35 /* template.html in Resources */, 848363082262A3DD00DA1D35 /* Main.storyboard in Resources */, - 51EF0F8E2279C9260050506E /* AccountsAdd.xib in Resources */, 84C9FC8F22629E8F00D921D6 /* NetNewsWire.sdef in Resources */, 84C9FC7D22629E1200D921D6 /* AccountsDetail.xib in Resources */, 517630042336215100E15FFF /* main.js in Resources */, @@ -4843,7 +4829,6 @@ 65ED3FCF235DEF6C0081F399 /* TimelineContainerView.swift in Sources */, 65ED3FD0235DEF6C0081F399 /* Author+Scriptability.swift in Sources */, 65ED3FD1235DEF6C0081F399 /* PseudoFeed.swift in Sources */, - 65ED3FD2235DEF6C0081F399 /* AccountsAddViewController.swift in Sources */, 65ED3FD3235DEF6C0081F399 /* NSScriptCommand+NetNewsWire.swift in Sources */, 65ED3FD4235DEF6C0081F399 /* Article+Scriptability.swift in Sources */, 515A5172243E802B0089E588 /* ExtensionPointDetailViewController.swift in Sources */, @@ -4916,7 +4901,6 @@ 65ED400D235DEF6C0081F399 /* SmartFeedDelegate.swift in Sources */, 65ED400E235DEF6C0081F399 /* ImageDownloader.swift in Sources */, 65ED400F235DEF6C0081F399 /* LegacyArticleExtractorButton.swift in Sources */, - 65ED4010235DEF6C0081F399 /* AccountsAddTableCellView.swift in Sources */, 65ED4011235DEF6C0081F399 /* AddFolderWindowController.swift in Sources */, 65ED4012235DEF6C0081F399 /* TimelineContainerViewController.swift in Sources */, 65ED4013235DEF6C0081F399 /* MainWIndowKeyboardHandler.swift in Sources */, @@ -5204,7 +5188,6 @@ 8405DD9922153B6B008CE1BF /* TimelineContainerView.swift in Sources */, D5A2678C20130ECF00A8D3C0 /* Author+Scriptability.swift in Sources */, 84F2D5371FC22FCC00998D64 /* PseudoFeed.swift in Sources */, - 51EF0F902279C9500050506E /* AccountsAddViewController.swift in Sources */, D57BE6E0204CD35F00D11AAC /* NSScriptCommand+NetNewsWire.swift in Sources */, D553738B20186C20006D8857 /* Article+Scriptability.swift in Sources */, 845EE7C11FC2488C00854A1F /* SmartFeed.swift in Sources */, @@ -5281,7 +5264,6 @@ 84DEE56522C32CA4005FC42C /* SmartFeedDelegate.swift in Sources */, 845213231FCA5B11003B6E93 /* ImageDownloader.swift in Sources */, 51FA73B72332D5F70090D516 /* LegacyArticleExtractorButton.swift in Sources */, - 51EF0F922279CA620050506E /* AccountsAddTableCellView.swift in Sources */, 849A97431ED9EAA9007D329B /* AddFolderWindowController.swift in Sources */, 8405DDA522168C62008CE1BF /* TimelineContainerViewController.swift in Sources */, 844B5B671FEA18E300C7C76A /* MainWIndowKeyboardHandler.swift in Sources */, From 48138b1bb4d54ac0e6b196a90b6ce76cbc02f8c3 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Fri, 30 Oct 2020 04:25:33 -0500 Subject: [PATCH 13/35] Retain a reference to the Add Account Window Controllers so that they don't get deallocated before they have a chance to get used --- .../AccountsPreferencesViewController.swift | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/Mac/Preferences/Accounts/AccountsPreferencesViewController.swift b/Mac/Preferences/Accounts/AccountsPreferencesViewController.swift index c33b1ea85..fcd97b81e 100644 --- a/Mac/Preferences/Accounts/AccountsPreferencesViewController.swift +++ b/Mac/Preferences/Accounts/AccountsPreferencesViewController.swift @@ -23,7 +23,7 @@ final class AccountsPreferencesViewController: NSViewController { @IBOutlet weak var detailView: NSView! @IBOutlet weak var deleteButton: NSButton! var addAccountDelegate: AccountsPreferencesAddAccountDelegate? - + var addAccountWindowController: NSWindowController? private var sortedAccounts = [Account]() @@ -153,7 +153,7 @@ extension AccountsPreferencesViewController: AccountsPreferencesAddAccountDelega case .onMyMac: let accountsAddLocalWindowController = AccountsAddLocalWindowController() accountsAddLocalWindowController.runSheetOnWindow(self.view.window!) - + addAccountWindowController = accountsAddLocalWindowController case .cloudKit: let accountsAddCloudKitWindowController = AccountsAddCloudKitWindowController() accountsAddCloudKitWindowController.runSheetOnWindow(self.view.window!) { response in @@ -161,17 +161,20 @@ extension AccountsPreferencesViewController: AccountsPreferencesAddAccountDelega self.tableView.reloadData() } } - + addAccountWindowController = accountsAddCloudKitWindowController case .feedbin: let accountsFeedbinWindowController = AccountsFeedbinWindowController() accountsFeedbinWindowController.runSheetOnWindow(self.view.window!) + addAccountWindowController = accountsFeedbinWindowController case .feedWrangler: let accountsFeedWranglerWindowController = AccountsFeedWranglerWindowController() accountsFeedWranglerWindowController.runSheetOnWindow(self.view.window!) - case .freshRSS: + addAccountWindowController = accountsFeedWranglerWindowController + case .freshRSS, .inoreader, .bazQux, .theOldReader: let accountsReaderAPIWindowController = AccountsReaderAPIWindowController() - accountsReaderAPIWindowController.accountType = .freshRSS + accountsReaderAPIWindowController.accountType = accountType accountsReaderAPIWindowController.runSheetOnWindow(self.view.window!) + addAccountWindowController = accountsReaderAPIWindowController case .feedly: let addAccount = OAuthAccountAuthorizationOperation(accountType: .feedly) addAccount.delegate = self @@ -181,18 +184,7 @@ extension AccountsPreferencesViewController: AccountsPreferencesAddAccountDelega case .newsBlur: let accountsNewsBlurWindowController = AccountsNewsBlurWindowController() accountsNewsBlurWindowController.runSheetOnWindow(self.view.window!) - case .inoreader: - let accountsReaderAPIWindowController = AccountsReaderAPIWindowController() - accountsReaderAPIWindowController.accountType = .inoreader - accountsReaderAPIWindowController.runSheetOnWindow(self.view.window!) - case .bazQux: - let accountsReaderAPIWindowController = AccountsReaderAPIWindowController() - accountsReaderAPIWindowController.accountType = .bazQux - accountsReaderAPIWindowController.runSheetOnWindow(self.view.window!) - case .theOldReader: - let accountsReaderAPIWindowController = AccountsReaderAPIWindowController() - accountsReaderAPIWindowController.accountType = .theOldReader - accountsReaderAPIWindowController.runSheetOnWindow(self.view.window!) + addAccountWindowController = accountsNewsBlurWindowController } } From 3aad0b5075ce4121396ca7e9f5d2d702b5ca1ca3 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Fri, 30 Oct 2020 09:44:24 -0500 Subject: [PATCH 14/35] Remove no longer needed system events. Fixes #2537 --- .../Detail/DetailWebViewController.swift | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Mac/MainWindow/Detail/DetailWebViewController.swift b/Mac/MainWindow/Detail/DetailWebViewController.swift index c032589a0..28f85df91 100644 --- a/Mac/MainWindow/Detail/DetailWebViewController.swift +++ b/Mac/MainWindow/Detail/DetailWebViewController.swift @@ -12,11 +12,6 @@ import RSCore import RSWeb import Articles -extension Notification.Name { - static let appleColorPreferencesChangedNotification = Notification.Name("AppleColorPreferencesChangedNotification") - static let appleInterfaceThemeChangedNotification = Notification.Name("AppleInterfaceThemeChangedNotification") -} - protocol DetailWebViewControllerDelegate: class { func mouseDidEnter(_: DetailWebViewController, link: String) func mouseDidExit(_: DetailWebViewController, link: String) @@ -125,9 +120,6 @@ final class DetailWebViewController: NSViewController, WKUIDelegate { NotificationCenter.default.addObserver(self, selector: #selector(faviconDidBecomeAvailable(_:)), name: .FaviconDidBecomeAvailable, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(faviconDidBecomeAvailable(_:)), name: .FaviconDidBecomeAvailable, object: nil) - DistributedNotificationCenter.default().addObserver(self, selector: #selector(appleColorPreferencesChanged(_:)), name: .appleColorPreferencesChangedNotification, object: nil) - DistributedNotificationCenter.default().addObserver(self, selector: #selector(appleInterfaceThemeChanged(_:)), name: .appleInterfaceThemeChangedNotification, object: nil) - webView.loadFileURL(ArticleRenderer.blank.url, allowingReadAccessTo: ArticleRenderer.blank.baseURL) } @@ -145,14 +137,6 @@ final class DetailWebViewController: NSViewController, WKUIDelegate { reloadArticleImage() } - @objc func appleColorPreferencesChanged(_ note: Notification) { - reloadHTML() - } - - @objc func appleInterfaceThemeChanged(_ note: Notification) { - reloadHTML() - } - // MARK: Media Functions func stopMediaPlayback() { From b6c66a7f2c31116195f58c27cf577b0e2ace672c Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Fri, 30 Oct 2020 09:47:30 -0500 Subject: [PATCH 15/35] Remove unnecessary system notification checks --- .../macOS/Article/WebViewController.swift | 15 --------------- NetNewsWire.xcodeproj/project.pbxproj | 2 ++ 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/Multiplatform/macOS/Article/WebViewController.swift b/Multiplatform/macOS/Article/WebViewController.swift index c0ebfc927..b415f71d2 100644 --- a/Multiplatform/macOS/Article/WebViewController.swift +++ b/Multiplatform/macOS/Article/WebViewController.swift @@ -11,11 +11,6 @@ import Combine import RSCore import Articles -extension Notification.Name { - static let appleColorPreferencesChangedNotification = Notification.Name("AppleColorPreferencesChangedNotification") - static let appleInterfaceThemeChangedNotification = Notification.Name("AppleInterfaceThemeChangedNotification") -} - protocol WebViewControllerDelegate: class { func webViewController(_: WebViewController, articleExtractorButtonStateDidUpdate: ArticleExtractorButtonState) } @@ -67,8 +62,6 @@ class WebViewController: NSViewController { NotificationCenter.default.addObserver(self, selector: #selector(webFeedIconDidBecomeAvailable(_:)), name: .WebFeedIconDidBecomeAvailable, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(avatarDidBecomeAvailable(_:)), name: .AvatarDidBecomeAvailable, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(faviconDidBecomeAvailable(_:)), name: .FaviconDidBecomeAvailable, object: nil) - DistributedNotificationCenter.default().addObserver(self, selector: #selector(appleColorPreferencesChanged(_:)), name: .appleColorPreferencesChangedNotification, object: nil) - DistributedNotificationCenter.default().addObserver(self, selector: #selector(appleInterfaceThemeChanged(_:)), name: .appleInterfaceThemeChangedNotification, object: nil) statusBarView = WebStatusBarView() statusBarView.translatesAutoresizingMaskIntoConstraints = false @@ -100,14 +93,6 @@ class WebViewController: NSViewController { reloadArticleImage() } - @objc func appleColorPreferencesChanged(_ note: Notification) { - loadWebView() - } - - @objc func appleInterfaceThemeChanged(_ note: Notification) { - loadWebView() - } - // MARK: API func focus() { diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 6dfaabae5..eda6c2337 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -5618,6 +5618,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 51C0519824A7808F00194D5E /* NetNewsWire_multiplatform_macOSapp_target.xcconfig */; buildSettings = { + MACOSX_DEPLOYMENT_TARGET = 11.0; }; name = Debug; }; @@ -5625,6 +5626,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 51C0519824A7808F00194D5E /* NetNewsWire_multiplatform_macOSapp_target.xcconfig */; buildSettings = { + MACOSX_DEPLOYMENT_TARGET = 11.0; }; name = Release; }; From c1c8b97b0839c3a3810f0e8d12ccc042ae78ae72 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Fri, 30 Oct 2020 11:21:18 -0500 Subject: [PATCH 16/35] Remove build settings from project file --- NetNewsWire.xcodeproj/project.pbxproj | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index eda6c2337..1bc8e2501 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -105,12 +105,6 @@ 510C418424E5D1B4008226FD /* ExtensionFeedAddRequestFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51B5C8BF23F3866C00032075 /* ExtensionFeedAddRequestFile.swift */; }; 510C418524E5D1B4008226FD /* ExtensionContainers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51B5C87623F22B8200032075 /* ExtensionContainers.swift */; }; 510C418624E5D1B4008226FD /* ExtensionFeedAddRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51B5C87A23F2317700032075 /* ExtensionFeedAddRequest.swift */; }; - 510C43ED243C0973009F70C3 /* ExtensionPointAdd.xib in Resources */ = {isa = PBXBuildFile; fileRef = 510C43EC243C0973009F70C3 /* ExtensionPointAdd.xib */; }; - 510C43EE243C0973009F70C3 /* ExtensionPointAdd.xib in Resources */ = {isa = PBXBuildFile; fileRef = 510C43EC243C0973009F70C3 /* ExtensionPointAdd.xib */; }; - 510C43F0243C0A80009F70C3 /* ExtensionPointAddViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 510C43EF243C0A80009F70C3 /* ExtensionPointAddViewController.swift */; }; - 510C43F1243C0A80009F70C3 /* ExtensionPointAddViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 510C43EF243C0A80009F70C3 /* ExtensionPointAddViewController.swift */; }; - 510C43F3243C11FE009F70C3 /* ExtensionPointAddTableCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 510C43F2243C11FE009F70C3 /* ExtensionPointAddTableCellView.swift */; }; - 510C43F4243C11FE009F70C3 /* ExtensionPointAddTableCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 510C43F2243C11FE009F70C3 /* ExtensionPointAddTableCellView.swift */; }; 510C43F7243D035C009F70C3 /* ExtensionPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 510C43F6243D035C009F70C3 /* ExtensionPoint.swift */; }; 510C43F8243D035C009F70C3 /* ExtensionPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 510C43F6243D035C009F70C3 /* ExtensionPoint.swift */; }; 51102165233A7D6C0007A5F7 /* ArticleExtractorButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51102164233A7D6C0007A5F7 /* ArticleExtractorButton.swift */; }; @@ -1495,9 +1489,6 @@ 510C416524E5CDE3008226FD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 510C416624E5CDE3008226FD /* ShareExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ShareExtension.entitlements; sourceTree = ""; }; 510C418724E5D2E3008226FD /* NetNewsWire_shareextension_target.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = NetNewsWire_shareextension_target.xcconfig; sourceTree = ""; }; - 510C43EC243C0973009F70C3 /* ExtensionPointAdd.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ExtensionPointAdd.xib; sourceTree = ""; }; - 510C43EF243C0A80009F70C3 /* ExtensionPointAddViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionPointAddViewController.swift; sourceTree = ""; }; - 510C43F2243C11FE009F70C3 /* ExtensionPointAddTableCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionPointAddTableCellView.swift; sourceTree = ""; }; 510C43F6243D035C009F70C3 /* ExtensionPoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionPoint.swift; sourceTree = ""; }; 51102164233A7D6C0007A5F7 /* ArticleExtractorButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleExtractorButton.swift; sourceTree = ""; }; 51107745243BEE2500D97C8C /* ExtensionPointPreferencesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionPointPreferencesViewController.swift; sourceTree = ""; }; @@ -2312,9 +2303,6 @@ 51107744243BEDD300D97C8C /* ExtensionPoints */ = { isa = PBXGroup; children = ( - 510C43EC243C0973009F70C3 /* ExtensionPointAdd.xib */, - 510C43F2243C11FE009F70C3 /* ExtensionPointAddTableCellView.swift */, - 510C43EF243C0A80009F70C3 /* ExtensionPointAddViewController.swift */, 515A5167243E66910089E588 /* ExtensionPointEnable.xib */, 515A5147243E64BA0089E588 /* ExtensionPointEnableWindowController.swift */, 51107745243BEE2500D97C8C /* ExtensionPointPreferencesViewController.swift */, @@ -4180,7 +4168,6 @@ 65ED4051235DEF6C0081F399 /* TimelineKeyboardShortcuts.plist in Resources */, 65ED4052235DEF6C0081F399 /* template.html in Resources */, 65ED4054235DEF6C0081F399 /* Main.storyboard in Resources */, - 510C43EE243C0973009F70C3 /* ExtensionPointAdd.xib in Resources */, 65ED4056235DEF6C0081F399 /* NetNewsWire.sdef in Resources */, 65ED4057235DEF6C0081F399 /* AccountsDetail.xib in Resources */, 65ED4058235DEF6C0081F399 /* main.js in Resources */, @@ -4303,7 +4290,6 @@ 3B826DCB2385C84800FC1ADB /* AccountsFeedWrangler.xib in Resources */, 55E15BCB229D65A900D6602A /* AccountsReaderAPI.xib in Resources */, 49F40DF82335B71000552BF4 /* newsfoot.js in Resources */, - 510C43ED243C0973009F70C3 /* ExtensionPointAdd.xib in Resources */, 51333D3B2468615D00EB5C91 /* AddRedditFeedSheet.xib in Resources */, BDCB516724282C8A00102A80 /* AccountsNewsBlur.xib in Resources */, 514A89A2244FD63F0085E65D /* AddTwitterFeedSheet.xib in Resources */, @@ -4918,7 +4904,6 @@ 65ED401C235DEF6C0081F399 /* FaviconGenerator.swift in Sources */, 65ED401D235DEF6C0081F399 /* RefreshInterval.swift in Sources */, 65ED401E235DEF6C0081F399 /* TimelineCellData.swift in Sources */, - 510C43F1243C0A80009F70C3 /* ExtensionPointAddViewController.swift in Sources */, 65ED401F235DEF6C0081F399 /* BuiltinSmartFeedInspectorViewController.swift in Sources */, 65ED4020235DEF6C0081F399 /* AppDelegate+Scriptability.swift in Sources */, 65ED4021235DEF6C0081F399 /* NNW3Document.swift in Sources */, @@ -4958,7 +4943,6 @@ 65ED403D235DEF6C0081F399 /* TimelineTableCellView.swift in Sources */, 65ED403E235DEF6C0081F399 /* TimelineCellAppearance.swift in Sources */, 51C4CFF124D37D1F00AF9874 /* Secrets.swift in Sources */, - 510C43F4243C11FE009F70C3 /* ExtensionPointAddTableCellView.swift in Sources */, 65ED403F235DEF6C0081F399 /* ArticleRenderer.swift in Sources */, 65ED4040235DEF6C0081F399 /* GeneralPrefencesViewController.swift in Sources */, 179DB1DFBCF9177104B12E0F /* AccountsNewsBlurWindowController.swift in Sources */, @@ -5203,7 +5187,6 @@ 849A97671ED9EB96007D329B /* UnreadCountView.swift in Sources */, 510C418024E5D1AE008226FD /* ExtensionFeedAddRequestFile.swift in Sources */, 51FE10092346739D0056195D /* ActivityType.swift in Sources */, - 510C43F3243C11FE009F70C3 /* ExtensionPointAddTableCellView.swift in Sources */, 840BEE4121D70E64009BBAFA /* CrashReportWindowController.swift in Sources */, 8426118A1FCB67AA0086A189 /* WebFeedIconDownloader.swift in Sources */, 84C9FC7B22629E1200D921D6 /* PreferencesControlsBackgroundView.swift in Sources */, @@ -5287,7 +5270,6 @@ 518651B223555EB20078E021 /* NNW3Document.swift in Sources */, D5F4EDB5200744A700B9E363 /* ScriptingObject.swift in Sources */, D5F4EDB920074D7C00B9E363 /* Folder+Scriptability.swift in Sources */, - 510C43F0243C0A80009F70C3 /* ExtensionPointAddViewController.swift in Sources */, 849A97781ED9EC04007D329B /* TimelineCellLayout.swift in Sources */, 84E8E0EB202F693600562D8F /* DetailWebView.swift in Sources */, 849A976C1ED9EBC8007D329B /* TimelineTableRowView.swift in Sources */, @@ -5618,7 +5600,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = 51C0519824A7808F00194D5E /* NetNewsWire_multiplatform_macOSapp_target.xcconfig */; buildSettings = { - MACOSX_DEPLOYMENT_TARGET = 11.0; }; name = Debug; }; @@ -5626,7 +5607,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = 51C0519824A7808F00194D5E /* NetNewsWire_multiplatform_macOSapp_target.xcconfig */; buildSettings = { - MACOSX_DEPLOYMENT_TARGET = 11.0; }; name = Release; }; From 81ae58e061f1f3abe706597647b2d44486a5b201 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Fri, 30 Oct 2020 11:21:49 -0500 Subject: [PATCH 17/35] Remove code duplication --- .../Accounts/AccountsPreferencesViewController.swift | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Mac/Preferences/Accounts/AccountsPreferencesViewController.swift b/Mac/Preferences/Accounts/AccountsPreferencesViewController.swift index fcd97b81e..2153f13d3 100644 --- a/Mac/Preferences/Accounts/AccountsPreferencesViewController.swift +++ b/Mac/Preferences/Accounts/AccountsPreferencesViewController.swift @@ -225,11 +225,7 @@ private extension AccountsPreferencesViewController { } func showController(_ controller: NSViewController) { - - if let controller = children.first { - children.removeAll() - controller.view.removeFromSuperview() - } + hideController() addChild(controller) controller.view.translatesAutoresizingMaskIntoConstraints = false From ba03f0bc07844212474d75fe5ece4d639d4d883b Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Fri, 30 Oct 2020 14:29:08 -0500 Subject: [PATCH 18/35] Adjust parameters to deal with Reddit's recent, stricter parameter checks --- .../Account/FeedProvider/Reddit/RedditFeedProvider.swift | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Account/Sources/Account/FeedProvider/Reddit/RedditFeedProvider.swift b/Account/Sources/Account/FeedProvider/Reddit/RedditFeedProvider.swift index 91f87218e..9f740a5a8 100644 --- a/Account/Sources/Account/FeedProvider/Reddit/RedditFeedProvider.swift +++ b/Account/Sources/Account/FeedProvider/Reddit/RedditFeedProvider.swift @@ -280,7 +280,7 @@ extension RedditFeedProvider: OAuth2SwiftProvider { consumerSecret: "", authorizeUrl: "https://www.reddit.com/api/v1/authorize.compact?", accessTokenUrl: "https://www.reddit.com/api/v1/access_token", - responseType: "token") + responseType: "code") oauth2.accessTokenBasicAuthentification = true return oauth2 } @@ -293,12 +293,7 @@ extension RedditFeedProvider: OAuth2SwiftProvider { let state = generateState(withLength: 20) let scope = "identity mysubreddits read" let params = [ - "client_id" : SecretsManager.provider.redditConsumerKey, - "response_type" : "code", - "state" : state, - "redirect_uri" : "netnewswire://success", "duration" : "permanent", - "scope" : scope ] return (state: state, scope: scope, params: params) } From 3b196a5f2af4ce1190b44ac82650b74d5cc9995b Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Fri, 30 Oct 2020 14:43:42 -0500 Subject: [PATCH 19/35] Update extension maintenance so that it matches the new account maintenance look and feel --- .../EnableExtensionPointView.swift | 172 ++++++++++++++++++ .../ExtensionPoints/ExtensionPointAdd.xib | 121 ------------ .../ExtensionPointAddTableCellView.swift | 28 --- .../ExtensionPointAddViewController.swift | 76 -------- .../ExtensionPoints/ExtensionPointEnable.xib | 116 ------------ ...ensionPointPreferencesViewController.swift | 149 ++++++++++++++- NetNewsWire.xcodeproj/project.pbxproj | 16 +- 7 files changed, 319 insertions(+), 359 deletions(-) create mode 100644 Mac/Preferences/ExtensionPoints/EnableExtensionPointView.swift delete mode 100644 Mac/Preferences/ExtensionPoints/ExtensionPointAdd.xib delete mode 100644 Mac/Preferences/ExtensionPoints/ExtensionPointAddTableCellView.swift delete mode 100644 Mac/Preferences/ExtensionPoints/ExtensionPointAddViewController.swift delete mode 100644 Mac/Preferences/ExtensionPoints/ExtensionPointEnable.xib diff --git a/Mac/Preferences/ExtensionPoints/EnableExtensionPointView.swift b/Mac/Preferences/ExtensionPoints/EnableExtensionPointView.swift new file mode 100644 index 000000000..424265c12 --- /dev/null +++ b/Mac/Preferences/ExtensionPoints/EnableExtensionPointView.swift @@ -0,0 +1,172 @@ +// +// EnableExtensionPointView.swift +// NetNewsWire +// +// Created by Maurice Parker on 10/30/20. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import AppKit +import SwiftUI +import RSCore + +struct EnableExtensionPointView: View { + + weak var parent: NSHostingController? // required because presentationMode.dismiss() doesn't work + weak var enabler: ExtensionPointPreferencesEnabler? + @State private var extensionPointTypeName = String(describing: ExtensionPointManager.shared.possibleExtensionPointTypes.first!) + + init(enabler: ExtensionPointPreferencesEnabler?) { + self.enabler = enabler + } + + var body: some View { + VStack(alignment: .leading, spacing: 8) { + Text("Choose an extension point to add...") + .font(.headline) + .padding() + + sendToCommandExtensionPoints + feedProviderExtensionPoints + + HStack(spacing: 12) { + Spacer() + if #available(OSX 11.0, *) { + Button(action: { + parent?.dismiss(nil) + }, label: { + Text("Cancel") + .frame(width: 80) + }) + .help("Cancel") + .keyboardShortcut(.cancelAction) + + } else { + Button(action: { + parent?.dismiss(nil) + }, label: { + Text("Cancel") + .frame(width: 80) + }) + .accessibility(label: Text("Add Account")) + } + if #available(OSX 11.0, *) { + Button(action: { + enabler?.enable(typeFromName(extensionPointTypeName)) + parent?.dismiss(nil) + }, label: { + Text("Continue") + .frame(width: 80) + }) + .help("Add Account") + .keyboardShortcut(.defaultAction) + + } else { + Button(action: { + enabler?.enable(typeFromName(extensionPointTypeName)) + parent?.dismiss(nil) + }, label: { + Text("Continue") + .frame(width: 80) + }) + } + } + .padding(.top, 12) + .padding(.bottom, 4) + } + .pickerStyle(RadioGroupPickerStyle()) + .fixedSize(horizontal: false, vertical: true) + .frame(width: 420) + .padding() + } + + var sendToCommandExtensionPoints: some View { + VStack(alignment: .leading) { + let extensionPointTypeNames = sendToCommandExtensionPointTypes.map { String(describing: $0) } + if extensionPointTypeNames.count > 0 { + Text("Third-Party Integration") + .font(.headline) + .padding(.horizontal) + + Picker(selection: $extensionPointTypeName, label: Text(""), content: { + ForEach(extensionPointTypeNames, id: \.self, content: { extensionPointTypeName in + let extensionPointType = typeFromName(extensionPointTypeName) + HStack(alignment: .center) { + Image(nsImage: extensionPointType.templateImage) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 25, height: 25, alignment: .center) + .padding(.leading, 4) + + + Text(extensionPointType.title) + } + .tag(extensionPointTypeNames) + }) + }) + .pickerStyle(RadioGroupPickerStyle()) + .offset(x: 7.5, y: 0) + + Text("An extension point that enables a share menu item that passes article data to a third-party application.") + .foregroundColor(.gray) + .font(.caption) + .padding(.horizontal) + } + } + + } + + var feedProviderExtensionPoints: some View { + VStack(alignment: .leading) { + let extensionPointTypeNames = feedProviderExtensionPointTypes.map { String(describing: $0) } + if extensionPointTypeNames.count > 0 { + Text("Feed Provider") + .font(.headline) + .padding(.horizontal) + .padding(.top, 8) + + Picker(selection: $extensionPointTypeName, label: Text(""), content: { + ForEach(extensionPointTypeNames, id: \.self, content: { extensionPointTypeName in + let extensionPointType = typeFromName(extensionPointTypeName) + HStack(alignment: .center) { + Image(nsImage: extensionPointType.templateImage) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 25, height: 25, alignment: .center) + .padding(.leading, 4) + + + Text(extensionPointType.title) + } + .tag(extensionPointTypeNames) + }) + }) + .pickerStyle(RadioGroupPickerStyle()) + .offset(x: 7.5, y: 0) + + Text("An extension point that makes websites appear to provide RSS feeds for their content.") + .foregroundColor(.gray) + .font(.caption) + .padding(.horizontal) + } + } + + } + + var sendToCommandExtensionPointTypes: [ExtensionPoint.Type] { + return ExtensionPointManager.shared.availableExtensionPointTypes.filter({ $0 is SendToCommand.Type }) + } + + var feedProviderExtensionPointTypes: [ExtensionPoint.Type] { + return ExtensionPointManager.shared.availableExtensionPointTypes.filter({ !($0 is SendToCommand.Type) }) + } + + func typeFromName(_ name: String) -> ExtensionPoint.Type { + for type in ExtensionPointManager.shared.possibleExtensionPointTypes { + if name == String(describing: type) { + return type + } + } + fatalError() + } +} diff --git a/Mac/Preferences/ExtensionPoints/ExtensionPointAdd.xib b/Mac/Preferences/ExtensionPoints/ExtensionPointAdd.xib deleted file mode 100644 index bacf26bc0..000000000 --- a/Mac/Preferences/ExtensionPoints/ExtensionPointAdd.xib +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Mac/Preferences/ExtensionPoints/ExtensionPointAddTableCellView.swift b/Mac/Preferences/ExtensionPoints/ExtensionPointAddTableCellView.swift deleted file mode 100644 index 5b8dc99a3..000000000 --- a/Mac/Preferences/ExtensionPoints/ExtensionPointAddTableCellView.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// ExtensionPointAddTableCellView.swift -// NetNewsWire -// -// Created by Maurice Parker on 4/6/20. -// Copyright © 2020 Ranchero Software. All rights reserved. -// - -import AppKit - -protocol ExtensionPointTableCellViewDelegate: class { - func addExtensionPoint(_ extensionPointType: ExtensionPoint.Type) -} - -class ExtensionPointAddTableCellView: NSTableCellView { - - weak var delegate: ExtensionPointTableCellViewDelegate? - var extensionPointType: ExtensionPoint.Type? - - @IBOutlet weak var templateImageView: NSImageView? - @IBOutlet weak var titleLabel: NSTextField? - - @IBAction func pressed(_ sender: Any) { - guard let extensionPointType = extensionPointType else { return } - delegate?.addExtensionPoint(extensionPointType) - } - -} diff --git a/Mac/Preferences/ExtensionPoints/ExtensionPointAddViewController.swift b/Mac/Preferences/ExtensionPoints/ExtensionPointAddViewController.swift deleted file mode 100644 index a5f6b2b3f..000000000 --- a/Mac/Preferences/ExtensionPoints/ExtensionPointAddViewController.swift +++ /dev/null @@ -1,76 +0,0 @@ -// -// ExtensionPointAddViewController.swift -// NetNewsWire -// -// Created by Maurice Parker on 4/6/20. -// Copyright © 2020 Ranchero Software. All rights reserved. -// - -import AppKit - -class ExtensionPointAddViewController: NSViewController { - - @IBOutlet weak var tableView: NSTableView! - - private var availableExtensionPointTypes = [ExtensionPoint.Type]() - private var extensionPointAddWindowController: NSWindowController? - - init() { - super.init(nibName: "ExtensionPointAdd", bundle: nil) - } - - public required init?(coder: NSCoder) { - super.init(coder: coder) - } - - override func viewDidLoad() { - super.viewDidLoad() - tableView.dataSource = self - tableView.delegate = self - availableExtensionPointTypes = ExtensionPointManager.shared.availableExtensionPointTypes.sorted(by: { $0.title < $1.title }) - } - -} - -// MARK: - NSTableViewDataSource - -extension ExtensionPointAddViewController: NSTableViewDataSource { - - func numberOfRows(in tableView: NSTableView) -> Int { - return availableExtensionPointTypes.count - } - - func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? { - return nil - } - -} - -// MARK: - NSTableViewDelegate - -extension ExtensionPointAddViewController: NSTableViewDelegate { - - func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { - if let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "Cell"), owner: nil) as? ExtensionPointAddTableCellView { - let extensionPointType = availableExtensionPointTypes[row] - cell.extensionPointType = extensionPointType - cell.delegate = self - cell.titleLabel?.stringValue = extensionPointType.title - cell.imageView?.image = extensionPointType.templateImage - return cell - } - return nil - } - -} - -extension ExtensionPointAddViewController: ExtensionPointTableCellViewDelegate { - - func addExtensionPoint(_ extensionPointType: ExtensionPoint.Type) { - let windowController = ExtensionPointEnableWindowController() - windowController.extensionPointType = extensionPointType - windowController.runSheetOnWindow(self.view.window!) - extensionPointAddWindowController = windowController - } - -} diff --git a/Mac/Preferences/ExtensionPoints/ExtensionPointEnable.xib b/Mac/Preferences/ExtensionPoints/ExtensionPointEnable.xib deleted file mode 100644 index ead100ad5..000000000 --- a/Mac/Preferences/ExtensionPoints/ExtensionPointEnable.xib +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Mac/Preferences/ExtensionPoints/ExtensionPointPreferencesViewController.swift b/Mac/Preferences/ExtensionPoints/ExtensionPointPreferencesViewController.swift index 25038d720..40e13dc61 100644 --- a/Mac/Preferences/ExtensionPoints/ExtensionPointPreferencesViewController.swift +++ b/Mac/Preferences/ExtensionPoints/ExtensionPointPreferencesViewController.swift @@ -7,6 +7,14 @@ // import AppKit +import SwiftUI +import AuthenticationServices +import OAuthSwift +import Secrets + +protocol ExtensionPointPreferencesEnabler: class { + func enable(_ extensionPointType: ExtensionPoint.Type) +} final class ExtensionPointPreferencesViewController: NSViewController { @@ -15,6 +23,8 @@ final class ExtensionPointPreferencesViewController: NSViewController { @IBOutlet weak var deleteButton: NSButton! private var activeExtensionPoints = [ExtensionPoint]() + private var callbackURL: URL? = nil + private var oauth: OAuthSwift? override func viewDidLoad() { super.viewDidLoad() @@ -30,11 +40,17 @@ final class ExtensionPointPreferencesViewController: NSViewController { tableView.frame = rTable showDefaultView() + + // Set initial row selection + if activeExtensionPoints.count > 0 { + tableView.selectRow(0) + } } @IBAction func enableExtensionPoints(_ sender: Any) { - tableView.selectRowIndexes([], byExtendingSelection: false) - showController(ExtensionPointAddViewController()) + let controller = NSHostingController(rootView: EnableExtensionPointView(enabler: self)) + controller.rootView.parent = controller + presentAsSheet(controller) } @IBAction func disableExtensionPoint(_ sender: Any) { @@ -44,8 +60,7 @@ final class ExtensionPointPreferencesViewController: NSViewController { let extensionPoint = activeExtensionPoints[tableView.selectedRow] ExtensionPointManager.shared.deactivateExtensionPoint(extensionPoint.extensionPointID) - - showController(ExtensionPointAddViewController()) + hideController() } } @@ -83,6 +98,7 @@ extension ExtensionPointPreferencesViewController: NSTableViewDelegate { let selectedRow = tableView.selectedRow if tableView.selectedRow == -1 { deleteButton.isEnabled = false + hideController() return } else { deleteButton.isEnabled = true @@ -96,6 +112,62 @@ extension ExtensionPointPreferencesViewController: NSTableViewDelegate { } +// MARK: ExtensionPointPreferencesViewController + +extension ExtensionPointPreferencesViewController: ExtensionPointPreferencesEnabler { + + func enable(_ extensionPointType: ExtensionPoint.Type) { + if let oauth1 = extensionPointType as? OAuth1SwiftProvider.Type { + enableOauth1(oauth1, extensionPointType: extensionPointType) + } else if let oauth2 = extensionPointType as? OAuth2SwiftProvider.Type { + enableOauth2(oauth2, extensionPointType: extensionPointType) + } else { + ExtensionPointManager.shared.activateExtensionPoint(extensionPointType) { result in + if case .failure(let error) = result { + self.presentError(error) + } + } + } + } + +} + +extension ExtensionPointPreferencesViewController: OAuthSwiftURLHandlerType { + + public func handle(_ url: URL) { + let session = ASWebAuthenticationSession(url: url, callbackURLScheme: callbackURL!.scheme, completionHandler: { (url, error) in + if let callbackedURL = url { + OAuth1Swift.handle(url: callbackedURL) + } + + guard let error = error else { return } + + self.oauth?.cancel() + self.oauth = nil + + if case ASWebAuthenticationSessionError.canceledLogin = error { + print("Login cancelled.") + } else { + NSApplication.shared.presentError(error) + } + }) + + session.presentationContextProvider = self + if !session.start() { + print("Session failed to start!!!") + } + + } +} + +extension ExtensionPointPreferencesViewController: ASWebAuthenticationPresentationContextProviding { + + public func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor { + return view.window! + } + +} + // MARK: - Private private extension ExtensionPointPreferencesViewController { @@ -107,20 +179,77 @@ private extension ExtensionPointPreferencesViewController { func showDefaultView() { activeExtensionPoints = Array(ExtensionPointManager.shared.activeExtensionPoints.values).sorted(by: { $0.title < $1.title }) tableView.reloadData() - showController(ExtensionPointAddViewController()) } func showController(_ controller: NSViewController) { - - if let controller = children.first { - children.removeAll() - controller.view.removeFromSuperview() - } + hideController() addChild(controller) controller.view.translatesAutoresizingMaskIntoConstraints = false detailView.addSubview(controller.view) detailView.addFullSizeConstraints(forSubview: controller.view) + } + + func hideController() { + if let controller = children.first { + children.removeAll() + controller.view.removeFromSuperview() + } + } + + func enableOauth1(_ provider: OAuth1SwiftProvider.Type, extensionPointType: ExtensionPoint.Type) { + callbackURL = provider.callbackURL + + let oauth1 = provider.oauth1Swift + self.oauth = oauth1 + oauth1.authorizeURLHandler = self + + oauth1.authorize(withCallbackURL: callbackURL!) { [weak self] result in + guard let self = self else { return } + + switch result { + case .success(let tokenSuccess): + ExtensionPointManager.shared.activateExtensionPoint(extensionPointType, tokenSuccess: tokenSuccess) { result in + if case .failure(let error) = result { + self.presentError(error) + } + } + case .failure(let oauthSwiftError): + self.presentError(oauthSwiftError) + } + + self.oauth?.cancel() + self.oauth = nil + } + + } + + func enableOauth2(_ provider: OAuth2SwiftProvider.Type, extensionPointType: ExtensionPoint.Type) { + callbackURL = provider.callbackURL + + let oauth2 = provider.oauth2Swift + self.oauth = oauth2 + oauth2.authorizeURLHandler = self + + let oauth2Vars = provider.oauth2Vars + + oauth2.authorize(withCallbackURL: callbackURL!, scope: oauth2Vars.scope, state: oauth2Vars.state, parameters: oauth2Vars.params) { [weak self] result in + guard let self = self else { return } + + switch result { + case .success(let tokenSuccess): + ExtensionPointManager.shared.activateExtensionPoint(extensionPointType, tokenSuccess: tokenSuccess) { result in + if case .failure(let error) = result { + self.presentError(error) + } + } + case .failure(let oauthSwiftError): + self.presentError(oauthSwiftError) + } + + self.oauth?.cancel() + self.oauth = nil + } } diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 1bc8e2501..6ce989f16 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -216,8 +216,6 @@ 515A5108243D0CCD0089E588 /* TwitterFeedProvider-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515A5106243D0CCD0089E588 /* TwitterFeedProvider-Extensions.swift */; }; 515A5148243E64BA0089E588 /* ExtensionPointEnableWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515A5147243E64BA0089E588 /* ExtensionPointEnableWindowController.swift */; }; 515A5149243E64BA0089E588 /* ExtensionPointEnableWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515A5147243E64BA0089E588 /* ExtensionPointEnableWindowController.swift */; }; - 515A5168243E66910089E588 /* ExtensionPointEnable.xib in Resources */ = {isa = PBXBuildFile; fileRef = 515A5167243E66910089E588 /* ExtensionPointEnable.xib */; }; - 515A5169243E66910089E588 /* ExtensionPointEnable.xib in Resources */ = {isa = PBXBuildFile; fileRef = 515A5167243E66910089E588 /* ExtensionPointEnable.xib */; }; 515A516E243E7F950089E588 /* ExtensionPointDetail.xib in Resources */ = {isa = PBXBuildFile; fileRef = 515A516D243E7F950089E588 /* ExtensionPointDetail.xib */; }; 515A516F243E7F950089E588 /* ExtensionPointDetail.xib in Resources */ = {isa = PBXBuildFile; fileRef = 515A516D243E7F950089E588 /* ExtensionPointDetail.xib */; }; 515A5171243E802B0089E588 /* ExtensionPointDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515A5170243E802B0089E588 /* ExtensionPointDetailViewController.swift */; }; @@ -294,6 +292,8 @@ 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 */; }; + 5183CFAF254C78C8006B83A5 /* EnableExtensionPointView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CFAE254C78C8006B83A5 /* EnableExtensionPointView.swift */; }; + 5183CFB0254C78C8006B83A5 /* EnableExtensionPointView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CFAE254C78C8006B83A5 /* EnableExtensionPointView.swift */; }; 518651B223555EB20078E021 /* NNW3Document.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518651AB23555EB20078E021 /* NNW3Document.swift */; }; 518651DA235621840078E021 /* ImageTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518651D9235621840078E021 /* ImageTransition.swift */; }; 51868BF1254386630011A17B /* SidebarDeleteItemsAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51868BF0254386630011A17B /* SidebarDeleteItemsAlert.swift */; }; @@ -1551,7 +1551,6 @@ 515A50E5243D07A90089E588 /* ExtensionPointManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionPointManager.swift; sourceTree = ""; }; 515A5106243D0CCD0089E588 /* TwitterFeedProvider-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TwitterFeedProvider-Extensions.swift"; sourceTree = ""; }; 515A5147243E64BA0089E588 /* ExtensionPointEnableWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionPointEnableWindowController.swift; sourceTree = ""; }; - 515A5167243E66910089E588 /* ExtensionPointEnable.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ExtensionPointEnable.xib; sourceTree = ""; }; 515A516D243E7F950089E588 /* ExtensionPointDetail.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ExtensionPointDetail.xib; sourceTree = ""; }; 515A5170243E802B0089E588 /* ExtensionPointDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionPointDetailViewController.swift; sourceTree = ""; }; 515A5176243E90200089E588 /* ExtensionPointIdentifer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionPointIdentifer.swift; sourceTree = ""; }; @@ -1611,6 +1610,7 @@ 5183CCD9226E31A50010922C /* NonIntrinsicImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonIntrinsicImageView.swift; sourceTree = ""; }; 5183CCE4226F4DFA0010922C /* RefreshInterval.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshInterval.swift; sourceTree = ""; }; 5183CCE7226F68D90010922C /* AccountRefreshTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountRefreshTimer.swift; sourceTree = ""; }; + 5183CFAE254C78C8006B83A5 /* EnableExtensionPointView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnableExtensionPointView.swift; sourceTree = ""; }; 518651AB23555EB20078E021 /* NNW3Document.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NNW3Document.swift; sourceTree = ""; }; 518651D9235621840078E021 /* ImageTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageTransition.swift; sourceTree = ""; }; 51868BF0254386630011A17B /* SidebarDeleteItemsAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarDeleteItemsAlert.swift; sourceTree = ""; }; @@ -2303,11 +2303,11 @@ 51107744243BEDD300D97C8C /* ExtensionPoints */ = { isa = PBXGroup; children = ( - 515A5167243E66910089E588 /* ExtensionPointEnable.xib */, - 515A5147243E64BA0089E588 /* ExtensionPointEnableWindowController.swift */, - 51107745243BEE2500D97C8C /* ExtensionPointPreferencesViewController.swift */, + 5183CFAE254C78C8006B83A5 /* EnableExtensionPointView.swift */, 515A516D243E7F950089E588 /* ExtensionPointDetail.xib */, 515A5170243E802B0089E588 /* ExtensionPointDetailViewController.swift */, + 515A5147243E64BA0089E588 /* ExtensionPointEnableWindowController.swift */, + 51107745243BEE2500D97C8C /* ExtensionPointPreferencesViewController.swift */, ); path = ExtensionPoints; sourceTree = ""; @@ -4172,7 +4172,6 @@ 65ED4057235DEF6C0081F399 /* AccountsDetail.xib in Resources */, 65ED4058235DEF6C0081F399 /* main.js in Resources */, 65ED40A1235DEFF00081F399 /* container-migration.plist in Resources */, - 515A5169243E66910089E588 /* ExtensionPointEnable.xib in Resources */, 65ED4059235DEF6C0081F399 /* AccountsAddLocal.xib in Resources */, 65ED405A235DEF6C0081F399 /* main_mac.js in Resources */, 65ED405B235DEF6C0081F399 /* KeyboardShortcuts.html in Resources */, @@ -4271,7 +4270,6 @@ 5144EA362279FC3D00D19003 /* AccountsAddLocal.xib in Resources */, 5142194B2353C1CF00E07E2C /* main_mac.js in Resources */, 84C9FC8C22629E8F00D921D6 /* KeyboardShortcuts.html in Resources */, - 515A5168243E66910089E588 /* ExtensionPointEnable.xib in Resources */, B27EEBF9244D15F3000932E6 /* shared.css in Resources */, 5144EA3B227A379E00D19003 /* ImportOPMLSheet.xib in Resources */, 844B5B691FEA20DF00C7C76A /* SidebarKeyboardShortcuts.plist in Resources */, @@ -4821,6 +4819,7 @@ 65ED3FD5235DEF6C0081F399 /* SmartFeed.swift in Sources */, 51333D1724685D2E00EB5C91 /* AddRedditFeedWindowController.swift in Sources */, 65ED3FD6235DEF6C0081F399 /* MarkStatusCommand.swift in Sources */, + 5183CFB0254C78C8006B83A5 /* EnableExtensionPointView.swift in Sources */, 65ED3FD7235DEF6C0081F399 /* NSApplication+Scriptability.swift in Sources */, 65ED3FD8235DEF6C0081F399 /* NSView-Extensions.swift in Sources */, 51A052CF244FB9D7006C2024 /* AddFeedWIndowController.swift in Sources */, @@ -5211,6 +5210,7 @@ 51107746243BEE2500D97C8C /* ExtensionPointPreferencesViewController.swift in Sources */, 519B8D332143397200FA689C /* SharingServiceDelegate.swift in Sources */, FF3ABF1523259DDB0074C542 /* ArticleSorter.swift in Sources */, + 5183CFAF254C78C8006B83A5 /* EnableExtensionPointView.swift in Sources */, 84E8E0DB202EC49300562D8F /* TimelineViewController+ContextualMenus.swift in Sources */, 849A97791ED9EC04007D329B /* ArticleStringFormatter.swift in Sources */, B24E9ADC245AB88400DA5718 /* NSAttributedString+NetNewsWire.swift in Sources */, From 5f7d3961bd0ad00d876813c2144d65530b0cefeb Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Fri, 30 Oct 2020 15:01:25 -0500 Subject: [PATCH 20/35] Change resources so that they will work better with SwiftUI --- .../extensionPointReddit.imageset/Contents.json | 14 ++++++++++++-- .../reddit24x24.png | Bin 0 -> 2472 bytes .../reddit48x48.png | Bin 0 -> 4440 bytes .../reddit_logo.pdf | Bin 4297 -> 0 bytes .../extensionPointTwitter.imageset/Contents.json | 14 ++++++++++++-- .../extensionPointTwitter.imageset/twitter.pdf | Bin 4237 -> 0 bytes .../twitter24x24.png | Bin 0 -> 2328 bytes .../twitter48x48.png | Bin 0 -> 3987 bytes 8 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 Mac/Resources/Assets.xcassets/extensionPointReddit.imageset/reddit24x24.png create mode 100644 Mac/Resources/Assets.xcassets/extensionPointReddit.imageset/reddit48x48.png delete mode 100644 Mac/Resources/Assets.xcassets/extensionPointReddit.imageset/reddit_logo.pdf delete mode 100644 Mac/Resources/Assets.xcassets/extensionPointTwitter.imageset/twitter.pdf create mode 100644 Mac/Resources/Assets.xcassets/extensionPointTwitter.imageset/twitter24x24.png create mode 100644 Mac/Resources/Assets.xcassets/extensionPointTwitter.imageset/twitter48x48.png diff --git a/Mac/Resources/Assets.xcassets/extensionPointReddit.imageset/Contents.json b/Mac/Resources/Assets.xcassets/extensionPointReddit.imageset/Contents.json index 237cc2c56..a3c8f225b 100644 --- a/Mac/Resources/Assets.xcassets/extensionPointReddit.imageset/Contents.json +++ b/Mac/Resources/Assets.xcassets/extensionPointReddit.imageset/Contents.json @@ -1,8 +1,18 @@ { "images" : [ { - "filename" : "reddit_logo.pdf", - "idiom" : "universal" + "filename" : "reddit24x24.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "reddit48x48.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" } ], "info" : { diff --git a/Mac/Resources/Assets.xcassets/extensionPointReddit.imageset/reddit24x24.png b/Mac/Resources/Assets.xcassets/extensionPointReddit.imageset/reddit24x24.png new file mode 100644 index 0000000000000000000000000000000000000000..c925e31b430ded98a21f164f45f7ec4bcf533b0f GIT binary patch literal 2472 zcmZ`*2UJsO7XAYS91vj<#~_vv5ETh26gM$M5kvw65dwzdNPxhEgd`+EnvMbkY;-JC zH6Q~BDpG?1k)_Cibq1x(0*kxD3ZaZNE25%+%uBGauD)~byZ68Mez*Pio%6)*Zu_(~ z*J%O(v?)#w9uP+;XoWiTmPgsnLQE~xj%o*h^sLrA0}h>$K~5f20Afu6IPoI@Zz0u* zaR4H*089n|K)e9JT7FL50TN`WWYQ@iR4OooqFdR^Ubc)oz zFuYRMhh#wt3#dU{;hzkV;&FmVaaM9iP7I41ilj0bBBWgqPryamSlC$L0UnFT5^-3f zB^HUZB3cuOSONg5c`%@=L__#Im5-4Td8(ge$PNLh4+qEhaOh-<`d%dB6ET>ms3?mlOADSL6oVrW z2pB9LgU6#G5413bD`G^WxkBTmARpp5Foi(^7GK2TagmC+j6hzb$QFfCB>MQguQQzg zF%ehzzALCdOf-X!!C7E2Uji|sS)a=LAC$uKRhWns@)elEvIJ8OW2r_GG*P0x0J>kE zfX3r-$X~f}66SNqPkkz5P_Dkev?=Y{hH zOrf$mYZB)Fbf5dvJ(xlsCsMH=WJNPdz;fm10G}@bmMh-_NEpSsEnB~(-BxO$emEW<`uivJ{PkDl_K>uR9Zr^DLhgIey z@jnI7A0khY4()ACtpWb`Ow&=ui6f5}uR8b0ZB7dAUi1=3#)7!#kA%=m7aW=2_3V79 zCeJ=rSe$aROnqZ34js=v6N(i`twJ;tt_fm}x1-#Su-VBIRpPUxzE`&!k5~QOAMC$< zy^$^v7Kz^Kux1al7^-fB(c;{+kXm}`8_!ey#fRRR)JTTsk)->0=WAEuvy)qX0l7j(rWHN!Rqy1)UgYra#Mf* zIlXakl~<-m>$hY1ft$-g-x~LZ<{HA`lba)(exIj?q^ z93RXNPBbOO*=}s!#Ce`-Wqj0=tc|&thFhKE zd7#pI8x^kW{m!6y9$BrnVYVu`aqh1%h$MD-SbXrte;Y^YP;A|^+MecAWqU?W`$Z(o zop?NYVP?QHtqU%SbJb4633Q87ze{spBh`32l|gIzo7u%}4R61ZYZPXdi2JI#+MdF% zUHA2E{o}4s$2D2QM99g^3~;jbFt;T<2~U}h1(B03BK>p5yWkq|0>70`Eoh@5^n{(N8pIoEGwNDRo&9<{`ys`OPimhk&&sM!ig`_*K&KrW-n!)!`k!!Oc<%V%m7xax^;RXTI*}3` zstW5b4b9xjg}PEN--xE(TK~GjRq(q*mciVnnGJ9Lvwv4rFHI%a-7&R^du%4D=;(=L z|5p)mvaIs8%b<%m@hJUZ;lSfoK!f=+tm9p8zeL1tpAMVxo)$Nm$k?J{$wXmX=gp}{ zp0_;MgtnAMYDV5Y>B(D1O}$4R{@S{`6eh{2rEPnD=eNMLFl%{#_cm9{%qjU!&L&Qy zgSj7KA$MO%lHQJrQJ$`sV?=)?YR4t*8@Nu&0&TRP^zDW5S*a_&g654rzzt|wH*ljt zyjMrIw*L?NkwXQ(D3$Hw+9RZv70Es8FW~Qqf36sA8S1_JeIV7ox2U~ru%}6cxZ7y- ls_VaN=M54wo>o`4Et=Dwd)LgFnJE4#D0|%;%J&2${0aAT%Ju*N literal 0 HcmV?d00001 diff --git a/Mac/Resources/Assets.xcassets/extensionPointReddit.imageset/reddit48x48.png b/Mac/Resources/Assets.xcassets/extensionPointReddit.imageset/reddit48x48.png new file mode 100644 index 0000000000000000000000000000000000000000..49cca5e25c7d941bf91ad4097fc99c47db0abd14 GIT binary patch literal 4440 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 u{ZH0E`bOMVg%8b{1ljcZy@k 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 G!v6q1keZkP literal 0 HcmV?d00001 From 549b35ffdf2657b8a636f41bf0dc65bda5073e3f Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Fri, 30 Oct 2020 15:10:40 -0500 Subject: [PATCH 21/35] Clear webbed metadata when deleting an iCloud webfeed --- Account/Sources/Account/CloudKit/CloudKitAccountDelegate.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Account/Sources/Account/CloudKit/CloudKitAccountDelegate.swift b/Account/Sources/Account/CloudKit/CloudKitAccountDelegate.swift index 71ea4da7a..c9716e984 100644 --- a/Account/Sources/Account/CloudKit/CloudKitAccountDelegate.swift +++ b/Account/Sources/Account/CloudKit/CloudKitAccountDelegate.swift @@ -194,6 +194,7 @@ final class CloudKitAccountDelegate: AccountDelegate { removeWebFeedFromCloud(for: account, with: feed, from: container) { result in switch result { case .success: + account.clearWebFeedMetadata(feed) container.removeWebFeed(feed) completion(.success(())) case .failure(let error): From d4dbc5a8b247fc34f8c9263a8798763f521db79e Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Fri, 30 Oct 2020 15:33:44 -0500 Subject: [PATCH 22/35] Put Feed Providers first as they will probably be used most often in extensions --- .../EnableExtensionPointView.swift | 86 +++++++++---------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/Mac/Preferences/ExtensionPoints/EnableExtensionPointView.swift b/Mac/Preferences/ExtensionPoints/EnableExtensionPointView.swift index 424265c12..84f1b915b 100644 --- a/Mac/Preferences/ExtensionPoints/EnableExtensionPointView.swift +++ b/Mac/Preferences/ExtensionPoints/EnableExtensionPointView.swift @@ -14,7 +14,7 @@ struct EnableExtensionPointView: View { weak var parent: NSHostingController? // required because presentationMode.dismiss() doesn't work weak var enabler: ExtensionPointPreferencesEnabler? - @State private var extensionPointTypeName = String(describing: ExtensionPointManager.shared.possibleExtensionPointTypes.first!) + @State private var extensionPointTypeName = String(describing: Self.feedProviderExtensionPointTypes.first!) init(enabler: ExtensionPointPreferencesEnabler?) { self.enabler = enabler @@ -26,9 +26,9 @@ struct EnableExtensionPointView: View { .font(.headline) .padding() - sendToCommandExtensionPoints feedProviderExtensionPoints - + sendToCommandExtensionPoints + HStack(spacing: 12) { Spacer() if #available(OSX 11.0, *) { @@ -80,50 +80,13 @@ struct EnableExtensionPointView: View { .padding() } - var sendToCommandExtensionPoints: some View { - VStack(alignment: .leading) { - let extensionPointTypeNames = sendToCommandExtensionPointTypes.map { String(describing: $0) } - if extensionPointTypeNames.count > 0 { - Text("Third-Party Integration") - .font(.headline) - .padding(.horizontal) - - Picker(selection: $extensionPointTypeName, label: Text(""), content: { - ForEach(extensionPointTypeNames, id: \.self, content: { extensionPointTypeName in - let extensionPointType = typeFromName(extensionPointTypeName) - HStack(alignment: .center) { - Image(nsImage: extensionPointType.templateImage) - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: 25, height: 25, alignment: .center) - .padding(.leading, 4) - - - Text(extensionPointType.title) - } - .tag(extensionPointTypeNames) - }) - }) - .pickerStyle(RadioGroupPickerStyle()) - .offset(x: 7.5, y: 0) - - Text("An extension point that enables a share menu item that passes article data to a third-party application.") - .foregroundColor(.gray) - .font(.caption) - .padding(.horizontal) - } - } - - } - var feedProviderExtensionPoints: some View { VStack(alignment: .leading) { - let extensionPointTypeNames = feedProviderExtensionPointTypes.map { String(describing: $0) } + let extensionPointTypeNames = Self.feedProviderExtensionPointTypes.map { String(describing: $0) } if extensionPointTypeNames.count > 0 { Text("Feed Provider") .font(.headline) .padding(.horizontal) - .padding(.top, 8) Picker(selection: $extensionPointTypeName, label: Text(""), content: { ForEach(extensionPointTypeNames, id: \.self, content: { extensionPointTypeName in @@ -153,11 +116,48 @@ struct EnableExtensionPointView: View { } - var sendToCommandExtensionPointTypes: [ExtensionPoint.Type] { + var sendToCommandExtensionPoints: some View { + VStack(alignment: .leading) { + let extensionPointTypeNames = Self.sendToCommandExtensionPointTypes.map { String(describing: $0) } + if extensionPointTypeNames.count > 0 { + Text("Third-Party Integration") + .font(.headline) + .padding(.horizontal) + .padding(.top, 8) + + Picker(selection: $extensionPointTypeName, label: Text(""), content: { + ForEach(extensionPointTypeNames, id: \.self, content: { extensionPointTypeName in + let extensionPointType = typeFromName(extensionPointTypeName) + HStack(alignment: .center) { + Image(nsImage: extensionPointType.templateImage) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 25, height: 25, alignment: .center) + .padding(.leading, 4) + + + Text(extensionPointType.title) + } + .tag(extensionPointTypeNames) + }) + }) + .pickerStyle(RadioGroupPickerStyle()) + .offset(x: 7.5, y: 0) + + Text("An extension point that enables a share menu item that passes article data to a third-party application.") + .foregroundColor(.gray) + .font(.caption) + .padding(.horizontal) + } + } + + } + + static var sendToCommandExtensionPointTypes: [ExtensionPoint.Type] { return ExtensionPointManager.shared.availableExtensionPointTypes.filter({ $0 is SendToCommand.Type }) } - var feedProviderExtensionPointTypes: [ExtensionPoint.Type] { + static var feedProviderExtensionPointTypes: [ExtensionPoint.Type] { return ExtensionPointManager.shared.availableExtensionPointTypes.filter({ !($0 is SendToCommand.Type) }) } From 198a5c29bf0ba7facbe279ad682cfbe8b9f227f9 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Fri, 30 Oct 2020 15:42:45 -0500 Subject: [PATCH 23/35] Rename templateImage to just image since we don't use template images anymore --- .../ExtensionPoints/EnableExtensionPointView.swift | 4 ++-- .../ExtensionPointDetailViewController.swift | 2 +- .../ExtensionPointEnableWindowController.swift | 2 +- .../ExtensionPointPreferencesViewController.swift | 2 +- Shared/ExtensionPoints/ExtensionPoint.swift | 6 +++--- Shared/ExtensionPoints/RedditFeedProvider-Extensions.swift | 2 +- Shared/ExtensionPoints/SendToMarsEditCommand.swift | 2 +- Shared/ExtensionPoints/SendToMicroBlogCommand.swift | 2 +- Shared/ExtensionPoints/TwitterFeedProvider-Extensions.swift | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Mac/Preferences/ExtensionPoints/EnableExtensionPointView.swift b/Mac/Preferences/ExtensionPoints/EnableExtensionPointView.swift index 84f1b915b..b7c707321 100644 --- a/Mac/Preferences/ExtensionPoints/EnableExtensionPointView.swift +++ b/Mac/Preferences/ExtensionPoints/EnableExtensionPointView.swift @@ -92,7 +92,7 @@ struct EnableExtensionPointView: View { ForEach(extensionPointTypeNames, id: \.self, content: { extensionPointTypeName in let extensionPointType = typeFromName(extensionPointTypeName) HStack(alignment: .center) { - Image(nsImage: extensionPointType.templateImage) + Image(nsImage: extensionPointType.image) .resizable() .aspectRatio(contentMode: .fit) .frame(width: 25, height: 25, alignment: .center) @@ -129,7 +129,7 @@ struct EnableExtensionPointView: View { ForEach(extensionPointTypeNames, id: \.self, content: { extensionPointTypeName in let extensionPointType = typeFromName(extensionPointTypeName) HStack(alignment: .center) { - Image(nsImage: extensionPointType.templateImage) + Image(nsImage: extensionPointType.image) .resizable() .aspectRatio(contentMode: .fit) .frame(width: 25, height: 25, alignment: .center) diff --git a/Mac/Preferences/ExtensionPoints/ExtensionPointDetailViewController.swift b/Mac/Preferences/ExtensionPoints/ExtensionPointDetailViewController.swift index da5749f82..f94d0ae59 100644 --- a/Mac/Preferences/ExtensionPoints/ExtensionPointDetailViewController.swift +++ b/Mac/Preferences/ExtensionPoints/ExtensionPointDetailViewController.swift @@ -29,7 +29,7 @@ class ExtensionPointDetailViewController: NSViewController { override func viewDidLoad() { super.viewDidLoad() guard let extensionPoint = extensionPoint else { return } - imageView.image = extensionPoint.templateImage + imageView.image = extensionPoint.image titleLabel.stringValue = extensionPoint.title descriptionLabel.attributedStringValue = extensionPoint.description } diff --git a/Mac/Preferences/ExtensionPoints/ExtensionPointEnableWindowController.swift b/Mac/Preferences/ExtensionPoints/ExtensionPointEnableWindowController.swift index f68d57370..f8aed7ff5 100644 --- a/Mac/Preferences/ExtensionPoints/ExtensionPointEnableWindowController.swift +++ b/Mac/Preferences/ExtensionPoints/ExtensionPointEnableWindowController.swift @@ -33,7 +33,7 @@ class ExtensionPointEnableWindowController: NSWindowController { super.windowDidLoad() guard let extensionPointType = extensionPointType else { return } - imageView.image = extensionPointType.templateImage + imageView.image = extensionPointType.image titleLabel.stringValue = extensionPointType.title descriptionLabel.attributedStringValue = extensionPointType.description } diff --git a/Mac/Preferences/ExtensionPoints/ExtensionPointPreferencesViewController.swift b/Mac/Preferences/ExtensionPoints/ExtensionPointPreferencesViewController.swift index 40e13dc61..d07249fba 100644 --- a/Mac/Preferences/ExtensionPoints/ExtensionPointPreferencesViewController.swift +++ b/Mac/Preferences/ExtensionPoints/ExtensionPointPreferencesViewController.swift @@ -87,7 +87,7 @@ extension ExtensionPointPreferencesViewController: NSTableViewDelegate { if let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "Cell"), owner: nil) as? NSTableCellView { let extensionPoint = activeExtensionPoints[row] cell.textField?.stringValue = extensionPoint.title - cell.imageView?.image = extensionPoint.templateImage + cell.imageView?.image = extensionPoint.image return cell } return nil diff --git a/Shared/ExtensionPoints/ExtensionPoint.swift b/Shared/ExtensionPoints/ExtensionPoint.swift index 148b48485..cbc2ef645 100644 --- a/Shared/ExtensionPoints/ExtensionPoint.swift +++ b/Shared/ExtensionPoints/ExtensionPoint.swift @@ -18,7 +18,7 @@ protocol ExtensionPoint { static var isSinglton: Bool { get } static var isDeveloperBuildRestricted: Bool { get } static var title: String { get } - static var templateImage: RSImage { get } + static var image: RSImage { get } static var description: NSAttributedString { get } var title: String { get } @@ -28,8 +28,8 @@ protocol ExtensionPoint { extension ExtensionPoint { - var templateImage: RSImage { - return extensionPointID.extensionPointType.templateImage + var image: RSImage { + return extensionPointID.extensionPointType.image } var description: NSAttributedString { diff --git a/Shared/ExtensionPoints/RedditFeedProvider-Extensions.swift b/Shared/ExtensionPoints/RedditFeedProvider-Extensions.swift index bde0735cc..86981f547 100644 --- a/Shared/ExtensionPoints/RedditFeedProvider-Extensions.swift +++ b/Shared/ExtensionPoints/RedditFeedProvider-Extensions.swift @@ -14,7 +14,7 @@ extension RedditFeedProvider: ExtensionPoint { static var isSinglton = false static var isDeveloperBuildRestricted = true static var title = NSLocalizedString("Reddit", comment: "Reddit") - static var templateImage = AppAssets.extensionPointReddit + static var image = AppAssets.extensionPointReddit static var description: NSAttributedString = { return RedditFeedProvider.makeAttrString("This extension enables you to subscribe to Reddit URL's as if they were RSS feeds. It only works with \(Account.defaultLocalAccountName) or iCloud accounts.") }() diff --git a/Shared/ExtensionPoints/SendToMarsEditCommand.swift b/Shared/ExtensionPoints/SendToMarsEditCommand.swift index 7394bebea..298ff5746 100644 --- a/Shared/ExtensionPoints/SendToMarsEditCommand.swift +++ b/Shared/ExtensionPoints/SendToMarsEditCommand.swift @@ -15,7 +15,7 @@ final class SendToMarsEditCommand: ExtensionPoint, SendToCommand { static var isSinglton = true static var isDeveloperBuildRestricted = false static var title = NSLocalizedString("MarsEdit", comment: "MarsEdit") - static var templateImage = AppAssets.extensionPointMarsEdit + static var image = AppAssets.extensionPointMarsEdit static var description: NSAttributedString = { let attrString = SendToMarsEditCommand.makeAttrString("This extension enables share menu functionality to send selected article text to MarsEdit. You need the MarsEdit application for this to work.") let range = NSRange(location: 81, length: 8) diff --git a/Shared/ExtensionPoints/SendToMicroBlogCommand.swift b/Shared/ExtensionPoints/SendToMicroBlogCommand.swift index 0b1bcbec2..c4ebeddfe 100644 --- a/Shared/ExtensionPoints/SendToMicroBlogCommand.swift +++ b/Shared/ExtensionPoints/SendToMicroBlogCommand.swift @@ -17,7 +17,7 @@ final class SendToMicroBlogCommand: ExtensionPoint, SendToCommand { static var isSinglton = true static var isDeveloperBuildRestricted = false static var title: String = NSLocalizedString("Micro.blog", comment: "Micro.blog") - static var templateImage = AppAssets.extensionPointMicroblog + static var image = AppAssets.extensionPointMicroblog static var description: NSAttributedString = { let attrString = SendToMicroBlogCommand.makeAttrString("This extension enables share menu functionality to send selected article text to Micro.blog. You need the Micro.blog application for this to work.") let range = NSRange(location: 81, length: 10) diff --git a/Shared/ExtensionPoints/TwitterFeedProvider-Extensions.swift b/Shared/ExtensionPoints/TwitterFeedProvider-Extensions.swift index 50f3383f0..d38917b66 100644 --- a/Shared/ExtensionPoints/TwitterFeedProvider-Extensions.swift +++ b/Shared/ExtensionPoints/TwitterFeedProvider-Extensions.swift @@ -14,7 +14,7 @@ extension TwitterFeedProvider: ExtensionPoint { static var isSinglton = false static var isDeveloperBuildRestricted = true static var title = NSLocalizedString("Twitter", comment: "Twitter") - static var templateImage = AppAssets.extensionPointTwitter + static var image = AppAssets.extensionPointTwitter static var description: NSAttributedString = { return TwitterFeedProvider.makeAttrString("This extension enables you to subscribe to Twitter URL's as if they were RSS feeds. It only works with \(Account.defaultLocalAccountName) or iCloud accounts.") }() From 5338cd88fe710913d10ca2528144cf1b155c9282 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Fri, 30 Oct 2020 16:43:32 -0500 Subject: [PATCH 24/35] Automatically loop and play Twitter animated gifs without video controls --- .../Twitter/TwitterExtendedMedia.swift | 19 ++++++++++++++++++- Shared/Article Rendering/main.js | 4 +++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/Account/Sources/Account/FeedProvider/Twitter/TwitterExtendedMedia.swift b/Account/Sources/Account/FeedProvider/Twitter/TwitterExtendedMedia.swift index 2ee2b3454..614fd5438 100644 --- a/Account/Sources/Account/FeedProvider/Twitter/TwitterExtendedMedia.swift +++ b/Account/Sources/Account/FeedProvider/Twitter/TwitterExtendedMedia.swift @@ -36,8 +36,10 @@ struct TwitterExtendedMedia: Codable { switch type { case "photo": html += renderPhotoAsHTML() - case "video", "animated_gif": + case "video": html += renderVideoAsHTML() + case "animated_gif": + html += renderAnimatedGIFAsHTML() default: break } @@ -74,6 +76,21 @@ private extension TwitterExtendedMedia { return html } + func renderAnimatedGIFAsHTML() -> String { + guard let bestVariantURL = findBestVariant()?.url else { return "" } + + var html = "" + return html + } + func findBestVariant() -> TwitterVideo.Variant? { var best: TwitterVideo.Variant? = nil if let variants = video?.variants { diff --git a/Shared/Article Rendering/main.js b/Shared/Article Rendering/main.js index 184df9008..befc09c0d 100644 --- a/Shared/Article Rendering/main.js +++ b/Shared/Article Rendering/main.js @@ -53,7 +53,9 @@ function wrapTables() { function inlineVideos() { document.querySelectorAll("video").forEach(element => { element.setAttribute("playsinline", true) - element.setAttribute("controls", true) + if !element.classList.contains("nnwAnimatedGIF") { + element.setAttribute("controls", true) + } }); } From 6f42628428c3e18ad7625feff14d4f6b0c35f192 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Fri, 30 Oct 2020 17:09:01 -0500 Subject: [PATCH 25/35] Treat animated gifs different from regular video --- .../FeedProvider/Reddit/RedditLink.swift | 17 ++++++++- .../FeedProvider/Reddit/RedditPreview.swift | 38 ++++++++++++++++++- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/Account/Sources/Account/FeedProvider/Reddit/RedditLink.swift b/Account/Sources/Account/FeedProvider/Reddit/RedditLink.swift index 3ec8aa295..1e859f81f 100644 --- a/Account/Sources/Account/FeedProvider/Reddit/RedditLink.swift +++ b/Account/Sources/Account/FeedProvider/Reddit/RedditLink.swift @@ -109,12 +109,25 @@ final class RedditLinkData: Codable { if let width = media?.video?.width, let height = media?.video?.height { html += "width=\"\(width)\" height=\"\(height)\" " } - html += "src=\"\(videoURL)\" autoplay muted loop>" + html += "src=\"\(videoURL)\">" + return html + } + + if let imageVariantURL = preview?.images?.first?.variants?.mp4?.source?.url { + var html = "" + html += linkURL(url) return html } if let videoPreviewURL = preview?.videoPreview?.url { - var html = "