From 29b5f426fd956ab9199229ad8064806fb64954d8 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Mon, 29 Jun 2020 15:03:17 -0500 Subject: [PATCH 1/3] Add accounts to Sidebar --- .../Shared/Sidebar/SidebarModel.swift | 18 ++++++++++++++++++ Multiplatform/Shared/Sidebar/SidebarView.swift | 6 ++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Multiplatform/Shared/Sidebar/SidebarModel.swift b/Multiplatform/Shared/Sidebar/SidebarModel.swift index 1375ab87a..19407a997 100644 --- a/Multiplatform/Shared/Sidebar/SidebarModel.swift +++ b/Multiplatform/Shared/Sidebar/SidebarModel.swift @@ -30,6 +30,24 @@ class SidebarModel: ObservableObject { } items.append(smartFeedControllerItem) + for account in AccountManager.shared.sortedActiveAccounts { + var accountItem = SidebarItem(account) + + for webFeed in account.topLevelWebFeeds { + accountItem.addChild(SidebarItem(webFeed, unreadCount: delegate.unreadCount(for: webFeed))) + } + + for folder in account.folders ?? Set() { + var folderItem = SidebarItem(folder, unreadCount: delegate.unreadCount(for: folder)) + for webFeed in folder.topLevelWebFeeds { + folderItem.addChild(SidebarItem(webFeed, unreadCount: delegate.unreadCount(for: webFeed))) + } + accountItem.addChild(folderItem) + } + + items.append(accountItem) + } + sidebarItems = items } diff --git a/Multiplatform/Shared/Sidebar/SidebarView.swift b/Multiplatform/Shared/Sidebar/SidebarView.swift index 0af760cb5..b67dfa340 100644 --- a/Multiplatform/Shared/Sidebar/SidebarView.swift +++ b/Multiplatform/Shared/Sidebar/SidebarView.swift @@ -14,10 +14,8 @@ struct SidebarView: View { var body: some View { List { - ForEach(sidebarModel.sidebarItems) { section in - OutlineGroup(sidebarModel.sidebarItems, children: \.children) { sidebarItem in - Text(sidebarItem.nameForDisplay) - } + OutlineGroup(sidebarModel.sidebarItems, children: \.children) { sidebarItem in + Text(sidebarItem.nameForDisplay) } } } From 61ad0fbfa427adafe6c831c8abb9c7708c924ddc Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Mon, 29 Jun 2020 16:58:10 -0500 Subject: [PATCH 2/3] Add unread counts to Sidebar --- .../Shared/SceneNavigationView.swift | 2 +- .../Shared/Sidebar/SidebarItem.swift | 3 ++ .../Shared/Sidebar/SidebarItemView.swift | 25 ++++++++++++++ .../Shared/Sidebar/SidebarModel.swift | 33 +++++++++++++++++-- .../Shared/Sidebar/SidebarView.swift | 2 +- .../Shared/Sidebar/UnreadCountView.swift | 27 +++++++++++++++ NetNewsWire.xcodeproj/project.pbxproj | 12 +++++++ 7 files changed, 99 insertions(+), 5 deletions(-) create mode 100644 Multiplatform/Shared/Sidebar/SidebarItemView.swift create mode 100644 Multiplatform/Shared/Sidebar/UnreadCountView.swift diff --git a/Multiplatform/Shared/SceneNavigationView.swift b/Multiplatform/Shared/SceneNavigationView.swift index fecdc5cec..533c6692a 100644 --- a/Multiplatform/Shared/SceneNavigationView.swift +++ b/Multiplatform/Shared/SceneNavigationView.swift @@ -18,7 +18,7 @@ struct SceneNavigationView: View { NavigationView { #if os(macOS) RegularSidebarContainerView() - .frame(minWidth: 100, idealWidth: 150, maxWidth: 200, maxHeight: .infinity) + .frame(minWidth: 100, idealWidth: 150, maxHeight: .infinity) #else if horizontalSizeClass == .compact { CompactSidebarContainerView() diff --git a/Multiplatform/Shared/Sidebar/SidebarItem.swift b/Multiplatform/Shared/Sidebar/SidebarItem.swift index f2b9abe40..14a1abdb1 100644 --- a/Multiplatform/Shared/Sidebar/SidebarItem.swift +++ b/Multiplatform/Shared/Sidebar/SidebarItem.swift @@ -47,6 +47,9 @@ struct SidebarItem: Identifiable { self.id = .feed(feed.feedID!) self.represented = feed self.unreadCount = unreadCount + if let container = feed as? Container, container.hasAtLeastOneWebFeed() { + self.children = [SidebarItem]() + } } mutating func addChild(_ sidebarItem: SidebarItem) { diff --git a/Multiplatform/Shared/Sidebar/SidebarItemView.swift b/Multiplatform/Shared/Sidebar/SidebarItemView.swift new file mode 100644 index 000000000..a38175dbe --- /dev/null +++ b/Multiplatform/Shared/Sidebar/SidebarItemView.swift @@ -0,0 +1,25 @@ +// +// SidebarItemView.swift +// NetNewsWire +// +// Created by Maurice Parker on 6/29/20. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import SwiftUI + +struct SidebarItemView: View { + + var sidebarItem: SidebarItem + + var body: some View { + HStack { + Text(verbatim: sidebarItem.nameForDisplay) + Spacer() + if sidebarItem.unreadCount > 0 { + UnreadCountView(count: sidebarItem.unreadCount) + } + } + } + +} diff --git a/Multiplatform/Shared/Sidebar/SidebarModel.swift b/Multiplatform/Shared/Sidebar/SidebarModel.swift index 19407a997..38aff59a1 100644 --- a/Multiplatform/Shared/Sidebar/SidebarModel.swift +++ b/Multiplatform/Shared/Sidebar/SidebarModel.swift @@ -7,6 +7,7 @@ // import Foundation +import RSCore import Account protocol SidebarModelDelegate: class { @@ -20,6 +21,12 @@ class SidebarModel: ObservableObject { @Published var sidebarItems = [SidebarItem]() + init() { + NotificationCenter.default.addObserver(self, selector: #selector(unreadCountDidInitialize(_:)), name: .UnreadCountDidInitialize, object: nil) + } + + // MARK: API + func rebuildSidebarItems() { guard let delegate = delegate else { return } var items = [SidebarItem]() @@ -33,13 +40,13 @@ class SidebarModel: ObservableObject { for account in AccountManager.shared.sortedActiveAccounts { var accountItem = SidebarItem(account) - for webFeed in account.topLevelWebFeeds { + for webFeed in sort(account.topLevelWebFeeds) { accountItem.addChild(SidebarItem(webFeed, unreadCount: delegate.unreadCount(for: webFeed))) } - for folder in account.folders ?? Set() { + for folder in sort(account.folders ?? Set()) { var folderItem = SidebarItem(folder, unreadCount: delegate.unreadCount(for: folder)) - for webFeed in folder.topLevelWebFeeds { + for webFeed in sort(folder.topLevelWebFeeds) { folderItem.addChild(SidebarItem(webFeed, unreadCount: delegate.unreadCount(for: webFeed))) } accountItem.addChild(folderItem) @@ -52,3 +59,23 @@ class SidebarModel: ObservableObject { } } + +// MARK: Private +private extension SidebarModel { + + @objc func unreadCountDidInitialize(_ notification: Notification) { + guard notification.object is AccountManager else { + return + } + rebuildSidebarItems() + } + + func sort(_ folders: Set) -> [Folder] { + return folders.sorted(by: { $0.nameForDisplay.localizedStandardCompare($1.nameForDisplay) == .orderedAscending }) + } + + func sort(_ feeds: Set) -> [Feed] { + return feeds.sorted(by: { $0.nameForDisplay.localizedStandardCompare($1.nameForDisplay) == .orderedAscending }) + } + +} diff --git a/Multiplatform/Shared/Sidebar/SidebarView.swift b/Multiplatform/Shared/Sidebar/SidebarView.swift index b67dfa340..71a5bd083 100644 --- a/Multiplatform/Shared/Sidebar/SidebarView.swift +++ b/Multiplatform/Shared/Sidebar/SidebarView.swift @@ -15,7 +15,7 @@ struct SidebarView: View { var body: some View { List { OutlineGroup(sidebarModel.sidebarItems, children: \.children) { sidebarItem in - Text(sidebarItem.nameForDisplay) + SidebarItemView(sidebarItem: sidebarItem) } } } diff --git a/Multiplatform/Shared/Sidebar/UnreadCountView.swift b/Multiplatform/Shared/Sidebar/UnreadCountView.swift new file mode 100644 index 000000000..6e4779fd2 --- /dev/null +++ b/Multiplatform/Shared/Sidebar/UnreadCountView.swift @@ -0,0 +1,27 @@ +// +// UnreadCountView.swift +// NetNewsWire +// +// Created by Maurice Parker on 6/29/20. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import SwiftUI + +struct UnreadCountView: View { + + var count: Int + + var body: some View { + Text(verbatim: String(count)) + .padding(.horizontal, 7) + .background(SwiftUI.Color.gray.opacity(0.5)) + .cornerRadius(8) + } +} + +struct UnreadCountView_Previews: PreviewProvider { + static var previews: some View { + UnreadCountView(count: 123) + } +} diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 53baf34f0..147174865 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -208,6 +208,10 @@ 518ED21D23D0F26000E0A862 /* UIViewController-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518ED21C23D0F26000E0A862 /* UIViewController-Extensions.swift */; }; 51919FA624AA64B000541E64 /* SidebarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51919FA524AA64B000541E64 /* SidebarView.swift */; }; 51919FA724AA64B000541E64 /* SidebarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51919FA524AA64B000541E64 /* SidebarView.swift */; }; + 51919FAC24AA8CCA00541E64 /* UnreadCountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51919FAB24AA8CCA00541E64 /* UnreadCountView.swift */; }; + 51919FAD24AA8CCA00541E64 /* UnreadCountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51919FAB24AA8CCA00541E64 /* UnreadCountView.swift */; }; + 51919FAF24AA8EFA00541E64 /* SidebarItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51919FAE24AA8EFA00541E64 /* SidebarItemView.swift */; }; + 51919FB024AA8EFA00541E64 /* SidebarItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51919FAE24AA8EFA00541E64 /* SidebarItemView.swift */; }; 51934CCB230F599B006127BE /* InteractiveNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51934CC1230F5963006127BE /* InteractiveNavigationController.swift */; }; 51934CCE2310792F006127BE /* ActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51934CCD2310792F006127BE /* ActivityManager.swift */; }; 51938DF2231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51938DF1231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift */; }; @@ -1797,6 +1801,8 @@ 518B2EE92351B4C200400001 /* NetNewsWire_iOSTests_target.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = NetNewsWire_iOSTests_target.xcconfig; sourceTree = ""; }; 518ED21C23D0F26000E0A862 /* UIViewController-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController-Extensions.swift"; sourceTree = ""; }; 51919FA524AA64B000541E64 /* SidebarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarView.swift; sourceTree = ""; }; + 51919FAB24AA8CCA00541E64 /* UnreadCountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnreadCountView.swift; sourceTree = ""; }; + 51919FAE24AA8EFA00541E64 /* SidebarItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarItemView.swift; sourceTree = ""; }; 51934CC1230F5963006127BE /* InteractiveNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractiveNavigationController.swift; sourceTree = ""; }; 51934CCD2310792F006127BE /* ActivityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityManager.swift; sourceTree = ""; }; 51938DF1231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchTimelineFeedDelegate.swift; sourceTree = ""; }; @@ -2810,6 +2816,8 @@ 51408B7D24A9EC6F0073CF4E /* SidebarItem.swift */, 51E499FC24A9137600B667CB /* SidebarModel.swift */, 51919FA524AA64B000541E64 /* SidebarView.swift */, + 51919FAB24AA8CCA00541E64 /* UnreadCountView.swift */, + 51919FAE24AA8EFA00541E64 /* SidebarItemView.swift */, ); path = Sidebar; sourceTree = ""; @@ -4650,6 +4658,7 @@ 51E498F124A8085D00B667CB /* StarredFeedDelegate.swift in Sources */, 51E498FF24A808BB00B667CB /* SingleFaviconDownloader.swift in Sources */, 51E4997224A8784300B667CB /* DefaultFeedsImporter.swift in Sources */, + 51919FAF24AA8EFA00541E64 /* SidebarItemView.swift in Sources */, 51E4990D24A808C500B667CB /* RSHTMLMetadata+Extension.swift in Sources */, 51E49A0024A91FC100B667CB /* RegularSidebarContainerView.swift in Sources */, 51E4995C24A875F300B667CB /* ArticleRenderer.swift in Sources */, @@ -4699,6 +4708,7 @@ 51E4992124A8095000B667CB /* RSImage-Extensions.swift in Sources */, 51E4990324A808BB00B667CB /* FaviconDownloader.swift in Sources */, 51E4990224A808BB00B667CB /* ColorHash.swift in Sources */, + 51919FAC24AA8CCA00541E64 /* UnreadCountView.swift in Sources */, 51E4991924A8090A00B667CB /* CacheCleaner.swift in Sources */, 51E498F724A8085D00B667CB /* SearchTimelineFeedDelegate.swift in Sources */, 51E4993524A867E800B667CB /* AppNotifications.swift in Sources */, @@ -4723,6 +4733,7 @@ 51E4994B24A8734C00B667CB /* SendToMicroBlogCommand.swift in Sources */, 51E4996F24A8764C00B667CB /* ActivityType.swift in Sources */, 51E4994E24A8734C00B667CB /* SendToMarsEditCommand.swift in Sources */, + 51919FB024AA8EFA00541E64 /* SidebarItemView.swift in Sources */, 51E4996624A8760B00B667CB /* ArticleStyle.swift in Sources */, 51E4996C24A8762D00B667CB /* ExtractedArticle.swift in Sources */, 51E4990824A808C300B667CB /* RSHTMLMetadata+Extension.swift in Sources */, @@ -4745,6 +4756,7 @@ 1729529724AA1CD000D65E66 /* MacPreferencesView.swift in Sources */, 51E4994C24A8734C00B667CB /* RedditFeedProvider-Extensions.swift in Sources */, 1729529324AA1CAA00D65E66 /* AccountsPreferencesView.swift in Sources */, + 51919FAD24AA8CCA00541E64 /* UnreadCountView.swift in Sources */, 51E4994124A8713B00B667CB /* RefreshInterval.swift in Sources */, 51E498C924A8085D00B667CB /* PseudoFeed.swift in Sources */, 51E498FC24A808BA00B667CB /* FaviconURLFinder.swift in Sources */, From 835b04c53df402c96809cea66ca10d2957eda401 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Mon, 29 Jun 2020 20:09:11 -0500 Subject: [PATCH 3/3] Add feed icons --- .../Shared/Images/FeedImageLoader.swift | 58 +++++++++++++++++++ .../Shared/Images/IconImageView.swift | 37 ++++++++++++ .../Shared/Sidebar/SidebarItemView.swift | 10 ++++ .../Shared/Sidebar/UnreadCountView.swift | 2 + NetNewsWire.xcodeproj/project.pbxproj | 20 +++++++ 5 files changed, 127 insertions(+) create mode 100644 Multiplatform/Shared/Images/FeedImageLoader.swift create mode 100644 Multiplatform/Shared/Images/IconImageView.swift diff --git a/Multiplatform/Shared/Images/FeedImageLoader.swift b/Multiplatform/Shared/Images/FeedImageLoader.swift new file mode 100644 index 000000000..5dc6a40c7 --- /dev/null +++ b/Multiplatform/Shared/Images/FeedImageLoader.swift @@ -0,0 +1,58 @@ +// +// FeedImageLoader.swift +// NetNewsWire +// +// Created by Maurice Parker on 6/29/20. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import SwiftUI +import Account + +final class FeedImageLoader: ObservableObject { + + private var feed: Feed? + + @Published var image: IconImage? + + init() { + NotificationCenter.default.addObserver(self, selector: #selector(faviconDidBecomeAvailable(_:)), name: .FaviconDidBecomeAvailable, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(webFeedIconDidBecomeAvailable(_:)), name: .WebFeedIconDidBecomeAvailable, object: nil) + } + + func loadImage(for feed: Feed) { + self.feed = feed + + if let webFeed = feed as? WebFeed { + if let feedIconImage = appDelegate.webFeedIconDownloader.icon(for: webFeed) { + image = feedIconImage + return + } + if let faviconImage = appDelegate.faviconDownloader.faviconAsIcon(for: webFeed) { + image = faviconImage + return + } + } + + if let smallIconProvider = feed as? SmallIconProvider { + image = smallIconProvider.smallIcon + } + } + +} + +private extension FeedImageLoader { + + @objc func faviconDidBecomeAvailable(_ note: Notification) { + guard let feed = feed else { return } + loadImage(for: feed) + } + + @objc func webFeedIconDidBecomeAvailable(_ note: Notification) { + guard let feed = feed as? WebFeed, let noteFeed = note.userInfo?[UserInfoKey.webFeed] as? WebFeed, feed == noteFeed else { + return + } + loadImage(for: feed) + } + +} diff --git a/Multiplatform/Shared/Images/IconImageView.swift b/Multiplatform/Shared/Images/IconImageView.swift new file mode 100644 index 000000000..3eb74a1ca --- /dev/null +++ b/Multiplatform/Shared/Images/IconImageView.swift @@ -0,0 +1,37 @@ +// +// IconImageView.swift +// NetNewsWire +// +// Created by Maurice Parker on 6/29/20. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import SwiftUI + +struct IconImageView: View { + + var iconImage: IconImage + + var body: some View { + #if os(macOS) + return Image(nsImage: iconImage.image) + .resizable() + .scaledToFit() + .frame(width: 20, height: 20, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/) + .cornerRadius(4) + #endif + #if os(iOS) + return Image(uiImage: iconImage.image) + .resizable() + .scaledToFit() + .frame(width: 20, height: 20, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/) + .cornerRadius(4) + #endif + } +} + +struct IconImageView_Previews: PreviewProvider { + static var previews: some View { + IconImageView(iconImage: IconImage(AppAssets.faviconTemplateImage)) + } +} diff --git a/Multiplatform/Shared/Sidebar/SidebarItemView.swift b/Multiplatform/Shared/Sidebar/SidebarItemView.swift index a38175dbe..e1dcaa41b 100644 --- a/Multiplatform/Shared/Sidebar/SidebarItemView.swift +++ b/Multiplatform/Shared/Sidebar/SidebarItemView.swift @@ -7,19 +7,29 @@ // import SwiftUI +import Account struct SidebarItemView: View { + @StateObject var feedImageLoader = FeedImageLoader() var sidebarItem: SidebarItem var body: some View { HStack { + if let image = feedImageLoader.image { + IconImageView(iconImage: image) + } Text(verbatim: sidebarItem.nameForDisplay) Spacer() if sidebarItem.unreadCount > 0 { UnreadCountView(count: sidebarItem.unreadCount) } } + .onAppear { + if let feed = sidebarItem.represented as? Feed { + feedImageLoader.loadImage(for: feed) + } + } } } diff --git a/Multiplatform/Shared/Sidebar/UnreadCountView.swift b/Multiplatform/Shared/Sidebar/UnreadCountView.swift index 6e4779fd2..f1c760bfd 100644 --- a/Multiplatform/Shared/Sidebar/UnreadCountView.swift +++ b/Multiplatform/Shared/Sidebar/UnreadCountView.swift @@ -14,7 +14,9 @@ struct UnreadCountView: View { var body: some View { Text(verbatim: String(count)) + .font(.footnote) .padding(.horizontal, 7) + .padding(.vertical, 1) .background(SwiftUI.Color.gray.opacity(0.5)) .cornerRadius(8) } diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 147174865..dcc2ebd26 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -212,6 +212,10 @@ 51919FAD24AA8CCA00541E64 /* UnreadCountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51919FAB24AA8CCA00541E64 /* UnreadCountView.swift */; }; 51919FAF24AA8EFA00541E64 /* SidebarItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51919FAE24AA8EFA00541E64 /* SidebarItemView.swift */; }; 51919FB024AA8EFA00541E64 /* SidebarItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51919FAE24AA8EFA00541E64 /* SidebarItemView.swift */; }; + 51919FB324AAB97900541E64 /* FeedImageLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51919FB224AAB97900541E64 /* FeedImageLoader.swift */; }; + 51919FB424AAB97900541E64 /* FeedImageLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51919FB224AAB97900541E64 /* FeedImageLoader.swift */; }; + 51919FB624AABCA100541E64 /* IconImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51919FB524AABCA100541E64 /* IconImageView.swift */; }; + 51919FB724AABCA100541E64 /* IconImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51919FB524AABCA100541E64 /* IconImageView.swift */; }; 51934CCB230F599B006127BE /* InteractiveNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51934CC1230F5963006127BE /* InteractiveNavigationController.swift */; }; 51934CCE2310792F006127BE /* ActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51934CCD2310792F006127BE /* ActivityManager.swift */; }; 51938DF2231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51938DF1231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift */; }; @@ -1803,6 +1807,8 @@ 51919FA524AA64B000541E64 /* SidebarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarView.swift; sourceTree = ""; }; 51919FAB24AA8CCA00541E64 /* UnreadCountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnreadCountView.swift; sourceTree = ""; }; 51919FAE24AA8EFA00541E64 /* SidebarItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarItemView.swift; sourceTree = ""; }; + 51919FB224AAB97900541E64 /* FeedImageLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedImageLoader.swift; sourceTree = ""; }; + 51919FB524AABCA100541E64 /* IconImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconImageView.swift; sourceTree = ""; }; 51934CC1230F5963006127BE /* InteractiveNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractiveNavigationController.swift; sourceTree = ""; }; 51934CCD2310792F006127BE /* ActivityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityManager.swift; sourceTree = ""; }; 51938DF1231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchTimelineFeedDelegate.swift; sourceTree = ""; }; @@ -2571,6 +2577,15 @@ path = NNW3; sourceTree = ""; }; + 51919FB124AAB95300541E64 /* Images */ = { + isa = PBXGroup; + children = ( + 51919FB224AAB97900541E64 /* FeedImageLoader.swift */, + 51919FB524AABCA100541E64 /* IconImageView.swift */, + ); + path = Images; + sourceTree = ""; + }; 51934CCC231078DC006127BE /* Activity */ = { isa = PBXGroup; children = ( @@ -2635,6 +2650,7 @@ 51E4992824A866F000B667CB /* AppDefaults.swift */, 51E4995824A873F900B667CB /* ErrorHandler.swift */, 51C0513824A77DF800194D5E /* Assets.xcassets */, + 51919FB124AAB95300541E64 /* Images */, 51E499FB24A9135A00B667CB /* Sidebar */, ); path = Shared; @@ -4688,6 +4704,7 @@ 51E4994224A8713C00B667CB /* ArticleStatusSyncTimer.swift in Sources */, 51E498F624A8085D00B667CB /* SearchFeedDelegate.swift in Sources */, 51E498F224A8085D00B667CB /* SmartFeedsController.swift in Sources */, + 51919FB624AABCA100541E64 /* IconImageView.swift in Sources */, 51919FA624AA64B000541E64 /* SidebarView.swift in Sources */, 51E4997024A8764C00B667CB /* ActivityManager.swift in Sources */, 51E4990F24A808CC00B667CB /* HTMLMetadataDownloader.swift in Sources */, @@ -4700,6 +4717,7 @@ 51E4997124A8764C00B667CB /* ActivityType.swift in Sources */, 51E4991E24A8094300B667CB /* RSImage-AppIcons.swift in Sources */, 51E499D824A912C200B667CB /* SceneModel.swift in Sources */, + 51919FB324AAB97900541E64 /* FeedImageLoader.swift in Sources */, 51E4991324A808FB00B667CB /* AddWebFeedDefaultContainer.swift in Sources */, 51E4993C24A8709900B667CB /* AppDelegate.swift in Sources */, 51E498F924A8085D00B667CB /* SmartFeed.swift in Sources */, @@ -4727,6 +4745,7 @@ 51E4993A24A8708800B667CB /* AppDelegate.swift in Sources */, 51E498CE24A8085D00B667CB /* UnreadFeed.swift in Sources */, 51E498C724A8085D00B667CB /* StarredFeedDelegate.swift in Sources */, + 51919FB724AABCA100541E64 /* IconImageView.swift in Sources */, 51E498FA24A808BA00B667CB /* SingleFaviconDownloader.swift in Sources */, 51E4993F24A8713B00B667CB /* ArticleStatusSyncTimer.swift in Sources */, 51E4993724A8680E00B667CB /* Reachability.swift in Sources */, @@ -4762,6 +4781,7 @@ 51E498FC24A808BA00B667CB /* FaviconURLFinder.swift in Sources */, 51E4991C24A8092000B667CB /* NSAttributedString+NetNewsWire.swift in Sources */, 51E499D924A912C200B667CB /* SceneModel.swift in Sources */, + 51919FB424AAB97900541E64 /* FeedImageLoader.swift in Sources */, 51E4994A24A8734C00B667CB /* ExtensionPointManager.swift in Sources */, 51E4996D24A8762D00B667CB /* ArticleExtractor.swift in Sources */, 51E4994024A8713B00B667CB /* AccountRefreshTimer.swift in Sources */,