From 781f24454e0196af824c2a3538dd6deb8b33d3e2 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Wed, 1 Jul 2020 16:33:07 -0500 Subject: [PATCH] Add read/starred indicator to timeline --- Multiplatform/Shared/AppAssets.swift | 10 ++++ .../Shared/Images/IconImageView.swift | 11 +--- .../Shared/Previews/PreviewArticles.swift | 58 +++++++++++++++++++ .../SwiftUI Extensions/Image-Extensions.swift | 23 ++++++++ .../Shared/Timeline/TimelineItem.swift | 16 +++++ .../Timeline/TimelineItemStatusView.swift | 40 +++++++++++++ .../Shared/Timeline/TimelineItemView.swift | 24 +++++--- NetNewsWire.xcodeproj/project.pbxproj | 34 +++++++++++ 8 files changed, 199 insertions(+), 17 deletions(-) create mode 100644 Multiplatform/Shared/Previews/PreviewArticles.swift create mode 100644 Multiplatform/Shared/SwiftUI Extensions/Image-Extensions.swift create mode 100644 Multiplatform/Shared/Timeline/TimelineItemStatusView.swift diff --git a/Multiplatform/Shared/AppAssets.swift b/Multiplatform/Shared/AppAssets.swift index 37998ed7b..b6930bb34 100644 --- a/Multiplatform/Shared/AppAssets.swift +++ b/Multiplatform/Shared/AppAssets.swift @@ -104,6 +104,16 @@ struct AppAssets { #endif }() + static var timelineStarred: Image = { + return Image(systemName: "star.fill") + + }() + + static var timelineUnread: Image = { + return Image(systemName: "circle.fill") + + }() + static var todayFeedImage: IconImage = { #if os(macOS) return IconImage(NSImage(systemSymbolName: "sun.max.fill", accessibilityDescription: nil)!) diff --git a/Multiplatform/Shared/Images/IconImageView.swift b/Multiplatform/Shared/Images/IconImageView.swift index 3eb74a1ca..83bdcf7be 100644 --- a/Multiplatform/Shared/Images/IconImageView.swift +++ b/Multiplatform/Shared/Images/IconImageView.swift @@ -13,20 +13,11 @@ struct IconImageView: View { var iconImage: IconImage var body: some View { - #if os(macOS) - return Image(nsImage: iconImage.image) + return Image(rsImage: 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 } } diff --git a/Multiplatform/Shared/Previews/PreviewArticles.swift b/Multiplatform/Shared/Previews/PreviewArticles.swift new file mode 100644 index 000000000..75cc895d9 --- /dev/null +++ b/Multiplatform/Shared/Previews/PreviewArticles.swift @@ -0,0 +1,58 @@ +// +// PreviewArticles.swift +// NetNewsWire +// +// Created by Maurice Parker on 7/1/20. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import Foundation +import Articles + +enum PreviewArticles { + + static var basicUnread: Article { + return makeBasicArticle(read: false, starred: false) + } + + static var basicRead: Article { + return makeBasicArticle(read: true, starred: false) + } + + static var basicStarred: Article { + return makeBasicArticle(read: false, starred: true) + } + +} + +private extension PreviewArticles { + + static var shortTitle: String { + return "Short article title" + } + + static var shortSummary: String { + return "Summary of article to be shown after title." + } + + static func makeBasicArticle(read: Bool, starred: Bool) -> Article { + let articleID = "prototype" + let status = ArticleStatus(articleID: articleID, read: read, starred: starred, dateArrived: Date()) + return Article(accountID: articleID, + articleID: articleID, + webFeedID: articleID, + uniqueID: articleID, + title: shortTitle, + contentHTML: nil, + contentText: nil, + url: nil, + externalURL: nil, + summary: shortSummary, + imageURL: nil, + datePublished: Date(), + dateModified: nil, + authors: nil, + status: status) + } + +} diff --git a/Multiplatform/Shared/SwiftUI Extensions/Image-Extensions.swift b/Multiplatform/Shared/SwiftUI Extensions/Image-Extensions.swift new file mode 100644 index 000000000..517991676 --- /dev/null +++ b/Multiplatform/Shared/SwiftUI Extensions/Image-Extensions.swift @@ -0,0 +1,23 @@ +// +// Image-Extensions.swift +// NetNewsWire +// +// Created by Maurice Parker on 7/1/20. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import SwiftUI +import RSCore + +extension Image { + + init(rsImage: RSImage) { + #if os(macOS) + self = Image(nsImage: rsImage) + #endif + #if os(iOS) + self = Image(uiImage: rsImage) + #endif + } + +} diff --git a/Multiplatform/Shared/Timeline/TimelineItem.swift b/Multiplatform/Shared/Timeline/TimelineItem.swift index c15c6c432..730530b1a 100644 --- a/Multiplatform/Shared/Timeline/TimelineItem.swift +++ b/Multiplatform/Shared/Timeline/TimelineItem.swift @@ -9,6 +9,12 @@ import SwiftUI import Articles +enum TimelineItemStatus { + case showStar + case showUnread + case showNone +} + struct TimelineItem: Identifiable { var article: Article @@ -17,4 +23,14 @@ struct TimelineItem: Identifiable { return article.articleID } + var status: TimelineItemStatus { + if article.status.starred == true { + return .showStar + } + if article.status.read == false { + return .showUnread + } + return .showNone + } + } diff --git a/Multiplatform/Shared/Timeline/TimelineItemStatusView.swift b/Multiplatform/Shared/Timeline/TimelineItemStatusView.swift new file mode 100644 index 000000000..766aba6dd --- /dev/null +++ b/Multiplatform/Shared/Timeline/TimelineItemStatusView.swift @@ -0,0 +1,40 @@ +// +// TimelineItemStatusView.swift +// NetNewsWire +// +// Created by Maurice Parker on 7/1/20. +// Copyright © 2020 Ranchero Software. All rights reserved. +// + +import SwiftUI + +struct TimelineItemStatusView: View { + + var status: TimelineItemStatus + + @ViewBuilder var statusView: some View { + switch status { + case .showUnread: + AppAssets.timelineUnread + .resizable() + .frame(width: 8, height: 8, alignment: .center) + .padding(.all, 2) + .foregroundColor(.accentColor) + case .showStar: + AppAssets.timelineStarred + .resizable() + .frame(width: 10, height: 10, alignment: .center) + .foregroundColor(.yellow) + case .showNone: + Spacer() + .frame(width: 10, height: 10, alignment: .center) + } + } + + var body: some View { + statusView + .padding(.top, 4) + .padding(.leading, 4) + } + +} diff --git a/Multiplatform/Shared/Timeline/TimelineItemView.swift b/Multiplatform/Shared/Timeline/TimelineItemView.swift index 021c7cb5c..b5c1b2138 100644 --- a/Multiplatform/Shared/Timeline/TimelineItemView.swift +++ b/Multiplatform/Shared/Timeline/TimelineItemView.swift @@ -14,15 +14,25 @@ struct TimelineItemView: View { var body: some View { VStack { - Text(verbatim: timelineItem.article.title ?? "N/A") - .frame(maxWidth: .infinity, alignment: .leading) + HStack(alignment: .top) { + TimelineItemStatusView(status: timelineItem.status) + Text(verbatim: timelineItem.article.title ?? "N/A") + .frame(maxWidth: .infinity, alignment: .leading) + } Divider() } } } -//struct TimelineItemView_Previews: PreviewProvider { -// static var previews: some View { -// TimelineItemView() -// } -//} +struct TimelineItemView_Previews: PreviewProvider { + static var previews: some View { + Group { + TimelineItemView(timelineItem: TimelineItem(article: PreviewArticles.basicRead)) + .frame(maxWidth: 250) + TimelineItemView(timelineItem: TimelineItem(article: PreviewArticles.basicUnread)) + .frame(maxWidth: 250) + TimelineItemView(timelineItem: TimelineItem(article: PreviewArticles.basicStarred)) + .frame(maxWidth: 250) + } + } +} diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 4173f467b..425d3cf58 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -147,6 +147,12 @@ 514B7D1F23219F3C00BAC947 /* AddControllerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514B7D1E23219F3C00BAC947 /* AddControllerType.swift */; }; 514E6BDA24ACEA0400AC6F6E /* TimelineItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514E6BD924ACEA0400AC6F6E /* TimelineItemView.swift */; }; 514E6BDB24ACEA0400AC6F6E /* TimelineItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514E6BD924ACEA0400AC6F6E /* TimelineItemView.swift */; }; + 514E6BFF24AD255D00AC6F6E /* PreviewArticles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514E6BFE24AD255D00AC6F6E /* PreviewArticles.swift */; }; + 514E6C0024AD255D00AC6F6E /* PreviewArticles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514E6BFE24AD255D00AC6F6E /* PreviewArticles.swift */; }; + 514E6C0224AD29A300AC6F6E /* TimelineItemStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514E6C0124AD29A300AC6F6E /* TimelineItemStatusView.swift */; }; + 514E6C0324AD29A300AC6F6E /* TimelineItemStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514E6C0124AD29A300AC6F6E /* TimelineItemStatusView.swift */; }; + 514E6C0624AD2B5F00AC6F6E /* Image-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514E6C0524AD2B5F00AC6F6E /* Image-Extensions.swift */; }; + 514E6C0724AD2B5F00AC6F6E /* Image-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514E6C0524AD2B5F00AC6F6E /* Image-Extensions.swift */; }; 5154368B229404D1005E1CDF /* FaviconGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F76227716200050506E /* FaviconGenerator.swift */; }; 51554C24228B71910055115A /* SyncDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51554C01228B6EB50055115A /* SyncDatabase.framework */; }; 51554C25228B71910055115A /* SyncDatabase.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 51554C01228B6EB50055115A /* SyncDatabase.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -1783,6 +1789,9 @@ 514B7C8223205EFB00BAC947 /* RootSplitViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootSplitViewController.swift; sourceTree = ""; }; 514B7D1E23219F3C00BAC947 /* AddControllerType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddControllerType.swift; sourceTree = ""; }; 514E6BD924ACEA0400AC6F6E /* TimelineItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemView.swift; sourceTree = ""; }; + 514E6BFE24AD255D00AC6F6E /* PreviewArticles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewArticles.swift; sourceTree = ""; }; + 514E6C0124AD29A300AC6F6E /* TimelineItemStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemStatusView.swift; sourceTree = ""; }; + 514E6C0524AD2B5F00AC6F6E /* Image-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Image-Extensions.swift"; sourceTree = ""; }; 51554BFC228B6EB50055115A /* SyncDatabase.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SyncDatabase.xcodeproj; path = Frameworks/SyncDatabase/SyncDatabase.xcodeproj; sourceTree = SOURCE_ROOT; }; 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 = ""; }; @@ -2524,6 +2533,22 @@ path = OPML; sourceTree = ""; }; + 514E6BFD24AD252400AC6F6E /* Previews */ = { + isa = PBXGroup; + children = ( + 514E6BFE24AD255D00AC6F6E /* PreviewArticles.swift */, + ); + path = Previews; + sourceTree = ""; + }; + 514E6C0424AD2B0400AC6F6E /* SwiftUI Extensions */ = { + isa = PBXGroup; + children = ( + 514E6C0524AD2B5F00AC6F6E /* Image-Extensions.swift */, + ); + path = "SwiftUI Extensions"; + sourceTree = ""; + }; 51554BFD228B6EB50055115A /* Products */ = { isa = PBXGroup; children = ( @@ -2628,6 +2653,7 @@ 514E6BD924ACEA0400AC6F6E /* TimelineItemView.swift */, 51919FF024AB864A00541E64 /* TimelineModel.swift */, 51919FF624AB8B7700541E64 /* TimelineView.swift */, + 514E6C0124AD29A300AC6F6E /* TimelineItemStatusView.swift */, ); path = Timeline; sourceTree = ""; @@ -2700,7 +2726,9 @@ 51E49A0224A91FF600B667CB /* SceneNavigationView.swift */, 51C0513824A77DF800194D5E /* Assets.xcassets */, 51919FB124AAB95300541E64 /* Images */, + 514E6BFD24AD252400AC6F6E /* Previews */, 51E499FB24A9135A00B667CB /* Sidebar */, + 514E6C0424AD2B0400AC6F6E /* SwiftUI Extensions */, 51919FCB24AB855000541E64 /* Timeline */, ); path = Shared; @@ -4732,6 +4760,7 @@ 514E6BDA24ACEA0400AC6F6E /* TimelineItemView.swift in Sources */, 51E4990D24A808C500B667CB /* RSHTMLMetadata+Extension.swift in Sources */, 51919FF424AB869C00541E64 /* TimelineItem.swift in Sources */, + 514E6C0224AD29A300AC6F6E /* TimelineItemStatusView.swift in Sources */, 51E49A0024A91FC100B667CB /* RegularSidebarContainerView.swift in Sources */, 51E4995C24A875F300B667CB /* ArticleRenderer.swift in Sources */, 51E4992324A8095700B667CB /* URL-Extensions.swift in Sources */, @@ -4743,6 +4772,7 @@ 172199F124AB716900A31D04 /* SidebarToolbar.swift in Sources */, 51E4990B24A808C500B667CB /* ImageDownloader.swift in Sources */, 51E498F424A8085D00B667CB /* SmartFeedDelegate.swift in Sources */, + 514E6BFF24AD255D00AC6F6E /* PreviewArticles.swift in Sources */, 51E4993024A8676400B667CB /* ArticleSorter.swift in Sources */, 51408B7E24A9EC6F0073CF4E /* SidebarItem.swift in Sources */, 51E4990A24A808C500B667CB /* FeaturedImageDownloader.swift in Sources */, @@ -4769,6 +4799,7 @@ 51E4990F24A808CC00B667CB /* HTMLMetadataDownloader.swift in Sources */, 51E4993124A8676400B667CB /* FetchRequestOperation.swift in Sources */, 51E4992624A80AAB00B667CB /* AppAssets.swift in Sources */, + 514E6C0624AD2B5F00AC6F6E /* Image-Extensions.swift in Sources */, 51E4995624A8734D00B667CB /* TwitterFeedProvider-Extensions.swift in Sources */, 51E4992924A866F000B667CB /* AppDefaults.swift in Sources */, 51E4996824A8760C00B667CB /* ArticleStyle.swift in Sources */, @@ -4821,6 +4852,7 @@ 51E4990824A808C300B667CB /* RSHTMLMetadata+Extension.swift in Sources */, 51919FF824AB8B7700541E64 /* TimelineView.swift in Sources */, 51E4992B24A8676300B667CB /* ArticleArray.swift in Sources */, + 514E6C0724AD2B5F00AC6F6E /* Image-Extensions.swift in Sources */, 51E4994D24A8734C00B667CB /* ExtensionPointIdentifer.swift in Sources */, 51E4992224A8095600B667CB /* URL-Extensions.swift in Sources */, 51E4990424A808C300B667CB /* WebFeedIconDownloader.swift in Sources */, @@ -4848,6 +4880,7 @@ 51E499D924A912C200B667CB /* SceneModel.swift in Sources */, 51919FB424AAB97900541E64 /* FeedImageLoader.swift in Sources */, 51E4994A24A8734C00B667CB /* ExtensionPointManager.swift in Sources */, + 514E6C0324AD29A300AC6F6E /* TimelineItemStatusView.swift in Sources */, 51E4996D24A8762D00B667CB /* ArticleExtractor.swift in Sources */, 51E4994024A8713B00B667CB /* AccountRefreshTimer.swift in Sources */, 51E49A0424A91FF600B667CB /* SceneNavigationView.swift in Sources */, @@ -4883,6 +4916,7 @@ 51E4996124A875F400B667CB /* ArticleRenderer.swift in Sources */, 51392D1C24AC19A000BE0D35 /* SidebarExpandedContainers.swift in Sources */, 51C0515F24A77DF800194D5E /* MainApp.swift in Sources */, + 514E6C0024AD255D00AC6F6E /* PreviewArticles.swift in Sources */, 1729529524AA1CAA00D65E66 /* GeneralPreferencesView.swift in Sources */, 1729529424AA1CAA00D65E66 /* AdvancedPreferencesView.swift in Sources */, 51E4992D24A8676300B667CB /* FetchRequestOperation.swift in Sources */,