From 9878ca4b17f4e543b926d69887b258b28529061f Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Mon, 27 Jul 2020 08:19:34 -0500 Subject: [PATCH] Switch to using LazyVStack for the Timeline --- .../Shared/Timeline/TimelineItemView.swift | 10 +- .../Shared/Timeline/TimelineView.swift | 103 ++++++++++-------- 2 files changed, 62 insertions(+), 51 deletions(-) diff --git a/Multiplatform/Shared/Timeline/TimelineItemView.swift b/Multiplatform/Shared/Timeline/TimelineItemView.swift index 955d6dd97..ab2f546a5 100644 --- a/Multiplatform/Shared/Timeline/TimelineItemView.swift +++ b/Multiplatform/Shared/Timeline/TimelineItemView.swift @@ -17,13 +17,6 @@ struct TimelineItemView: View { var width: CGFloat var timelineItem: TimelineItem - #if os(macOS) - var verticalPadding: CGFloat = 10 - #endif - #if os(iOS) - var verticalPadding: CGFloat = 0 - #endif - var body: some View { HStack(alignment: .top) { TimelineItemStatusView(selected: selected, status: timelineItem.status) @@ -65,7 +58,8 @@ struct TimelineItemView: View { } } } - .padding(.vertical, verticalPadding) + .padding(.vertical, 10) + .padding(.horizontal) .onAppear { articleIconImageLoader.loadImage(for: timelineItem.article) } diff --git a/Multiplatform/Shared/Timeline/TimelineView.swift b/Multiplatform/Shared/Timeline/TimelineView.swift index b2e8c916b..175f918ca 100644 --- a/Multiplatform/Shared/Timeline/TimelineView.swift +++ b/Multiplatform/Shared/Timeline/TimelineView.swift @@ -15,6 +15,7 @@ struct TimelineView: View { @EnvironmentObject private var timelineModel: TimelineModel + @State private var navigate = false @State private var timelineItemFrames = [String: CGRect]() @ViewBuilder var body: some View { @@ -40,24 +41,31 @@ struct TimelineView: View { .buttonStyle(PlainButtonStyle()) .help(isReadFiltered ?? false ? "Show Read Articles" : "Filter Read Articles") } - ScrollViewReader { scrollViewProxy in - List(timelineItems.items, selection: $timelineModel.selectedTimelineItemIDs) { timelineItem in - let selected = timelineModel.selectedTimelineItemIDs.contains(timelineItem.article.articleID) - TimelineItemView(selected: selected, width: geometryReaderProxy.size.width, timelineItem: timelineItem) - .background(TimelineItemFramePreferenceView(timelineItem: timelineItem)) - } - .onPreferenceChange(TimelineItemFramePreferenceKey.self) { preferences in - for pref in preferences { - timelineItemFrames[pref.articleID] = pref.frame - } - } - .onChange(of: timelineModel.selectedTimelineItemIDs) { selectedArticleIDs in - let proxyFrame = geometryReaderProxy.frame(in: .global) - for articleID in selectedArticleIDs { - if let itemFrame = timelineItemFrames[articleID] { - if itemFrame.minY < proxyFrame.minY + 3 || itemFrame.maxY > proxyFrame.maxY - 35 { - withAnimation { - scrollViewProxy.scrollTo(articleID, anchor: .center) + ScrollView { + ScrollViewReader { scrollViewProxy in + LazyVStack { + ForEach(timelineItems.items) { timelineItem in + let selected = timelineModel.selectedTimelineItemIDs.contains(timelineItem.article.articleID) + TimelineItemView(selected: selected, width: geometryReaderProxy.size.width, timelineItem: timelineItem) + .background(TimelineItemBackgroundView(selected: selected, timelineItem: timelineItem)) + .onTapGesture { + timelineModel.selectedTimelineItemIDs = Set([timelineItem.id]) + } + } + .onPreferenceChange(TimelineItemFramePreferenceKey.self) { preferences in + for pref in preferences { + timelineItemFrames[pref.articleID] = pref.frame + } + } + .onChange(of: timelineModel.selectedTimelineItemIDs) { selectedArticleIDs in + let proxyFrame = geometryReaderProxy.frame(in: .global) + for articleID in selectedArticleIDs { + if let itemFrame = timelineItemFrames[articleID] { + if itemFrame.minY < proxyFrame.minY + 3 || itemFrame.maxY > proxyFrame.maxY - 35 { + withAnimation { + scrollViewProxy.scrollTo(articleID, anchor: .center) + } + } } } } @@ -67,30 +75,36 @@ struct TimelineView: View { } .navigationTitle(Text(verbatim: timelineModel.nameForDisplay)) #else - ScrollViewReader { scrollViewProxy in - List(timelineItems.items) { timelineItem in - ZStack { - let selected = timelineModel.selectedTimelineItemID == timelineItem.article.articleID - TimelineItemView(selected: selected, width: geometryReaderProxy.size.width, timelineItem: timelineItem) - .background(TimelineItemFramePreferenceView(timelineItem: timelineItem)) - NavigationLink(destination: ArticleContainerView(), - tag: timelineItem.article.articleID, - selection: $timelineModel.selectedTimelineItemID) { - EmptyView() - }.buttonStyle(PlainButtonStyle()) - } + ZStack { + NavigationLink(destination: ArticleView(), isActive: $navigate) { + EmptyView() } - .onPreferenceChange(TimelineItemFramePreferenceKey.self) { preferences in - for pref in preferences { - timelineItemFrames[pref.articleID] = pref.frame - } - } - .onChange(of: timelineModel.selectedTimelineItemID) { selectedArticleID in - let proxyFrame = geometryReaderProxy.frame(in: .global) - if let articleID = selectedArticleID, let itemFrame = timelineItemFrames[articleID] { - if itemFrame.minY < proxyFrame.minY + 3 || itemFrame.maxY > proxyFrame.maxY - 3 { - withAnimation { - scrollViewProxy.scrollTo(articleID, anchor: .center) + ScrollView { + ScrollViewReader { scrollViewProxy in + LazyVStack { + ForEach(timelineItems.items) { timelineItem in + let selected = timelineModel.selectedTimelineItemID == timelineItem.article.articleID + TimelineItemView(selected: selected, width: geometryReaderProxy.size.width, timelineItem: timelineItem) + .background(TimelineItemBackgroundView(selected: selected, timelineItem: timelineItem)) + .onTapGesture { + timelineModel.selectedTimelineItemIDs = Set([timelineItem.id]) + navigate = true + } + } + } + .onPreferenceChange(TimelineItemFramePreferenceKey.self) { preferences in + for pref in preferences { + timelineItemFrames[pref.articleID] = pref.frame + } + } + .onChange(of: timelineModel.selectedTimelineItemID) { selectedArticleID in + let proxyFrame = geometryReaderProxy.frame(in: .global) + if let articleID = selectedArticleID, let itemFrame = timelineItemFrames[articleID] { + if itemFrame.minY < proxyFrame.minY + 3 || itemFrame.maxY > proxyFrame.maxY - 3 { + withAnimation { + scrollViewProxy.scrollTo(articleID, anchor: .center) + } + } } } } @@ -118,13 +132,16 @@ struct TimelineItemFramePreference: Equatable { let frame: CGRect } -struct TimelineItemFramePreferenceView: View { +struct TimelineItemBackgroundView: View { + + let selected: Bool let timelineItem: TimelineItem var body: some View { GeometryReader { proxy in Rectangle() - .fill(Color.clear) + .fill(selected ? Color.accentColor : Color.clear) + .cornerRadius(6) .preference(key: TimelineItemFramePreferenceKey.self, value: [TimelineItemFramePreference(articleID: timelineItem.article.articleID, frame: proxy.frame(in: .global))]) }